Coverage Report

Created: 2025-06-16 07:00

/src/imagemagick/coders/map.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            M   M   AAA   PPPP                               %
7
%                            MM MM  A   A  P   P                              %
8
%                            M M M  AAAAA  PPPP                               %
9
%                            M   M  A   A  P                                  %
10
%                            M   M  A   A  P                                  %
11
%                                                                             %
12
%                                                                             %
13
%                  Read/Write Image Colormaps as an Image File.               %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/script/license.php                               %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/attribute.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/color.h"
48
#include "MagickCore/color-private.h"
49
#include "MagickCore/colormap.h"
50
#include "MagickCore/colormap-private.h"
51
#include "MagickCore/colorspace.h"
52
#include "MagickCore/colorspace-private.h"
53
#include "MagickCore/exception.h"
54
#include "MagickCore/exception-private.h"
55
#include "MagickCore/histogram.h"
56
#include "MagickCore/image.h"
57
#include "MagickCore/image-private.h"
58
#include "MagickCore/list.h"
59
#include "MagickCore/magick.h"
60
#include "MagickCore/memory_.h"
61
#include "MagickCore/pixel-accessor.h"
62
#include "MagickCore/quantum-private.h"
63
#include "MagickCore/static.h"
64
#include "MagickCore/statistic.h"
65
#include "MagickCore/string_.h"
66
#include "MagickCore/module.h"
67

68
/*
69
  Forward declarations.
70
*/
71
static MagickBooleanType
72
  WriteMAPImage(const ImageInfo *,Image *,ExceptionInfo *);
73

74
/*
75
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76
%                                                                             %
77
%                                                                             %
78
%                                                                             %
79
%   R e a d M A P I m a g e                                                   %
80
%                                                                             %
81
%                                                                             %
82
%                                                                             %
83
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84
%
85
%  ReadMAPImage() reads an image of raw RGB colormap and colormap index
86
%  bytes and returns it.  It allocates the memory necessary for the new Image
87
%  structure and returns a pointer to the new image.
88
%
89
%  The format of the ReadMAPImage method is:
90
%
91
%      Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
92
%
93
%  A description of each parameter follows:
94
%
95
%    o image_info: the image info.
96
%
97
%    o exception: return any errors or warnings in this structure.
98
%
99
*/
100
static Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
101
185
{
102
185
  Image
103
185
    *image;
104
105
185
  MagickBooleanType
106
185
    status;
107
108
185
  Quantum
109
185
    index;
110
111
185
  Quantum
112
185
    *q;
113
114
185
  size_t
115
185
    depth,
116
185
    packet_size,
117
185
    quantum;
118
119
185
  ssize_t
120
185
    count,
121
185
    i,
122
185
    x,
123
185
    y;
124
125
185
  unsigned char
126
185
    *colormap,
127
185
    *p,
128
185
    *pixels;
129
130
  /*
131
    Open image file.
132
  */
133
185
  assert(image_info != (const ImageInfo *) NULL);
134
185
  assert(image_info->signature == MagickCoreSignature);
135
185
  assert(exception != (ExceptionInfo *) NULL);
136
185
  assert(exception->signature == MagickCoreSignature);
137
185
  if (IsEventLogging() != MagickFalse)
138
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
139
0
      image_info->filename);
140
185
  image=AcquireImage(image_info,exception);
141
185
  if ((image->columns == 0) || (image->rows == 0))
142
183
    ThrowReaderException(OptionError,"MustSpecifyImageSize");
143
2
  if (image_info->depth == 0)
144
2
    ThrowReaderException(OptionError,"MustSpecifyImageDepth");
145
0
  status=SetImageExtent(image,image->columns,image->rows,exception);
146
0
  if (status == MagickFalse)
147
0
    return(DestroyImageList(image));
148
0
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
149
0
  if (status == MagickFalse)
150
0
    {
151
0
      image=DestroyImageList(image);
152
0
      return((Image *) NULL);
153
0
    }
154
  /*
155
    Initialize image structure.
156
  */
157
0
  image->storage_class=PseudoClass;
158
0
  status=AcquireImageColormap(image,(size_t)
159
0
    (image->offset != 0 ? image->offset : 256),exception);
160
0
  if (status == MagickFalse)
161
0
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
162
0
  depth=GetImageQuantumDepth(image,MagickTrue);
163
0
  packet_size=(size_t) (depth/8);
164
0
  pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
165
0
    sizeof(*pixels));
166
0
  packet_size=(size_t) (depth > 8 ? 6UL : 3UL);
167
0
  colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
168
0
    sizeof(*colormap));
169
0
  if ((pixels == (unsigned char *) NULL) ||
170
0
      (colormap == (unsigned char *) NULL))
171
0
    {
172
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
173
0
      colormap=(unsigned char *) RelinquishMagickMemory(colormap);
174
0
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
175
0
    }
176
  /*
177
    Read image colormap.
178
  */
179
0
  count=ReadBlob(image,packet_size*image->colors,colormap);
