/src/imagemagick/coders/pcx.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % PPPP CCCC X X % |
7 | | % P P C X X % |
8 | | % PPPP C X % |
9 | | % P C X X % |
10 | | % P CCCC X X % |
11 | | % % |
12 | | % % |
13 | | % Read/Write ZSoft IBM PC Paintbrush Image Format % |
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/colorspace.h" |
51 | | #include "MagickCore/colorspace-private.h" |
52 | | #include "MagickCore/exception.h" |
53 | | #include "MagickCore/exception-private.h" |
54 | | #include "MagickCore/image.h" |
55 | | #include "MagickCore/image-private.h" |
56 | | #include "MagickCore/list.h" |
57 | | #include "MagickCore/magick.h" |
58 | | #include "MagickCore/memory_.h" |
59 | | #include "MagickCore/memory-private.h" |
60 | | #include "MagickCore/monitor.h" |
61 | | #include "MagickCore/monitor-private.h" |
62 | | #include "MagickCore/pixel-accessor.h" |
63 | | #include "MagickCore/quantum-private.h" |
64 | | #include "MagickCore/static.h" |
65 | | #include "MagickCore/string_.h" |
66 | | #include "MagickCore/module.h" |
67 | | |
68 | | /* |
69 | | Typedef declarations. |
70 | | */ |
71 | | typedef struct _PCXInfo |
72 | | { |
73 | | unsigned char |
74 | | identifier, |
75 | | version, |
76 | | encoding, |
77 | | bits_per_pixel; |
78 | | |
79 | | unsigned short |
80 | | left, |
81 | | top, |
82 | | right, |
83 | | bottom, |
84 | | horizontal_resolution, |
85 | | vertical_resolution; |
86 | | |
87 | | unsigned char |
88 | | reserved, |
89 | | planes; |
90 | | |
91 | | unsigned short |
92 | | bytes_per_line, |
93 | | palette_info, |
94 | | horizontal_screensize, |
95 | | vertical_screensize; |
96 | | |
97 | | unsigned char |
98 | | colormap_signature; |
99 | | } PCXInfo; |
100 | | |
101 | | /* |
102 | | Forward declarations. |
103 | | */ |
104 | | static MagickBooleanType |
105 | | WritePCXImage(const ImageInfo *,Image *,ExceptionInfo *); |
106 | | |
107 | | /* |
108 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
109 | | % % |
110 | | % % |
111 | | % % |
112 | | % I s D C X % |
113 | | % % |
114 | | % % |
115 | | % % |
116 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
117 | | % |
118 | | % IsDCX() returns MagickTrue if the image format type, identified by the |
119 | | % magick string, is DCX. |
120 | | % |
121 | | % The format of the IsDCX method is: |
122 | | % |
123 | | % MagickBooleanType IsDCX(const unsigned char *magick,const size_t length) |
124 | | % |
125 | | % A description of each parameter follows: |
126 | | % |
127 | | % o magick: compare image format pattern against these bytes. |
128 | | % |
129 | | % o length: Specifies the length of the magick string. |
130 | | % |
131 | | */ |
132 | | static MagickBooleanType IsDCX(const unsigned char *magick,const size_t length) |
133 | 0 | { |
134 | 0 | if (length < 4) |
135 | 0 | return(MagickFalse); |
136 | 0 | if (memcmp(magick,"\261\150\336\72",4) == 0) |
137 | 0 | return(MagickTrue); |
138 | 0 | return(MagickFalse); |
139 | 0 | } |
140 | | |
141 | | /* |
142 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
143 | | % % |
144 | | % % |
145 | | % % |
146 | | % I s P C X % |
147 | | % % |
148 | | % % |
149 | | % % |
150 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
151 | | % |
152 | | % IsPCX() returns MagickTrue if the image format type, identified by the |
153 | | % magick string, is PCX. |
154 | | % |
155 | | % The format of the IsPCX method is: |
156 | | % |
157 | | % MagickBooleanType IsPCX(const unsigned char *magick,const size_t length) |
158 | | % |
159 | | % A description of each parameter follows: |
160 | | % |
161 | | % o magick: compare image format pattern against these bytes. |
162 | | % |
163 | | % o length: Specifies the length of the magick string. |
164 | | % |
165 | | */ |
166 | | static MagickBooleanType IsPCX(const unsigned char *magick,const size_t length) |
167 | 0 | { |
168 | 0 | if (length < 2) |
169 | 0 | return(MagickFalse); |
170 | 0 | if (memcmp(magick,"\012\002",2) == 0) |
171 | 0 | return(MagickTrue); |
172 | 0 | if (memcmp(magick,"\012\005",2) == 0) |
173 | 0 | return(MagickTrue); |
174 | 0 | return(MagickFalse); |
175 | 0 | } |
176 | | |
177 | | /* |
178 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
179 | | % % |
180 | | % % |
181 | | % % |
182 | | % R e a d P C X I m a g e % |
183 | | % % |
184 | | % % |
185 | | % % |
186 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
187 | | % |
188 | | % ReadPCXImage() reads a ZSoft IBM PC Paintbrush file and returns it. |
189 | | % It allocates the memory necessary for the new Image structure and returns |
190 | | % a pointer to the new image. |
191 | | % |
192 | | % The format of the ReadPCXImage method is: |
193 | | % |
194 | | % Image *ReadPCXImage(const ImageInfo *image_info,ExceptionInfo *exception) |
195 | | % |
196 | | % A description of each parameter follows: |
197 | | % |
198 | | % o image_info: the image info. |
199 | | % |
200 | | % o exception: return any errors or warnings in this structure. |
201 | | % |
202 | | */ |
203 | | static Image *ReadPCXImage(const ImageInfo *image_info,ExceptionInfo *exception) |
204 | 957 | { |
205 | 2.37k | #define MaxNumberScenes 1024 |
206 | 957 | #define ThrowPCXException(severity,tag) \ |
207 | 532 | { \ |
208 | 532 | if (scanline != (unsigned char *) NULL) \ |
209 | 532 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); \ |
210 | 532 | if (pixel_info != (MemoryInfo *) NULL) \ |
211 | 532 | pixel_info=RelinquishVirtualMemory(pixel_info); \ |
212 | 532 | if (page_table != (MagickOffsetType *) NULL) \ |
213 | 532 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); \ |
214 | 532 | ThrowReaderException(severity,tag); \ |
215 | 0 | } |
216 | | |
217 | 957 | Image |
218 | 957 | *image; |
219 | | |
220 | 957 | int |
221 | 957 | bits, |
222 | 957 | id, |
223 | 957 | mask; |
224 | | |
225 | 957 | MagickBooleanType |
226 | 957 | status; |
227 | | |
228 | 957 | MagickOffsetType |
229 | 957 | offset, |
230 | 957 | *page_table; |
231 | | |
232 | 957 | MemoryInfo |
233 | 957 | *pixel_info; |
234 | | |
235 | 957 | PCXInfo |
236 | 957 | pcx_info; |
237 | | |
238 | 957 | Quantum |
239 | 957 | *q; |
240 | | |
241 | 957 | size_t |
242 | 957 | one, |
243 | 957 | pcx_packets; |
244 | | |
245 | 957 | ssize_t |
246 | 957 | count, |
247 | 957 | i, |
248 | 957 | x, |
249 | 957 | y; |
250 | | |
251 | 957 | unsigned char |
252 | 957 | *p, |
253 | 957 | packet, |
254 | 957 | pcx_colormap[768], |
255 | 957 | *pixels, |
256 | 957 | *r, |
257 | 957 | *scanline; |
258 | | |
259 | | /* |
260 | | Open image file. |
261 | | */ |
262 | 957 | assert(image_info != (const ImageInfo *) NULL); |
263 | 957 | assert(image_info->signature == MagickCoreSignature); |
264 | 957 | assert(exception != (ExceptionInfo *) NULL); |
265 | 957 | assert(exception->signature == MagickCoreSignature); |
266 | 957 | if (IsEventLogging() != MagickFalse) |
267 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
268 | 0 | image_info->filename); |
269 | 957 | image=AcquireImage(image_info,exception); |
270 | 957 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
271 | 957 | if (status == MagickFalse) |
272 | 0 | { |
273 | 0 | image=DestroyImageList(image); |
274 | 0 | return((Image *) NULL); |
275 | 0 | } |
276 | | /* |
277 | | Determine if this a PCX file. |
278 | | */ |
279 | 957 | page_table=(MagickOffsetType *) NULL; |
280 | 957 | scanline=(unsigned char *) NULL; |
281 | 957 | pixel_info=(MemoryInfo *) NULL; |
282 | 957 | if (LocaleCompare(image_info->magick,"DCX") == 0) |
283 | 1 | { |
284 | 1 | size_t |
285 | 1 | magic; |
286 | | |
287 | | /* |
288 | | Read the DCX page table. |
289 | | */ |
290 | 1 | magic=ReadBlobLSBLong(image); |
291 | 1 | if (magic != 987654321) |
292 | 1 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
293 | 1 | page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes, |
294 | 1 | sizeof(*page_table)); |
295 | 1 | if (page_table == (MagickOffsetType *) NULL) |
296 | 1 | ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed"); |
297 | 1.02k | for (id=0; id < MaxNumberScenes; id++) |
298 | 1.02k | { |
299 | 1.02k | page_table[id]=(MagickOffsetType) ReadBlobLSBLong(image); |
300 | 1.02k | if (page_table[id] == 0) |
301 | 0 | break; |
302 | 1.02k | } |
303 | 1 | } |
304 | 957 | if (page_table != (MagickOffsetType *) NULL) |
305 | 1 | { |
306 | 1 | offset=SeekBlob(image,(MagickOffsetType) page_table[0],SEEK_SET); |
307 | 1 | if (offset < 0) |
308 | 1 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
309 | 1 | } |
310 | 957 | count=ReadBlob(image,1,&pcx_info.identifier); |
311 | 957 | for (id=1; id < MaxNumberScenes; id++) |
312 | 957 | { |
313 | 957 | int |
314 | 957 | bits_per_pixel; |
315 | | |
316 | | /* |
317 | | Verify PCX identifier. |
318 | | */ |
319 | 957 | pcx_info.version=(unsigned char) ReadBlobByte(image); |
320 | 957 | if ((count != 1) || (pcx_info.identifier != 0x0a)) |
321 | 907 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
322 | 907 | pcx_info.encoding=(unsigned char) ReadBlobByte(image); |
323 | 907 | bits_per_pixel=ReadBlobByte(image); |
324 | 907 | if (bits_per_pixel == -1) |
325 | 904 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
326 | 904 | pcx_info.bits_per_pixel=(unsigned char) bits_per_pixel; |
327 | 904 | pcx_info.left=ReadBlobLSBShort(image); |
328 | 904 | pcx_info.top=ReadBlobLSBShort(image); |
329 | 904 | pcx_info.right=ReadBlobLSBShort(image); |
330 | 904 | pcx_info.bottom=ReadBlobLSBShort(image); |
331 | 904 | pcx_info.horizontal_resolution=ReadBlobLSBShort(image); |
332 | 904 | pcx_info.vertical_resolution=ReadBlobLSBShort(image); |
333 | 904 | if (EOFBlob(image) != MagickFalse) |
334 | 884 | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
335 | | /* |
336 | | Read PCX raster colormap. |
337 | | */ |
338 | 884 | if ((pcx_info.right < pcx_info.left) || (pcx_info.bottom < pcx_info.top) || |
339 | 882 | ((pcx_info.bits_per_pixel != 1) && (pcx_info.bits_per_pixel != 2) && |
340 | 391 | (pcx_info.bits_per_pixel != 4) && (pcx_info.bits_per_pixel != 8))) |
341 | 866 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
342 | 866 | image->columns=(size_t) (pcx_info.right-pcx_info.left)+1UL; |
343 | 866 | image->rows=(size_t) (pcx_info.bottom-pcx_info.top)+1UL; |
344 | 866 | image->depth=pcx_info.bits_per_pixel; |
345 | 866 | image->units=PixelsPerInchResolution; |
346 | 866 | image->resolution.x=(double) pcx_info.horizontal_resolution; |
347 | 866 | image->resolution.y=(double) pcx_info.vertical_resolution; |
348 | 866 | image->colors=16; |
349 | 866 | if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) |
350 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
351 | 0 | break; |
352 | 866 | if ((MagickSizeType) (image->columns*image->rows/255) > GetBlobSize(image)) |
353 | 828 | ThrowPCXException(CorruptImageError,"InsufficientImageDataInFile"); |
354 | 828 | status=SetImageExtent(image,image->columns,image->rows,exception); |
355 | 828 | if (status == MagickFalse) |
356 | 777 | ThrowPCXException(exception->severity,exception->reason); |
357 | 777 | (void) SetImageBackgroundColor(image,exception); |
358 | 777 | (void) memset(pcx_colormap,0,sizeof(pcx_colormap)); |
359 | 777 | count=ReadBlob(image,3*image->colors,pcx_colormap); |
360 | 777 | if (count != (ssize_t) (3*image->colors)) |
361 | 679 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
362 | 679 | pcx_info.reserved=(unsigned char) ReadBlobByte(image); |
363 | 679 | pcx_info.planes=(unsigned char) ReadBlobByte(image); |
364 | 679 | if (pcx_info.planes == 0) |
365 | 671 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
366 | 671 | if (pcx_info.planes > 6) |
367 | 659 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
368 | 659 | if ((pcx_info.bits_per_pixel*pcx_info.planes) >= 64) |
369 | 659 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
370 | 659 | one=1; |
371 | 659 | if ((pcx_info.bits_per_pixel != 8) || (pcx_info.planes == 1)) |
372 | 525 | if ((pcx_info.version == 3) || (pcx_info.version == 5) || |
373 | 318 | ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)) |
374 | 308 | image->colors=(size_t) MagickMin(one << (1UL* |
375 | 659 | (pcx_info.bits_per_pixel*pcx_info.planes)),256UL); |
376 | 659 | if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) |
377 | 659 | ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed"); |
378 | 659 | if ((pcx_info.bits_per_pixel >= 8) && (pcx_info.planes != 1)) |
379 | 134 | image->storage_class=DirectClass; |
380 | 659 | p=pcx_colormap; |
381 | 19.7k | for (i=0; i < (ssize_t) image->colors; i++) |
382 | 19.1k | { |
383 | 19.1k | image->colormap[i].red=ScaleCharToQuantum(*p++); |
384 | 19.1k | image->colormap[i].green=ScaleCharToQuantum(*p++); |
385 | 19.1k | image->colormap[i].blue=ScaleCharToQuantum(*p++); |
386 | 19.1k | } |
387 | 659 | pcx_info.bytes_per_line=ReadBlobLSBShort(image); |
388 | 659 | pcx_info.palette_info=ReadBlobLSBShort(image); |
389 | 659 | pcx_info.horizontal_screensize=ReadBlobLSBShort(image); |
390 | 659 | pcx_info.vertical_screensize=ReadBlobLSBShort(image); |
391 | 36.2k | for (i=0; i < 54; i++) |
392 | 35.5k | (void) ReadBlobByte(image); |
393 | | /* |
394 | | Read image data. |
395 | | */ |
396 | 659 | if (HeapOverflowSanityCheckGetSize(image->rows,(size_t) pcx_info.bytes_per_line,&pcx_packets) != MagickFalse) |
397 | 641 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
398 | 641 | if (HeapOverflowSanityCheckGetSize(pcx_packets,(size_t) pcx_info.planes,&pcx_packets) != MagickFalse) |
399 | 641 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
400 | 641 | if ((size_t) (pcx_info.bits_per_pixel*pcx_info.planes*image->columns) > (pcx_packets*8U)) |
401 | 624 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
402 | 624 | if ((MagickSizeType) (pcx_packets/32+128) > GetBlobSize(image)) |
403 | 570 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
404 | 570 | { |
405 | 570 | size_t bytes_per_line = image->columns*pcx_info.bits_per_pixel; |
406 | 570 | if (bytes_per_line != 0) |
407 | 570 | bytes_per_line+=7U; |
408 | 570 | if (bytes_per_line != 0) |
409 | 570 | bytes_per_line/=8U; |
410 | 570 | if ((bytes_per_line == 0) || (pcx_info.bytes_per_line < bytes_per_line)) |
411 | 529 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
412 | 529 | } |
413 | 529 | scanline=(unsigned char *) AcquireQuantumMemory(MagickMax(image->columns, |
414 | 529 | pcx_info.bytes_per_line),MagickMax(pcx_info.planes,8)*sizeof(*scanline)); |
415 | 529 | pixel_info=AcquireVirtualMemory(pcx_packets,2*sizeof(*pixels)); |
416 | 529 | if ((scanline == (unsigned char *) NULL) || |
417 | 529 | (pixel_info == (MemoryInfo *) NULL)) |
418 | 0 | { |
419 | 0 | if (scanline != (unsigned char *) NULL) |
420 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
421 | 0 | if (pixel_info != (MemoryInfo *) NULL) |
422 | 0 | pixel_info=RelinquishVirtualMemory(pixel_info); |
423 | 0 | ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed"); |
424 | 0 | } |
425 | 529 | (void) memset(scanline,0,(size_t) MagickMax(image->columns, |
426 | 529 | pcx_info.bytes_per_line)*MagickMax(pcx_info.planes,8)*sizeof(*scanline)); |
427 | 529 | pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); |
428 | 529 | (void) memset(pixels,0,(size_t) pcx_packets*(2*sizeof(*pixels))); |
429 | | /* |
430 | | Uncompress image data. |
431 | | */ |
432 | 529 | p=pixels; |
433 | 529 | if (pcx_info.encoding == 0) |
434 | 13.0k | while (pcx_packets != 0) |
435 | 13.0k | { |
436 | 13.0k | packet=(unsigned char) ReadBlobByte(image); |
437 | 13.0k | if (EOFBlob(image) != MagickFalse) |
438 | 13.0k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
439 | 13.0k | *p++=packet; |
440 | 13.0k | pcx_packets--; |
441 | 13.0k | } |
442 | 484 | else |
443 | 117k | while (pcx_packets != 0) |
444 | 117k | { |
445 | 117k | packet=(unsigned char) ReadBlobByte(image); |
446 | 117k | if (EOFBlob(image) != MagickFalse) |
447 | 117k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
448 | 117k | if ((packet & 0xc0) != 0xc0) |
449 | 59.9k | { |
450 | 59.9k | *p++=packet; |
451 | 59.9k | pcx_packets--; |
452 | 59.9k | continue; |
453 | 59.9k | } |
454 | 57.0k | count=(ssize_t) (packet & 0x3f); |
455 | 57.0k | packet=(unsigned char) ReadBlobByte(image); |
456 | 57.0k | if (EOFBlob(image) != MagickFalse) |
457 | 57.0k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
458 | 3.13M | for ( ; count != 0; count--) |
459 | 3.07M | { |
460 | 3.07M | *p++=packet; |
461 | 3.07M | pcx_packets--; |
462 | 3.07M | if (pcx_packets == 0) |
463 | 358 | break; |
464 | 3.07M | } |
465 | 57.0k | } |
466 | 425 | if (image->storage_class == DirectClass) |
467 | 93 | image->alpha_trait=pcx_info.planes > 3 ? BlendPixelTrait : |
468 | 93 | UndefinedPixelTrait; |
469 | 332 | else |
470 | 332 | if ((pcx_info.version == 5) || |
471 | 201 | ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)) |
472 | 201 | { |
473 | | /* |
474 | | Initialize image colormap. |
475 | | */ |
476 | 201 | if (image->colors > 256) |
477 | 201 | ThrowPCXException(CorruptImageError,"ColormapExceeds256Colors"); |
478 | 201 | if ((pcx_info.bits_per_pixel*pcx_info.planes) == 1) |
479 | 84 | { |
480 | | /* |
481 | | Monochrome colormap. |
482 | | */ |
483 | 84 | image->colormap[0].red=(Quantum) 0; |
484 | 84 | image->colormap[0].green=(Quantum) 0; |
485 | 84 | image->colormap[0].blue=(Quantum) 0; |
486 | 84 | image->colormap[1].red=QuantumRange; |
487 | 84 | image->colormap[1].green=QuantumRange; |
488 | 84 | image->colormap[1].blue=QuantumRange; |
489 | 84 | } |
490 | 117 | else |
491 | 117 | if (image->colors > 16) |
492 | 63 | { |
493 | | /* |
494 | | 256 color images have their color map at the end of the file. |
495 | | */ |
496 | 63 | offset=SeekBlob(image,(MagickOffsetType) GetBlobSize(image)-3* |
497 | 63 | image->colors-1,SEEK_SET); |
498 | 63 | pcx_info.colormap_signature=(unsigned char) ReadBlobByte(image); |
499 | 63 | count=ReadBlob(image,3*image->colors,pcx_colormap); |
500 | 63 | p=pcx_colormap; |
501 | 7.83k | for (i=0; i < (ssize_t) image->colors; i++) |
502 | 7.77k | { |
503 | 7.77k | image->colormap[i].red=ScaleCharToQuantum(*p++); |
504 | 7.77k | image->colormap[i].green=ScaleCharToQuantum(*p++); |
505 | 7.77k | image->colormap[i].blue=ScaleCharToQuantum(*p++); |
506 | 7.77k | } |
507 | 63 | } |
508 | 201 | } |
509 | | /* |
510 | | Convert PCX raster image to pixel packets. |
511 | | */ |
512 | 71.5k | for (y=0; y < (ssize_t) image->rows; y++) |
513 | 71.1k | { |
514 | 71.1k | p=pixels+(y*pcx_info.bytes_per_line*pcx_info.planes); |
515 | 71.1k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
516 | 71.1k | if (q == (Quantum *) NULL) |
517 | 0 | break; |
518 | 71.1k | r=scanline; |
519 | 71.1k | if (image->storage_class == DirectClass) |
520 | 30.2k | for (i=0; i < pcx_info.planes; i++) |
521 | 21.0k | { |
522 | 21.0k | r=scanline+i; |
523 | 227k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
524 | 206k | { |
525 | 206k | switch (i) |
526 | 206k | { |
527 | 99.3k | case 0: |
528 | 99.3k | { |
529 | 99.3k | *r=(*p++); |
530 | 99.3k | break; |
531 | 0 | } |
532 | 99.3k | case 1: |
533 | 99.3k | { |
534 | 99.3k | *r=(*p++); |
535 | 99.3k | break; |
536 | 0 | } |
537 | 3.45k | case 2: |
538 | 3.45k | { |
539 | 3.45k | *r=(*p++); |
540 | 3.45k | break; |
541 | 0 | } |
542 | 3.09k | case 3: |
543 | 4.48k | default: |
544 | 4.48k | { |
545 | 4.48k | *r=(*p++); |
546 | 4.48k | break; |
547 | 3.09k | } |
548 | 206k | } |
549 | 206k | r+=(ptrdiff_t) pcx_info.planes; |
550 | 206k | } |
551 | 21.0k | } |
552 | 61.9k | else |
553 | 61.9k | if (pcx_info.planes > 1) |
554 | 13.6k | { |
555 | 252k | for (x=0; x < (ssize_t) image->columns; x++) |
556 | 238k | *r++=0; |
557 | 44.3k | for (i=0; i < pcx_info.planes; i++) |
558 | 30.6k | { |
559 | 30.6k | r=scanline; |
560 | 579k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
561 | 548k | { |
562 | 548k | bits=(*p++); |
563 | 4.94M | for (mask=0x80; mask != 0; mask>>=1) |
564 | 4.39M | { |
565 | 4.39M | if (bits & mask) |
566 | 3.75M | *r|=1 << i; |
567 | 4.39M | r++; |
568 | 4.39M | } |
569 | 548k | } |
570 | 30.6k | } |
571 | 13.6k | } |
572 | 48.2k | else |
573 | 48.2k | switch (pcx_info.bits_per_pixel) |
574 | 48.2k | { |
575 | 13.3k | case 1: |
576 | 13.3k | { |
577 | 13.3k | ssize_t |
578 | 13.3k | bit; |
579 | | |
580 | 550k | for (x=0; x < ((ssize_t) image->columns-7); x+=8) |
581 | 537k | { |
582 | 4.83M | for (bit=7; bit >= 0; bit--) |
583 | 4.29M | *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01); |
584 | 537k | p++; |
585 | 537k | } |
586 | 13.3k | if ((image->columns % 8) != 0) |
587 | 10.9k | { |
588 | 77.2k | for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--) |
589 | 66.3k | *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01); |
590 | 10.9k | p++; |
591 | 10.9k | } |
592 | 13.3k | break; |
593 | 0 | } |
594 | 32.7k | case 2: |
595 | 32.7k | { |
596 | 594k | for (x=0; x < ((ssize_t) image->columns-3); x+=4) |
597 | 561k | { |
598 | 561k | *r++=(*p >> 6) & 0x3; |
599 | 561k | *r++=(*p >> 4) & 0x3; |
600 | 561k | *r++=(*p >> 2) & 0x3; |
601 | 561k | *r++=(*p) & 0x3; |
602 | 561k | p++; |
603 | 561k | } |
604 | 32.7k | if ((image->columns % 4) != 0) |
605 | 30.3k | { |
606 | 101k | for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--) |
607 | 71.0k | *r++=(unsigned char) ((*p >> (i*2)) & 0x03); |
608 | 30.3k | p++; |
609 | 30.3k | } |
610 | 32.7k | break; |
611 | 0 | } |
612 | 1.65k | case 4: |
613 | 1.65k | { |
614 | 5.47k | for (x=0; x < ((ssize_t) image->columns-1); x+=2) |
615 | 3.81k | { |
616 | 3.81k | *r++=(*p >> 4) & 0xf; |
617 | 3.81k | *r++=(*p) & 0xf; |
618 | 3.81k | p++; |
619 | 3.81k | } |
620 | 1.65k | if ((image->columns % 2) != 0) |
621 | 1.32k | *r++=(*p++ >> 4) & 0xf; |
622 | 1.65k | break; |
623 | 0 | } |
624 | 564 | case 8: |
625 | 564 | { |
626 | 564 | (void) memcpy(r,p,image->columns); |
627 | 564 | break; |
628 | 0 | } |
629 | 0 | default: |
630 | 0 | break; |
631 | 48.2k | } |
632 | | /* |
633 | | Transfer image scanline. |
634 | | */ |
635 | 71.1k | r=scanline; |
636 | 7.02M | for (x=0; x < (ssize_t) image->columns; x++) |
637 | 6.95M | { |
638 | 6.95M | if (image->storage_class == PseudoClass) |
639 | 6.93M | SetPixelIndex(image,*r++,q); |
640 | 19.2k | else |
641 | 19.2k | { |
642 | 19.2k | SetPixelRed(image,ScaleCharToQuantum(*r++),q); |
643 | 19.2k | SetPixelGreen(image,ScaleCharToQuantum(*r++),q); |
644 | 19.2k | SetPixelBlue(image,ScaleCharToQuantum(*r++),q); |
645 | 19.2k | if (image->alpha_trait != UndefinedPixelTrait) |
646 | 1.91k | SetPixelAlpha(image,ScaleCharToQuantum(*r++),q); |
647 | 19.2k | } |
648 | 6.95M | q+=(ptrdiff_t) GetPixelChannels(image); |
649 | 6.95M | } |
650 | 71.1k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
651 | 0 | break; |
652 | 71.1k | if (image->previous == (Image *) NULL) |
653 | 71.1k | { |
654 | 71.1k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
655 | 71.1k | image->rows); |
656 | 71.1k | if (status == MagickFalse) |
657 | 0 | break; |
658 | 71.1k | } |
659 | 71.1k | } |
660 | 425 | if (image->storage_class == PseudoClass) |
661 | 332 | (void) SyncImage(image,exception); |
662 | 425 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
663 | 425 | pixel_info=RelinquishVirtualMemory(pixel_info); |
664 | 425 | if (EOFBlob(image) != MagickFalse) |
665 | 27 | { |
666 | 27 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
667 | 27 | image->filename); |
668 | 27 | break; |
669 | 27 | } |
670 | | /* |
671 | | Proceed to next image. |
672 | | */ |
673 | 398 | if (image_info->number_scenes != 0) |
674 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
675 | 0 | break; |
676 | 398 | if (page_table == (MagickOffsetType *) NULL) |
677 | 398 | break; |
678 | 0 | if (page_table[id] == 0) |
679 | 0 | break; |
680 | 0 | offset=SeekBlob(image,(MagickOffsetType) page_table[id],SEEK_SET); |
681 | 0 | if (offset < 0) |
682 | 0 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
683 | 0 | count=ReadBlob(image,1,&pcx_info.identifier); |
684 | 0 | if ((count != 0) && (pcx_info.identifier == 0x0a)) |
685 | 0 | { |
686 | | /* |
687 | | Allocate next image structure. |
688 | | */ |
689 | 0 | AcquireNextImage(image_info,image,exception); |
690 | 0 | if (GetNextImageInList(image) == (Image *) NULL) |
691 | 0 | { |
692 | 0 | status=MagickFalse; |
693 | 0 | break; |
694 | 0 | } |
695 | 0 | image=SyncNextImageInList(image); |
696 | 0 | status=SetImageProgress(image,LoadImagesTag,TellBlob(image), |
697 | 0 | GetBlobSize(image)); |
698 | 0 | if (status == MagickFalse) |
699 | 0 | break; |
700 | 0 | } |
701 | 0 | } |
702 | 425 | if (page_table != (MagickOffsetType *) NULL) |
703 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
704 | 425 | if (CloseBlob(image) == MagickFalse) |
705 | 0 | status=MagickFalse; |
706 | 425 | if (status == MagickFalse) |
707 | 0 | return(DestroyImageList(image)); |
708 | 425 | return(GetFirstImageInList(image)); |
709 | 425 | } |
710 | | |
711 | | /* |
712 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
713 | | % % |
714 | | % % |
715 | | % % |
716 | | % R e g i s t e r P C X I m a g e % |
717 | | % % |
718 | | % % |
719 | | % % |
720 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
721 | | % |
722 | | % RegisterPCXImage() adds attributes for the PCX image format to |
723 | | % the list of supported formats. The attributes include the image format |
724 | | % tag, a method to read and/or write the format, whether the format |
725 | | % supports the saving of more than one frame to the same file or blob, |
726 | | % whether the format supports native in-memory I/O, and a brief |
727 | | % description of the format. |
728 | | % |
729 | | % The format of the RegisterPCXImage method is: |
730 | | % |
731 | | % size_t RegisterPCXImage(void) |
732 | | % |
733 | | */ |
734 | | ModuleExport size_t RegisterPCXImage(void) |
735 | 9 | { |
736 | 9 | MagickInfo |
737 | 9 | *entry; |
738 | | |
739 | 9 | entry=AcquireMagickInfo("PCX","DCX","ZSoft IBM PC multi-page Paintbrush"); |
740 | 9 | entry->decoder=(DecodeImageHandler *) ReadPCXImage; |
741 | 9 | entry->encoder=(EncodeImageHandler *) WritePCXImage; |
742 | 9 | entry->flags|=CoderDecoderSeekableStreamFlag; |
743 | 9 | entry->flags|=CoderEncoderSeekableStreamFlag; |
744 | 9 | entry->magick=(IsImageFormatHandler *) IsDCX; |
745 | 9 | (void) RegisterMagickInfo(entry); |
746 | 9 | entry=AcquireMagickInfo("PCX","PCX","ZSoft IBM PC Paintbrush"); |
747 | 9 | entry->decoder=(DecodeImageHandler *) ReadPCXImage; |
748 | 9 | entry->encoder=(EncodeImageHandler *) WritePCXImage; |
749 | 9 | entry->magick=(IsImageFormatHandler *) IsPCX; |
750 | 9 | entry->flags^=CoderAdjoinFlag; |
751 | 9 | entry->flags|=CoderDecoderSeekableStreamFlag; |
752 | 9 | entry->flags|=CoderEncoderSeekableStreamFlag; |
753 | 9 | (void) RegisterMagickInfo(entry); |
754 | 9 | return(MagickImageCoderSignature); |
755 | 9 | } |
756 | | |
757 | | /* |
758 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
759 | | % % |
760 | | % % |
761 | | % % |
762 | | % U n r e g i s t e r P C X I m a g e % |
763 | | % % |
764 | | % % |
765 | | % % |
766 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
767 | | % |
768 | | % UnregisterPCXImage() removes format registrations made by the |
769 | | % PCX module from the list of supported formats. |
770 | | % |
771 | | % The format of the UnregisterPCXImage method is: |
772 | | % |
773 | | % UnregisterPCXImage(void) |
774 | | % |
775 | | */ |
776 | | ModuleExport void UnregisterPCXImage(void) |
777 | 0 | { |
778 | 0 | (void) UnregisterMagickInfo("DCX"); |
779 | 0 | (void) UnregisterMagickInfo("PCX"); |
780 | 0 | } |
781 | | |
782 | | /* |
783 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
784 | | % % |
785 | | % % |
786 | | % % |
787 | | % W r i t e P C X I m a g e % |
788 | | % % |
789 | | % % |
790 | | % % |
791 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
792 | | % |
793 | | % WritePCXImage() writes an image in the ZSoft IBM PC Paintbrush file |
794 | | % format. |
795 | | % |
796 | | % The format of the WritePCXImage method is: |
797 | | % |
798 | | % MagickBooleanType WritePCXImage(const ImageInfo *image_info, |
799 | | % Image *image,ExceptionInfo *exception) |
800 | | % |
801 | | % A description of each parameter follows. |
802 | | % |
803 | | % o image_info: the image info. |
804 | | % |
805 | | % o image: The image. |
806 | | % |
807 | | % o exception: return any errors or warnings in this structure. |
808 | | % |
809 | | */ |
810 | | |
811 | | static MagickBooleanType PCXWritePixels(PCXInfo *pcx_info, |
812 | | const unsigned char *pixels,Image *image) |
813 | 70.3k | { |
814 | 70.3k | const unsigned char |
815 | 70.3k | *q; |
816 | | |
817 | 70.3k | ssize_t |
818 | 70.3k | count, |
819 | 70.3k | i, |
820 | 70.3k | x; |
821 | | |
822 | 70.3k | unsigned char |
823 | 70.3k | packet, |
824 | 70.3k | previous; |
825 | | |
826 | 70.3k | q=pixels; |
827 | 160k | for (i=0; i < (ssize_t) pcx_info->planes; i++) |
828 | 89.8k | { |
829 | 89.8k | if (pcx_info->encoding == 0) |
830 | 0 | { |
831 | 0 | for (x=0; x < (ssize_t) pcx_info->bytes_per_line; x++) |
832 | 0 | (void) WriteBlobByte(image,(unsigned char) (*q++)); |
833 | 0 | } |
834 | 89.8k | else |
835 | 89.8k | { |
836 | 89.8k | previous=(*q++); |
837 | 89.8k | count=1; |
838 | 3.16M | for (x=0; x < (ssize_t) (pcx_info->bytes_per_line-1); x++) |
839 | 3.07M | { |
840 | 3.07M | packet=(*q++); |
841 | 3.07M | if ((packet == previous) && (count < 63)) |
842 | 1.64M | { |
843 | 1.64M | count++; |
844 | 1.64M | continue; |
845 | 1.64M | } |
846 | 1.42M | if ((count > 1) || ((previous & 0xc0) == 0xc0)) |
847 | 506k | { |
848 | 506k | count|=0xc0; |
849 | 506k | (void) WriteBlobByte(image,(unsigned char) count); |
850 | 506k | } |
851 | 1.42M | (void) WriteBlobByte(image,previous); |
852 | 1.42M | previous=packet; |
853 | 1.42M | count=1; |
854 | 1.42M | } |
855 | 89.8k | if ((count > 1) || ((previous & 0xc0) == 0xc0)) |
856 | 51.9k | { |
857 | 51.9k | count|=0xc0; |
858 | 51.9k | (void) WriteBlobByte(image,(unsigned char) count); |
859 | 51.9k | } |
860 | 89.8k | (void) WriteBlobByte(image,previous); |
861 | 89.8k | } |
862 | 89.8k | } |
863 | 70.3k | return (MagickTrue); |
864 | 70.3k | } |
865 | | |
866 | | static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image, |
867 | | ExceptionInfo *exception) |
868 | 387 | { |
869 | 387 | const Quantum |
870 | 387 | *p; |
871 | | |
872 | 387 | MagickBooleanType |
873 | 387 | status; |
874 | | |
875 | 387 | MagickOffsetType |
876 | 387 | offset, |
877 | 387 | *page_table, |
878 | 387 | scene; |
879 | | |
880 | 387 | MemoryInfo |
881 | 387 | *pixel_info; |
882 | | |
883 | 387 | PCXInfo |
884 | 387 | pcx_info; |
885 | | |
886 | 387 | size_t |
887 | 387 | number_scenes, |
888 | 387 | length; |
889 | | |
890 | 387 | ssize_t |
891 | 387 | i, |
892 | 387 | x, |
893 | 387 | y; |
894 | | |
895 | 387 | unsigned char |
896 | 387 | *pcx_colormap, |
897 | 387 | *pixels, |
898 | 387 | *q; |
899 | | |
900 | | /* |
901 | | Open output image file. |
902 | | */ |
903 | 387 | assert(image_info != (const ImageInfo *) NULL); |
904 | 387 | assert(image_info->signature == MagickCoreSignature); |
905 | 387 | assert(image != (Image *) NULL); |
906 | 387 | assert(image->signature == MagickCoreSignature); |
907 | 387 | assert(exception != (ExceptionInfo *) NULL); |
908 | 387 | assert(exception->signature == MagickCoreSignature); |
909 | 387 | if (IsEventLogging() != MagickFalse) |
910 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
911 | 387 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
912 | 387 | if (status == MagickFalse) |
913 | 0 | return(status); |
914 | 387 | number_scenes=GetImageListLength(image); |
915 | 387 | if (number_scenes > MaxNumberScenes) |
916 | 387 | ThrowWriterException(ResourceLimitError,"ListLengthExceedsLimit"); |
917 | 387 | page_table=(MagickOffsetType *) NULL; |
918 | 387 | if ((LocaleCompare(image_info->magick,"DCX") == 0) || |
919 | 387 | ((GetNextImageInList(image) != (Image *) NULL) && |
920 | 0 | (image_info->adjoin != MagickFalse))) |
921 | 0 | { |
922 | | /* |
923 | | Write the DCX page table. |
924 | | */ |
925 | 0 | (void) WriteBlobLSBLong(image,0x3ADE68B1L); |
926 | 0 | page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes+1, |
927 | 0 | sizeof(*page_table)); |
928 | 0 | if (page_table == (MagickOffsetType *) NULL) |
929 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
930 | 0 | for (scene=0; scene < MaxNumberScenes; scene++) |
931 | 0 | (void) WriteBlobLSBLong(image,0x00000000L); |
932 | 0 | } |
933 | 387 | scene=0; |
934 | 387 | do |
935 | 387 | { |
936 | 387 | if (page_table != (MagickOffsetType *) NULL) |
937 | 0 | page_table[scene]=TellBlob(image); |
938 | | /* |
939 | | Initialize PCX raster file header. |
940 | | */ |
941 | 387 | pcx_info.identifier=0x0a; |
942 | 387 | pcx_info.version=5; |
943 | 387 | pcx_info.encoding=image_info->compression == NoCompression ? 0 : 1; |
944 | 387 | pcx_info.bits_per_pixel=8; |
945 | 387 | if ((image->storage_class == PseudoClass) && |
946 | 294 | (SetImageMonochrome(image,exception) != MagickFalse)) |
947 | 117 | pcx_info.bits_per_pixel=1; |
948 | 270 | else |
949 | 270 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
950 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
951 | 387 | pcx_info.left=0; |
952 | 387 | pcx_info.top=0; |
953 | 387 | pcx_info.right=(unsigned short) (image->columns-1); |
954 | 387 | pcx_info.bottom=(unsigned short) (image->rows-1); |
955 | 387 | switch (image->units) |
956 | 387 | { |
957 | 0 | case UndefinedResolution: |
958 | 387 | case PixelsPerInchResolution: |
959 | 387 | default: |
960 | 387 | { |
961 | 387 | pcx_info.horizontal_resolution=CastDoubleToUShort(image->resolution.x); |
962 | 387 | pcx_info.vertical_resolution=CastDoubleToUShort(image->resolution.y); |
963 | 387 | break; |
964 | 387 | } |
965 | 0 | case PixelsPerCentimeterResolution: |
966 | 0 | { |
967 | 0 | pcx_info.horizontal_resolution=CastDoubleToUShort(2.54*image->resolution.x+0.5); |
968 | 0 | pcx_info.vertical_resolution=CastDoubleToUShort(2.54*image->resolution.y+0.5); |
969 | 0 | break; |
970 | 387 | } |
971 | 387 | } |
972 | 387 | pcx_info.reserved=0; |
973 | 387 | pcx_info.planes=1; |
974 | 387 | if ((image->storage_class == DirectClass) || (image->colors > 256)) |
975 | 93 | { |
976 | 93 | pcx_info.planes=3; |
977 | 93 | if (image->alpha_trait != UndefinedPixelTrait) |
978 | 43 | pcx_info.planes++; |
979 | 93 | } |
980 | 387 | length=(((size_t) image->columns*pcx_info.bits_per_pixel+7)/8); |
981 | 387 | if ((image->columns > 65535UL) || (image->rows > 65535UL) || |
982 | 387 | (length > 65535UL)) |
983 | 0 | { |
984 | 0 | if (page_table != (MagickOffsetType *) NULL) |
985 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
986 | 0 | ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); |
987 | 0 | } |
988 | 387 | pcx_info.bytes_per_line=(unsigned short) length; |
989 | 387 | pcx_info.palette_info=1; |
990 | 387 | pcx_info.colormap_signature=0x0c; |
991 | | /* |
992 | | Write PCX header. |
993 | | */ |
994 | 387 | (void) WriteBlobByte(image,pcx_info.identifier); |
995 | 387 | (void) WriteBlobByte(image,pcx_info.version); |
996 | 387 | (void) WriteBlobByte(image,pcx_info.encoding); |
997 | 387 | (void) WriteBlobByte(image,pcx_info.bits_per_pixel); |
998 | 387 | (void) WriteBlobLSBShort(image,pcx_info.left); |
999 | 387 | (void) WriteBlobLSBShort(image,pcx_info.top); |
1000 | 387 | (void) WriteBlobLSBShort(image,pcx_info.right); |
1001 | 387 | (void) WriteBlobLSBShort(image,pcx_info.bottom); |
1002 | 387 | (void) WriteBlobLSBShort(image,pcx_info.horizontal_resolution); |
1003 | 387 | (void) WriteBlobLSBShort(image,pcx_info.vertical_resolution); |
1004 | | /* |
1005 | | Dump colormap to file. |
1006 | | */ |
1007 | 387 | pcx_colormap=(unsigned char *) AcquireQuantumMemory(256UL, |
1008 | 387 | 3*sizeof(*pcx_colormap)); |
1009 | 387 | if (pcx_colormap == (unsigned char *) NULL) |
1010 | 0 | { |
1011 | 0 | if (page_table != (MagickOffsetType *) NULL) |
1012 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1013 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
1014 | 0 | } |
1015 | 387 | (void) memset(pcx_colormap,0,3*256*sizeof(*pcx_colormap)); |
1016 | 387 | q=pcx_colormap; |
1017 | 387 | if ((image->storage_class == PseudoClass) && (image->colors <= 256)) |
1018 | 6.63k | for (i=0; i < (ssize_t) image->colors; i++) |
1019 | 6.34k | { |
1020 | 6.34k | *q++=ScaleQuantumToChar((Quantum) image->colormap[i].red); |
1021 | 6.34k | *q++=ScaleQuantumToChar((Quantum) image->colormap[i].green); |
1022 | 6.34k | *q++=ScaleQuantumToChar((Quantum) image->colormap[i].blue); |
1023 | 6.34k | } |
1024 | 387 | (void) WriteBlob(image,3*16,(const unsigned char *) pcx_colormap); |
1025 | 387 | (void) WriteBlobByte(image,pcx_info.reserved); |
1026 | 387 | (void) WriteBlobByte(image,pcx_info.planes); |
1027 | 387 | (void) WriteBlobLSBShort(image,pcx_info.bytes_per_line); |
1028 | 387 | (void) WriteBlobLSBShort(image,pcx_info.palette_info); |
1029 | 22.8k | for (i=0; i < 58; i++) |
1030 | 22.4k | (void) WriteBlobByte(image,'\0'); |
1031 | 387 | length=(size_t) pcx_info.bytes_per_line; |
1032 | 387 | pixel_info=AcquireVirtualMemory(length,pcx_info.planes*sizeof(*pixels)); |
1033 | 387 | if (pixel_info == (MemoryInfo *) NULL) |
1034 | 0 | { |
1035 | 0 | pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap); |
1036 | 0 | if (page_table != (MagickOffsetType *) NULL) |
1037 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1038 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
1039 | 0 | } |
1040 | 387 | pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); |
1041 | 387 | q=pixels; |
1042 | 387 | if ((image->storage_class == DirectClass) || (image->colors > 256)) |
1043 | 93 | { |
1044 | | /* |
1045 | | Convert DirectClass image to PCX raster pixels. |
1046 | | */ |
1047 | 9.28k | for (y=0; y < (ssize_t) image->rows; y++) |
1048 | 9.18k | { |
1049 | 9.18k | q=pixels; |
1050 | 37.8k | for (i=0; i < pcx_info.planes; i++) |
1051 | 28.6k | { |
1052 | 28.6k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
1053 | 28.6k | if (p == (const Quantum *) NULL) |
1054 | 0 | break; |
1055 | 28.6k | switch ((int) i) |
1056 | 28.6k | { |
1057 | 9.18k | case 0: |
1058 | 9.18k | { |
1059 | 28.4k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
1060 | 19.2k | { |
1061 | 19.2k | *q++=ScaleQuantumToChar(GetPixelRed(image,p)); |
1062 | 19.2k | p+=(ptrdiff_t) GetPixelChannels(image); |
1063 | 19.2k | } |
1064 | 9.18k | break; |
1065 | 0 | } |
1066 | 9.18k | case 1: |
1067 | 9.18k | { |
1068 | 28.4k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
1069 | 19.2k | { |
1070 | 19.2k | *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); |
1071 | 19.2k | p+=(ptrdiff_t) GetPixelChannels(image); |
1072 | 19.2k | } |
1073 | 9.18k | break; |
1074 | 0 | } |
1075 | 9.18k | case 2: |
1076 | 9.18k | { |
1077 | 28.4k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
1078 | 19.2k | { |
1079 | 19.2k | *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); |
1080 | 19.2k | p+=(ptrdiff_t) GetPixelChannels(image); |
1081 | 19.2k | } |
1082 | 9.18k | break; |
1083 | 0 | } |
1084 | 1.12k | case 3: |
1085 | 1.12k | default: |
1086 | 1.12k | { |
1087 | 3.04k | for (x=(ssize_t) pcx_info.bytes_per_line; x != 0; x--) |
1088 | 1.91k | { |
1089 | 1.91k | *q++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p))); |
1090 | 1.91k | p+=(ptrdiff_t) GetPixelChannels(image); |
1091 | 1.91k | } |
1092 | 1.12k | break; |
1093 | 1.12k | } |
1094 | 28.6k | } |
1095 | 28.6k | } |
1096 | 9.18k | if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse) |
1097 | 0 | break; |
1098 | 9.18k | if (image->previous == (Image *) NULL) |
1099 | 9.18k | { |
1100 | 9.18k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
1101 | 9.18k | image->rows); |
1102 | 9.18k | if (status == MagickFalse) |
1103 | 0 | break; |
1104 | 9.18k | } |
1105 | 9.18k | } |
1106 | 93 | } |
1107 | 294 | else |
1108 | 294 | { |
1109 | 294 | if (pcx_info.bits_per_pixel > 1) |
1110 | 47.3k | for (y=0; y < (ssize_t) image->rows; y++) |
1111 | 47.1k | { |
1112 | 47.1k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
1113 | 47.1k | if (p == (const Quantum *) NULL) |
1114 | 0 | break; |
1115 | 47.1k | q=pixels; |
1116 | 2.60M | for (x=0; x < (ssize_t) image->columns; x++) |
1117 | 2.55M | { |
1118 | 2.55M | *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p)); |
1119 | 2.55M | p+=(ptrdiff_t) GetPixelChannels(image); |
1120 | 2.55M | } |
1121 | 47.1k | if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse) |
1122 | 0 | break; |
1123 | 47.1k | if (image->previous == (Image *) NULL) |
1124 | 47.1k | { |
1125 | 47.1k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) |
1126 | 47.1k | y,image->rows); |
1127 | 47.1k | if (status == MagickFalse) |
1128 | 0 | break; |
1129 | 47.1k | } |
1130 | 47.1k | } |
1131 | 117 | else |
1132 | 117 | { |
1133 | 117 | unsigned char |
1134 | 117 | bit, |
1135 | 117 | byte; |
1136 | | |
1137 | | /* |
1138 | | Convert PseudoClass image to a PCX monochrome image. |
1139 | | */ |
1140 | 14.0k | for (y=0; y < (ssize_t) image->rows; y++) |
1141 | 13.9k | { |
1142 | 13.9k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
1143 | 13.9k | if (p == (const Quantum *) NULL) |
1144 | 0 | break; |
1145 | 13.9k | bit=0; |
1146 | 13.9k | byte=0; |
1147 | 13.9k | q=pixels; |
1148 | 4.38M | for (x=0; x < (ssize_t) image->columns; x++) |
1149 | 4.36M | { |
1150 | 4.36M | byte<<=1; |
1151 | 4.36M | if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0)) |
1152 | 3.53M | byte|=0x01; |
1153 | 4.36M | bit++; |
1154 | 4.36M | if (bit == 8) |
1155 | 537k | { |
1156 | 537k | *q++=byte; |
1157 | 537k | bit=0; |
1158 | 537k | byte=0; |
1159 | 537k | } |
1160 | 4.36M | p+=(ptrdiff_t) GetPixelChannels(image); |
1161 | 4.36M | } |
1162 | 13.9k | if (bit != 0) |
1163 | 11.5k | *q++=byte << (8-bit); |
1164 | 13.9k | if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse) |
1165 | 0 | break; |
1166 | 13.9k | if (image->previous == (Image *) NULL) |
1167 | 13.9k | { |
1168 | 13.9k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) |
1169 | 13.9k | y,image->rows); |
1170 | 13.9k | if (status == MagickFalse) |
1171 | 0 | break; |
1172 | 13.9k | } |
1173 | 13.9k | } |
1174 | 117 | } |
1175 | 294 | (void) WriteBlobByte(image,pcx_info.colormap_signature); |
1176 | 294 | (void) WriteBlob(image,3*256,pcx_colormap); |
1177 | 294 | } |
1178 | 387 | pixel_info=RelinquishVirtualMemory(pixel_info); |
1179 | 387 | pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap); |
1180 | 387 | if (page_table == (MagickOffsetType *) NULL) |
1181 | 387 | break; |
1182 | 0 | if (GetNextImageInList(image) == (Image *) NULL) |
1183 | 0 | break; |
1184 | 0 | image=SyncNextImageInList(image); |
1185 | 0 | status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes); |
1186 | 0 | if (status == MagickFalse) |
1187 | 0 | break; |
1188 | 0 | } while (image_info->adjoin != MagickFalse); |
1189 | 387 | if (page_table != (MagickOffsetType *) NULL) |
1190 | 0 | { |
1191 | | /* |
1192 | | Write the DCX page table. |
1193 | | */ |
1194 | 0 | page_table[scene+1]=0; |
1195 | 0 | offset=SeekBlob(image,0L,SEEK_SET); |
1196 | 0 | if (offset < 0) |
1197 | 0 | { |
1198 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1199 | 0 | ThrowWriterException(CorruptImageError,"ImproperImageHeader"); |
1200 | 0 | } |
1201 | 0 | (void) WriteBlobLSBLong(image,0x3ADE68B1L); |
1202 | 0 | for (i=0; i <= (ssize_t) scene; i++) |
1203 | 0 | (void) WriteBlobLSBLong(image,(unsigned int) page_table[i]); |
1204 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1205 | 0 | } |
1206 | 387 | if (status == MagickFalse) |
1207 | 0 | { |
1208 | 0 | char |
1209 | 0 | *message; |
1210 | |
|
1211 | 0 | message=GetExceptionMessage(errno); |
1212 | 0 | (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, |
1213 | 0 | "UnableToWriteFile","`%s': %s",image->filename,message); |
1214 | 0 | message=DestroyString(message); |
1215 | 0 | } |
1216 | 387 | if (CloseBlob(image) == MagickFalse) |
1217 | 0 | status=MagickFalse; |
1218 | 387 | return(status); |
1219 | 387 | } |