/src/graphicsmagick/coders/ps2.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % SPDX-License-Identifier: MIT |
6 | | % |
7 | | % This program is covered by multiple licenses, which are described in |
8 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
9 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
10 | | % |
11 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
12 | | % % |
13 | | % % |
14 | | % % |
15 | | % PPPP SSSSS 22222 % |
16 | | % P P SS 22 % |
17 | | % PPPP SSS 222 % |
18 | | % P SS 22 % |
19 | | % P SSSSS 22222 % |
20 | | % % |
21 | | % % |
22 | | % Write Postscript Level II Format. % |
23 | | % % |
24 | | % % |
25 | | % Software Design % |
26 | | % John Cristy % |
27 | | % July 1992 % |
28 | | % % |
29 | | % % |
30 | | % % |
31 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
32 | | % |
33 | | % |
34 | | */ |
35 | | |
36 | | /* |
37 | | Include declarations. |
38 | | */ |
39 | | #include "magick/studio.h" |
40 | | #include "magick/analyze.h" |
41 | | #include "magick/attribute.h" |
42 | | #include "magick/blob.h" |
43 | | #include "magick/pixel_cache.h" |
44 | | #include "magick/color.h" |
45 | | #include "magick/constitute.h" |
46 | | #include "magick/compress.h" |
47 | | #include "magick/enum_strings.h" |
48 | | #include "magick/magick.h" |
49 | | #include "magick/monitor.h" |
50 | | #include "magick/tempfile.h" |
51 | | #include "magick/utility.h" |
52 | | #include "magick/static.h" |
53 | | #if defined(HasTIFF) |
54 | 0 | #define CCITTParam "-1" |
55 | | #else |
56 | | #define CCITTParam "0" |
57 | | #endif |
58 | | |
59 | | /* |
60 | | Forward declarations. |
61 | | */ |
62 | | static unsigned int |
63 | | WritePS2Image(const ImageInfo *,Image *); |
64 | | |
65 | | #if defined(HasTIFF) |
66 | | #if defined(HAVE_TIFFCONF_H) |
67 | | # include "tiffconf.h" |
68 | | #endif |
69 | | #include "tiffio.h" |
70 | | |
71 | | #if (TIFFLIB_VERSION >= 20201219) |
72 | | # undef uint16 |
73 | 0 | # define uint16 uint16_t |
74 | | # undef uint32 |
75 | | # define uint32 uint32_t |
76 | | #endif /* TIFFLIB_VERSION */ |
77 | | |
78 | | /* |
79 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
80 | | % % |
81 | | % % |
82 | | % % |
83 | | % H u f f m a n 2 D E n c o d e I m a g e % |
84 | | % % |
85 | | % % |
86 | | % % |
87 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
88 | | % |
89 | | % Method Huffman2DEncodeImage compresses an image via two-dimensional |
90 | | % Huffman-coding. |
91 | | % |
92 | | % The format of the Huffman2DEncodeImage method is: |
93 | | % |
94 | | % MagickPassFail Huffman2DEncodeImage(const ImageInfo *image_info, |
95 | | % Image *image) |
96 | | % |
97 | | % A description of each parameter follows: |
98 | | % |
99 | | % o status: Method Huffman2DEncodeImage returns True if all the pixels are |
100 | | % compressed without error, otherwise False. |
101 | | % |
102 | | % o image_info: The image info.. |
103 | | % |
104 | | % o image: The image. |
105 | | % |
106 | | */ |
107 | | static MagickPassFail Huffman2DEncodeImage(const ImageInfo *image_info, |
108 | | Image *image) |
109 | 0 | { |
110 | 0 | char |
111 | 0 | filename[MaxTextExtent]; |
112 | |
|
113 | 0 | Image |
114 | 0 | *huffman_image; |
115 | |
|
116 | 0 | ImageInfo |
117 | 0 | *clone_info; |
118 | |
|
119 | 0 | long |
120 | 0 | count, |
121 | 0 | j; |
122 | |
|
123 | 0 | register long |
124 | 0 | i; |
125 | |
|
126 | 0 | TIFF |
127 | 0 | *tiff; |
128 | |
|
129 | 0 | uint16 |
130 | 0 | fillorder; |
131 | |
|
132 | 0 | unsigned char |
133 | 0 | *buffer; |
134 | |
|
135 | 0 | unsigned int |
136 | 0 | status; |
137 | |
|
138 | 0 | unsigned long |
139 | 0 | *byte_count, |
140 | 0 | strip_size; |
141 | | |
142 | | /* |
143 | | Write image as CCITTFax4 TIFF image to a temporary file. |
144 | | */ |
145 | 0 | assert(image_info != (ImageInfo *) NULL); |
146 | 0 | assert(image_info->signature == MagickSignature); |
147 | 0 | assert(image != (Image *) NULL); |
148 | 0 | assert(image->signature == MagickSignature); |
149 | 0 | huffman_image=CloneImage(image,0,0,True,&image->exception); |
150 | 0 | if (huffman_image == (Image *) NULL) |
151 | 0 | return MagickFail; |
152 | 0 | if (SetImageType(huffman_image,BilevelType) == MagickFail) |
153 | 0 | { |
154 | 0 | CopyException(&image->exception,&huffman_image->exception); |
155 | 0 | DestroyImage(huffman_image); |
156 | 0 | return MagickFail; |
157 | 0 | } |
158 | 0 | if(!AcquireTemporaryFileName(filename)) |
159 | 0 | { |
160 | 0 | DestroyImage(huffman_image); |
161 | 0 | ThrowBinaryException(FileOpenError,UnableToCreateTemporaryFile, |
162 | 0 | filename); |
163 | 0 | } |
164 | 0 | MagickFormatString(huffman_image->filename,sizeof(huffman_image->filename),"tiff:%s",filename); |
165 | 0 | clone_info=CloneImageInfo(image_info); |
166 | 0 | clone_info->compression=Group4Compression; |
167 | 0 | clone_info->type=BilevelType; |
168 | 0 | (void) AddDefinitions(clone_info,"tiff:fill-order=msb2lsb", |
169 | 0 | &image->exception); |
170 | 0 | status=WriteImage(clone_info,huffman_image); |
171 | 0 | DestroyImageInfo(clone_info); |
172 | 0 | DestroyImage(huffman_image); |
173 | 0 | if (status == MagickFail) |
174 | 0 | return(MagickFail); |
175 | 0 | tiff=TIFFOpen(filename,"rb"); |
176 | 0 | if (tiff == (TIFF *) NULL) |
177 | 0 | { |
178 | 0 | (void) LiberateTemporaryFile(filename); |
179 | 0 | ThrowBinaryException(FileOpenError,UnableToOpenFile, |
180 | 0 | image_info->filename); |
181 | 0 | } |
182 | | /* |
183 | | Allocate raw strip buffer. |
184 | | */ |
185 | 0 | (void) TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count); |
186 | 0 | strip_size=byte_count[0]; |
187 | 0 | for (i=1; i < (long) TIFFNumberOfStrips(tiff); i++) |
188 | 0 | if (byte_count[i] > strip_size) |
189 | 0 | strip_size=byte_count[i]; |
190 | 0 | buffer=MagickAllocateResourceLimitedMemory(unsigned char *,strip_size); |
191 | 0 | if (buffer == (unsigned char *) NULL) |
192 | 0 | { |
193 | 0 | TIFFClose(tiff); |
194 | 0 | (void) LiberateTemporaryFile(filename); |
195 | 0 | ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed, |
196 | 0 | (char *) NULL); |
197 | 0 | } |
198 | | /* |
199 | | Compress runlength encoded to 2D Huffman pixels. |
200 | | */ |
201 | 0 | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fillorder); |
202 | 0 | for (i=0; i < (long) TIFFNumberOfStrips(tiff); i++) |
203 | 0 | { |
204 | 0 | Ascii85Initialize(image); |
205 | 0 | count=TIFFReadRawStrip(tiff,(uint32) i,buffer,(long) byte_count[i]); |
206 | 0 | if (fillorder == FILLORDER_LSB2MSB) |
207 | 0 | TIFFReverseBits(buffer,count); |
208 | 0 | for (j=0; j < count; j++) |
209 | 0 | Ascii85Encode(image,(unsigned long) buffer[j]); |
210 | 0 | Ascii85Flush(image); |
211 | 0 | } |
212 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,buffer); |
213 | 0 | TIFFClose(tiff); |
214 | 0 | (void) LiberateTemporaryFile(filename); |
215 | 0 | return(MagickPass); |
216 | 0 | } |
217 | | #else |
218 | | static MagickPassFail Huffman2DEncodeImage(const ImageInfo *image_info, |
219 | | Image *image) |
220 | | { |
221 | | ARG_NOT_USED(image_info); |
222 | | assert(image != (Image *) NULL); |
223 | | assert(image->signature == MagickSignature); |
224 | | ThrowBinaryException(MissingDelegateError,TIFFLibraryIsNotAvailable,image->filename); |
225 | | } |
226 | | #endif |
227 | | |
228 | | /* |
229 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
230 | | % % |
231 | | % % |
232 | | % % |
233 | | % R e g i s t e r P S 2 I m a g e % |
234 | | % % |
235 | | % % |
236 | | % % |
237 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
238 | | % |
239 | | % Method RegisterPS2Image adds attributes for the PS2 image format to |
240 | | % the list of supported formats. The attributes include the image format |
241 | | % tag, a method to read and/or write the format, whether the format |
242 | | % supports the saving of more than one frame to the same file or blob, |
243 | | % whether the format supports native in-memory I/O, and a brief |
244 | | % description of the format. |
245 | | % |
246 | | % The format of the RegisterPS2Image method is: |
247 | | % |
248 | | % RegisterPS2Image(void) |
249 | | % |
250 | | */ |
251 | | ModuleExport void RegisterPS2Image(void) |
252 | 0 | { |
253 | 0 | MagickInfo |
254 | 0 | *entry; |
255 | |
|
256 | 0 | entry=SetMagickInfo("EPS2"); |
257 | 0 | entry->encoder=(EncoderHandler) WritePS2Image; |
258 | 0 | entry->adjoin=False; |
259 | 0 | entry->seekable_stream=True; |
260 | 0 | entry->description="Adobe Level II Encapsulated PostScript"; |
261 | 0 | entry->module="PS2"; |
262 | 0 | entry->coder_class=PrimaryCoderClass; |
263 | 0 | (void) RegisterMagickInfo(entry); |
264 | |
|
265 | 0 | entry=SetMagickInfo("PS2"); |
266 | 0 | entry->encoder=(EncoderHandler) WritePS2Image; |
267 | 0 | entry->seekable_stream=True; |
268 | 0 | entry->description="Adobe Level II PostScript"; |
269 | 0 | entry->module="PS2"; |
270 | 0 | entry->coder_class=PrimaryCoderClass; |
271 | 0 | (void) RegisterMagickInfo(entry); |
272 | 0 | } |
273 | | |
274 | | /* |
275 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
276 | | % % |
277 | | % % |
278 | | % % |
279 | | % U n r e g i s t e r P S 2 I m a g e % |
280 | | % % |
281 | | % % |
282 | | % % |
283 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
284 | | % |
285 | | % Method UnregisterPS2Image removes format registrations made by the |
286 | | % PS2 module from the list of supported formats. |
287 | | % |
288 | | % The format of the UnregisterPS2Image method is: |
289 | | % |
290 | | % UnregisterPS2Image(void) |
291 | | % |
292 | | */ |
293 | | ModuleExport void UnregisterPS2Image(void) |
294 | 0 | { |
295 | 0 | (void) UnregisterMagickInfo("EPS2"); |
296 | 0 | (void) UnregisterMagickInfo("PS2"); |
297 | 0 | } |
298 | | |
299 | | /* |
300 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
301 | | % % |
302 | | % % |
303 | | % % |
304 | | % W r i t e P S 2 I m a g e % |
305 | | % % |
306 | | % % |
307 | | % % |
308 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
309 | | % |
310 | | % Method WritePS2Image translates an image to encapsulated Postscript |
311 | | % Level II for printing. If the supplied geometry is null, the image is |
312 | | % centered on the Postscript page. Otherwise, the image is positioned as |
313 | | % specified by the geometry. |
314 | | % |
315 | | % The format of the WritePS2Image method is: |
316 | | % |
317 | | % MagickPassFail WritePS2Image(const ImageInfo *image_info,Image *image) |
318 | | % |
319 | | % A description of each parameter follows: |
320 | | % |
321 | | % o status: Method WritePS2Image return True if the image is printed. |
322 | | % False is returned if the image file cannot be opened for printing. |
323 | | % |
324 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
325 | | % |
326 | | % o image: The address of a structure of type Image; returned from |
327 | | % ReadImage. |
328 | | % |
329 | | % |
330 | | */ |
331 | | static MagickPassFail WritePS2Image(const ImageInfo *image_info,Image *image) |
332 | 0 | { |
333 | 0 | char |
334 | 0 | buffer[MaxTextExtent], |
335 | 0 | date[MaxTextExtent], |
336 | 0 | density[MaxTextExtent], |
337 | 0 | page_geometry[MaxTextExtent], |
338 | 0 | **labels; |
339 | |
|
340 | 0 | CompressionType |
341 | 0 | compression; |
342 | |
|
343 | 0 | const ImageAttribute |
344 | 0 | *attribute; |
345 | |
|
346 | 0 | double |
347 | 0 | dx_resolution, |
348 | 0 | dy_resolution, |
349 | 0 | x_resolution, |
350 | 0 | x_scale, |
351 | 0 | y_resolution, |
352 | 0 | y_scale; |
353 | |
|
354 | 0 | magick_off_t |
355 | 0 | current, |
356 | 0 | start, |
357 | 0 | stop; |
358 | |
|
359 | 0 | int |
360 | 0 | count, |
361 | 0 | status; |
362 | |
|
363 | 0 | long |
364 | 0 | j, |
365 | 0 | y; |
366 | |
|
367 | 0 | RectangleInfo |
368 | 0 | geometry; |
369 | |
|
370 | 0 | register const PixelPacket |
371 | 0 | *p; |
372 | |
|
373 | 0 | register const IndexPacket |
374 | 0 | *indexes; |
375 | |
|
376 | 0 | register long |
377 | 0 | x; |
378 | |
|
379 | 0 | register long |
380 | 0 | i; |
381 | |
|
382 | 0 | SegmentInfo |
383 | 0 | bounds={0.0,0.0,0.0,0.0}; |
384 | |
|
385 | 0 | size_t |
386 | 0 | length; |
387 | |
|
388 | 0 | time_t |
389 | 0 | timer; |
390 | |
|
391 | 0 | unsigned char |
392 | 0 | *pixels; |
393 | |
|
394 | 0 | unsigned long |
395 | 0 | number_pixels, |
396 | 0 | page, |
397 | 0 | scene, |
398 | 0 | text_size; |
399 | |
|
400 | 0 | void |
401 | 0 | *blob; |
402 | |
|
403 | 0 | size_t |
404 | 0 | image_list_length; |
405 | | |
406 | | /* |
407 | | Open output image file. |
408 | | */ |
409 | 0 | assert(image_info != (const ImageInfo *) NULL); |
410 | 0 | assert(image_info->signature == MagickSignature); |
411 | 0 | assert(image != (Image *) NULL); |
412 | 0 | assert(image->signature == MagickSignature); |
413 | 0 | image_list_length=GetImageListLength(image); |
414 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
415 | 0 | if (status == MagickFail) |
416 | 0 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
417 | 0 | compression=image->compression; |
418 | 0 | if (image_info->compression != UndefinedCompression) |
419 | 0 | compression=image_info->compression; |
420 | 0 | switch (compression) |
421 | 0 | { |
422 | | #if !defined(HasJPEG) |
423 | | case JPEGCompression: |
424 | | { |
425 | | compression=RLECompression; |
426 | | ThrowException(&image->exception,MissingDelegateError,JPEGLibraryIsNotAvailable,image->filename); |
427 | | break; |
428 | | } |
429 | | #endif |
430 | | #if !defined(HasZLIB) |
431 | | case ZipCompression: |
432 | | { |
433 | | compression=RLECompression; |
434 | | ThrowException(&image->exception,MissingDelegateError,ZipLibraryIsNotAvailable,image->filename); |
435 | | break; |
436 | | } |
437 | | #endif |
438 | 0 | default: |
439 | 0 | break; |
440 | 0 | } |
441 | 0 | page=1; |
442 | 0 | scene=0; |
443 | 0 | do |
444 | 0 | { |
445 | 0 | ImageCharacteristics |
446 | 0 | characteristics; |
447 | | |
448 | | /* |
449 | | Analyze image to be written. |
450 | | */ |
451 | 0 | if (GetImageCharacteristics(image,&characteristics, |
452 | 0 | (OptimizeType == image_info->type), |
453 | 0 | &image->exception) == MagickFail) |
454 | 0 | ThrowWriterException(CoderError,UnableToGetImageCharacteristics,image); |
455 | | |
456 | | /* |
457 | | Scale image to size of Postscript page. |
458 | | */ |
459 | 0 | text_size=0; |
460 | 0 | attribute=GetImageAttribute(image,"label"); |
461 | 0 | if (attribute != (const ImageAttribute *) NULL) |
462 | 0 | text_size=(unsigned int) |
463 | 0 | (MultilineCensus(attribute->value)*image_info->pointsize+12); |
464 | 0 | SetGeometry(image,&geometry); |
465 | 0 | geometry.y=(long) text_size; |
466 | 0 | MagickFormatString(page_geometry,sizeof(page_geometry),"%lux%lu",image->columns,image->rows); |
467 | 0 | if (image_info->page != (char *) NULL) |
468 | 0 | (void) strlcpy(page_geometry,image_info->page,MaxTextExtent); |
469 | 0 | else |
470 | 0 | if ((image->page.width != 0) && (image->page.height != 0)) |
471 | 0 | (void) MagickFormatString(page_geometry,sizeof(page_geometry),"%lux%lu%+ld%+ld",image->page.width, |
472 | 0 | image->page.height,image->page.x,image->page.y); |
473 | 0 | else |
474 | 0 | if (LocaleCompare(image_info->magick,"PS2") == 0) |
475 | 0 | (void) strlcpy(page_geometry,PSPageGeometry,sizeof(page_geometry)); |
476 | 0 | (void) GetMagickGeometry(page_geometry,&geometry.x,&geometry.y, |
477 | 0 | &geometry.width,&geometry.height); |
478 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
479 | 0 | "Image Resolution: %gx%g %s", |
480 | 0 | image->x_resolution, |
481 | 0 | image->y_resolution, |
482 | 0 | ResolutionTypeToString(image->units)); |
483 | | /* |
484 | | Scale relative to dots-per-inch. |
485 | | */ |
486 | 0 | dx_resolution=72.0; |
487 | 0 | dy_resolution=72.0; |
488 | 0 | x_resolution=72.0; |
489 | 0 | (void) strlcpy(density,PSDensityGeometry,sizeof(density)); |
490 | 0 | count=GetMagickDimension(density,&x_resolution,&y_resolution,NULL,NULL); |
491 | 0 | if (count != 2) |
492 | 0 | y_resolution=x_resolution; |
493 | | /* |
494 | | Use override resolution information if it appears to be valid. |
495 | | */ |
496 | 0 | if ((image_info->density != (char *) NULL) && |
497 | 0 | ((image_info->units == PixelsPerInchResolution) || |
498 | 0 | (image_info->units == PixelsPerCentimeterResolution))) |
499 | 0 | { |
500 | 0 | count=GetMagickDimension(image_info->density,&x_resolution, |
501 | 0 | &y_resolution,NULL,NULL); |
502 | 0 | if (count != 2) |
503 | 0 | y_resolution=x_resolution; |
504 | 0 | if (image_info->units == PixelsPerCentimeterResolution) |
505 | 0 | { |
506 | 0 | x_resolution *= 2.54; |
507 | 0 | y_resolution *= 2.54; |
508 | 0 | } |
509 | 0 | } |
510 | | /* |
511 | | Use image resolution information if it appears to be valid. |
512 | | */ |
513 | 0 | else if ((image->x_resolution > 0.0) && (image->y_resolution > 0.0) && |
514 | 0 | ((image->units == PixelsPerInchResolution) || |
515 | 0 | (image->units == PixelsPerCentimeterResolution))) |
516 | 0 | { |
517 | 0 | x_resolution = image->x_resolution; |
518 | 0 | y_resolution = image->y_resolution; |
519 | 0 | if (image->units == PixelsPerCentimeterResolution) |
520 | 0 | { |
521 | 0 | x_resolution *= 2.54; |
522 | 0 | y_resolution *= 2.54; |
523 | 0 | } |
524 | 0 | } |
525 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
526 | 0 | "Postscript Resolution: %gx%g DPI", |
527 | 0 | x_resolution,y_resolution); |
528 | 0 | x_scale=(geometry.width*dx_resolution)/x_resolution; |
529 | 0 | geometry.width=(unsigned long) (x_scale+0.5); |
530 | 0 | y_scale=(geometry.height*dy_resolution)/y_resolution; |
531 | 0 | geometry.height=(unsigned long) (y_scale+0.5); |
532 | | /* |
533 | | Enforce maximum Postscript dimensions to avoid denial of service |
534 | | */ |
535 | 0 | { |
536 | 0 | magick_uint64_t |
537 | 0 | pixels; |
538 | |
|
539 | 0 | if (AcquireMagickResource(WidthResource,geometry.width) != MagickPass) |
540 | 0 | ThrowWriterException(ResourceLimitError,ImagePixelWidthLimitExceeded,image); |
541 | 0 | if (AcquireMagickResource(HeightResource,geometry.height) != MagickPass) |
542 | 0 | ThrowWriterException(ResourceLimitError,ImagePixelHeightLimitExceeded,image); |
543 | 0 | pixels=(magick_uint64_t)geometry.width*geometry.height; |
544 | 0 | if ((0 == pixels) || (pixels/geometry.width != geometry.height) || |
545 | 0 | (AcquireMagickResource(PixelsResource,pixels) != MagickPass)) |
546 | 0 | ThrowWriterException(ResourceLimitError,ImagePixelLimitExceeded,image); |
547 | 0 | } |
548 | 0 | if (page == 1) |
549 | 0 | { |
550 | | /* |
551 | | Output Postscript header. |
552 | | */ |
553 | 0 | #if defined(HAVE_CTIME_R) |
554 | 0 | char time_buf[26]; |
555 | 0 | #endif /* defined(HAVE_CTIME_R) */ |
556 | 0 | if (LocaleCompare(image_info->magick,"PS2") == 0) |
557 | 0 | (void) strlcpy(buffer,"%!PS-Adobe-3.0\n",sizeof(buffer)); |
558 | 0 | else |
559 | 0 | (void) strlcpy(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",sizeof(buffer)); |
560 | 0 | (void) WriteBlobString(image,buffer); |
561 | 0 | (void) WriteBlobString(image,"%%Creator: (GraphicsMagick)\n"); |
562 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%Title: (%.1024s)\n",image->filename); |
563 | 0 | (void) WriteBlobString(image,buffer); |
564 | 0 | timer=time((time_t *) NULL); |
565 | 0 | #if defined(HAVE_CTIME_R) |
566 | 0 | (void) strlcpy(date,ctime_r(&timer,time_buf),MaxTextExtent); |
567 | | #else |
568 | | (void) strlcpy(date,ctime(&timer),MaxTextExtent); /* Thread-unsafe version */ |
569 | | #endif /* defined(HAVE_CTIME_R) */ |
570 | 0 | date[strlen(date)-1]='\0'; |
571 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%CreationDate: (%.1024s)\n",date); |
572 | 0 | (void) WriteBlobString(image,buffer); |
573 | 0 | bounds.x1=geometry.x; |
574 | 0 | bounds.y1=geometry.y; |
575 | 0 | bounds.x2=geometry.x+(size_t) geometry.width; |
576 | 0 | bounds.y2=geometry.y+(size_t) geometry.height+text_size; |
577 | 0 | if (image_info->adjoin && (image->next != (Image *) NULL)) |
578 | 0 | (void) strlcpy(buffer,"%%BoundingBox: (atend)\n",sizeof(buffer)); |
579 | 0 | else |
580 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%BoundingBox: %g %g %g %g\n", |
581 | 0 | floor(bounds.x1+0.5),floor(bounds.y1+0.5),ceil(bounds.x2-0.5), |
582 | 0 | ceil(bounds.y2-0.5)); |
583 | 0 | (void) WriteBlobString(image,buffer); |
584 | 0 | attribute=GetImageAttribute(image,"label"); |
585 | 0 | if (attribute != (const ImageAttribute *) NULL) |
586 | 0 | (void) WriteBlobString(image, |
587 | 0 | "%%DocumentNeededResources: font Helvetica\n"); |
588 | 0 | (void) WriteBlobString(image,"%%LanguageLevel: 2\n"); |
589 | 0 | if (LocaleCompare(image_info->magick,"PS2") != 0) |
590 | 0 | (void) WriteBlobString(image,"%%Pages: 1\n"); |
591 | 0 | else |
592 | 0 | { |
593 | 0 | (void) WriteBlobString(image,"%%Orientation: Portrait\n"); |
594 | 0 | (void) WriteBlobString(image,"%%PageOrder: Ascend\n"); |
595 | 0 | if (!image_info->adjoin) |
596 | 0 | (void) strlcpy(buffer,"%%Pages: 1\n",sizeof(buffer)); |
597 | 0 | else |
598 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%Pages: %lu\n",(unsigned long) |
599 | 0 | image_list_length); |
600 | 0 | (void) WriteBlobString(image,buffer); |
601 | 0 | } |
602 | 0 | (void) WriteBlobString(image,"%%EndComments\n"); |
603 | 0 | (void) WriteBlobString(image,"\n%%BeginDefaults\n"); |
604 | 0 | (void) WriteBlobString(image,"%%EndDefaults\n\n"); |
605 | | /* |
606 | | Output Postscript commands. |
607 | | */ |
608 | 0 | { |
609 | 0 | const char * ps_compress; |
610 | |
|
611 | 0 | switch (compression) |
612 | 0 | { |
613 | 0 | case NoCompression: ps_compress="ASCII85Decode"; break; |
614 | 0 | case JPEGCompression: ps_compress="DCTDecode"; break; |
615 | 0 | case LZWCompression: ps_compress="LZWDecode"; break; |
616 | 0 | case FaxCompression: ps_compress="ASCII85Decode"; break; |
617 | 0 | default: ps_compress="RunLengthDecode"; break; |
618 | 0 | } |
619 | 0 | (void) WriteBlobString(image, |
620 | 0 | "%%BeginProlog\n" |
621 | 0 | "%\n" |
622 | 0 | "% Display a color image. The image is displayed in color on\n" |
623 | 0 | "% Postscript viewers or printers that support color, otherwise\n" |
624 | 0 | "% it is displayed as grayscale.\n" |
625 | 0 | "%\n" |
626 | 0 | "/DirectClassImage\n"); |
627 | 0 | MagickFormatString(buffer,sizeof(buffer), |
628 | 0 | "{\n" |
629 | 0 | " %%\n" |
630 | 0 | " %% Display a DirectClass image.\n" |
631 | 0 | " %%\n" |
632 | 0 | " colorspace 0 eq\n" |
633 | 0 | " {\n" |
634 | 0 | " /DeviceRGB setcolorspace\n" |
635 | 0 | " <<\n" |
636 | 0 | " /ImageType 1\n" |
637 | 0 | " /Width columns\n" |
638 | 0 | " /Height rows\n" |
639 | 0 | " /BitsPerComponent 8\n" |
640 | 0 | " /Decode [0 1 0 1 0 1]\n" |
641 | 0 | " /ImageMatrix [columns 0 0 rows neg 0 rows]\n" |
642 | 0 | " compression 0 gt\n" |
643 | 0 | " { /DataSource pixel_stream /%.1024s filter }\n" |
644 | 0 | " { /DataSource pixel_stream /%.1024s filter } ifelse\n" |
645 | 0 | " >> image\n" |
646 | 0 | " }\n", |
647 | 0 | ps_compress, ps_compress); |
648 | 0 | (void) WriteBlobString(image,buffer); |
649 | 0 | MagickFormatString(buffer,sizeof(buffer), |
650 | 0 | " {\n" |
651 | 0 | " /DeviceCMYK setcolorspace\n" |
652 | 0 | " <<\n" |
653 | 0 | " /ImageType 1\n" |
654 | 0 | " /Width columns\n" |
655 | 0 | " /Height rows\n" |
656 | 0 | " /BitsPerComponent 8\n" |
657 | 0 | " /Decode [1 0 1 0 1 0 1 0]\n" |
658 | 0 | " /ImageMatrix [columns 0 0 rows neg 0 rows]\n" |
659 | 0 | " compression 0 gt\n" |
660 | 0 | " { /DataSource pixel_stream /%.1024s filter }\n" |
661 | 0 | " { /DataSource pixel_stream /%.1024s filter } ifelse\n" |
662 | 0 | " >> image\n" |
663 | 0 | " } ifelse\n" |
664 | 0 | "} bind def\n" |
665 | 0 | "\n", |
666 | 0 | ps_compress, ps_compress); |
667 | 0 | (void) WriteBlobString(image,buffer); |
668 | 0 | MagickFormatString(buffer,sizeof(buffer), |
669 | 0 | "/PseudoClassImage\n" |
670 | 0 | "{\n" |
671 | 0 | " %%\n" |
672 | 0 | " %% Display a PseudoClass image.\n" |
673 | 0 | " %%\n" |
674 | 0 | " %% Parameters:\n" |
675 | 0 | " %% colors: number of colors in the colormap.\n" |
676 | 0 | " %%\n" |
677 | 0 | " currentfile buffer readline pop\n" |
678 | 0 | " token pop /colors exch def pop\n" |
679 | 0 | " colors 0 eq\n" |
680 | 0 | " {\n" |
681 | 0 | " %%\n" |
682 | 0 | " %% Image is grayscale.\n" |
683 | 0 | " %%\n" |
684 | 0 | " currentfile buffer readline pop\n" |
685 | 0 | " token pop /bits exch def pop\n" |
686 | 0 | " /DeviceGray setcolorspace\n" |
687 | 0 | " <<\n" |
688 | 0 | " /ImageType 1\n" |
689 | 0 | " /Width columns\n" |
690 | 0 | " /Height rows\n" |
691 | 0 | " /BitsPerComponent bits\n" |
692 | 0 | " /Decode [0 1]\n" |
693 | 0 | " /ImageMatrix [columns 0 0 rows neg 0 rows]\n" |
694 | 0 | " compression 0 gt\n" |
695 | 0 | " { /DataSource pixel_stream /%.1024s filter }\n" |
696 | 0 | " {\n" |
697 | 0 | " /DataSource pixel_stream /%.1024s filter\n" |
698 | 0 | " <<\n" |
699 | 0 | " /K " CCITTParam "\n" |
700 | 0 | " /Columns columns\n" |
701 | 0 | " /Rows rows\n" |
702 | 0 | " >> /CCITTFaxDecode filter\n" |
703 | 0 | " } ifelse\n" |
704 | 0 | " >> image\n" |
705 | 0 | " }\n", |
706 | 0 | ps_compress, ps_compress); |
707 | 0 | (void) WriteBlobString(image,buffer); |
708 | 0 | MagickFormatString(buffer,sizeof(buffer), |
709 | 0 | " {\n" |
710 | 0 | " %%\n" |
711 | 0 | " %% Parameters:\n" |
712 | 0 | " %% colormap: red, green, blue color packets.\n" |
713 | 0 | " %%\n" |
714 | 0 | " /colormap colors 3 mul string def\n" |
715 | 0 | " currentfile colormap readhexstring pop pop\n" |
716 | 0 | " currentfile buffer readline pop\n" |
717 | 0 | " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace\n" |
718 | 0 | " <<\n" |
719 | 0 | " /ImageType 1\n" |
720 | 0 | " /Width columns\n" |
721 | 0 | " /Height rows\n" |
722 | 0 | " /BitsPerComponent 8\n" |
723 | 0 | " /Decode [0 255]\n" |
724 | 0 | " /ImageMatrix [columns 0 0 rows neg 0 rows]\n" |
725 | 0 | " compression 0 gt\n" |
726 | 0 | " { /DataSource pixel_stream /%.1024s filter }\n" |
727 | 0 | " { /DataSource pixel_stream /%.1024s filter } ifelse\n" |
728 | 0 | " >> image\n" |
729 | 0 | " } ifelse\n" |
730 | 0 | "} bind def\n" |
731 | 0 | "\n", |
732 | 0 | ps_compress, ps_compress); |
733 | 0 | (void) WriteBlobString(image,buffer); |
734 | 0 | (void) WriteBlobString(image, |
735 | 0 | "/DisplayImage\n" |
736 | 0 | "{\n" |
737 | 0 | " %\n" |
738 | 0 | " % Display a DirectClass or PseudoClass image.\n" |
739 | 0 | " %\n" |
740 | 0 | " % Parameters:\n" |
741 | 0 | " % x & y translation.\n" |
742 | 0 | " % x & y scale.\n" |
743 | 0 | " % label pointsize.\n" |
744 | 0 | " % image label.\n" |
745 | 0 | " % image columns & rows.\n" |
746 | 0 | " % class: 0-DirectClass or 1-PseudoClass.\n" |
747 | 0 | " % colorspace: 0-RGB or 1-CMYK.\n" |
748 | 0 | " % compression: 0-RLECompression or 1-NoCompression.\n" |
749 | 0 | " % hex color packets.\n" |
750 | 0 | " %\n" |
751 | 0 | " gsave\n" |
752 | 0 | " /buffer 512 string def\n" |
753 | 0 | " /pixel_stream currentfile def\n" |
754 | 0 | "\n" |
755 | 0 | " currentfile buffer readline pop\n" |
756 | 0 | " token pop /x exch def\n" |
757 | 0 | " token pop /y exch def pop\n" |
758 | 0 | " x y translate\n" |
759 | 0 | " currentfile buffer readline pop\n" |
760 | 0 | " token pop /x exch def\n" |
761 | 0 | " token pop /y exch def pop\n" |
762 | 0 | " currentfile buffer readline pop\n" |
763 | 0 | " token pop /pointsize exch def pop\n" |
764 | 0 | " /Helvetica findfont pointsize scalefont setfont\n" |
765 | 0 | ); |
766 | 0 | } |
767 | 0 | attribute=GetImageAttribute(image,"label"); |
768 | 0 | if (attribute != (const ImageAttribute *) NULL) |
769 | 0 | for (j=(long) MultilineCensus(attribute->value)-1; j >= 0; j--) |
770 | 0 | { |
771 | 0 | (void) WriteBlobString(image," /label 512 string def\n"); |
772 | 0 | (void) WriteBlobString(image," currentfile label readline pop\n"); |
773 | 0 | MagickFormatString(buffer,sizeof(buffer)," 0 y %g add moveto label show pop\n", |
774 | 0 | j*image_info->pointsize+12); |
775 | 0 | (void) WriteBlobString(image,buffer); |
776 | 0 | } |
777 | 0 | (void) WriteBlobString(image, |
778 | 0 | " x y scale\n" |
779 | 0 | " currentfile buffer readline pop\n" |
780 | 0 | " token pop /columns exch def\n" |
781 | 0 | " token pop /rows exch def pop\n" |
782 | 0 | " currentfile buffer readline pop\n" |
783 | 0 | " token pop /class exch def pop\n" |
784 | 0 | " currentfile buffer readline pop\n" |
785 | 0 | " token pop /colorspace exch def pop\n" |
786 | 0 | " currentfile buffer readline pop\n" |
787 | 0 | " token pop /compression exch def pop\n" |
788 | 0 | " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse\n" |
789 | 0 | " grestore\n"); |
790 | 0 | if (LocaleCompare(image_info->magick,"PS2") == 0) |
791 | 0 | (void) WriteBlobString(image," showpage\n"); |
792 | 0 | (void) WriteBlobString(image,"} bind def\n"); |
793 | 0 | (void) WriteBlobString(image,"%%EndProlog\n"); |
794 | 0 | } |
795 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%Page: 1 %lu\n",page++); |
796 | 0 | (void) WriteBlobString(image,buffer); |
797 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x, |
798 | 0 | geometry.y,geometry.x+(long) geometry.width,geometry.y+(long) |
799 | 0 | (geometry.height+text_size)); |
800 | 0 | (void) WriteBlobString(image,buffer); |
801 | 0 | if (geometry.x < bounds.x1) |
802 | 0 | bounds.x1=geometry.x; |
803 | 0 | if (geometry.y < bounds.y1) |
804 | 0 | bounds.y1=geometry.y; |
805 | 0 | if ((geometry.x+(size_t) geometry.width-1) > bounds.x2) |
806 | 0 | bounds.x2=geometry.x+(size_t) geometry.width-1; |
807 | 0 | if ((geometry.y+((size_t) geometry.height+text_size)-1) > bounds.y2) |
808 | 0 | bounds.y2=geometry.y+((size_t) geometry.height+text_size)-1; |
809 | 0 | attribute=GetImageAttribute(image,"label"); |
810 | 0 | if (attribute != (const ImageAttribute *) NULL) |
811 | 0 | (void) WriteBlobString(image,"%%PageResources: font Times-Roman\n"); |
812 | 0 | if (LocaleCompare(image_info->magick,"PS2") != 0) |
813 | 0 | (void) WriteBlobString(image,"userdict begin\n"); |
814 | 0 | start=TellBlob(image); |
815 | 0 | if (start < 0) |
816 | 0 | ThrowWriterException(BlobError,UnableToObtainOffset,image); |
817 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%BeginData:%13ld %s Bytes\n",0L, |
818 | 0 | compression == NoCompression ? "ASCII" : "Binary"); |
819 | 0 | (void) WriteBlobString(image,buffer); |
820 | 0 | stop=TellBlob(image); |
821 | 0 | if (stop < 0) |
822 | 0 | ThrowWriterException(BlobError,UnableToObtainOffset,image); |
823 | 0 | (void) WriteBlobString(image,"DisplayImage\n"); |
824 | | /* |
825 | | Output image data. |
826 | | */ |
827 | 0 | MagickFormatString(buffer,sizeof(buffer),"%ld %ld\n%g %g\n%f\n",geometry.x,geometry.y, |
828 | 0 | x_scale,y_scale,image_info->pointsize); |
829 | 0 | (void) WriteBlobString(image,buffer); |
830 | 0 | labels=(char **) NULL; |
831 | 0 | attribute=GetImageAttribute(image,"label"); |
832 | 0 | if (attribute != (const ImageAttribute *) NULL) |
833 | 0 | labels=StringToList(attribute->value); |
834 | 0 | if (labels != (char **) NULL) |
835 | 0 | { |
836 | 0 | for (i=0; labels[i] != (char *) NULL; i++) |
837 | 0 | { |
838 | 0 | MagickFormatString(buffer,sizeof(buffer),"%.1024s \n",labels[i]); |
839 | 0 | (void) WriteBlobString(image,buffer); |
840 | 0 | MagickFreeMemory(labels[i]); |
841 | 0 | } |
842 | 0 | MagickFreeMemory(labels); |
843 | 0 | } |
844 | 0 | number_pixels=image->columns*image->rows; |
845 | |
|
846 | 0 | if ((compression == FaxCompression) || |
847 | 0 | ((image_info->type != TrueColorType) && |
848 | 0 | (characteristics.grayscale))) |
849 | 0 | { |
850 | 0 | MagickFormatString(buffer,sizeof(buffer),"%lu %lu\n1\n%d\n",image->columns,image->rows, |
851 | 0 | (int) (image->colorspace == CMYKColorspace)); |
852 | 0 | (void) WriteBlobString(image,buffer); |
853 | 0 | MagickFormatString(buffer,sizeof(buffer),"%d\n",(int) (compression != FaxCompression)); |
854 | 0 | (void) WriteBlobString(image,buffer); |
855 | 0 | (void) WriteBlobString(image,"0\n"); |
856 | 0 | MagickFormatString(buffer,sizeof(buffer),"%d\n",compression == FaxCompression ? 1 : 8); |
857 | 0 | (void) WriteBlobString(image,buffer); |
858 | 0 | switch (compression) |
859 | 0 | { |
860 | 0 | case FaxCompression: |
861 | 0 | { |
862 | 0 | if (LocaleCompare(CCITTParam,"0") == 0) |
863 | 0 | { |
864 | 0 | (void) HuffmanEncodeImage(image_info,image); |
865 | 0 | break; |
866 | 0 | } |
867 | 0 | (void) Huffman2DEncodeImage(image_info,image); |
868 | 0 | break; |
869 | 0 | } |
870 | 0 | case JPEGCompression: |
871 | 0 | { |
872 | | /* |
873 | | Write image in JPEG format. |
874 | | */ |
875 | 0 | blob=ImageToJPEGBlob(image,image_info,&length,&image->exception); |
876 | 0 | if (blob == (char *) NULL) |
877 | 0 | ThrowWriterException2(CoderError,image->exception.reason,image); |
878 | 0 | (void) WriteBlob(image,length,blob); |
879 | 0 | MagickFreeMemory(blob); |
880 | 0 | break; |
881 | 0 | } |
882 | 0 | case RLECompression: |
883 | 0 | default: |
884 | 0 | { |
885 | 0 | register unsigned char |
886 | 0 | *q; |
887 | | |
888 | | /* |
889 | | Allocate pixel array. |
890 | | */ |
891 | 0 | length=number_pixels; |
892 | 0 | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,length); |
893 | 0 | if (pixels == (unsigned char *) NULL) |
894 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
895 | 0 | image); |
896 | | /* |
897 | | Dump Runlength encoded pixels. |
898 | | */ |
899 | 0 | q=pixels; |
900 | 0 | for (y=0; y < (long) image->rows; y++) |
901 | 0 | { |
902 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
903 | 0 | &image->exception); |
904 | 0 | if (p == (const PixelPacket *) NULL) |
905 | 0 | break; |
906 | 0 | for (x=0; x < (long) image->columns; x++) |
907 | 0 | { |
908 | 0 | *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p)); |
909 | 0 | p++; |
910 | 0 | } |
911 | 0 | if (image->previous == (Image *) NULL) |
912 | 0 | if (QuantumTick(y,image->rows)) |
913 | 0 | { |
914 | 0 | status=MagickMonitorFormatted(y,image->rows, |
915 | 0 | &image->exception, |
916 | 0 | SaveImageText, |
917 | 0 | image->filename, |
918 | 0 | image->columns,image->rows); |
919 | 0 | if (status == False) |
920 | 0 | break; |
921 | 0 | } |
922 | 0 | } |
923 | 0 | if (compression == LZWCompression) |
924 | 0 | status=LZWEncodeImage(image,length,pixels); |
925 | 0 | else |
926 | 0 | status=PackbitsEncodeImage(image,length,pixels); |
927 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
928 | 0 | if (!status) |
929 | 0 | { |
930 | 0 | CloseBlob(image); |
931 | 0 | return(MagickFail); |
932 | 0 | } |
933 | 0 | break; |
934 | 0 | } |
935 | 0 | case NoCompression: |
936 | 0 | { |
937 | | /* |
938 | | Dump uncompressed PseudoColor packets. |
939 | | */ |
940 | 0 | Ascii85Initialize(image); |
941 | 0 | for (y=0; y < (long) image->rows; y++) |
942 | 0 | { |
943 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
944 | 0 | &image->exception); |
945 | 0 | if (p == (const PixelPacket *) NULL) |
946 | 0 | break; |
947 | 0 | for (x=0; x < (long) image->columns; x++) |
948 | 0 | { |
949 | 0 | Ascii85Encode(image, |
950 | 0 | ScaleQuantumToChar(PixelIntensityToQuantum(p))); |
951 | 0 | p++; |
952 | 0 | } |
953 | 0 | if (image->previous == (Image *) NULL) |
954 | 0 | if (QuantumTick(y,image->rows)) |
955 | 0 | { |
956 | 0 | status=MagickMonitorFormatted(y,image->rows, |
957 | 0 | &image->exception, |
958 | 0 | SaveImageText, |
959 | 0 | image->filename, |
960 | 0 | image->columns,image->rows); |
961 | 0 | if (status == MagickFail) |
962 | 0 | break; |
963 | 0 | } |
964 | 0 | } |
965 | 0 | Ascii85Flush(image); |
966 | 0 | break; |
967 | 0 | } |
968 | 0 | } |
969 | 0 | } |
970 | 0 | else |
971 | 0 | if ((image->storage_class == DirectClass) || (image->colors > 256) || |
972 | 0 | (compression == JPEGCompression)) |
973 | 0 | { |
974 | 0 | MagickFormatString(buffer,sizeof(buffer),"%lu %lu\n0\n%d\n",image->columns,image->rows, |
975 | 0 | (int) (image->colorspace == CMYKColorspace)); |
976 | 0 | (void) WriteBlobString(image,buffer); |
977 | 0 | MagickFormatString(buffer,sizeof(buffer),"%d\n",(int) (compression == NoCompression)); |
978 | 0 | (void) WriteBlobString(image,buffer); |
979 | 0 | switch (compression) |
980 | 0 | { |
981 | 0 | case JPEGCompression: |
982 | 0 | { |
983 | | /* |
984 | | Write image in JPEG format. |
985 | | */ |
986 | 0 | blob=ImageToJPEGBlob(image,image_info,&length,&image->exception); |
987 | 0 | if (blob == (char *) NULL) |
988 | 0 | ThrowWriterException2(CoderError,image->exception.reason,image); |
989 | 0 | (void) WriteBlob(image,length,blob); |
990 | 0 | MagickFreeMemory(blob); |
991 | 0 | break; |
992 | 0 | } |
993 | 0 | case RLECompression: |
994 | 0 | default: |
995 | 0 | { |
996 | 0 | register unsigned char |
997 | 0 | *q; |
998 | | |
999 | | /* |
1000 | | Allocate pixel array. |
1001 | | */ |
1002 | 0 | length=MagickArraySize(image->colorspace == CMYKColorspace ? 4 : 3, |
1003 | 0 | number_pixels); |
1004 | 0 | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,length); |
1005 | 0 | if (pixels == (unsigned char *) NULL) |
1006 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
1007 | | /* |
1008 | | Dump Packbit encoded pixels. |
1009 | | */ |
1010 | 0 | q=pixels; |
1011 | 0 | for (y=0; y < (long) image->rows; y++) |
1012 | 0 | { |
1013 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
1014 | 0 | &image->exception); |
1015 | 0 | if (p == (const PixelPacket *) NULL) |
1016 | 0 | break; |
1017 | 0 | for (x=0; x < (long) image->columns; x++) |
1018 | 0 | { |
1019 | 0 | if (image->matte && (p->opacity == TransparentOpacity)) |
1020 | 0 | { |
1021 | 0 | *q++=ScaleQuantumToChar(MaxRGB); |
1022 | 0 | *q++=ScaleQuantumToChar(MaxRGB); |
1023 | 0 | *q++=ScaleQuantumToChar(MaxRGB); |
1024 | 0 | } |
1025 | 0 | else |
1026 | 0 | if (image->colorspace != CMYKColorspace) |
1027 | 0 | { |
1028 | 0 | *q++=ScaleQuantumToChar(p->red); |
1029 | 0 | *q++=ScaleQuantumToChar(p->green); |
1030 | 0 | *q++=ScaleQuantumToChar(p->blue); |
1031 | 0 | } |
1032 | 0 | else |
1033 | 0 | { |
1034 | 0 | *q++=ScaleQuantumToChar(p->red); |
1035 | 0 | *q++=ScaleQuantumToChar(p->green); |
1036 | 0 | *q++=ScaleQuantumToChar(p->blue); |
1037 | 0 | *q++=ScaleQuantumToChar(p->opacity); |
1038 | 0 | } |
1039 | 0 | p++; |
1040 | 0 | } |
1041 | 0 | if (image->previous == (Image *) NULL) |
1042 | 0 | if (QuantumTick(y,image->rows)) |
1043 | 0 | { |
1044 | 0 | status=MagickMonitorFormatted(y,image->rows, |
1045 | 0 | &image->exception, |
1046 | 0 | SaveImageText, |
1047 | 0 | image->filename, |
1048 | 0 | image->columns,image->rows); |
1049 | 0 | if (status == MagickFail) |
1050 | 0 | break; |
1051 | 0 | } |
1052 | 0 | } |
1053 | 0 | if (compression == LZWCompression) |
1054 | 0 | status=LZWEncodeImage(image,length,pixels); |
1055 | 0 | else |
1056 | 0 | status=PackbitsEncodeImage(image,length,pixels); |
1057 | 0 | if (!status) |
1058 | 0 | { |
1059 | 0 | CloseBlob(image); |
1060 | 0 | return(MagickFail); |
1061 | 0 | } |
1062 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
1063 | 0 | break; |
1064 | 0 | } |
1065 | 0 | case NoCompression: |
1066 | 0 | { |
1067 | | /* |
1068 | | Dump uncompressed DirectColor packets. |
1069 | | */ |
1070 | 0 | Ascii85Initialize(image); |
1071 | 0 | for (y=0; y < (long) image->rows; y++) |
1072 | 0 | { |
1073 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
1074 | 0 | &image->exception); |
1075 | 0 | if (p == (const PixelPacket *) NULL) |
1076 | 0 | break; |
1077 | 0 | for (x=0; x < (long) image->columns; x++) |
1078 | 0 | { |
1079 | 0 | if (image->matte && (p->opacity == TransparentOpacity)) |
1080 | 0 | { |
1081 | 0 | Ascii85Encode(image,ScaleQuantumToChar(MaxRGB)); |
1082 | 0 | Ascii85Encode(image,ScaleQuantumToChar(MaxRGB)); |
1083 | 0 | Ascii85Encode(image,ScaleQuantumToChar(MaxRGB)); |
1084 | 0 | } |
1085 | 0 | else |
1086 | 0 | if (image->colorspace != CMYKColorspace) |
1087 | 0 | { |
1088 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->red)); |
1089 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->green)); |
1090 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->blue)); |
1091 | 0 | } |
1092 | 0 | else |
1093 | 0 | { |
1094 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->red)); |
1095 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->green)); |
1096 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->blue)); |
1097 | 0 | Ascii85Encode(image,ScaleQuantumToChar(p->opacity)); |
1098 | 0 | } |
1099 | 0 | p++; |
1100 | 0 | } |
1101 | 0 | if (image->previous == (Image *) NULL) |
1102 | 0 | if (QuantumTick(y,image->rows)) |
1103 | 0 | { |
1104 | 0 | status=MagickMonitorFormatted(y,image->rows, |
1105 | 0 | &image->exception, |
1106 | 0 | SaveImageText, |
1107 | 0 | image->filename, |
1108 | 0 | image->columns,image->rows); |
1109 | 0 | if (status == MagickFail) |
1110 | 0 | break; |
1111 | 0 | } |
1112 | 0 | } |
1113 | 0 | Ascii85Flush(image); |
1114 | 0 | break; |
1115 | 0 | } |
1116 | 0 | } |
1117 | 0 | } |
1118 | 0 | else |
1119 | 0 | { |
1120 | | /* |
1121 | | Dump number of colors and colormap. |
1122 | | */ |
1123 | 0 | MagickFormatString(buffer,sizeof(buffer),"%lu %lu\n1\n%d\n",image->columns,image->rows, |
1124 | 0 | (int) (image->colorspace == CMYKColorspace)); |
1125 | 0 | (void) WriteBlobString(image,buffer); |
1126 | 0 | MagickFormatString(buffer,sizeof(buffer),"%d\n",(int) (compression == NoCompression)); |
1127 | 0 | (void) WriteBlobString(image,buffer); |
1128 | 0 | MagickFormatString(buffer,sizeof(buffer),"%u\n",image->colors); |
1129 | 0 | (void) WriteBlobString(image,buffer); |
1130 | 0 | for (i=0; i < (long) image->colors; i++) |
1131 | 0 | { |
1132 | 0 | MagickFormatString(buffer,sizeof(buffer),"%02X%02X%02X\n", |
1133 | 0 | ScaleQuantumToChar(image->colormap[i].red), |
1134 | 0 | ScaleQuantumToChar(image->colormap[i].green), |
1135 | 0 | ScaleQuantumToChar(image->colormap[i].blue)); |
1136 | 0 | (void) WriteBlobString(image,buffer); |
1137 | 0 | } |
1138 | 0 | switch (compression) |
1139 | 0 | { |
1140 | 0 | case RLECompression: |
1141 | 0 | default: |
1142 | 0 | { |
1143 | 0 | register unsigned char |
1144 | 0 | *q; |
1145 | | |
1146 | | /* |
1147 | | Allocate pixel array. |
1148 | | */ |
1149 | 0 | length=number_pixels; |
1150 | 0 | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,length); |
1151 | 0 | if (pixels == (unsigned char *) NULL) |
1152 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
1153 | | /* |
1154 | | Dump Runlength encoded pixels. |
1155 | | */ |
1156 | 0 | q=pixels; |
1157 | 0 | for (y=0; y < (long) image->rows; y++) |
1158 | 0 | { |
1159 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
1160 | 0 | &image->exception); |
1161 | 0 | if (p == (const PixelPacket *) NULL) |
1162 | 0 | break; |
1163 | 0 | indexes=AccessImmutableIndexes(image); |
1164 | 0 | for (x=0; x < (long) image->columns; x++) |
1165 | 0 | *q++=indexes[x]; |
1166 | 0 | if (image->previous == (Image *) NULL) |
1167 | 0 | if (QuantumTick(y,image->rows)) |
1168 | 0 | { |
1169 | 0 | status=MagickMonitorFormatted(y,image->rows, |
1170 | 0 | &image->exception, |
1171 | 0 | SaveImageText, |
1172 | 0 | image->filename, |
1173 | 0 | image->columns,image->rows); |
1174 | 0 | if (status == MagickFail) |
1175 | 0 | break; |
1176 | 0 | } |
1177 | 0 | } |
1178 | 0 | if (compression == LZWCompression) |
1179 | 0 | status=LZWEncodeImage(image,length,pixels); |
1180 | 0 | else |
1181 | 0 | status=PackbitsEncodeImage(image,length,pixels); |
1182 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
1183 | 0 | if (!status) |
1184 | 0 | { |
1185 | 0 | CloseBlob(image); |
1186 | 0 | return(MagickFail); |
1187 | 0 | } |
1188 | 0 | break; |
1189 | 0 | } |
1190 | 0 | case NoCompression: |
1191 | 0 | { |
1192 | | /* |
1193 | | Dump uncompressed PseudoColor packets. |
1194 | | */ |
1195 | 0 | Ascii85Initialize(image); |
1196 | 0 | for (y=0; y < (long) image->rows; y++) |
1197 | 0 | { |
1198 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1, |
1199 | 0 | &image->exception); |
1200 | 0 | if (p == (const PixelPacket *) NULL) |
1201 | 0 | break; |
1202 | 0 | indexes=AccessImmutableIndexes(image); |
1203 | 0 | for (x=0; x < (long) image->columns; x++) |
1204 | 0 | Ascii85Encode(image,indexes[x]); |
1205 | 0 | if (image->previous == (Image *) NULL) |
1206 | 0 | if (QuantumTick(y,image->rows)) |
1207 | 0 | { |
1208 | 0 | status=MagickMonitorFormatted(y,image->rows, |
1209 | 0 | &image->exception, |
1210 | 0 | SaveImageText, |
1211 | 0 | image->filename, |
1212 | 0 | image->columns,image->rows); |
1213 | 0 | if (status == MagickFail) |
1214 | 0 | break; |
1215 | 0 | } |
1216 | 0 | } |
1217 | 0 | Ascii85Flush(image); |
1218 | 0 | break; |
1219 | 0 | } |
1220 | 0 | } |
1221 | 0 | } |
1222 | 0 | (void) WriteBlobByte(image,'\n'); |
1223 | 0 | current=TellBlob(image); |
1224 | 0 | if (current < 0) |
1225 | 0 | ThrowWriterException(BlobError,UnableToObtainOffset,image); |
1226 | 0 | length=current-stop; |
1227 | 0 | stop=TellBlob(image); |
1228 | 0 | if (stop < 0) |
1229 | 0 | ThrowWriterException(BlobError,UnableToObtainOffset,image); |
1230 | 0 | if (SeekBlob(image,start,SEEK_SET) != start) |
1231 | 0 | ThrowWriterException(BlobError,UnableToSeekToOffset,image); |
1232 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%BeginData:%13ld %s Bytes\n",(long) length, |
1233 | 0 | compression == NoCompression ? "ASCII" : "Binary"); |
1234 | 0 | (void) WriteBlobString(image,buffer); |
1235 | 0 | if (SeekBlob(image,stop,SEEK_SET) != stop) |
1236 | 0 | ThrowWriterException(BlobError,UnableToSeekToOffset,image); |
1237 | 0 | (void) WriteBlobString(image,"%%EndData\n"); |
1238 | 0 | if (LocaleCompare(image_info->magick,"PS2") != 0) |
1239 | 0 | (void) WriteBlobString(image,"end\n"); |
1240 | 0 | (void) WriteBlobString(image,"%%PageTrailer\n"); |
1241 | 0 | if (image->next == (Image *) NULL) |
1242 | 0 | break; |
1243 | 0 | image=SyncNextImageInList(image); |
1244 | 0 | status=MagickMonitorFormatted(scene++,image_list_length, |
1245 | 0 | &image->exception,SaveImagesText, |
1246 | 0 | image->filename); |
1247 | 0 | if (status == MagickFail) |
1248 | 0 | break; |
1249 | 0 | } while (image_info->adjoin); |
1250 | 0 | if (image_info->adjoin) |
1251 | 0 | while (image->previous != (Image *) NULL) |
1252 | 0 | image=image->previous; |
1253 | 0 | (void) WriteBlobString(image,"%%Trailer\n"); |
1254 | 0 | if (page > 1) |
1255 | 0 | { |
1256 | 0 | MagickFormatString(buffer,sizeof(buffer),"%%%%BoundingBox: %g %g %g %g\n",floor(bounds.x1+0.5), |
1257 | 0 | floor(bounds.y1+0.5),ceil(bounds.x2-0.5),ceil(bounds.y2-0.5)); |
1258 | 0 | (void) WriteBlobString(image,buffer); |
1259 | 0 | } |
1260 | 0 | (void) WriteBlobString(image,"%%EOF\n"); |
1261 | 0 | status &= CloseBlob(image); |
1262 | 0 | return(status); |
1263 | 0 | } |