180
0
  if (count != (ssize_t) (packet_size*image->colors))
181
0
    {
182
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
183
0
      colormap=(unsigned char *) RelinquishMagickMemory(colormap);
184
0
      ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
185
0
    }
186
0
  p=colormap;
187
0
  if (image->depth <= 8)
188
0
    for (i=0; i < (ssize_t) image->colors; i++)
189
0
    {
190
0
      image->colormap[i].red=ScaleCharToQuantum(*p++);
191
0
      image->colormap[i].green=ScaleCharToQuantum(*p++);
192
0
      image->colormap[i].blue=ScaleCharToQuantum(*p++);
193
0
    }
194
0
  else
195
0
    for (i=0; i < (ssize_t) image->colors; i++)
196
0
    {
197
0
      quantum=(size_t) (*p++ << 8);
198
0
      quantum|=(*p++);
199
0
      image->colormap[i].red=(Quantum) quantum;
200
0
      quantum=(size_t) (*p++ << 8);
201
0
      quantum|=(size_t) (*p++);
202
0
      image->colormap[i].green=(Quantum) quantum;
203
0
      quantum=(size_t) (*p++ << 8);
204
0
      quantum|=(*p++);
205
0
      image->colormap[i].blue=(Quantum) quantum;
206
0
    }
207
0
  colormap=(unsigned char *) RelinquishMagickMemory(colormap);
208
0
  if (image_info->ping != MagickFalse)
209
0
    {
210
0
      (void) CloseBlob(image);
211
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
212
0
      return(GetFirstImageInList(image));
213
0
    }
214
0
  status=SetImageExtent(image,image->columns,image->rows,exception);
215
0
  if (status == MagickFalse)
216
0
    {
217
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
218
0
      return(DestroyImageList(image));
219
0
    }
220
  /*
221
    Read image pixels.
222
  */
223
0
  packet_size=(size_t) (depth/8);
224
0
  for (y=0; y < (ssize_t) image->rows; y++)
225
0
  {
226
0
    p=pixels;
227
0
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
228
0
    if (q == (Quantum *) NULL)
229
0
      break;
230
0
    count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
231
0
    if (count != (ssize_t) (packet_size*image->columns))
232
0
      break;
233
0
    for (x=0; x < (ssize_t) image->columns; x++)
234
0
    {
235
0
      index=(Quantum) ConstrainColormapIndex(image,*p,exception);
236
0
      p++;
237
0
      if (image->colors > 256)
238
0
        {
239
0
          index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (((size_t) index << 8)+
240
0
            (size_t) (*p)),exception);
241
0
          p++;
242
0
        }
243
0
      SetPixelIndex(image,index,q);
244
0
      SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
245
0
      q+=(ptrdiff_t) GetPixelChannels(image);
246
0
    }
247
0
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
248
0
      break;
249
0
  }
250
0
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
251
0
  if (y < (ssize_t) image->rows)
252
0
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
253
0
      image->filename);
254
0
  if (CloseBlob(image) == MagickFalse)
255
0
    status=MagickFalse;
256
0
  if (status == MagickFalse)
257
0
    return(DestroyImageList(image));
258
0
  return(GetFirstImageInList(image));
259
0
}
260

261
/*
262
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263
%                                                                             %
264
%                                                                             %
265
%                                                                             %
266
%   R e g i s t e r M A P I m a g e                                           %
267
%                                                                             %
268
%                                                                             %
269
%                                                                             %
270
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271
%
272
%  RegisterMAPImage() adds attributes for the MAP image format to
273
%  the list of supported formats.  The attributes include the image format
274
%  tag, a method to read and/or write the format, whether the format
275
%  supports the saving of more than one frame to the same file or blob,
276
%  whether the format supports native in-memory I/O, and a brief
277
%  description of the format.
278
%
279
%  The format of the RegisterMAPImage method is:
280
%
281
%      size_t RegisterMAPImage(void)
282
%
283
*/
284
ModuleExport size_t RegisterMAPImage(void)
285
9
{
286
9
  MagickInfo
287
9
    *entry;
288
289
9
  entry=AcquireMagickInfo("MAP","MAP","Colormap intensities and indices");
290
9
  entry->decoder=(DecodeImageHandler *) ReadMAPImage;
291
9
  entry->encoder=(EncodeImageHandler *) WriteMAPImage;
292
9
  entry->flags^=CoderAdjoinFlag;
293
9
  entry->format_type=ExplicitFormatType;
294
9
  entry->flags|=CoderRawSupportFlag;
295
9
  entry->flags|=CoderEndianSupportFlag;
296
9
  (void) RegisterMagickInfo(entry);
297
9
  return(MagickImageCoderSignature);
298
9
}
299

