/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/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 "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 | 1.29k | { |
205 | 3.67k | #define MaxNumberScenes 1024 |
206 | 1.29k | #define ThrowPCXException(severity,tag) \ |
207 | 764 | { \ |
208 | 764 | if (scanline != (unsigned char *) NULL) \ |
209 | 764 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); \ |
210 | 764 | if (pixel_info != (MemoryInfo *) NULL) \ |
211 | 764 | pixel_info=RelinquishVirtualMemory(pixel_info); \ |
212 | 764 | if (page_table != (MagickOffsetType *) NULL) \ |
213 | 764 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); \ |
214 | 764 | ThrowReaderException(severity,tag); \ |
215 | 0 | } |
216 | | |
217 | 1.29k | Image |
218 | 1.29k | *image; |
219 | | |
220 | 1.29k | int |
221 | 1.29k | bits, |
222 | 1.29k | id, |
223 | 1.29k | mask; |
224 | | |
225 | 1.29k | MagickBooleanType |
226 | 1.29k | status; |
227 | | |
228 | 1.29k | MagickOffsetType |
229 | 1.29k | offset, |
230 | 1.29k | *page_table; |
231 | | |
232 | 1.29k | MemoryInfo |
233 | 1.29k | *pixel_info; |
234 | | |
235 | 1.29k | PCXInfo |
236 | 1.29k | pcx_info; |
237 | | |
238 | 1.29k | Quantum |
239 | 1.29k | *q; |
240 | | |
241 | 1.29k | size_t |
242 | 1.29k | one, |
243 | 1.29k | pcx_packets; |
244 | | |
245 | 1.29k | ssize_t |
246 | 1.29k | count, |
247 | 1.29k | i, |
248 | 1.29k | x, |
249 | 1.29k | y; |
250 | | |
251 | 1.29k | unsigned char |
252 | 1.29k | *p, |
253 | 1.29k | packet, |
254 | 1.29k | pcx_colormap[768], |
255 | 1.29k | *pixels, |
256 | 1.29k | *r, |
257 | 1.29k | *scanline; |
258 | | |
259 | | /* |
260 | | Open image file. |
261 | | */ |
262 | 1.29k | assert(image_info != (const ImageInfo *) NULL); |
263 | 1.29k | assert(image_info->signature == MagickCoreSignature); |
264 | 1.29k | assert(exception != (ExceptionInfo *) NULL); |
265 | 1.29k | assert(exception->signature == MagickCoreSignature); |
266 | 1.29k | if (IsEventLogging() != MagickFalse) |
267 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
268 | 0 | image_info->filename); |
269 | 1.29k | image=AcquireImage(image_info,exception); |
270 | 1.29k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
271 | 1.29k | 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 | 1.29k | page_table=(MagickOffsetType *) NULL; |
280 | 1.29k | scanline=(unsigned char *) NULL; |
281 | 1.29k | pixel_info=(MemoryInfo *) NULL; |
282 | 1.29k | if (LocaleCompare(image_info->magick,"DCX") == 0) |
283 | 65 | { |
284 | 65 | size_t |
285 | 65 | magic; |
286 | | |
287 | | /* |
288 | | Read the DCX page table. |
289 | | */ |
290 | 65 | magic=ReadBlobLSBLong(image); |
291 | 65 | if (magic != 987654321) |
292 | 65 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
293 | 65 | page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes, |
294 | 65 | sizeof(*page_table)); |
295 | 65 | if (page_table == (MagickOffsetType *) NULL) |
296 | 65 | ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed"); |
297 | 1.92k | for (id=0; id < MaxNumberScenes; id++) |
298 | 1.92k | { |
299 | 1.92k | page_table[id]=(MagickOffsetType) ReadBlobLSBLong(image); |
300 | 1.92k | if (page_table[id] == 0) |
301 | 64 | break; |
302 | 1.92k | } |
303 | 65 | } |
304 | 1.29k | if (page_table != (MagickOffsetType *) NULL) |
305 | 65 | { |
306 | 65 | offset=SeekBlob(image,(MagickOffsetType) page_table[0],SEEK_SET); |
307 | 65 | if (offset < 0) |
308 | 65 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
309 | 65 | } |
310 | 1.29k | count=ReadBlob(image,1,&pcx_info.identifier); |
311 | 1.29k | for (id=1; id < MaxNumberScenes; id++) |
312 | 1.29k | { |
313 | 1.29k | int |
314 | 1.29k | bits_per_pixel; |
315 | | |
316 | | /* |
317 | | Verify PCX identifier. |
318 | | */ |
319 | 1.29k | pcx_info.version=(unsigned char) ReadBlobByte(image); |
320 | 1.29k | if ((count != 1) || (pcx_info.identifier != 0x0a)) |
321 | 1.04k | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
322 | 1.04k | pcx_info.encoding=(unsigned char) ReadBlobByte(image); |
323 | 1.04k | bits_per_pixel=ReadBlobByte(image); |
324 | 1.04k | if (bits_per_pixel == -1) |
325 | 1.03k | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
326 | 1.03k | pcx_info.bits_per_pixel=(unsigned char) bits_per_pixel; |
327 | 1.03k | pcx_info.left=ReadBlobLSBShort(image); |
328 | 1.03k | pcx_info.top=ReadBlobLSBShort(image); |
329 | 1.03k | pcx_info.right=ReadBlobLSBShort(image); |
330 | 1.03k | pcx_info.bottom=ReadBlobLSBShort(image); |
331 | 1.03k | pcx_info.horizontal_resolution=ReadBlobLSBShort(image); |
332 | 1.03k | pcx_info.vertical_resolution=ReadBlobLSBShort(image); |
333 | 1.03k | if (EOFBlob(image) != MagickFalse) |
334 | 1.01k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
335 | | /* |
336 | | Read PCX raster colormap. |
337 | | */ |
338 | 1.01k | if ((pcx_info.right < pcx_info.left) || (pcx_info.bottom < pcx_info.top) || |
339 | 1.00k | ((pcx_info.bits_per_pixel != 1) && (pcx_info.bits_per_pixel != 2) && |
340 | 418 | (pcx_info.bits_per_pixel != 4) && (pcx_info.bits_per_pixel != 8))) |
341 | 987 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
342 | 987 | image->columns=(size_t) (pcx_info.right-pcx_info.left)+1UL; |
343 | 987 | image->rows=(size_t) (pcx_info.bottom-pcx_info.top)+1UL; |
344 | 987 | image->depth=pcx_info.bits_per_pixel; |
345 | 987 | image->units=PixelsPerInchResolution; |
346 | 987 | image->resolution.x=(double) pcx_info.horizontal_resolution; |
347 | 987 | image->resolution.y=(double) pcx_info.vertical_resolution; |
348 | 987 | image->colors=16; |
349 | 987 | 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 | 987 | if ((MagickSizeType) (image->columns*image->rows/255) > GetBlobSize(image)) |
353 | 942 | ThrowPCXException(CorruptImageError,"InsufficientImageDataInFile"); |
354 | 942 | status=SetImageExtent(image,image->columns,image->rows,exception); |
355 | 942 | if (status == MagickFalse) |
356 | 889 | ThrowPCXException(exception->severity,exception->reason); |
357 | 889 | (void) SetImageBackgroundColor(image,exception); |
358 | 889 | (void) memset(pcx_colormap,0,sizeof(pcx_colormap)); |
359 | 889 | count=ReadBlob(image,3*image->colors,pcx_colormap); |
360 | 889 | if (count != (ssize_t) (3*image->colors)) |
361 | 780 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
362 | 780 | pcx_info.reserved=(unsigned char) ReadBlobByte(image); |
363 | 780 | pcx_info.planes=(unsigned char) ReadBlobByte(image); |
364 | 780 | if (pcx_info.planes == 0) |
365 | 772 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
366 | 772 | if (pcx_info.planes > 6) |
367 | 753 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
368 | 753 | if ((pcx_info.bits_per_pixel*pcx_info.planes) >= 64) |
369 | 753 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
370 | 753 | one=1; |
371 | 753 | if ((pcx_info.bits_per_pixel != 8) || (pcx_info.planes == 1)) |
372 | 613 | if ((pcx_info.version == 3) || (pcx_info.version == 5) || |
373 | 411 | ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)) |
374 | 318 | image->colors=(size_t) MagickMin(one << (1UL* |
375 | 753 | (pcx_info.bits_per_pixel*pcx_info.planes)),256UL); |
376 | 753 | if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) |
377 | 753 | ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed"); |
378 | 753 | if ((pcx_info.bits_per_pixel >= 8) && (pcx_info.planes != 1)) |
379 | 140 | image->storage_class=DirectClass; |
380 | 753 | p=pcx_colormap; |
381 | 20.8k | for (i=0; i < (ssize_t) image->colors; i++) |
382 | 20.0k | { |
383 | 20.0k | image->colormap[i].red=ScaleCharToQuantum(*p++); |
384 | 20.0k | image->colormap[i].green=ScaleCharToQuantum(*p++); |
385 | 20.0k | image->colormap[i].blue=ScaleCharToQuantum(*p++); |
386 | 20.0k | } |
387 | 753 | pcx_info.bytes_per_line=ReadBlobLSBShort(image); |
388 | 753 | pcx_info.palette_info=ReadBlobLSBShort(image); |
389 | 753 | pcx_info.horizontal_screensize=ReadBlobLSBShort(image); |
390 | 753 | pcx_info.vertical_screensize=ReadBlobLSBShort(image); |
391 | 41.4k | for (i=0; i < 54; i++) |
392 | 40.6k | (void) ReadBlobByte(image); |
393 | | /* |
394 | | Read image data. |
395 | | */ |
396 | 753 | if (HeapOverflowSanityCheckGetSize(image->rows,(size_t) pcx_info.bytes_per_line,&pcx_packets) != MagickFalse) |
397 | 728 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
398 | 728 | if (HeapOverflowSanityCheckGetSize(pcx_packets,(size_t) pcx_info.planes,&pcx_packets) != MagickFalse) |
399 | 728 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
400 | 728 | if ((size_t) (pcx_info.bits_per_pixel*pcx_info.planes*image->columns) > (pcx_packets*8U)) |
401 | 710 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
402 | 710 | if ((MagickSizeType) (pcx_packets/32+128) > GetBlobSize(image)) |
403 | 645 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
404 | 645 | scanline=(unsigned char *) AcquireQuantumMemory(MagickMax(image->columns, |
405 | 645 | pcx_info.bytes_per_line),MagickMax(pcx_info.planes,8)*sizeof(*scanline)); |
406 | 645 | pixel_info=AcquireVirtualMemory(pcx_packets,2*sizeof(*pixels)); |
407 | 645 | if ((scanline == (unsigned char *) NULL) || |
408 | 645 | (pixel_info == (MemoryInfo *) NULL)) |
409 | 0 | { |
410 | 0 | if (scanline != (unsigned char *) NULL) |
411 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
412 | 0 | if (pixel_info != (MemoryInfo *) NULL) |
413 | 0 | pixel_info=RelinquishVirtualMemory(pixel_info); |
414 | 0 | ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed"); |
415 | 0 | } |
416 | 645 | (void) memset(scanline,0,(size_t) MagickMax(image->columns, |
417 | 645 | pcx_info.bytes_per_line)*MagickMax(pcx_info.planes,8)*sizeof(*scanline)); |
418 | 645 | pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); |
419 | 645 | (void) memset(pixels,0,(size_t) pcx_packets*(2*sizeof(*pixels))); |
420 | | /* |
421 | | Uncompress image data. |
422 | | */ |
423 | 645 | p=pixels; |
424 | 645 | if (pcx_info.encoding == 0) |
425 | 7.22k | while (pcx_packets != 0) |
426 | 7.20k | { |
427 | 7.20k | packet=(unsigned char) ReadBlobByte(image); |
428 | 7.20k | if (EOFBlob(image) != MagickFalse) |
429 | 7.16k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
430 | 7.16k | *p++=packet; |
431 | 7.16k | pcx_packets--; |
432 | 7.16k | } |
433 | 589 | else |
434 | 88.4k | while (pcx_packets != 0) |
435 | 87.9k | { |
436 | 87.9k | packet=(unsigned char) ReadBlobByte(image); |
437 | 87.9k | if (EOFBlob(image) != MagickFalse) |
438 | 87.8k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
439 | 87.8k | if ((packet & 0xc0) != 0xc0) |
440 | 52.5k | { |
441 | 52.5k | *p++=packet; |
442 | 52.5k | pcx_packets--; |
443 | 52.5k | continue; |
444 | 52.5k | } |
445 | 35.3k | count=(ssize_t) (packet & 0x3f); |
446 | 35.3k | packet=(unsigned char) ReadBlobByte(image); |
447 | 35.3k | if (EOFBlob(image) != MagickFalse) |
448 | 35.3k | ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile"); |
449 | 1.94M | for ( ; count != 0; count--) |
450 | 1.91M | { |
451 | 1.91M | *p++=packet; |
452 | 1.91M | pcx_packets--; |
453 | 1.91M | if (pcx_packets == 0) |
454 | 443 | break; |
455 | 1.91M | } |
456 | 35.3k | } |
457 | 532 | if (image->storage_class == DirectClass) |
458 | 106 | image->alpha_trait=pcx_info.planes > 3 ? BlendPixelTrait : |
459 | 106 | UndefinedPixelTrait; |
460 | 426 | else |
461 | 426 | if ((pcx_info.version == 5) || |
462 | 300 | ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)) |
463 | 211 | { |
464 | | /* |
465 | | Initialize image colormap. |
466 | | */ |
467 | 211 | if (image->colors > 256) |
468 | 211 | ThrowPCXException(CorruptImageError,"ColormapExceeds256Colors"); |
469 | 211 | if ((pcx_info.bits_per_pixel*pcx_info.planes) == 1) |
470 | 90 | { |
471 | | /* |
472 | | Monochrome colormap. |
473 | | */ |
474 | 90 | image->colormap[0].red=(Quantum) 0; |
475 | 90 | image->colormap[0].green=(Quantum) 0; |
476 | 90 | image->colormap[0].blue=(Quantum) 0; |
477 | 90 | image->colormap[1].red=QuantumRange; |
478 | 90 | image->colormap[1].green=QuantumRange; |
479 | 90 | image->colormap[1].blue=QuantumRange; |
480 | 90 | } |
481 | 121 | else |
482 | 121 | if (image->colors > 16) |
483 | 72 | { |
484 | | /* |
485 | | 256 color images have their color map at the end of the file. |
486 | | */ |
487 | 72 | offset=SeekBlob(image,(MagickOffsetType) GetBlobSize(image)-3* |
488 | 72 | image->colors-1,SEEK_SET); |
489 | 72 | pcx_info.colormap_signature=(unsigned char) ReadBlobByte(image); |
490 | 72 | count=ReadBlob(image,3*image->colors,pcx_colormap); |
491 | 72 | p=pcx_colormap; |
492 | 7.36k | for (i=0; i < (ssize_t) image->colors; i++) |
493 | 7.29k | { |
494 | 7.29k | image->colormap[i].red=ScaleCharToQuantum(*p++); |
495 | 7.29k | image->colormap[i].green=ScaleCharToQuantum(*p++); |
496 | 7.29k | image->colormap[i].blue=ScaleCharToQuantum(*p++); |
497 | 7.29k | } |
498 | 72 | } |
499 | 211 | } |
500 | | /* |
501 | | Convert PCX raster image to pixel packets. |
502 | | */ |
503 | 80.8k | for (y=0; y < (ssize_t) image->rows; y++) |
504 | 80.3k | { |
505 | 80.3k | p=pixels+(y*pcx_info.bytes_per_line*pcx_info.planes); |
506 | 80.3k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
507 | 80.3k | if (q == (Quantum *) NULL) |
508 | 0 | break; |
509 | 80.3k | r=scanline; |
510 | 80.3k | if (image->storage_class == DirectClass) |
511 | 66.8k | for (i=0; i < pcx_info.planes; i++) |
512 | 52.8k | { |
513 | 52.8k | r=scanline+i; |
514 | 799k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
515 | 746k | { |
516 | 746k | switch (i) |
517 | 746k | { |
518 | 256k | case 0: |
519 | 256k | { |
520 | 256k | *r=(*p++); |
521 | 256k | break; |
522 | 0 | } |
523 | 256k | case 1: |
524 | 256k | { |
525 | 256k | *r=(*p++); |
526 | 256k | break; |
527 | 0 | } |
528 | 81.7k | case 2: |
529 | 81.7k | { |
530 | 81.7k | *r=(*p++); |
531 | 81.7k | break; |
532 | 0 | } |
533 | 80.5k | case 3: |
534 | 151k | default: |
535 | 151k | { |
536 | 151k | *r=(*p++); |
537 | 151k | break; |
538 | 80.5k | } |
539 | 746k | } |
540 | 746k | r+=(ptrdiff_t) pcx_info.planes; |
541 | 746k | } |
542 | 52.8k | } |
543 | 66.3k | else |
544 | 66.3k | if (pcx_info.planes > 1) |
545 | 5.54k | { |
546 | 1.92M | for (x=0; x < (ssize_t) image->columns; x++) |
547 | 1.92M | *r++=0; |
548 | 21.4k | for (i=0; i < pcx_info.planes; i++) |
549 | 15.9k | { |
550 | 15.9k | r=scanline; |
551 | 404k | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
552 | 388k | { |
553 | 388k | bits=(*p++); |
554 | 3.49M | for (mask=0x80; mask != 0; mask>>=1) |
555 | 3.10M | { |
556 | 3.10M | if (bits & mask) |
557 | 2.87M | *r|=1 << i; |
558 | 3.10M | r++; |
559 | 3.10M | } |
560 | 388k | } |
561 | 15.9k | } |
562 | 5.54k | } |
563 | 60.7k | else |
564 | 60.7k | switch (pcx_info.bits_per_pixel) |
565 | 60.7k | { |
566 | 6.83k | case 1: |
567 | 6.83k | { |
568 | 6.83k | ssize_t |
569 | 6.83k | bit; |
570 | | |
571 | 289k | for (x=0; x < ((ssize_t) image->columns-7); x+=8) |
572 | 282k | { |
573 | 2.54M | for (bit=7; bit >= 0; bit--) |
574 | 2.25M | *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01); |
575 | 282k | p++; |
576 | 282k | } |
577 | 6.83k | if ((image->columns % 8) != 0) |
578 | 3.62k | { |
579 | 23.7k | for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--) |
580 | 20.1k | *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01); |
581 | 3.62k | p++; |
582 | 3.62k | } |
583 | 6.83k | break; |
584 | 0 | } |
585 | 48.3k | case 2: |
586 | 48.3k | { |
587 | 3.69M | for (x=0; x < ((ssize_t) image->columns-3); x+=4) |
588 | 3.64M | { |
589 | 3.64M | *r++=(*p >> 6) & 0x3; |
590 | 3.64M | *r++=(*p >> 4) & 0x3; |
591 | 3.64M | *r++=(*p >> 2) & 0x3; |
592 | 3.64M | *r++=(*p) & 0x3; |
593 | 3.64M | p++; |
594 | 3.64M | } |
595 | 48.3k | if ((image->columns % 4) != 0) |
596 | 45.3k | { |
597 | 157k | for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--) |
598 | 112k | *r++=(unsigned char) ((*p >> (i*2)) & 0x03); |
599 | 45.3k | p++; |
600 | 45.3k | } |
601 | 48.3k | break; |
602 | 0 | } |
603 | 4.94k | case 4: |
604 | 4.94k | { |
605 | 780k | for (x=0; x < ((ssize_t) image->columns-1); x+=2) |
606 | 775k | { |
607 | 775k | *r++=(*p >> 4) & 0xf; |
608 | 775k | *r++=(*p) & 0xf; |
609 | 775k | p++; |
610 | 775k | } |
611 | 4.94k | if ((image->columns % 2) != 0) |
612 | 2.58k | *r++=(*p++ >> 4) & 0xf; |
613 | 4.94k | break; |
614 | 0 | } |
615 | 672 | case 8: |
616 | 672 | { |
617 | 672 | (void) memcpy(r,p,image->columns); |
618 | 672 | break; |
619 | 0 | } |
620 | 0 | default: |
621 | 0 | break; |
622 | 60.7k | } |
623 | | /* |
624 | | Transfer image scanline. |
625 | | */ |
626 | 80.3k | r=scanline; |
627 | 28.0M | for (x=0; x < (ssize_t) image->columns; x++) |
628 | 28.0M | { |
629 | 28.0M | if (image->storage_class == PseudoClass) |
630 | 20.5M | SetPixelIndex(image,*r++,q); |
631 | 7.46M | else |
632 | 7.46M | { |
633 | 7.46M | SetPixelRed(image,ScaleCharToQuantum(*r++),q); |
634 | 7.46M | SetPixelGreen(image,ScaleCharToQuantum(*r++),q); |
635 | 7.46M | SetPixelBlue(image,ScaleCharToQuantum(*r++),q); |
636 | 7.46M | if (image->alpha_trait != UndefinedPixelTrait) |
637 | 7.36M | SetPixelAlpha(image,ScaleCharToQuantum(*r++),q); |
638 | 7.46M | } |
639 | 28.0M | q+=(ptrdiff_t) GetPixelChannels(image); |
640 | 28.0M | } |
641 | 80.3k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
642 | 0 | break; |
643 | 80.3k | if (image->previous == (Image *) NULL) |
644 | 80.3k | { |
645 | 80.3k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
646 | 80.3k | image->rows); |
647 | 80.3k | if (status == MagickFalse) |
648 | 0 | break; |
649 | 80.3k | } |
650 | 80.3k | } |
651 | 532 | if (image->storage_class == PseudoClass) |
652 | 426 | (void) SyncImage(image,exception); |
653 | 532 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
654 | 532 | pixel_info=RelinquishVirtualMemory(pixel_info); |
655 | 532 | if (EOFBlob(image) != MagickFalse) |
656 | 32 | { |
657 | 32 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
658 | 32 | image->filename); |
659 | 32 | break; |
660 | 32 | } |
661 | | /* |
662 | | Proceed to next image. |
663 | | */ |
664 | 500 | if (image_info->number_scenes != 0) |
665 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
666 | 0 | break; |
667 | 500 | if (page_table == (MagickOffsetType *) NULL) |
668 | 499 | break; |
669 | 1 | if (page_table[id] == 0) |
670 | 0 | break; |
671 | 1 | offset=SeekBlob(image,(MagickOffsetType) page_table[id],SEEK_SET); |
672 | 1 | if (offset < 0) |
673 | 1 | ThrowPCXException(CorruptImageError,"ImproperImageHeader"); |
674 | 1 | count=ReadBlob(image,1,&pcx_info.identifier); |
675 | 1 | if ((count != 0) && (pcx_info.identifier == 0x0a)) |
676 | 0 | { |
677 | | /* |
678 | | Allocate next image structure. |
679 | | */ |
680 | 0 | AcquireNextImage(image_info,image,exception); |
681 | 0 | if (GetNextImageInList(image) == (Image *) NULL) |
682 | 0 | { |
683 | 0 | status=MagickFalse; |
684 | 0 | break; |
685 | 0 | } |
686 | 0 | image=SyncNextImageInList(image); |
687 | 0 | status=SetImageProgress(image,LoadImagesTag,TellBlob(image), |
688 | 0 | GetBlobSize(image)); |
689 | 0 | if (status == MagickFalse) |
690 | 0 | break; |
691 | 0 | } |
692 | 1 | } |
693 | 531 | if (page_table != (MagickOffsetType *) NULL) |
694 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
695 | 531 | if (CloseBlob(image) == MagickFalse) |
696 | 0 | status=MagickFalse; |
697 | 531 | if (status == MagickFalse) |
698 | 0 | return(DestroyImageList(image)); |
699 | 531 | return(GetFirstImageInList(image)); |
700 | 531 | } |
701 | | |
702 | | /* |
703 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
704 | | % % |
705 | | % % |
706 | | % % |
707 | | % R e g i s t e r P C X I m a g e % |
708 | | % % |
709 | | % % |
710 | | % % |
711 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
712 | | % |
713 | | % RegisterPCXImage() adds attributes for the PCX image format to |
714 | | % the list of supported formats. The attributes include the image format |
715 | | % tag, a method to read and/or write the format, whether the format |
716 | | % supports the saving of more than one frame to the same file or blob, |
717 | | % whether the format supports native in-memory I/O, and a brief |
718 | | % description of the format. |
719 | | % |
720 | | % The format of the RegisterPCXImage method is: |
721 | | % |
722 | | % size_t RegisterPCXImage(void) |
723 | | % |
724 | | */ |
725 | | ModuleExport size_t RegisterPCXImage(void) |
726 | 9 | { |
727 | 9 | MagickInfo |
728 | 9 | *entry; |
729 | | |
730 | 9 | entry=AcquireMagickInfo("PCX","DCX","ZSoft IBM PC multi-page Paintbrush"); |
731 | 9 | entry->decoder=(DecodeImageHandler *) ReadPCXImage; |
732 | 9 | entry->encoder=(EncodeImageHandler *) WritePCXImage; |
733 | 9 | entry->flags|=CoderDecoderSeekableStreamFlag; |
734 | 9 | entry->flags|=CoderEncoderSeekableStreamFlag; |
735 | 9 | entry->magick=(IsImageFormatHandler *) IsDCX; |
736 | 9 | (void) RegisterMagickInfo(entry); |
737 | 9 | entry=AcquireMagickInfo("PCX","PCX","ZSoft IBM PC Paintbrush"); |
738 | 9 | entry->decoder=(DecodeImageHandler *) ReadPCXImage; |
739 | 9 | entry->encoder=(EncodeImageHandler *) WritePCXImage; |
740 | 9 | entry->magick=(IsImageFormatHandler *) IsPCX; |
741 | 9 | entry->flags^=CoderAdjoinFlag; |
742 | 9 | entry->flags|=CoderDecoderSeekableStreamFlag; |
743 | 9 | entry->flags|=CoderEncoderSeekableStreamFlag; |
744 | 9 | (void) RegisterMagickInfo(entry); |
745 | 9 | return(MagickImageCoderSignature); |
746 | 9 | } |
747 | | |
748 | | /* |
749 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
750 | | % % |
751 | | % % |
752 | | % % |
753 | | % U n r e g i s t e r P C X I m a g e % |
754 | | % % |
755 | | % % |
756 | | % % |
757 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
758 | | % |
759 | | % UnregisterPCXImage() removes format registrations made by the |
760 | | % PCX module from the list of supported formats. |
761 | | % |
762 | | % The format of the UnregisterPCXImage method is: |
763 | | % |
764 | | % UnregisterPCXImage(void) |
765 | | % |
766 | | */ |
767 | | ModuleExport void UnregisterPCXImage(void) |
768 | 0 | { |
769 | 0 | (void) UnregisterMagickInfo("DCX"); |
770 | 0 | (void) UnregisterMagickInfo("PCX"); |
771 | 0 | } |
772 | | |
773 | | /* |
774 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
775 | | % % |
776 | | % % |
777 | | % % |
778 | | % W r i t e P C X I m a g e % |
779 | | % % |
780 | | % % |
781 | | % % |
782 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
783 | | % |
784 | | % WritePCXImage() writes an image in the ZSoft IBM PC Paintbrush file |
785 | | % format. |
786 | | % |
787 | | % The format of the WritePCXImage method is: |
788 | | % |
789 | | % MagickBooleanType WritePCXImage(const ImageInfo *image_info, |
790 | | % Image *image,ExceptionInfo *exception) |
791 | | % |
792 | | % A description of each parameter follows. |
793 | | % |
794 | | % o image_info: the image info. |
795 | | % |
796 | | % o image: The image. |
797 | | % |
798 | | % o exception: return any errors or warnings in this structure. |
799 | | % |
800 | | */ |
801 | | |
802 | | static MagickBooleanType PCXWritePixels(PCXInfo *pcx_info, |
803 | | const unsigned char *pixels,Image *image) |
804 | 76.0k | { |
805 | 76.0k | const unsigned char |
806 | 76.0k | *q; |
807 | | |
808 | 76.0k | ssize_t |
809 | 76.0k | count, |
810 | 76.0k | i, |
811 | 76.0k | x; |
812 | | |
813 | 76.0k | unsigned char |
814 | 76.0k | packet, |
815 | 76.0k | previous; |
816 | | |
817 | 76.0k | q=pixels; |
818 | 186k | for (i=0; i < (ssize_t) pcx_info->planes; i++) |
819 | 110k | { |
820 | 110k | if (pcx_info->encoding == 0) |
821 | 0 | { |
822 | 0 | for (x=0; x < (ssize_t) pcx_info->bytes_per_line; x++) |
823 | 0 | (void) WriteBlobByte(image,(unsigned char) (*q++)); |
824 | 0 | } |
825 | 110k | else |
826 | 110k | { |
827 | 110k | previous=(*q++); |
828 | 110k | count=1; |
829 | 47.4M | for (x=0; x < (ssize_t) (pcx_info->bytes_per_line-1); x++) |
830 | 47.3M | { |
831 | 47.3M | packet=(*q++); |
832 | 47.3M | if ((packet == previous) && (count < 63)) |
833 | 36.0M | { |
834 | 36.0M | count++; |
835 | 36.0M | continue; |
836 | 36.0M | } |
837 | 11.2M | if ((count > 1) || ((previous & 0xc0) == 0xc0)) |
838 | 4.15M | { |
839 | 4.15M | count|=0xc0; |
840 | 4.15M | (void) WriteBlobByte(image,(unsigned char) count); |
841 | 4.15M | } |
842 | 11.2M | (void) WriteBlobByte(image,previous); |
843 | 11.2M | previous=packet; |
844 | 11.2M | count=1; |
845 | 11.2M | } |
846 | 110k | if ((count > 1) || ((previous & 0xc0) == 0xc0)) |
847 | 81.1k | { |
848 | 81.1k | count|=0xc0; |
849 | 81.1k | (void) WriteBlobByte(image,(unsigned char) count); |
850 | 81.1k | } |
851 | 110k | (void) WriteBlobByte(image,previous); |
852 | 110k | } |
853 | 110k | } |
854 | 76.0k | return (MagickTrue); |
855 | 76.0k | } |
856 | | |
857 | | static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image, |
858 | | ExceptionInfo *exception) |
859 | 391 | { |
860 | 391 | const Quantum |
861 | 391 | *p; |
862 | | |
863 | 391 | MagickBooleanType |
864 | 391 | status; |
865 | | |
866 | 391 | MagickOffsetType |
867 | 391 | offset, |
868 | 391 | *page_table, |
869 | 391 | scene; |
870 | | |
871 | 391 | MemoryInfo |
872 | 391 | *pixel_info; |
873 | | |
874 | 391 | PCXInfo |
875 | 391 | pcx_info; |
876 | | |
877 | 391 | size_t |
878 | 391 | number_scenes, |
879 | 391 | length; |
880 | | |
881 | 391 | ssize_t |
882 | 391 | i, |
883 | 391 | x, |
884 | 391 | y; |
885 | | |
886 | 391 | unsigned char |
887 | 391 | *pcx_colormap, |
888 | 391 | *pixels, |
889 | 391 | *q; |
890 | | |
891 | | /* |
892 | | Open output image file. |
893 | | */ |
894 | 391 | assert(image_info != (const ImageInfo *) NULL); |
895 | 391 | assert(image_info->signature == MagickCoreSignature); |
896 | 391 | assert(image != (Image *) NULL); |
897 | 391 | assert(image->signature == MagickCoreSignature); |
898 | 391 | assert(exception != (ExceptionInfo *) NULL); |
899 | 391 | assert(exception->signature == MagickCoreSignature); |
900 | 391 | if (IsEventLogging() != MagickFalse) |
901 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
902 | 391 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
903 | 391 | if (status == MagickFalse) |
904 | 0 | return(status); |
905 | 391 | number_scenes=GetImageListLength(image); |
906 | 391 | if (number_scenes > MaxNumberScenes) |
907 | 391 | ThrowWriterException(ResourceLimitError,"ListLengthExceedsLimit"); |
908 | 391 | page_table=(MagickOffsetType *) NULL; |
909 | 391 | if ((LocaleCompare(image_info->magick,"DCX") == 0) || |
910 | 391 | ((GetNextImageInList(image) != (Image *) NULL) && |
911 | 0 | (image_info->adjoin != MagickFalse))) |
912 | 0 | { |
913 | | /* |
914 | | Write the DCX page table. |
915 | | */ |
916 | 0 | (void) WriteBlobLSBLong(image,0x3ADE68B1L); |
917 | 0 | page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes+1, |
918 | 0 | sizeof(*page_table)); |
919 | 0 | if (page_table == (MagickOffsetType *) NULL) |
920 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
921 | 0 | for (scene=0; scene < MaxNumberScenes; scene++) |
922 | 0 | (void) WriteBlobLSBLong(image,0x00000000L); |
923 | 0 | } |
924 | 391 | scene=0; |
925 | 391 | do |
926 | 391 | { |
927 | 391 | if (page_table != (MagickOffsetType *) NULL) |
928 | 0 | page_table[scene]=TellBlob(image); |
929 | | /* |
930 | | Initialize PCX raster file header. |
931 | | */ |
932 | 391 | pcx_info.identifier=0x0a; |
933 | 391 | pcx_info.version=5; |
934 | 391 | pcx_info.encoding=image_info->compression == NoCompression ? 0 : 1; |
935 | 391 | pcx_info.bits_per_pixel=8; |
936 | 391 | if ((image->storage_class == PseudoClass) && |
937 | 301 | (SetImageMonochrome(image,exception) != MagickFalse)) |
938 | 109 | pcx_info.bits_per_pixel=1; |
939 | 282 | else |
940 | 282 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
941 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
942 | 391 | pcx_info.left=0; |
943 | 391 | pcx_info.top=0; |
944 | 391 | pcx_info.right=(unsigned short) (image->columns-1); |
945 | 391 | pcx_info.bottom=(unsigned short) (image->rows-1); |
946 | 391 | switch (image->units) |
947 | 391 | { |
948 | 0 | case UndefinedResolution: |
949 | 391 | case PixelsPerInchResolution: |
950 | 391 | default: |
951 | 391 | { |
952 | 391 | pcx_info.horizontal_resolution=CastDoubleToUShort(image->resolution.x); |
953 | 391 | pcx_info.vertical_resolution=CastDoubleToUShort(image->resolution.y); |
954 | 391 | break; |
955 | 391 | } |
956 | 0 | case PixelsPerCentimeterResolution: |
957 | 0 | { |
958 | 0 | pcx_info.horizontal_resolution=CastDoubleToUShort(2.54*image->resolution.x+0.5); |
959 | 0 | pcx_info.vertical_resolution=CastDoubleToUShort(2.54*image->resolution.y+0.5); |
960 | 0 | break; |
961 | 391 | } |
962 | 391 | } |
963 | 391 | pcx_info.reserved=0; |
964 | 391 | pcx_info.planes=1; |
965 | 391 | if ((image->storage_class == DirectClass) || (image->colors > 256)) |
966 | 90 | { |
967 | 90 | pcx_info.planes=3; |
968 | 90 | if (image->alpha_trait != UndefinedPixelTrait) |
969 | 40 | pcx_info.planes++; |
970 | 90 | } |
971 | 391 | length=(((size_t) image->columns*pcx_info.bits_per_pixel+7)/8); |
972 | 391 | if ((image->columns > 65535UL) || (image->rows > 65535UL) || |
973 | 391 | (length > 65535UL)) |
974 | 0 | { |
975 | 0 | if (page_table != (MagickOffsetType *) NULL) |
976 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
977 | 0 | ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); |
978 | 0 | } |
979 | 391 | pcx_info.bytes_per_line=(unsigned short) length; |
980 | 391 | pcx_info.palette_info=1; |
981 | 391 | pcx_info.colormap_signature=0x0c; |
982 | | /* |
983 | | Write PCX header. |
984 | | */ |
985 | 391 | (void) WriteBlobByte(image,pcx_info.identifier); |
986 | 391 | (void) WriteBlobByte(image,pcx_info.version); |
987 | 391 | (void) WriteBlobByte(image,pcx_info.encoding); |
988 | 391 | (void) WriteBlobByte(image,pcx_info.bits_per_pixel); |
989 | 391 | (void) WriteBlobLSBShort(image,pcx_info.left); |
990 | 391 | (void) WriteBlobLSBShort(image,pcx_info.top); |
991 | 391 | (void) WriteBlobLSBShort(image,pcx_info.right); |
992 | 391 | (void) WriteBlobLSBShort(image,pcx_info.bottom); |
993 | 391 | (void) WriteBlobLSBShort(image,pcx_info.horizontal_resolution); |
994 | 391 | (void) WriteBlobLSBShort(image,pcx_info.vertical_resolution); |
995 | | /* |
996 | | Dump colormap to file. |
997 | | */ |
998 | 391 | pcx_colormap=(unsigned char *) AcquireQuantumMemory(256UL, |
999 | 391 | 3*sizeof(*pcx_colormap)); |
1000 | 391 | if (pcx_colormap == (unsigned char *) NULL) |
1001 | 0 | { |
1002 | 0 | if (page_table != (MagickOffsetType *) NULL) |
1003 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1004 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
1005 | 0 | } |
1006 | 391 | (void) memset(pcx_colormap,0,3*256*sizeof(*pcx_colormap)); |
1007 | 391 | q=pcx_colormap; |
1008 | 391 | if ((image->storage_class == PseudoClass) && (image->colors <= 256)) |
1009 | 5.59k | for (i=0; i < (ssize_t) image->colors; i++) |
1010 | 5.29k | { |
1011 | 5.29k | *q++=ScaleQuantumToChar((Quantum) image->colormap[i].red); |
1012 | 5.29k | *q++=ScaleQuantumToChar((Quantum) image->colormap[i].green); |
1013 | 5.29k | *q++=ScaleQuantumToChar((Quantum) image->colormap[i].blue); |
1014 | 5.29k | } |
1015 | 391 | (void) WriteBlob(image,3*16,(const unsigned char *) pcx_colormap); |
1016 | 391 | (void) WriteBlobByte(image,pcx_info.reserved); |
1017 | 391 | (void) WriteBlobByte(image,pcx_info.planes); |
1018 | 391 | (void) WriteBlobLSBShort(image,pcx_info.bytes_per_line); |
1019 | 391 | (void) WriteBlobLSBShort(image,pcx_info.palette_info); |
1020 | 23.0k | for (i=0; i < 58; i++) |
1021 | 22.6k | (void) WriteBlobByte(image,'\0'); |
1022 | 391 | length=(size_t) pcx_info.bytes_per_line; |
1023 | 391 | pixel_info=AcquireVirtualMemory(length,pcx_info.planes*sizeof(*pixels)); |
1024 | 391 | if (pixel_info == (MemoryInfo *) NULL) |
1025 | 0 | { |
1026 | 0 | pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap); |
1027 | 0 | if (page_table != (MagickOffsetType *) NULL) |
1028 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1029 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
1030 | 0 | } |
1031 | 391 | pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); |
1032 | 391 | q=pixels; |
1033 | 391 | if ((image->storage_class == DirectClass) || (image->colors > 256)) |
1034 | 90 | { |
1035 | | /* |
1036 | | Convert DirectClass image to PCX raster pixels. |
1037 | | */ |
1038 | 13.5k | for (y=0; y < (ssize_t) image->rows; y++) |
1039 | 13.4k | { |
1040 | 13.4k | q=pixels; |
1041 | 61.8k | for (i=0; i < pcx_info.planes; i++) |
1042 | 48.3k | { |
1043 | 48.3k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
1044 | 48.3k | if (p == (const Quantum *) NULL) |
1045 | 0 | break; |
1046 | 48.3k | switch ((int) i) |
1047 | 48.3k | { |
1048 | 13.4k | case 0: |
1049 | 13.4k | { |
1050 | 7.47M | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
1051 | 7.46M | { |
1052 | 7.46M | *q++=ScaleQuantumToChar(GetPixelRed(image,p)); |
1053 | 7.46M | p+=(ptrdiff_t) GetPixelChannels(image); |
1054 | 7.46M | } |
1055 | 13.4k | break; |
1056 | 0 | } |
1057 | 13.4k | case 1: |
1058 | 13.4k | { |
1059 | 7.47M | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
1060 | 7.46M | { |
1061 | 7.46M | *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); |
1062 | 7.46M | p+=(ptrdiff_t) GetPixelChannels(image); |
1063 | 7.46M | } |
1064 | 13.4k | break; |
1065 | 0 | } |
1066 | 13.4k | case 2: |
1067 | 13.4k | { |
1068 | 7.47M | for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++) |
1069 | 7.46M | { |
1070 | 7.46M | *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); |
1071 | 7.46M | p+=(ptrdiff_t) GetPixelChannels(image); |
1072 | 7.46M | } |
1073 | 13.4k | break; |
1074 | 0 | } |
1075 | 7.96k | case 3: |
1076 | 7.96k | default: |
1077 | 7.96k | { |
1078 | 7.37M | for (x=(ssize_t) pcx_info.bytes_per_line; x != 0; x--) |
1079 | 7.36M | { |
1080 | 7.36M | *q++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p))); |
1081 | 7.36M | p+=(ptrdiff_t) GetPixelChannels(image); |
1082 | 7.36M | } |
1083 | 7.96k | break; |
1084 | 7.96k | } |
1085 | 48.3k | } |
1086 | 48.3k | } |
1087 | 13.4k | if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse) |
1088 | 0 | break; |
1089 | 13.4k | if (image->previous == (Image *) NULL) |
1090 | 13.4k | { |
1091 | 13.4k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
1092 | 13.4k | image->rows); |
1093 | 13.4k | if (status == MagickFalse) |
1094 | 0 | break; |
1095 | 13.4k | } |
1096 | 13.4k | } |
1097 | 90 | } |
1098 | 301 | else |
1099 | 301 | { |
1100 | 301 | if (pcx_info.bits_per_pixel > 1) |
1101 | 50.9k | for (y=0; y < (ssize_t) image->rows; y++) |
1102 | 50.7k | { |
1103 | 50.7k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
1104 | 50.7k | if (p == (const Quantum *) NULL) |
1105 | 0 | break; |
1106 | 50.7k | q=pixels; |
1107 | 17.3M | for (x=0; x < (ssize_t) image->columns; x++) |
1108 | 17.3M | { |
1109 | 17.3M | *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p)); |
1110 | 17.3M | p+=(ptrdiff_t) GetPixelChannels(image); |
1111 | 17.3M | } |
1112 | 50.7k | if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse) |
1113 | 0 | break; |
1114 | 50.7k | if (image->previous == (Image *) NULL) |
1115 | 50.7k | { |
1116 | 50.7k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) |
1117 | 50.7k | y,image->rows); |
1118 | 50.7k | if (status == MagickFalse) |
1119 | 0 | break; |
1120 | 50.7k | } |
1121 | 50.7k | } |
1122 | 109 | else |
1123 | 109 | { |
1124 | 109 | unsigned char |
1125 | 109 | bit, |
1126 | 109 | byte; |
1127 | | |
1128 | | /* |
1129 | | Convert PseudoClass image to a PCX monochrome image. |
1130 | | */ |
1131 | 11.9k | for (y=0; y < (ssize_t) image->rows; y++) |
1132 | 11.8k | { |
1133 | 11.8k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
1134 | 11.8k | if (p == (const Quantum *) NULL) |
1135 | 0 | break; |
1136 | 11.8k | bit=0; |
1137 | 11.8k | byte=0; |
1138 | 11.8k | q=pixels; |
1139 | 2.98M | for (x=0; x < (ssize_t) image->columns; x++) |
1140 | 2.97M | { |
1141 | 2.97M | byte<<=1; |
1142 | 2.97M | if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0)) |
1143 | 1.73M | byte|=0x01; |
1144 | 2.97M | bit++; |
1145 | 2.97M | if (bit == 8) |
1146 | 368k | { |
1147 | 368k | *q++=byte; |
1148 | 368k | bit=0; |
1149 | 368k | byte=0; |
1150 | 368k | } |
1151 | 2.97M | p+=(ptrdiff_t) GetPixelChannels(image); |
1152 | 2.97M | } |
1153 | 11.8k | if (bit != 0) |
1154 | 7.56k | *q++=byte << (8-bit); |
1155 | 11.8k | if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse) |
1156 | 0 | break; |
1157 | 11.8k | if (image->previous == (Image *) NULL) |
1158 | 11.8k | { |
1159 | 11.8k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) |
1160 | 11.8k | y,image->rows); |
1161 | 11.8k | if (status == MagickFalse) |
1162 | 0 | break; |
1163 | 11.8k | } |
1164 | 11.8k | } |
1165 | 109 | } |
1166 | 301 | (void) WriteBlobByte(image,pcx_info.colormap_signature); |
1167 | 301 | (void) WriteBlob(image,3*256,pcx_colormap); |
1168 | 301 | } |
1169 | 391 | pixel_info=RelinquishVirtualMemory(pixel_info); |
1170 | 391 | pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap); |
1171 | 391 | if (page_table == (MagickOffsetType *) NULL) |
1172 | 391 | break; |
1173 | 0 | if (GetNextImageInList(image) == (Image *) NULL) |
1174 | 0 | break; |
1175 | 0 | image=SyncNextImageInList(image); |
1176 | 0 | status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes); |
1177 | 0 | if (status == MagickFalse) |
1178 | 0 | break; |
1179 | 0 | } while (image_info->adjoin != MagickFalse); |
1180 | 391 | if (page_table != (MagickOffsetType *) NULL) |
1181 | 0 | { |
1182 | | /* |
1183 | | Write the DCX page table. |
1184 | | */ |
1185 | 0 | page_table[scene+1]=0; |
1186 | 0 | offset=SeekBlob(image,0L,SEEK_SET); |
1187 | 0 | if (offset < 0) |
1188 | 0 | { |
1189 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1190 | 0 | ThrowWriterException(CorruptImageError,"ImproperImageHeader"); |
1191 | 0 | } |
1192 | 0 | (void) WriteBlobLSBLong(image,0x3ADE68B1L); |
1193 | 0 | for (i=0; i <= (ssize_t) scene; i++) |
1194 | 0 | (void) WriteBlobLSBLong(image,(unsigned int) page_table[i]); |
1195 | 0 | page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); |
1196 | 0 | } |
1197 | 391 | if (status == MagickFalse) |
1198 | 0 | { |
1199 | 0 | char |
1200 | 0 | *message; |
1201 | |
|
1202 | 0 | message=GetExceptionMessage(errno); |
1203 | 0 | (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, |
1204 | 0 | "UnableToWriteFile","`%s': %s",image->filename,message); |
1205 | 0 | message=DestroyString(message); |
1206 | 0 | } |
1207 | 391 | if (CloseBlob(image) == MagickFalse) |
1208 | 0 | status=MagickFalse; |
1209 | 391 | return(status); |
1210 | 391 | } |