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