300
/*
301
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302
%                                                                             %
303
%                                                                             %
304
%                                                                             %
305
%   U n r e g i s t e r M A P I m a g e                                       %
306
%                                                                             %
307
%                                                                             %
308
%                                                                             %
309
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310
%
311
%  UnregisterMAPImage() removes format registrations made by the
312
%  MAP module from the list of supported formats.
313
%
314
%  The format of the UnregisterMAPImage method is:
315
%
316
%      UnregisterMAPImage(void)
317
%
318
*/
319
ModuleExport void UnregisterMAPImage(void)
320
0
{
321
0
  (void) UnregisterMagickInfo("MAP");
322
0
}
323

324
/*
325
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326
%                                                                             %
327
%                                                                             %
328
%                                                                             %
329
%   W r i t e M A P I m a g e                                                 %
330
%                                                                             %
331
%                                                                             %
332
%                                                                             %
333
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334
%
335
%  WriteMAPImage() writes an image to a file as red, green, and blue
336
%  colormap bytes followed by the colormap indexes.
337
%
338
%  The format of the WriteMAPImage method is:
339
%
340
%      MagickBooleanType WriteMAPImage(const ImageInfo *image_info,
341
%        Image *image,ExceptionInfo *exception)
342
%
343
%  A description of each parameter follows.
344
%
345
%    o image_info: the image info.
346
%
347
%    o image:  The image.
348
%
349
%    o exception: return any errors or warnings in this structure.
350
%
351
*/
352
static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image,
353
  ExceptionInfo *exception)
354
0
{
355
0
  MagickBooleanType
356
0
    status;
357
358
0
  const Quantum
359
0
    *p;
360
361
0
  ssize_t
362
0
    i,
363
0
    x;
364
365
0
  unsigned char
366
0
    *q;
367
368
0
  size_t
369
0
    depth,
370
0
    packet_size;
371
372
0
  ssize_t
373
0
    y;
374
375
0
  unsigned char
376
0
    *colormap,
377
0
    *pixels;
378
379
  /*
380
    Open output image file.
381
  */
382
0
  assert(image_info != (const ImageInfo *) NULL);
383
0
  assert(image_info->signature == MagickCoreSignature);
384
0
  assert(image != (Image *) NULL);
385
0
  assert(image->signature == MagickCoreSignature);
386
0
  assert(exception != (ExceptionInfo *) NULL);
387
0
  assert(exception->signature == MagickCoreSignature);
388
0
  if (IsEventLogging() != MagickFalse)
389
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
390
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
391
0
  if (status == MagickFalse)
392
0
    return(status);
393
0
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
394
0
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
395
  /*
396
    Allocate colormap.
397
  */
398
0
  if (SetImageType(image,PaletteType,exception) == MagickFalse)
399
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
400
0
  depth=GetImageQuantumDepth(image,MagickTrue);
401
0
  packet_size=(size_t) (depth/8);
402
0
  pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
403
0
    sizeof(*pixels));
404
0
  packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
405
0
  colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
406
0
    sizeof(*colormap));
407
0
  if ((pixels == (unsigned char *) NULL) ||
408
0
      (colormap == (unsigned char *) NULL))
409
0
    {
410
0
      if (colormap != (unsigned char *) NULL)
411
0
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
412
0
      if (pixels != (unsigned char *) NULL)
413
0
        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
414
0
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
415
0
    }
416
  /*
417
    Write colormap to file.
418
  */
419
0
  q=colormap;
420
0
  if (image->colors <= 256)
421
0
    for (i=0; i < (ssize_t) image->colors; i++)
422
0
    {
423
0
      *q++=(unsigned char) ScaleQuantumToChar((Quantum) image->colormap[i].red);
424
0
      *q++=(unsigned char) ScaleQuantumToChar((Quantum) image->colormap[i].green);
425
0
      *q++=(unsigned char) ScaleQuantumToChar((Quantum) image->colormap[i].blue);
426
0
    }
427
0
  else
428
0
    for (i=0; i < (ssize_t) image->colors; i++)
429
0
    {
430
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].red) >> 8);
431
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].red) & 0xff);
432
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].green) >> 8);
433
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].green) &
434
0
        0xff);
435
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].blue) >> 8);
436
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].blue) &
437
0
        0xff);
438
0
    }
439
0
  (void) WriteBlob(image,packet_size*image->colors,colormap);
440
0
  colormap=(unsigned char *) RelinquishMagickMemory(colormap);
441
  /*
442
    Write image pixels to file.
443
  */
444
0
  for (y=0; y < (ssize_t) image->rows; y++)
445
0
  {
446
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
447
0
    if (p == (const Quantum *) NULL)
448
0
      break;
449
0
    q=pixels;
450
0
    for (x=0; x < (ssize_t) image->columns; x++)
451
0
    {
452
0
      if (image->colors > 256)
453
0
        *q++=(unsigned char) ((size_t) GetPixelIndex(image,p) >> 8);
454
0
      *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
455
0
      p+=(ptrdiff_t) GetPixelChannels(image);
456
0
    }
457
0
    (void) WriteBlob(image,(size_t) (q-pixels),pixels);
458
0
  }
459
0
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
460
0
  if (CloseBlob(image) == MagickFalse)
461
0
    status=MagickFalse;
462
0
  return(status);
463
0
}