Coverage Report

Created: 2026-06-07 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/map.c
Line
Count
Source
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/license/                                         %
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
30
{
102
30
  Image
103
30
    *image;
104
105
30
  MagickBooleanType
106
30
    status;
107
108
30
  Quantum
109
30
    index;
110
111
30
  Quantum
112
30
    *q;
113
114
30
  size_t
115
30
    depth,
116
30
    packet_size,
117
30
    quantum;
118
119
30
  ssize_t
120
30
    count,
121
30
    i,
122
30
    x,
123
30
    y;
124
125
30
  unsigned char
126
30
    *colormap,
127
30
    *p,
128
30
    *pixels;
129
130
  /*
131
    Open image file.
132
  */
133
30
  assert(image_info != (const ImageInfo *) NULL);
134
30
  assert(image_info->signature == MagickCoreSignature);
135
30
  assert(exception != (ExceptionInfo *) NULL);
136
30
  assert(exception->signature == MagickCoreSignature);
137
30
  if (IsEventLogging() != MagickFalse)
138
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
139
0
      image_info->filename);
140
30
  image=AcquireImage(image_info,exception);
141
30
  if ((image->columns == 0) || (image->rows == 0))
142
28
    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
  if ((depth <= 8) && (image->colors > 256))
164
0
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
165
0
  packet_size=(size_t) (depth/8);
166
0
  pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
167
0
    sizeof(*pixels));
168
0
  packet_size=(size_t) (depth > 8 ? 6UL : 3UL);
169
0
  colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
170
0
    sizeof(*colormap));
171
0
  if ((pixels == (unsigned char *) NULL) ||
172
0
      (colormap == (unsigned char *) NULL))
173
0
    {
174
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
175
0
      colormap=(unsigned char *) RelinquishMagickMemory(colormap);
176
0
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
177
0
    }
178
  /*
179
    Read image colormap.
180
  */
181
0
  count=ReadBlob(image,packet_size*image->colors,colormap);
182
0
  if (count != (ssize_t) (packet_size*image->colors))
183
0
    {
184
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
185
0
      colormap=(unsigned char *) RelinquishMagickMemory(colormap);
186
0
      ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
187
0
    }
188
0
  p=colormap;
189
0
  if (image->depth <= 8)
190
0
    for (i=0; i < (ssize_t) image->colors; i++)
191
0
    {
192
0
      image->colormap[i].red=ScaleCharToQuantum(*p++);
193
0
      image->colormap[i].green=ScaleCharToQuantum(*p++);
194
0
      image->colormap[i].blue=ScaleCharToQuantum(*p++);
195
0
    }
196
0
  else
197
0
    for (i=0; i < (ssize_t) image->colors; i++)
198
0
    {
199
0
      quantum=(size_t) (*p++ << 8);
200
0
      quantum|=(*p++);
201
0
      image->colormap[i].red=(Quantum) quantum;
202
0
      quantum=(size_t) (*p++ << 8);
203
0
      quantum|=(size_t) (*p++);
204
0
      image->colormap[i].green=(Quantum) quantum;
205
0
      quantum=(size_t) (*p++ << 8);
206
0
      quantum|=(*p++);
207
0
      image->colormap[i].blue=(Quantum) quantum;
208
0
    }
209
0
  colormap=(unsigned char *) RelinquishMagickMemory(colormap);
210
0
  if (image_info->ping != MagickFalse)
211
0
    {
212
0
      (void) CloseBlob(image);
213
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
214
0
      return(GetFirstImageInList(image));
215
0
    }
216
0
  status=SetImageExtent(image,image->columns,image->rows,exception);
217
0
  if (status == MagickFalse)
218
0
    {
219
0
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
220
0
      return(DestroyImageList(image));
221
0
    }
222
  /*
223
    Read image pixels.
224
  */
225
0
  packet_size=(size_t) (depth/8);
226
0
  for (y=0; y < (ssize_t) image->rows; y++)
