blob: 5b6e5749f270997a9ff808f99f178765691577fe [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy510d06a2011-07-06 23:43:54 +000052#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000053#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"
cristy3ed852e2009-09-05 21:47:34 +000067
68/*
69 Forward declarations.
70*/
71static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000072 WriteMAPImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000073
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*/
100static Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
101{
102 Image
103 *image;
104
cristy3ed852e2009-09-05 21:47:34 +0000105 MagickBooleanType
106 status;
107
cristy4c08aed2011-07-01 19:47:50 +0000108 Quantum
109 index;
cristy3ed852e2009-09-05 21:47:34 +0000110
cristybb503372010-05-27 20:51:26 +0000111 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000112 x;
113
cristy4c08aed2011-07-01 19:47:50 +0000114 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000115 *q;
116
cristybb503372010-05-27 20:51:26 +0000117 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000118 i;
119
120 register unsigned char
121 *p;
122
123 size_t
cristy524222d2011-04-25 00:37:06 +0000124 depth,
125 packet_size,
126 quantum;
cristy3ed852e2009-09-05 21:47:34 +0000127
128 ssize_t
cristy524222d2011-04-25 00:37:06 +0000129 count,
130 y;
cristy3ed852e2009-09-05 21:47:34 +0000131
132 unsigned char
133 *colormap,
134 *pixels;
135
cristy3ed852e2009-09-05 21:47:34 +0000136 /*
137 Open image file.
138 */
139 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000140 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000141 if (image_info->debug != MagickFalse)
142 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
143 image_info->filename);
144 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000145 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000146 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000147 if ((image->columns == 0) || (image->rows == 0))
148 ThrowReaderException(OptionError,"MustSpecifyImageSize");
149 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
150 if (status == MagickFalse)
151 {
152 image=DestroyImageList(image);
153 return((Image *) NULL);
154 }
155 /*
156 Initialize image structure.
157 */
158 image->storage_class=PseudoClass;
cristybb503372010-05-27 20:51:26 +0000159 status=AcquireImageColormap(image,(size_t)
cristy018f07f2011-09-04 21:15:19 +0000160 (image->offset != 0 ? image->offset : 256),exception);
cristy3ed852e2009-09-05 21:47:34 +0000161 if (status == MagickFalse)
162 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
163 depth=GetImageQuantumDepth(image,MagickTrue);
164 packet_size=(size_t) (depth/8);
165 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
166 sizeof(*pixels));
167 packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
168 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
169 sizeof(*colormap));
170 if ((pixels == (unsigned char *) NULL) ||
171 (colormap == (unsigned char *) NULL))
172 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
173 /*
174 Read image colormap.
175 */
176 count=ReadBlob(image,packet_size*image->colors,colormap);
177 if (count != (ssize_t) (packet_size*image->colors))
178 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
179 p=colormap;
180 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +0000181 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000182 {
183 image->colormap[i].red=ScaleCharToQuantum(*p++);
184 image->colormap[i].green=ScaleCharToQuantum(*p++);
185 image->colormap[i].blue=ScaleCharToQuantum(*p++);
186 }
187 else
cristybb503372010-05-27 20:51:26 +0000188 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000189 {
190 quantum=(*p++ << 8);
191 quantum|=(*p++);
192 image->colormap[i].red=(Quantum) quantum;
193 quantum=(*p++ << 8);
194 quantum|=(*p++);
195 image->colormap[i].green=(Quantum) quantum;
196 quantum=(*p++ << 8);
197 quantum|=(*p++);
198 image->colormap[i].blue=(Quantum) quantum;
199 }
200 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
201 if (image_info->ping != MagickFalse)
202 {
203 (void) CloseBlob(image);
204 return(GetFirstImageInList(image));
205 }
cristyacabb842014-12-14 23:36:33 +0000206 status=SetImageExtent(image,image->columns,image->rows,exception);
207 if (status == MagickFalse)
208 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000209 /*
210 Read image pixels.
211 */
212 packet_size=(size_t) (depth/8);
cristybb503372010-05-27 20:51:26 +0000213 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000214 {
215 p=pixels;
216 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000217 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000218 break;
cristy3ed852e2009-09-05 21:47:34 +0000219 count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
220 if (count != (ssize_t) (packet_size*image->columns))
221 break;
cristybb503372010-05-27 20:51:26 +0000222 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000223 {
cristyc82a27b2011-10-21 01:07:16 +0000224 index=ConstrainColormapIndex(image,*p,exception);
cristy3ed852e2009-09-05 21:47:34 +0000225 p++;
226 if (image->colors > 256)
227 {
cristyc82a27b2011-10-21 01:07:16 +0000228 index=ConstrainColormapIndex(image,((size_t) index << 8)+(*p),
229 exception);
cristy3ed852e2009-09-05 21:47:34 +0000230 p++;
231 }
cristy4c08aed2011-07-01 19:47:50 +0000232 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000233 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000234 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000235 }
236 if (SyncAuthenticPixels(image,exception) == MagickFalse)
237 break;
238 }
239 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
cristybb503372010-05-27 20:51:26 +0000240 if (y < (ssize_t) image->rows)
cristy3ed852e2009-09-05 21:47:34 +0000241 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
242 image->filename);
243 (void) CloseBlob(image);
244 return(GetFirstImageInList(image));
245}
246
247/*
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249% %
250% %
251% %
252% R e g i s t e r M A P I m a g e %
253% %
254% %
255% %
256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257%
258% RegisterMAPImage() adds attributes for the MAP image format to
259% the list of supported formats. The attributes include the image format
260% tag, a method to read and/or write the format, whether the format
261% supports the saving of more than one frame to the same file or blob,
262% whether the format supports native in-memory I/O, and a brief
263% description of the format.
264%
265% The format of the RegisterMAPImage method is:
266%
cristybb503372010-05-27 20:51:26 +0000267% size_t RegisterMAPImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000268%
269*/
cristybb503372010-05-27 20:51:26 +0000270ModuleExport size_t RegisterMAPImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000271{
272 MagickInfo
273 *entry;
274
dirk06b627a2015-04-06 18:59:17 +0000275 entry=AcquireMagickInfo("MAP","MAP","Colormap intensities and indices");
cristy3ed852e2009-09-05 21:47:34 +0000276 entry->decoder=(DecodeImageHandler *) ReadMAPImage;
277 entry->encoder=(EncodeImageHandler *) WriteMAPImage;
dirk08e9a112015-02-22 01:51:41 +0000278 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000279 entry->format_type=ExplicitFormatType;
dirk08e9a112015-02-22 01:51:41 +0000280 entry->flags|=CoderRawSupportFlag;
281 entry->flags|=CoderEndianSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000282 (void) RegisterMagickInfo(entry);
283 return(MagickImageCoderSignature);
284}
285
286/*
287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288% %
289% %
290% %
291% U n r e g i s t e r M A P I m a g e %
292% %
293% %
294% %
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296%
297% UnregisterMAPImage() removes format registrations made by the
298% MAP module from the list of supported formats.
299%
300% The format of the UnregisterMAPImage method is:
301%
302% UnregisterMAPImage(void)
303%
304*/
305ModuleExport void UnregisterMAPImage(void)
306{
307 (void) UnregisterMagickInfo("MAP");
308}
309
310/*
311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312% %
313% %
314% %
315% W r i t e M A P I m a g e %
316% %
317% %
318% %
319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320%
321% WriteMAPImage() writes an image to a file as red, green, and blue
322% colormap bytes followed by the colormap indexes.
323%
324% The format of the WriteMAPImage method is:
325%
cristy1e178e72011-08-28 19:44:34 +0000326% MagickBooleanType WriteMAPImage(const ImageInfo *image_info,
327% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000328%
329% A description of each parameter follows.
330%
331% o image_info: the image info.
332%
333% o image: The image.
334%
cristy1e178e72011-08-28 19:44:34 +0000335% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000336%
337*/
cristy1e178e72011-08-28 19:44:34 +0000338static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image,
339 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000340{
cristy3ed852e2009-09-05 21:47:34 +0000341 MagickBooleanType
342 status;
343
cristy4c08aed2011-07-01 19:47:50 +0000344 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000345 *p;
346
cristybb503372010-05-27 20:51:26 +0000347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000348 i,
349 x;
350
351 register unsigned char
352 *q;
353
354 size_t
cristy524222d2011-04-25 00:37:06 +0000355 depth,
cristy3ed852e2009-09-05 21:47:34 +0000356 packet_size;
357
cristy524222d2011-04-25 00:37:06 +0000358 ssize_t
359 y;
360
cristy3ed852e2009-09-05 21:47:34 +0000361 unsigned char
362 *colormap,
363 *pixels;
364
cristy3ed852e2009-09-05 21:47:34 +0000365 /*
366 Open output image file.
367 */
368 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000369 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000370 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000371 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000372 if (image->debug != MagickFalse)
373 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000374 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000375 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000376 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000377 if (status == MagickFalse)
378 return(status);
cristyaf8d3912014-02-21 14:50:33 +0000379 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000380 /*
381 Allocate colormap.
382 */
dirkab4f0bb2015-07-25 11:46:32 +0000383 if (IsPaletteImage(image) == MagickFalse)
cristy018f07f2011-09-04 21:15:19 +0000384 (void) SetImageType(image,PaletteType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000385 depth=GetImageQuantumDepth(image,MagickTrue);
386 packet_size=(size_t) (depth/8);
387 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
388 sizeof(*pixels));
389 packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
390 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
391 sizeof(*colormap));
392 if ((pixels == (unsigned char *) NULL) ||
393 (colormap == (unsigned char *) NULL))
394 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
395 /*
396 Write colormap to file.
397 */
398 q=colormap;
399 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +0000400 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000401 {
402 *q++=(unsigned char) image->colormap[i].red;
403 *q++=(unsigned char) image->colormap[i].green;
404 *q++=(unsigned char) image->colormap[i].blue;
405 }
406 else
cristybb503372010-05-27 20:51:26 +0000407 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000408 {
cristybb503372010-05-27 20:51:26 +0000409 *q++=(unsigned char) ((size_t) image->colormap[i].red >> 8);
cristy3ed852e2009-09-05 21:47:34 +0000410 *q++=(unsigned char) image->colormap[i].red;
cristybb503372010-05-27 20:51:26 +0000411 *q++=(unsigned char) ((size_t) image->colormap[i].green >> 8);
cristy3ed852e2009-09-05 21:47:34 +0000412 *q++=(unsigned char) image->colormap[i].green;
cristybb503372010-05-27 20:51:26 +0000413 *q++=(unsigned char) ((size_t) image->colormap[i].blue >> 8);
cristy3ed852e2009-09-05 21:47:34 +0000414 *q++=(unsigned char) image->colormap[i].blue;
415 }
416 (void) WriteBlob(image,packet_size*image->colors,colormap);
417 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
418 /*
419 Write image pixels to file.
420 */
cristybb503372010-05-27 20:51:26 +0000421 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000422 {
cristy1e178e72011-08-28 19:44:34 +0000423 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000424 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000425 break;
cristy3ed852e2009-09-05 21:47:34 +0000426 q=pixels;
cristybb503372010-05-27 20:51:26 +0000427 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000428 {
429 if (image->colors > 256)
cristy4c08aed2011-07-01 19:47:50 +0000430 *q++=(unsigned char) ((size_t) GetPixelIndex(image,p) >> 8);
431 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +0000432 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000433 }
434 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
435 }
436 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
437 (void) CloseBlob(image);
438 return(status);
439}