blob: a2b7926611c67788a741e056d4ca19b19c3bbf17 [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% %
cristyfe676ee2013-11-18 13:03:38 +000020% Copyright 1999-2014 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);
140 assert(image_info->signature == MagickSignature);
141 if (image_info->debug != MagickFalse)
142 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
143 image_info->filename);
144 assert(exception != (ExceptionInfo *) NULL);
145 assert(exception->signature == MagickSignature);
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 }
206 /*
207 Read image pixels.
208 */
209 packet_size=(size_t) (depth/8);
cristybb503372010-05-27 20:51:26 +0000210 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000211 {
212 p=pixels;
213 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000214 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000215 break;
cristy3ed852e2009-09-05 21:47:34 +0000216 count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
217 if (count != (ssize_t) (packet_size*image->columns))
218 break;
cristybb503372010-05-27 20:51:26 +0000219 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000220 {
cristyc82a27b2011-10-21 01:07:16 +0000221 index=ConstrainColormapIndex(image,*p,exception);
cristy3ed852e2009-09-05 21:47:34 +0000222 p++;
223 if (image->colors > 256)
224 {
cristyc82a27b2011-10-21 01:07:16 +0000225 index=ConstrainColormapIndex(image,((size_t) index << 8)+(*p),
226 exception);
cristy3ed852e2009-09-05 21:47:34 +0000227 p++;
228 }
cristy4c08aed2011-07-01 19:47:50 +0000229 SetPixelIndex(image,index,q);
cristy803640d2011-11-17 02:11:32 +0000230 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000231 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000232 }
233 if (SyncAuthenticPixels(image,exception) == MagickFalse)
234 break;
235 }
236 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
cristybb503372010-05-27 20:51:26 +0000237 if (y < (ssize_t) image->rows)
cristy3ed852e2009-09-05 21:47:34 +0000238 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
239 image->filename);
240 (void) CloseBlob(image);
241 return(GetFirstImageInList(image));
242}
243
244/*
245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246% %
247% %
248% %
249% R e g i s t e r M A P I m a g e %
250% %
251% %
252% %
253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254%
255% RegisterMAPImage() adds attributes for the MAP image format to
256% the list of supported formats. The attributes include the image format
257% tag, a method to read and/or write the format, whether the format
258% supports the saving of more than one frame to the same file or blob,
259% whether the format supports native in-memory I/O, and a brief
260% description of the format.
261%
262% The format of the RegisterMAPImage method is:
263%
cristybb503372010-05-27 20:51:26 +0000264% size_t RegisterMAPImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000265%
266*/
cristybb503372010-05-27 20:51:26 +0000267ModuleExport size_t RegisterMAPImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000268{
269 MagickInfo
270 *entry;
271
272 entry=SetMagickInfo("MAP");
273 entry->decoder=(DecodeImageHandler *) ReadMAPImage;
274 entry->encoder=(EncodeImageHandler *) WriteMAPImage;
275 entry->adjoin=MagickFalse;
276 entry->format_type=ExplicitFormatType;
277 entry->raw=MagickTrue;
278 entry->endian_support=MagickTrue;
279 entry->description=ConstantString("Colormap intensities and indices");
280 entry->module=ConstantString("MAP");
281 (void) RegisterMagickInfo(entry);
282 return(MagickImageCoderSignature);
283}
284
285/*
286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287% %
288% %
289% %
290% U n r e g i s t e r M A P I m a g e %
291% %
292% %
293% %
294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295%
296% UnregisterMAPImage() removes format registrations made by the
297% MAP module from the list of supported formats.
298%
299% The format of the UnregisterMAPImage method is:
300%
301% UnregisterMAPImage(void)
302%
303*/
304ModuleExport void UnregisterMAPImage(void)
305{
306 (void) UnregisterMagickInfo("MAP");
307}
308
309/*
310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311% %
312% %
313% %
314% W r i t e M A P I m a g e %
315% %
316% %
317% %
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319%
320% WriteMAPImage() writes an image to a file as red, green, and blue
321% colormap bytes followed by the colormap indexes.
322%
323% The format of the WriteMAPImage method is:
324%
cristy1e178e72011-08-28 19:44:34 +0000325% MagickBooleanType WriteMAPImage(const ImageInfo *image_info,
326% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000327%
328% A description of each parameter follows.
329%
330% o image_info: the image info.
331%
332% o image: The image.
333%
cristy1e178e72011-08-28 19:44:34 +0000334% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000335%
336*/
cristy1e178e72011-08-28 19:44:34 +0000337static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image,
338 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000339{
cristy3ed852e2009-09-05 21:47:34 +0000340 MagickBooleanType
341 status;
342
cristy4c08aed2011-07-01 19:47:50 +0000343 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000344 *p;
345
cristybb503372010-05-27 20:51:26 +0000346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000347 i,
348 x;
349
350 register unsigned char
351 *q;
352
353 size_t
cristy524222d2011-04-25 00:37:06 +0000354 depth,
cristy3ed852e2009-09-05 21:47:34 +0000355 packet_size;
356
cristy524222d2011-04-25 00:37:06 +0000357 ssize_t
358 y;
359
cristy3ed852e2009-09-05 21:47:34 +0000360 unsigned char
361 *colormap,
362 *pixels;
363
cristy3ed852e2009-09-05 21:47:34 +0000364 /*
365 Open output image file.
366 */
367 assert(image_info != (const ImageInfo *) NULL);
368 assert(image_info->signature == MagickSignature);
369 assert(image != (Image *) NULL);
370 assert(image->signature == MagickSignature);
371 if (image->debug != MagickFalse)
372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000373 assert(exception != (ExceptionInfo *) NULL);
374 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000375 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000376 if (status == MagickFalse)
377 return(status);
cristyaf8d3912014-02-21 14:50:33 +0000378 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000379 /*
380 Allocate colormap.
381 */
cristy1e178e72011-08-28 19:44:34 +0000382 if (IsPaletteImage(image,exception) == MagickFalse)
cristy018f07f2011-09-04 21:15:19 +0000383 (void) SetImageType(image,PaletteType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000384 depth=GetImageQuantumDepth(image,MagickTrue);
385 packet_size=(size_t) (depth/8);
386 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
387 sizeof(*pixels));
388 packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
389 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
390 sizeof(*colormap));
391 if ((pixels == (unsigned char *) NULL) ||
392 (colormap == (unsigned char *) NULL))
393 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
394 /*
395 Write colormap to file.
396 */
397 q=colormap;
398 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +0000399 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000400 {
401 *q++=(unsigned char) image->colormap[i].red;
402 *q++=(unsigned char) image->colormap[i].green;
403 *q++=(unsigned char) image->colormap[i].blue;
404 }
405 else
cristybb503372010-05-27 20:51:26 +0000406 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000407 {
cristybb503372010-05-27 20:51:26 +0000408 *q++=(unsigned char) ((size_t) image->colormap[i].red >> 8);
cristy3ed852e2009-09-05 21:47:34 +0000409 *q++=(unsigned char) image->colormap[i].red;
cristybb503372010-05-27 20:51:26 +0000410 *q++=(unsigned char) ((size_t) image->colormap[i].green >> 8);
cristy3ed852e2009-09-05 21:47:34 +0000411 *q++=(unsigned char) image->colormap[i].green;
cristybb503372010-05-27 20:51:26 +0000412 *q++=(unsigned char) ((size_t) image->colormap[i].blue >> 8);
cristy3ed852e2009-09-05 21:47:34 +0000413 *q++=(unsigned char) image->colormap[i].blue;
414 }
415 (void) WriteBlob(image,packet_size*image->colors,colormap);
416 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
417 /*
418 Write image pixels to file.
419 */
cristybb503372010-05-27 20:51:26 +0000420 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000421 {
cristy1e178e72011-08-28 19:44:34 +0000422 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000423 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000424 break;
cristy3ed852e2009-09-05 21:47:34 +0000425 q=pixels;
cristybb503372010-05-27 20:51:26 +0000426 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000427 {
428 if (image->colors > 256)
cristy4c08aed2011-07-01 19:47:50 +0000429 *q++=(unsigned char) ((size_t) GetPixelIndex(image,p) >> 8);
430 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +0000431 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000432 }
433 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
434 }
435 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
436 (void) CloseBlob(image);
437 return(status);
438}