227
0
  {
228
0
    p=pixels;
229
0
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
230
0
    if (q == (Quantum *) NULL)
231
0
      break;
232
0
    count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
233
0
    if (count != (ssize_t) (packet_size*image->columns))
234
0
      break;
235
0
    for (x=0; x < (ssize_t) image->columns; x++)
236
0
    {
237
0
      index=(Quantum) ConstrainColormapIndex(image,*p,exception);
238
0
      p++;
239
0
      if (image->colors > 256)
240
0
        {
241
0
          index=(Quantum) ConstrainColormapIndex(image,(ssize_t)
242
0
            (((size_t) index << 8)+(size_t) (*p)),exception);
243
0
          p++;
244
0
        }
245
0
      SetPixelIndex(image,index,q);
246
0
      SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
247
0
      q+=(ptrdiff_t) GetPixelChannels(image);
248
0
    }
249
0
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
250
0
      break;
251
0
  }
252
0
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
253
0
  if (y < (ssize_t) image->rows)
254
0
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
255
0
      image->filename);
256
0
  if (CloseBlob(image) == MagickFalse)
257
0
    status=MagickFalse;
258
0
  if (status == MagickFalse)
259
0
    return(DestroyImageList(image));
260
0
  return(GetFirstImageInList(image));
261
0
}
262

263
/*
264
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265
%                                                                             %
266
%                                                                             %
267
%                                                                             %
268
%   R e g i s t e r M A P I m a g e                                           %
269
%                                                                             %
270
%                                                                             %
271
%                                                                             %
272
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273
%
274
%  RegisterMAPImage() adds attributes for the MAP image format to
275
%  the list of supported formats.  The attributes include the image format
276
%  tag, a method to read and/or write the format, whether the format
277
%  supports the saving of more than one frame to the same file or blob,
278
%  whether the format supports native in-memory I/O, and a brief
279
%  description of the format.
280
%
281
%  The format of the RegisterMAPImage method is:
282
%
283
%      size_t RegisterMAPImage(void)
284
%
285
*/
286
ModuleExport size_t RegisterMAPImage(void)
287
9
{
288
9
  MagickInfo
289
9
    *entry;
290
291
9
  entry=AcquireMagickInfo("MAP","MAP","Colormap intensities and indices");
292
9
  entry->decoder=(DecodeImageHandler *) ReadMAPImage;
293
9
  entry->encoder=(EncodeImageHandler *) WriteMAPImage;
294
9
  entry->flags^=CoderAdjoinFlag;
295
9
  entry->format_type=ExplicitFormatType;
296
9
  entry->flags|=CoderRawSupportFlag;
297
9
  entry->flags|=CoderEndianSupportFlag;
298
9
  (void) RegisterMagickInfo(entry);
299
9
  return(MagickImageCoderSignature);
300
9
}
301

302
/*
303
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304
%                                                                             %
305
%                                                                             %
306
%                                                                             %
307
%   U n r e g i s t e r M A P I m a g e                                       %
308
%                                                                             %
309
%                                                                             %
310
%                                                                             %
311
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312
%
313
%  UnregisterMAPImage() removes format registrations made by the
314
%  MAP module from the list of supported formats.
315
%
316
%  The format of the UnregisterMAPImage method is:
317
%
318
%      UnregisterMAPImage(void)
319
%
320
*/
321
ModuleExport void UnregisterMAPImage(void)
322
0
{
323
0
  (void) UnregisterMagickInfo("MAP");
324
0
}
325

326
/*
327
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328
%                                                                             %
329
%                                                                             %
330
%                                                                             %
331
%   W r i t e M A P I m a g e                                                 %
332
%                                                                             %
333
%                                                                             %
334
%                                                                             %
335
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336
%
337
%  WriteMAPImage() writes an image to a file as red, green, and blue
338
%  colormap bytes followed by the colormap indexes.
339
%
340
%  The format of the WriteMAPImage method is:
341
%
342
%      MagickBooleanType WriteMAPImage(const ImageInfo *image_info,
343
%        Image *image,ExceptionInfo *exception)
344
%
345
%  A description of each parameter follows.
346
%
347
%    o image_info: the image info.
348
%
349
%    o image:  The image.
350
%
351
%    o exception: return any errors or warnings in this structure.
352
%
353
*/
354
static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image,
355
  ExceptionInfo *exception)
