blob: 1949b1042f063d2c6df9c6bddf21e4a9352008c5 [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 %
16% John Cristy %
17% July 1992 %
18% %
19% %
20% Copyright 1999-2009 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% 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*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/color.h"
cristy316d5172009-09-17 19:31:25 +000047#include "magick/colormap-private.h"
cristy3ed852e2009-09-05 21:47:34 +000048#include "magick/color-private.h"
49#include "magick/colorspace.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristyf2e11662009-10-14 01:24:43 +000052#include "magick/histogram.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/image.h"
54#include "magick/image-private.h"
55#include "magick/list.h"
56#include "magick/magick.h"
57#include "magick/memory_.h"
58#include "magick/quantum-private.h"
59#include "magick/static.h"
60#include "magick/statistic.h"
61#include "magick/string_.h"
62#include "magick/module.h"
63
64/*
65 Forward declarations.
66*/
67static MagickBooleanType
68 WriteMAPImage(const ImageInfo *,Image *);
69
70/*
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72% %
73% %
74% %
75% R e a d M A P I m a g e %
76% %
77% %
78% %
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%
81% ReadMAPImage() reads an image of raw RGB colormap and colormap index
82% bytes and returns it. It allocates the memory necessary for the new Image
83% structure and returns a pointer to the new image.
84%
85% The format of the ReadMAPImage method is:
86%
87% Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
88%
89% A description of each parameter follows:
90%
91% o image_info: the image info.
92%
93% o exception: return any errors or warnings in this structure.
94%
95*/
96static Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
97{
98 Image
99 *image;
100
101 IndexPacket
102 index;
103
104 long
105 y;
106
107 MagickBooleanType
108 status;
109
110 register IndexPacket
111 *indexes;
112
113 register long
114 x;
115
116 register PixelPacket
117 *q;
118
119 register long
120 i;
121
122 register unsigned char
123 *p;
124
125 size_t
126 packet_size;
127
128 ssize_t
129 count;
130
131 unsigned char
132 *colormap,
133 *pixels;
134
135 unsigned long
136 depth,
137 quantum;
138
139 /*
140 Open image file.
141 */
142 assert(image_info != (const ImageInfo *) NULL);
143 assert(image_info->signature == MagickSignature);
144 if (image_info->debug != MagickFalse)
145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
146 image_info->filename);
147 assert(exception != (ExceptionInfo *) NULL);
148 assert(exception->signature == MagickSignature);
149 image=AcquireImage(image_info);
150 if ((image->columns == 0) || (image->rows == 0))
151 ThrowReaderException(OptionError,"MustSpecifyImageSize");
152 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
153 if (status == MagickFalse)
154 {
155 image=DestroyImageList(image);
156 return((Image *) NULL);
157 }
158 /*
159 Initialize image structure.
160 */
161 image->storage_class=PseudoClass;
162 status=AcquireImageColormap(image,(unsigned long)
163 (image->offset != 0 ? image->offset : 256));
164 if (status == MagickFalse)
165 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
166 depth=GetImageQuantumDepth(image,MagickTrue);
167 packet_size=(size_t) (depth/8);
168 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
169 sizeof(*pixels));
170 packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
171 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
172 sizeof(*colormap));
173 if ((pixels == (unsigned char *) NULL) ||
174 (colormap == (unsigned char *) NULL))
175 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
176 /*
177 Read image colormap.
178 */
179 count=ReadBlob(image,packet_size*image->colors,colormap);
180 if (count != (ssize_t) (packet_size*image->colors))
181 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
182 p=colormap;
183 if (image->depth <= 8)
184 for (i=0; i < (long) image->colors; i++)
185 {
186 image->colormap[i].red=ScaleCharToQuantum(*p++);
187 image->colormap[i].green=ScaleCharToQuantum(*p++);
188 image->colormap[i].blue=ScaleCharToQuantum(*p++);
189 }
190 else
191 for (i=0; i < (long) image->colors; i++)
192 {
193 quantum=(*p++ << 8);
194 quantum|=(*p++);
195 image->colormap[i].red=(Quantum) quantum;
196 quantum=(*p++ << 8);
197 quantum|=(*p++);
198 image->colormap[i].green=(Quantum) quantum;
199 quantum=(*p++ << 8);
200 quantum|=(*p++);
201 image->colormap[i].blue=(Quantum) quantum;
202 }
203 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
204 if (image_info->ping != MagickFalse)
205 {
206 (void) CloseBlob(image);
207 return(GetFirstImageInList(image));
208 }
209 /*
210 Read image pixels.
211 */
212 packet_size=(size_t) (depth/8);
213 for (y=0; y < (long) image->rows; y++)
214 {
215 p=pixels;
216 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
217 if (q == (PixelPacket *) NULL)
218 break;
219 indexes=GetAuthenticIndexQueue(image);
220 count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
221 if (count != (ssize_t) (packet_size*image->columns))
222 break;
223 for (x=0; x < (long) image->columns; x++)
224 {
225 index=ConstrainColormapIndex(image,*p);
226 p++;
227 if (image->colors > 256)
228 {
229 index=ConstrainColormapIndex(image,((unsigned long) index << 8)+(*p));
230 p++;
231 }
232 indexes[x]=(IndexPacket) index;
233 *q++=image->colormap[(long) index];
234 }
235 if (SyncAuthenticPixels(image,exception) == MagickFalse)
236 break;
237 }
238 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
239 if (y < (long) image->rows)
240 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
241 image->filename);
242 (void) CloseBlob(image);
243 return(GetFirstImageInList(image));
244}
245
246/*
247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248% %
249% %
250% %
251% R e g i s t e r M A P I m a g e %
252% %
253% %
254% %
255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256%
257% RegisterMAPImage() adds attributes for the MAP image format to
258% the list of supported formats. The attributes include the image format
259% tag, a method to read and/or write the format, whether the format
260% supports the saving of more than one frame to the same file or blob,
261% whether the format supports native in-memory I/O, and a brief
262% description of the format.
263%
264% The format of the RegisterMAPImage method is:
265%
266% unsigned long RegisterMAPImage(void)
267%
268*/
269ModuleExport unsigned long RegisterMAPImage(void)
270{
271 MagickInfo
272 *entry;
273
274 entry=SetMagickInfo("MAP");
275 entry->decoder=(DecodeImageHandler *) ReadMAPImage;
276 entry->encoder=(EncodeImageHandler *) WriteMAPImage;
277 entry->adjoin=MagickFalse;
278 entry->format_type=ExplicitFormatType;
279 entry->raw=MagickTrue;
280 entry->endian_support=MagickTrue;
281 entry->description=ConstantString("Colormap intensities and indices");
282 entry->module=ConstantString("MAP");
283 (void) RegisterMagickInfo(entry);
284 return(MagickImageCoderSignature);
285}
286
287/*
288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289% %
290% %
291% %
292% U n r e g i s t e r M A P I m a g e %
293% %
294% %
295% %
296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297%
298% UnregisterMAPImage() removes format registrations made by the
299% MAP module from the list of supported formats.
300%
301% The format of the UnregisterMAPImage method is:
302%
303% UnregisterMAPImage(void)
304%
305*/
306ModuleExport void UnregisterMAPImage(void)
307{
308 (void) UnregisterMagickInfo("MAP");
309}
310
311/*
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313% %
314% %
315% %
316% W r i t e M A P I m a g e %
317% %
318% %
319% %
320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321%
322% WriteMAPImage() writes an image to a file as red, green, and blue
323% colormap bytes followed by the colormap indexes.
324%
325% The format of the WriteMAPImage method is:
326%
327% MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image)
328%
329% A description of each parameter follows.
330%
331% o image_info: the image info.
332%
333% o image: The image.
334%
335%
336*/
337static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image)
338{
339 long
340 y;
341
342 MagickBooleanType
343 status;
344
345 register const IndexPacket
346 *indexes;
347
348 register const PixelPacket
349 *p;
350
351 register long
352 i,
353 x;
354
355 register unsigned char
356 *q;
357
358 size_t
359 packet_size;
360
361 unsigned char
362 *colormap,
363 *pixels;
364
365 unsigned long
366 depth;
367
368 /*
369 Open output image file.
370 */
371 assert(image_info != (const ImageInfo *) NULL);
372 assert(image_info->signature == MagickSignature);
373 assert(image != (Image *) NULL);
374 assert(image->signature == MagickSignature);
375 if (image->debug != MagickFalse)
376 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
377 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
378 if (status == MagickFalse)
379 return(status);
380 if (image->colorspace != RGBColorspace)
381 (void) TransformImageColorspace(image,RGBColorspace);
382 /*
383 Allocate colormap.
384 */
385 if (IsPaletteImage(image,&image->exception) == MagickFalse)
386 (void) SetImageType(image,PaletteType);
387 depth=GetImageQuantumDepth(image,MagickTrue);
388 packet_size=(size_t) (depth/8);
389 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
390 sizeof(*pixels));
391 packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
392 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
393 sizeof(*colormap));
394 if ((pixels == (unsigned char *) NULL) ||
395 (colormap == (unsigned char *) NULL))
396 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
397 /*
398 Write colormap to file.
399 */
400 q=colormap;
401 if (image->depth <= 8)
402 for (i=0; i < (long) image->colors; i++)
403 {
404 *q++=(unsigned char) image->colormap[i].red;
405 *q++=(unsigned char) image->colormap[i].green;
406 *q++=(unsigned char) image->colormap[i].blue;
407 }
408 else
409 for (i=0; i < (long) image->colors; i++)
410 {
411 *q++=(unsigned char) ((unsigned long) image->colormap[i].red >> 8);
412 *q++=(unsigned char) image->colormap[i].red;
413 *q++=(unsigned char) ((unsigned long) image->colormap[i].green >> 8);
414 *q++=(unsigned char) image->colormap[i].green;
415 *q++=(unsigned char) ((unsigned long) image->colormap[i].blue >> 8);
416 *q++=(unsigned char) image->colormap[i].blue;
417 }
418 (void) WriteBlob(image,packet_size*image->colors,colormap);
419 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
420 /*
421 Write image pixels to file.
422 */
423 for (y=0; y < (long) image->rows; y++)
424 {
425 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
426 if (p == (const PixelPacket *) NULL)
427 break;
428 indexes=GetVirtualIndexQueue(image);
429 q=pixels;
430 for (x=0; x < (long) image->columns; x++)
431 {
432 if (image->colors > 256)
433 *q++=(unsigned char) ((unsigned long) indexes[x] >> 8);
434 *q++=(unsigned char) indexes[x];
435 }
436 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
437 }
438 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
439 (void) CloseBlob(image);
440 return(status);
441}