356
0
{
357
0
  MagickBooleanType
358
0
    status;
359
360
0
  const Quantum
361
0
    *p;
362
363
0
  ssize_t
364
0
    i,
365
0
    x;
366
367
0
  unsigned char
368
0
    *q;
369
370
0
  size_t
371
0
    depth,
372
0
    packet_size;
373
374
0
  ssize_t
375
0
    y;
376
377
0
  unsigned char
378
0
    *colormap,
379
0
    *pixels;
380
381
  /*
382
    Open output image file.
383
  */
384
0
  assert(image_info != (const ImageInfo *) NULL);
385
0
  assert(image_info->signature == MagickCoreSignature);
386
0
  assert(image != (Image *) NULL);
387
0
  assert(image->signature == MagickCoreSignature);
388
0
  assert(exception != (ExceptionInfo *) NULL);
389
0
  assert(exception->signature == MagickCoreSignature);
390
0
  if (IsEventLogging() != MagickFalse)
391
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
392
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
393
0
  if (status == MagickFalse)
394
0
    return(status);
395
0
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
396
0
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
397
  /*
398
    Allocate colormap.
399
  */
400
0
  if (SetImageType(image,PaletteType,exception) == MagickFalse)
401
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
402
0
  depth=GetImageQuantumDepth(image,MagickTrue);
403
0
  packet_size=(size_t) (depth/8);
404
0
  pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
405
0
    sizeof(*pixels));
406
0
  packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
407
0
  colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
408
0
    sizeof(*colormap));
409
0
  if ((pixels == (unsigned char *) NULL) ||
410
0
      (colormap == (unsigned char *) NULL))
411
0
    {
412
0
      if (colormap != (unsigned char *) NULL)
413
0
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
414
0
      if (pixels != (unsigned char *) NULL)
415
0
        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
416
0
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
417
0
    }
418
  /*
419
    Write colormap to file.
420
  */
421
0
  q=colormap;
422
0
  if (image->colors <= 256)
423
0
    for (i=0; i < (ssize_t) image->colors; i++)
424
0
    {
425
0
      *q++=(unsigned char) ScaleQuantumToChar((Quantum) image->colormap[i].red);
426
0
      *q++=(unsigned char) ScaleQuantumToChar((Quantum) image->colormap[i].green);
427
0
      *q++=(unsigned char) ScaleQuantumToChar((Quantum) image->colormap[i].blue);
428
0
    }
429
0
  else
430
0
    for (i=0; i < (ssize_t) image->colors; i++)
431
0
    {
432
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].red) >> 8);
433
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].red) & 0xff);
434
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].green) >> 8);
435
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].green) &
436
0
        0xff);
437
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].blue) >> 8);
438
0
      *q++=(unsigned char) (ScaleQuantumToShort((Quantum) image->colormap[i].blue) &
439
0
        0xff);
440
0
    }
441
0
  (void) WriteBlob(image,packet_size*image->colors,colormap);
442
0
  colormap=(unsigned char *) RelinquishMagickMemory(colormap);
443
  /*
444
    Write image pixels to file.
445
  */
446
0
  for (y=0; y < (ssize_t) image->rows; y++)
447
0
  {
448
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
449
0
    if (p == (const Quantum *) NULL)
450
0
      break;
451
0
    q=pixels;
452
0
    for (x=0; x < (ssize_t) image->columns; x++)
453
0
    {
454
0
      if (image->colors > 256)
455
0
        *q++=(unsigned char) ((size_t) GetPixelIndex(image,p) >> 8);
456
0
      *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
457
0
      p+=(ptrdiff_t) GetPixelChannels(image);
458
0
    }
459
0
    (void) WriteBlob(image,(size_t) (q-pixels),pixels);
460
0
  }
461
0
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
462
0
  if (CloseBlob(image) == MagickFalse)
463
0
    status=MagickFalse;
464
0
  return(status);
465
0
}