1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % PPPP SSSSS 33333 %
7 % P P SS 33 %
8 % PPPP SSS 333 %
9 % P SS 33 %
10 % P SSSSS 33333 %
11 % %
12 % %
13 % Write Postscript Level III Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % Lars Ruben Skyum %
18 % July 1992 %
19 % %
20 % %
21 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
23 % %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
26 % %
27 % https://imagemagick.org/script/license.php %
28 % %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
34 % %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39
40 /*
41 Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/channel.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/compress.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/magick.h"
62 #include "MagickCore/memory_.h"
63 #include "MagickCore/module.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/option.h"
67 #include "MagickCore/pixel-accessor.h"
68 #include "MagickCore/property.h"
69 #include "MagickCore/quantum-private.h"
70 #include "MagickCore/resource_.h"
71 #include "MagickCore/static.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/module.h"
74 #include "MagickCore/timer-private.h"
75 #include "MagickCore/token.h"
76 #include "MagickCore/utility.h"
77
78 /*
79 Define declarations.
80 */
81 #define PS3_NoCompression "0"
82 #define PS3_FaxCompression "1"
83 #define PS3_JPEGCompression "2"
84 #define PS3_LZWCompression "3"
85 #define PS3_RLECompression "4"
86 #define PS3_ZipCompression "5"
87
88 #define PS3_RGBColorspace "0"
89 #define PS3_CMYKColorspace "1"
90
91 #define PS3_DirectClass "0"
92 #define PS3_PseudoClass "1"
93
94 #if defined(MAGICKCORE_TIFF_DELEGATE)
95 #define CCITTParam "-1"
96 #else
97 #define CCITTParam "0"
98 #endif
99
100 /*
101 Forward declarations.
102 */
103 static MagickBooleanType
104 WritePS3Image(const ImageInfo *,Image *,ExceptionInfo *);
105
106 /*
107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 % %
109 % %
110 % %
111 % R e g i s t e r P S 3 I m a g e %
112 % %
113 % %
114 % %
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 %
117 % RegisterPS3Image() adds properties for the PS3 image format to the list of
118 % supported formats. The properties include the image format tag, a method to
119 % read and/or write the format, whether the format supports the saving of more
120 % than one frame to the same file or blob, whether the format supports native
121 % in-memory I/O, and a brief description of the format.
122 %
123 % The format of the RegisterPS3Image method is:
124 %
125 % size_t RegisterPS3Image(void)
126 %
127 */
RegisterPS3Image(void)128 ModuleExport size_t RegisterPS3Image(void)
129 {
130 MagickInfo
131 *entry;
132
133 entry=AcquireMagickInfo("PS3","EPS3","Level III Encapsulated PostScript");
134 entry->encoder=(EncodeImageHandler *) WritePS3Image;
135 entry->mime_type=ConstantString("application/postscript");
136 entry->flags|=CoderEncoderSeekableStreamFlag;
137 entry->flags^=CoderBlobSupportFlag;
138 (void) RegisterMagickInfo(entry);
139 entry=AcquireMagickInfo("PS3","PS3","Level III PostScript");
140 entry->encoder=(EncodeImageHandler *) WritePS3Image;
141 entry->mime_type=ConstantString("application/postscript");
142 entry->flags|=CoderEncoderSeekableStreamFlag;
143 entry->flags^=CoderBlobSupportFlag;
144 (void) RegisterMagickInfo(entry);
145 return(MagickImageCoderSignature);
146 }
147
148 /*
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 % %
151 % %
152 % %
153 % U n r e g i s t e r P S 3 I m a g e %
154 % %
155 % %
156 % %
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158 %
159 % UnregisterPS3Image() removes format registrations made by the PS3 module
160 % from the list of supported formats.
161 %
162 % The format of the UnregisterPS3Image method is:
163 %
164 % UnregisterPS3Image(void)
165 %
166 */
UnregisterPS3Image(void)167 ModuleExport void UnregisterPS3Image(void)
168 {
169 (void) UnregisterMagickInfo("EPS3");
170 (void) UnregisterMagickInfo("PS3");
171 }
172
173 /*
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175 % %
176 % %
177 % %
178 % W r i t e P S 3 I m a g e %
179 % %
180 % %
181 % %
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183 %
184 % WritePS3Image() translates an image to encapsulated Postscript Level III
185 % for printing. If the supplied geometry is null, the image is centered on
186 % the Postscript page. Otherwise, the image is positioned as specified by the
187 % geometry.
188 %
189 % The format of the WritePS3Image method is:
190 %
191 % MagickBooleanType WritePS3Image(const ImageInfo *image_info,
192 % Image *image,ExceptionInfo *exception)
193 %
194 % A description of each parameter follows:
195 %
196 % o image_info: Specifies a pointer to a ImageInfo structure.
197 %
198 % o image: the image.
199 %
200 % o exception: return any errors or warnings in this structure.
201 %
202 */
203
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image,Image * inject_image,ExceptionInfo * exception)204 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
205 Image *image,Image *inject_image,ExceptionInfo *exception)
206 {
207 Image
208 *group4_image;
209
210 ImageInfo
211 *write_info;
212
213 MagickBooleanType
214 status;
215
216 size_t
217 length;
218
219 unsigned char
220 *group4;
221
222 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
223 if (group4_image == (Image *) NULL)
224 return(MagickFalse);
225 status=MagickTrue;
226 write_info=CloneImageInfo(image_info);
227 (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
228 (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
229 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
230 exception);
231 group4_image=DestroyImage(group4_image);
232 write_info=DestroyImageInfo(write_info);
233 if (group4 == (unsigned char *) NULL)
234 return(MagickFalse);
235 if (WriteBlob(image,length,group4) != (ssize_t) length)
236 status=MagickFalse;
237 group4=(unsigned char *) RelinquishMagickMemory(group4);
238 return(status);
239 }
240
SerializeImage(const ImageInfo * image_info,Image * image,MemoryInfo ** pixel_info,size_t * length,ExceptionInfo * exception)241 static MagickBooleanType SerializeImage(const ImageInfo *image_info,
242 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
243 {
244 MagickBooleanType
245 status;
246
247 const Quantum
248 *p;
249
250 ssize_t
251 x;
252
253 unsigned char
254 *q;
255
256 ssize_t
257 y;
258
259 assert(image != (Image *) NULL);
260 assert(image->signature == MagickCoreSignature);
261 if (image->debug != MagickFalse)
262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
263 status=MagickTrue;
264 *length=(image->colorspace == CMYKColorspace ? 4 : 3)*(size_t)
265 image->columns*image->rows;
266 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
267 if (*pixel_info == (MemoryInfo *) NULL)
268 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
269 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
270 (void) memset(q,0,*length*sizeof(*q));
271 for (y=0; y < (ssize_t) image->rows; y++)
272 {
273 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
274 if (p == (const Quantum *) NULL)
275 break;
276 if (image->colorspace != CMYKColorspace)
277 for (x=0; x < (ssize_t) image->columns; x++)
278 {
279 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
280 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
281 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
282 p+=GetPixelChannels(image);
283 }
284 else
285 for (x=0; x < (ssize_t) image->columns; x++)
286 {
287 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
288 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
289 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
290 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
291 p+=GetPixelChannels(image);
292 }
293 if (image->previous == (Image *) NULL)
294 {
295 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
296 image->rows);
297 if (status == MagickFalse)
298 break;
299 }
300 }
301 if (status == MagickFalse)
302 *pixel_info=RelinquishVirtualMemory(*pixel_info);
303 return(status);
304 }
305
SerializeImageChannel(const ImageInfo * image_info,Image * image,MemoryInfo ** pixel_info,size_t * length,ExceptionInfo * exception)306 static MagickBooleanType SerializeImageChannel(const ImageInfo *image_info,
307 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
308 {
309 MagickBooleanType
310 status;
311
312 const Quantum
313 *p;
314
315 ssize_t
316 x;
317
318 unsigned char
319 *q;
320
321 size_t
322 pack,
323 padded_columns;
324
325 ssize_t
326 y;
327
328 unsigned char
329 code,
330 bit;
331
332 assert(image != (Image *) NULL);
333 assert(image->signature == MagickCoreSignature);
334 if (image->debug != MagickFalse)
335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
336 status=MagickTrue;
337 pack=SetImageMonochrome(image,exception) == MagickFalse ? 1UL : 8UL;
338 padded_columns=((image->columns+pack-1)/pack)*pack;
339 *length=(size_t) padded_columns*image->rows/pack;
340 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
341 if (*pixel_info == (MemoryInfo *) NULL)
342 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
343 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
344 for (y=0; y < (ssize_t) image->rows; y++)
345 {
346 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
347 if (p == (const Quantum *) NULL)
348 break;
349 if (pack == 1)
350 for (x=0; x < (ssize_t) image->columns; x++)
351 {
352 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
353 p+=GetPixelChannels(image);
354 }
355 else
356 {
357 code='\0';
358 for (x=0; x < (ssize_t) padded_columns; x++)
359 {
360 bit=(unsigned char) 0x00;
361 if (x < (ssize_t) image->columns)
362 bit=(unsigned char) (GetPixelLuma(image,p) == TransparentAlpha ?
363 0x01 : 0x00);
364 code=(code << 1)+bit;
365 if (((x+1) % pack) == 0)
366 {
367 *q++=code;
368 code='\0';
369 }
370 p+=GetPixelChannels(image);
371 }
372 }
373 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
374 image->rows);
375 if (status == MagickFalse)
376 break;
377 }
378 if (status == MagickFalse)
379 *pixel_info=RelinquishVirtualMemory(*pixel_info);
380 return(status);
381 }
382
SerializeImageIndexes(const ImageInfo * image_info,Image * image,MemoryInfo ** pixel_info,size_t * length,ExceptionInfo * exception)383 static MagickBooleanType SerializeImageIndexes(const ImageInfo *image_info,
384 Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
385 {
386 MagickBooleanType
387 status;
388
389 const Quantum
390 *p;
391
392 ssize_t
393 x;
394
395 unsigned char
396 *q;
397
398 ssize_t
399 y;
400
401 assert(image != (Image *) NULL);
402 assert(image->signature == MagickCoreSignature);
403 if (image->debug != MagickFalse)
404 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
405 status=MagickTrue;
406 *length=(size_t) image->columns*image->rows;
407 *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
408 if (*pixel_info == (MemoryInfo *) NULL)
409 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
410 q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
411 for (y=0; y < (ssize_t) image->rows; y++)
412 {
413 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
414 if (p == (const Quantum *) NULL)
415 break;
416 for (x=0; x < (ssize_t) image->columns; x++)
417 {
418 *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
419 p+=GetPixelChannels(image);
420 }
421 if (image->previous == (Image *) NULL)
422 {
423 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
424 image->rows);
425 if (status == MagickFalse)
426 break;
427 }
428 }
429 if (status == MagickFalse)
430 *pixel_info=RelinquishVirtualMemory(*pixel_info);
431 return(status);
432 }
433
WritePS3MaskImage(const ImageInfo * image_info,Image * image,const CompressionType compression,ExceptionInfo * exception)434 static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info,
435 Image *image,const CompressionType compression,ExceptionInfo *exception)
436 {
437 char
438 buffer[MagickPathExtent];
439
440 Image
441 *mask_image;
442
443 MagickBooleanType
444 status;
445
446 MagickOffsetType
447 offset,
448 start,
449 stop;
450
451 MemoryInfo
452 *pixel_info;
453
454 ssize_t
455 i;
456
457 size_t
458 length;
459
460 unsigned char
461 *pixels;
462
463 assert(image_info != (ImageInfo *) NULL);
464 assert(image_info->signature == MagickCoreSignature);
465 assert(image != (Image *) NULL);
466 assert(image->signature == MagickCoreSignature);
467 if (image->debug != MagickFalse)
468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
469 assert(image->alpha_trait != UndefinedPixelTrait);
470 status=MagickTrue;
471 /*
472 Note BeginData DSC comment for update later.
473 */
474 start=TellBlob(image);
475 if (start < 0)
476 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
477 (void) FormatLocaleString(buffer,MagickPathExtent,
478 "%%%%BeginData:%13ld %s Bytes\n",0L,compression == NoCompression ?
479 "ASCII" : "BINARY");
480 (void) WriteBlobString(image,buffer);
481 stop=TellBlob(image);
482 if (stop < 0)
483 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
484 /*
485 Only lossless compressions for the mask.
486 */
487 switch (compression)
488 {
489 case NoCompression:
490 default:
491 {
492 (void) FormatLocaleString(buffer,MagickPathExtent,
493 "currentfile %.20g %.20g " PS3_NoCompression
494 " ByteStreamDecodeFilter\n",(double) image->columns,(double)
495 image->rows);
496 break;
497 }
498 case FaxCompression:
499 case Group4Compression:
500 {
501 (void) FormatLocaleString(buffer,MagickPathExtent,
502 "currentfile %.20g %.20g " PS3_FaxCompression
503 " ByteStreamDecodeFilter\n",(double) image->columns,(double)
504 image->rows);
505 break;
506 }
507 case LZWCompression:
508 {
509 (void) FormatLocaleString(buffer,MagickPathExtent,
510 "currentfile %.20g %.20g " PS3_LZWCompression
511 " ByteStreamDecodeFilter\n",(double) image->columns,(double)
512 image->rows);
513 break;
514 }
515 case RLECompression:
516 {
517 (void) FormatLocaleString(buffer,MagickPathExtent,
518 "currentfile %.20g %.20g " PS3_RLECompression
519 " ByteStreamDecodeFilter\n",(double) image->columns,(double)
520 image->rows);
521 break;
522 }
523 case ZipCompression:
524 {
525 (void) FormatLocaleString(buffer,MagickPathExtent,
526 "currentfile %.20g %.20g " PS3_ZipCompression
527 " ByteStreamDecodeFilter\n",(double) image->columns,(double)
528 image->rows);
529 break;
530 }
531 }
532 (void) WriteBlobString(image,buffer);
533 (void) WriteBlobString(image,"/ReusableStreamDecode filter\n");
534 mask_image=SeparateImage(image,AlphaChannel,exception);
535 if (mask_image == (Image *) NULL)
536 ThrowWriterException(CoderError,exception->reason);
537 (void) SetImageType(mask_image,BilevelType,exception);
538 (void) SetImageType(mask_image,PaletteType,exception);
539 mask_image->alpha_trait=UndefinedPixelTrait;
540 pixels=(unsigned char *) NULL;
541 length=0;
542 switch (compression)
543 {
544 case NoCompression:
545 default:
546 {
547 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
548 exception);
549 if (status == MagickFalse)
550 break;
551 Ascii85Initialize(image);
552 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
553 for (i=0; i < (ssize_t) length; i++)
554 Ascii85Encode(image,pixels[i]);
555 Ascii85Flush(image);
556 pixel_info=RelinquishVirtualMemory(pixel_info);
557 break;
558 }
559 case FaxCompression:
560 case Group4Compression:
561 {
562 if ((compression == FaxCompression) ||
563 (LocaleCompare(CCITTParam,"0") == 0))
564 status=HuffmanEncodeImage(image_info,image,mask_image,exception);
565 else
566 status=Huffman2DEncodeImage(image_info,image,mask_image,exception);
567 break;
568 }
569 case LZWCompression:
570 {
571 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
572 exception);
573 if (status == MagickFalse)
574 break;
575 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
576 status=LZWEncodeImage(image,length,pixels,exception);
577 pixel_info=RelinquishVirtualMemory(pixel_info);
578 break;
579 }
580 case RLECompression:
581 {
582 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
583 exception);
584 if (status == MagickFalse)
585 break;
586 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
587 status=PackbitsEncodeImage(image,length,pixels,exception);
588 pixel_info=RelinquishVirtualMemory(pixel_info);
589 break;
590 }
591 case ZipCompression:
592 {
593 status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
594 exception);
595 if (status == MagickFalse)
596 break;
597 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
598 status=ZLIBEncodeImage(image,length,pixels,exception);
599 pixel_info=RelinquishVirtualMemory(pixel_info);
600 break;
601 }
602 }
603 mask_image=DestroyImage(mask_image);
604 (void) WriteBlobByte(image,'\n');
605 length=(size_t) (TellBlob(image)-stop);
606 stop=TellBlob(image);
607 if (stop < 0)
608 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
609 offset=SeekBlob(image,start,SEEK_SET);
610 if (offset < 0)
611 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
612 (void) FormatLocaleString(buffer,MagickPathExtent,
613 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
614 compression == NoCompression ? "ASCII" : "BINARY");
615 (void) WriteBlobString(image,buffer);
616 offset=SeekBlob(image,stop,SEEK_SET);
617 if (offset < 0)
618 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
619 (void) WriteBlobString(image,"%%EndData\n");
620 (void) WriteBlobString(image, "/mask_stream exch def\n");
621 return(status);
622 }
623
WritePS3Image(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)624 static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
625 ExceptionInfo *exception)
626 {
627 static const char
628 PostscriptProlog[] =
629 "/ByteStreamDecodeFilter\n"
630 "{\n"
631 " /z exch def\n"
632 " /r exch def\n"
633 " /c exch def\n"
634 " z " PS3_NoCompression " eq { /ASCII85Decode filter } if\n"
635 " z " PS3_FaxCompression " eq\n"
636 " {\n"
637 " <<\n"
638 " /K " CCITTParam "\n"
639 " /Columns c\n"
640 " /Rows r\n"
641 " >>\n"
642 " /CCITTFaxDecode filter\n"
643 " } if\n"
644 " z " PS3_JPEGCompression " eq { /DCTDecode filter } if\n"
645 " z " PS3_LZWCompression " eq { /LZWDecode filter } if\n"
646 " z " PS3_RLECompression " eq { /RunLengthDecode filter } if\n"
647 " z " PS3_ZipCompression " eq { /FlateDecode filter } if\n"
648 "} bind def\n"
649 "\n"
650 "/DirectClassImageDict\n"
651 "{\n"
652 " colorspace " PS3_RGBColorspace " eq\n"
653 " {\n"
654 " /DeviceRGB setcolorspace\n"
655 " <<\n"
656 " /ImageType 1\n"
657 " /Width columns\n"
658 " /Height rows\n"
659 " /BitsPerComponent 8\n"
660 " /DataSource pixel_stream\n"
661 " /MultipleDataSources false\n"
662 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
663 " /Decode [0 1 0 1 0 1]\n"
664 " >>\n"
665 " }\n"
666 " {\n"
667 " /DeviceCMYK setcolorspace\n"
668 " <<\n"
669 " /ImageType 1\n"
670 " /Width columns\n"
671 " /Height rows\n"
672 " /BitsPerComponent 8\n"
673 " /DataSource pixel_stream\n"
674 " /MultipleDataSources false\n"
675 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
676 " /Decode\n"
677 " compression " PS3_JPEGCompression " eq\n"
678 " { [1 0 1 0 1 0 1 0] }\n"
679 " { [0 1 0 1 0 1 0 1] }\n"
680 " ifelse\n"
681 " >>\n"
682 " }\n"
683 " ifelse\n"
684 "} bind def\n"
685 "\n"
686 "/PseudoClassImageDict\n"
687 "{\n"
688 " % Colors in colormap image.\n"
689 " currentfile buffer readline pop\n"
690 " token pop /colors exch def pop\n"
691 " colors 0 eq\n"
692 " {\n"
693 " % Depth of grayscale image.\n"
694 " currentfile buffer readline pop\n"
695 " token pop /bits exch def pop\n"
696 " /DeviceGray setcolorspace\n"
697 " <<\n"
698 " /ImageType 1\n"
699 " /Width columns\n"
700 " /Height rows\n"
701 " /BitsPerComponent bits\n"
702 " /Decode [0 1]\n"
703 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
704 " /DataSource pixel_stream\n"
705 " >>\n"
706 " }\n"
707 " {\n"
708 " % RGB colormap.\n"
709 " /colormap colors 3 mul string def\n"
710 " compression " PS3_NoCompression " eq\n"
711 " { currentfile /ASCII85Decode filter colormap readstring pop pop }\n"
712 " { currentfile colormap readstring pop pop }\n"
713 " ifelse\n"
714 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace\n"
715 " <<\n"
716 " /ImageType 1\n"
717 " /Width columns\n"
718 " /Height rows\n"
719 " /BitsPerComponent 8\n"
720 " /Decode [0 255]\n"
721 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
722 " /DataSource pixel_stream\n"
723 " >>\n"
724 " }\n"
725 " ifelse\n"
726 "} bind def\n"
727 "\n"
728 "/NonMaskedImageDict\n"
729 "{\n"
730 " class " PS3_PseudoClass " eq\n"
731 " { PseudoClassImageDict }\n"
732 " { DirectClassImageDict }\n"
733 " ifelse\n"
734 "} bind def\n"
735 "\n"
736 "/MaskedImageDict\n"
737 "{\n"
738 " <<\n"
739 " /ImageType 3\n"
740 " /InterleaveType 3\n"
741 " /DataDict NonMaskedImageDict\n"
742 " /MaskDict\n"
743 " <<\n"
744 " /ImageType 1\n"
745 " /Width columns\n"
746 " /Height rows\n"
747 " /BitsPerComponent 1\n"
748 " /DataSource mask_stream\n"
749 " /MultipleDataSources false\n"
750 " /ImageMatrix [ columns 0 0 rows neg 0 rows]\n"
751 " /Decode [ 0 1 ]\n"
752 " >>\n"
753 " >>\n"
754 "} bind def\n"
755 "\n"
756 "/ClipImage\n"
757 "{} def\n"
758 "\n"
759 "/DisplayImage\n"
760 "{\n"
761 " gsave\n"
762 " /buffer 512 string def\n"
763 " % Translation.\n"
764 " currentfile buffer readline pop\n"
765 " token pop /x exch def\n"
766 " token pop /y exch def pop\n"
767 " x y translate\n"
768 " % Image size and font size.\n"
769 " currentfile buffer readline pop\n"
770 " token pop /x exch def\n"
771 " token pop /y exch def pop\n"
772 " currentfile buffer readline pop\n"
773 " token pop /pointsize exch def pop\n";
774 static const char
775 PostscriptEpilog[] =
776 " x y scale\n"
777 " % Clipping path.\n"
778 " currentfile buffer readline pop\n"
779 " token pop /clipped exch def pop\n"
780 " % Showpage.\n"
781 " currentfile buffer readline pop\n"
782 " token pop /sp exch def pop\n"
783 " % Image pixel size.\n"
784 " currentfile buffer readline pop\n"
785 " token pop /columns exch def\n"
786 " token pop /rows exch def pop\n"
787 " % Colorspace (RGB/CMYK).\n"
788 " currentfile buffer readline pop\n"
789 " token pop /colorspace exch def pop\n"
790 " % Transparency.\n"
791 " currentfile buffer readline pop\n"
792 " token pop /alpha exch def pop\n"
793 " % Stencil mask?\n"
794 " currentfile buffer readline pop\n"
795 " token pop /stencil exch def pop\n"
796 " % Image class (direct/pseudo).\n"
797 " currentfile buffer readline pop\n"
798 " token pop /class exch def pop\n"
799 " % Compression type.\n"
800 " currentfile buffer readline pop\n"
801 " token pop /compression exch def pop\n"
802 " % Clip and render.\n"
803 " /pixel_stream currentfile columns rows compression ByteStreamDecodeFilter def\n"
804 " clipped { ClipImage } if\n"
805 " alpha stencil not and\n"
806 " { MaskedImageDict mask_stream resetfile }\n"
807 " { NonMaskedImageDict }\n"
808 " ifelse\n"
809 " stencil { 0 setgray imagemask } { image } ifelse\n"
810 " grestore\n"
811 " sp { showpage } if\n"
812 "} bind def\n";
813
814 char
815 buffer[MagickPathExtent],
816 date[MagickTimeExtent],
817 **labels,
818 page_geometry[MagickPathExtent];
819
820 CompressionType
821 compression;
822
823 const char
824 *option,
825 *value;
826
827 double
828 pointsize;
829
830 GeometryInfo
831 geometry_info;
832
833 MagickBooleanType
834 status;
835
836 MagickOffsetType
837 offset,
838 scene,
839 start,
840 stop;
841
842 MagickStatusType
843 flags;
844
845 MemoryInfo
846 *pixel_info;
847
848 PointInfo
849 delta,
850 resolution,
851 scale;
852
853 RectangleInfo
854 geometry,
855 media_info,
856 page_info;
857
858 ssize_t
859 i;
860
861 SegmentInfo
862 bounds;
863
864 size_t
865 imageListLength,
866 length,
867 page,
868 pixel,
869 text_size;
870
871 ssize_t
872 j;
873
874 time_t
875 timer;
876
877 unsigned char
878 *pixels;
879
880 /*
881 Open output image file.
882 */
883 assert(image_info != (const ImageInfo *) NULL);
884 assert(image_info->signature == MagickCoreSignature);
885 assert(image != (Image *) NULL);
886 assert(image->signature == MagickCoreSignature);
887 if (image->debug != MagickFalse)
888 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
889 assert(exception != (ExceptionInfo *) NULL);
890 assert(exception->signature == MagickCoreSignature);
891 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
892 if (status == MagickFalse)
893 return(MagickFalse);
894 compression=image->compression;
895 if (image_info->compression != UndefinedCompression)
896 compression=image_info->compression;
897 switch (compression)
898 {
899 case FaxCompression:
900 case Group4Compression:
901 {
902 if ((SetImageMonochrome(image,exception) == MagickFalse) ||
903 (image->alpha_trait != UndefinedPixelTrait))
904 compression=RLECompression;
905 break;
906 }
907 #if !defined(MAGICKCORE_JPEG_DELEGATE)
908 case JPEGCompression:
909 {
910 compression=RLECompression;
911 (void) ThrowMagickException(exception,GetMagickModule(),
912 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
913 image->filename);
914 break;
915 }
916 #endif
917 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
918 case ZipCompression:
919 {
920 compression=RLECompression;
921 (void) ThrowMagickException(exception,GetMagickModule(),
922 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
923 image->filename);
924 break;
925 }
926 #endif
927 default:
928 break;
929 }
930 (void) memset(&bounds,0,sizeof(bounds));
931 page=0;
932 scene=0;
933 imageListLength=GetImageListLength(image);
934 do
935 {
936 /*
937 Scale relative to dots-per-inch.
938 */
939 delta.x=DefaultResolution;
940 delta.y=DefaultResolution;
941 resolution.x=image->resolution.x;
942 resolution.y=image->resolution.y;
943 if ((resolution.x == 0.0) || (resolution.y == 0.0))
944 {
945 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
946 resolution.x=geometry_info.rho;
947 resolution.y=geometry_info.sigma;
948 if ((flags & SigmaValue) == 0)
949 resolution.y=resolution.x;
950 }
951 if (image_info->density != (char *) NULL)
952 {
953 flags=ParseGeometry(image_info->density,&geometry_info);
954 resolution.x=geometry_info.rho;
955 resolution.y=geometry_info.sigma;
956 if ((flags & SigmaValue) == 0)
957 resolution.y=resolution.x;
958 }
959 if (image->units == PixelsPerCentimeterResolution)
960 {
961 resolution.x=(100.0*2.54*resolution.x+0.5)/100.0;
962 resolution.y=(100.0*2.54*resolution.y+0.5)/100.0;
963 }
964 SetGeometry(image,&geometry);
965 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
966 (double) image->columns,(double) image->rows);
967 if (image_info->page != (char *) NULL)
968 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
969 else
970 if ((image->page.width != 0) && (image->page.height != 0))
971 (void) FormatLocaleString(page_geometry,MagickPathExtent,
972 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
973 image->page.height,(double) image->page.x,(double) image->page.y);
974 else
975 if ((image->gravity != UndefinedGravity) &&
976 (LocaleCompare(image_info->magick,"PS") == 0))
977 (void) CopyMagickString(page_geometry,PSPageGeometry,
978 MagickPathExtent);
979 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
980 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
981 &geometry.width,&geometry.height);
982 scale.x=PerceptibleReciprocal(resolution.x)*geometry.width*delta.x;
983 geometry.width=(size_t) floor(scale.x+0.5);
984 scale.y=PerceptibleReciprocal(resolution.y)*geometry.height*delta.y;
985 geometry.height=(size_t) floor(scale.y+0.5);
986 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
987 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
988 if (image->gravity != UndefinedGravity)
989 {
990 geometry.x=(-page_info.x);
991 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
992 }
993 pointsize=12.0;
994 if (image_info->pointsize != 0.0)
995 pointsize=image_info->pointsize;
996 text_size=0;
997 value=GetImageProperty(image,"label",exception);
998 if (value != (const char *) NULL)
999 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1000 page++;
1001 if (page == 1)
1002 {
1003 /*
1004 Postscript header on the first page.
1005 */
1006 if (LocaleCompare(image_info->magick,"PS3") == 0)
1007 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
1008 else
1009 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1010 MagickPathExtent);
1011 (void) WriteBlobString(image,buffer);
1012 (void) FormatLocaleString(buffer,MagickPathExtent,
1013 "%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
1014 (void) WriteBlobString(image,buffer);
1015 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: %s\n",
1016 image->filename);
1017 (void) WriteBlobString(image,buffer);
1018 timer=GetMagickTime();
1019 (void) FormatMagickTime(timer,sizeof(date),date);
1020 (void) FormatLocaleString(buffer,MagickPathExtent,
1021 "%%%%CreationDate: %s\n",date);
1022 (void) WriteBlobString(image,buffer);
1023 bounds.x1=(double) geometry.x;
1024 bounds.y1=(double) geometry.y;
1025 bounds.x2=(double) geometry.x+scale.x;
1026 bounds.y2=(double) geometry.y+scale.y+text_size;
1027 if ((image_info->adjoin != MagickFalse) &&
1028 (GetNextImageInList(image) != (Image *) NULL))
1029 {
1030 (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
1031 (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
1032 }
1033 else
1034 {
1035 (void) FormatLocaleString(buffer,MagickPathExtent,
1036 "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1037 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1038 (void) WriteBlobString(image,buffer);
1039 (void) FormatLocaleString(buffer,MagickPathExtent,
1040 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1041 bounds.y1,bounds.x2,bounds.y2);
1042 (void) WriteBlobString(image,buffer);
1043 if (image->colorspace == CMYKColorspace)
1044 (void) WriteBlobString(image,
1045 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1046 else
1047 if (SetImageGray(image,exception) != MagickFalse)
1048 (void) WriteBlobString(image,
1049 "%%DocumentProcessColors: Black\n");
1050 }
1051 /*
1052 Font resources
1053 */
1054 value=GetImageProperty(image,"label",exception);
1055 if (value != (const char *) NULL)
1056 (void) WriteBlobString(image,
1057 "%%DocumentNeededResources: font Helvetica\n");
1058 (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
1059 /*
1060 Pages, orientation and order.
1061 */
1062 if (LocaleCompare(image_info->magick,"PS3") != 0)
1063 (void) WriteBlobString(image,"%%Pages: 1\n");
1064 else
1065 {
1066 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1067 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1068 if (image_info->adjoin == MagickFalse)
1069 (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
1070 else
1071 (void) FormatLocaleString(buffer,MagickPathExtent,
1072 "%%%%Pages: %.20g\n",(double) imageListLength);
1073 (void) WriteBlobString(image,buffer);
1074 }
1075 if (image->colorspace == CMYKColorspace)
1076 (void) WriteBlobString(image,
1077 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1078 (void) WriteBlobString(image,"%%EndComments\n");
1079 /*
1080 The static postscript procedures prolog.
1081 */
1082 (void) WriteBlobString(image,"%%BeginProlog\n");
1083 (void) WriteBlob(image,sizeof(PostscriptProlog)-1,PostscriptProlog);
1084 /*
1085 One label line for each line in label string.
1086 */
1087 value=GetImageProperty(image,"label",exception);
1088 if (value != (const char *) NULL)
1089 {
1090 (void) WriteBlobString(image,"\n %% Labels.\n /Helvetica "
1091 " findfont pointsize scalefont setfont\n");
1092 for (i=(ssize_t) MultilineCensus(value)-1; i >= 0; i--)
1093 {
1094 (void) WriteBlobString(image,
1095 " currentfile buffer readline pop token pop\n");
1096 (void) FormatLocaleString(buffer,MagickPathExtent,
1097 " 0 y %g add moveto show pop\n",i*pointsize+12);
1098 (void) WriteBlobString(image,buffer);
1099 }
1100 }
1101 /*
1102 The static postscript procedures epilog.
1103 */
1104 (void) WriteBlob(image,sizeof(PostscriptEpilog)-1,PostscriptEpilog);
1105 (void) WriteBlobString(image,"%%EndProlog\n");
1106 }
1107 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
1108 (double) page);
1109 (void) WriteBlobString(image,buffer);
1110 /*
1111 Page bounding box.
1112 */
1113 (void) FormatLocaleString(buffer,MagickPathExtent,
1114 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1115 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+
1116 (double) (geometry.height+text_size));
1117 (void) WriteBlobString(image,buffer);
1118 /*
1119 Page process colors if not RGB.
1120 */
1121 if (image->colorspace == CMYKColorspace)
1122 (void) WriteBlobString(image,
1123 "%%PageProcessColors: Cyan Magenta Yellow Black\n");
1124 else
1125 if (SetImageGray(image,exception) != MagickFalse)
1126 (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
1127 /*
1128 Adjust document bounding box to bound page bounding box.
1129 */
1130 if ((double) geometry.x < bounds.x1)
1131 bounds.x1=(double) geometry.x;
1132 if ((double) geometry.y < bounds.y1)
1133 bounds.y1=(double) geometry.y;
1134 if ((double) (geometry.x+scale.x) > bounds.x2)
1135 bounds.x2=(double) geometry.x+scale.x;
1136 if ((double) (geometry.y+scale.y+text_size) > bounds.y2)
1137 bounds.y2=(double) geometry.y+scale.y+text_size;
1138 /*
1139 Page font resource if there's a label.
1140 */
1141 value=GetImageProperty(image,"label",exception);
1142 if (value != (const char *) NULL)
1143 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
1144 /*
1145 PS clipping path from Photoshop clipping path.
1146 */
1147 if (((image->channels & WriteMaskChannel) != 0) ||
1148 (LocaleNCompare("8BIM:",image->magick_filename,5) != 0))
1149 (void) WriteBlobString(image,"/ClipImage {} def\n");
1150 else
1151 {
1152 const char
1153 *value;
1154
1155 value=GetImageProperty(image,image->magick_filename,exception);
1156 if (value == (const char *) NULL)
1157 return(MagickFalse);
1158 (void) WriteBlobString(image,value);
1159 (void) WriteBlobByte(image,'\n');
1160 }
1161 /*
1162 Push a dictionary for our own def's if this an EPS.
1163 */
1164 if (LocaleCompare(image_info->magick,"PS3") != 0)
1165 (void) WriteBlobString(image,"userdict begin\n");
1166 /*
1167 Image mask.
1168 */
1169 if ((image->alpha_trait != UndefinedPixelTrait) &&
1170 (WritePS3MaskImage(image_info,image,compression,exception) == MagickFalse))
1171 {
1172 (void) CloseBlob(image);
1173 return(MagickFalse);
1174 }
1175 /*
1176 Remember position of BeginData comment so we can update it.
1177 */
1178 start=TellBlob(image);
1179 if (start < 0)
1180 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1181 (void) FormatLocaleString(buffer,MagickPathExtent,
1182 "%%%%BeginData:%13ld %s Bytes\n",0L,
1183 compression == NoCompression ? "ASCII" : "BINARY");
1184 (void) WriteBlobString(image,buffer);
1185 stop=TellBlob(image);
1186 if (stop < 0)
1187 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1188 (void) WriteBlobString(image,"DisplayImage\n");
1189 /*
1190 Translate, scale, and font point size.
1191 */
1192 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
1193 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1194 (void) WriteBlobString(image,buffer);
1195 /*
1196 Output labels.
1197 */
1198 labels=(char **) NULL;
1199 value=GetImageProperty(image,"label",exception);
1200 if (value != (const char *) NULL)
1201 labels=StringToList(value);
1202 if (labels != (char **) NULL)
1203 {
1204 for (i=0; labels[i] != (char *) NULL; i++)
1205 {
1206 if (compression != NoCompression)
1207 {
1208 for (j=0; labels[i][j] != '\0'; j++)
1209 (void) WriteBlobByte(image,(unsigned char) labels[i][j]);
1210 (void) WriteBlobByte(image,'\n');
1211 }
1212 else
1213 {
1214 (void) WriteBlobString(image,"<~");
1215 Ascii85Initialize(image);
1216 for (j=0; labels[i][j] != '\0'; j++)
1217 Ascii85Encode(image,(unsigned char) labels[i][j]);
1218 Ascii85Flush(image);
1219 }
1220 labels[i]=DestroyString(labels[i]);
1221 }
1222 labels=(char **) RelinquishMagickMemory(labels);
1223 }
1224 /*
1225 Photoshop clipping path active?
1226 */
1227 if (((image->channels & WriteMaskChannel) != 0) &&
1228 (LocaleNCompare("8BIM:",image->magick_filename,5) == 0))
1229 (void) WriteBlobString(image,"true\n");
1230 else
1231 (void) WriteBlobString(image,"false\n");
1232 /*
1233 Showpage for non-EPS.
1234 */
1235 (void) WriteBlobString(image, LocaleCompare(image_info->magick,"PS3") == 0 ?
1236 "true\n" : "false\n");
1237 /*
1238 Image columns, rows, and color space.
1239 */
1240 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%s\n",
1241 (double) image->columns,(double) image->rows,image->colorspace ==
1242 CMYKColorspace ? PS3_CMYKColorspace : PS3_RGBColorspace);
1243 (void) WriteBlobString(image,buffer);
1244 /*
1245 Masked image?
1246 */
1247 (void) WriteBlobString(image,image->alpha_trait != UndefinedPixelTrait ?
1248 "true\n" : "false\n");
1249 /*
1250 Render with imagemask operator?
1251 */
1252 option=GetImageOption(image_info,"ps3:imagemask");
1253 (void) WriteBlobString(image,((option != (const char *) NULL) &&
1254 (SetImageMonochrome(image,exception) != MagickFalse)) ?
1255 "true\n" : "false\n");
1256 /*
1257 Output pixel data.
1258 */
1259 pixels=(unsigned char *) NULL;
1260 length=0;
1261 if ((image_info->type != TrueColorType) &&
1262 (image_info->type != TrueColorAlphaType) &&
1263 (image_info->type != ColorSeparationType) &&
1264 (image_info->type != ColorSeparationAlphaType) &&
1265 (image->colorspace != CMYKColorspace) &&
1266 ((SetImageGray(image,exception) != MagickFalse) ||
1267 (SetImageMonochrome(image,exception) != MagickFalse)))
1268 {
1269 /*
1270 Gray images.
1271 */
1272 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1273 switch (compression)
1274 {
1275 case NoCompression:
1276 default:
1277 {
1278 (void) WriteBlobString(image,PS3_NoCompression"\n");
1279 break;
1280 }
1281 case FaxCompression:
1282 case Group4Compression:
1283 {
1284 (void) WriteBlobString(image,PS3_FaxCompression"\n");
1285 break;
1286 }
1287 case JPEGCompression:
1288 {
1289 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1290 break;
1291 }
1292 case LZWCompression:
1293 {
1294 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1295 break;
1296 }
1297 case RLECompression:
1298 {
1299 (void) WriteBlobString(image,PS3_RLECompression"\n");
1300 break;
1301 }
1302 case ZipCompression:
1303 {
1304 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1305 break;
1306 }
1307 }
1308 /*
1309 Number of colors -- 0 for single component non-color mapped data.
1310 */
1311 (void) WriteBlobString(image,"0\n");
1312 /*
1313 1 bit or 8 bit components?
1314 */
1315 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
1316 SetImageMonochrome(image,exception) != MagickFalse ? 1 : 8);
1317 (void) WriteBlobString(image,buffer);
1318 /*
1319 Image data.
1320 */
1321 if (compression == JPEGCompression)
1322 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1323 else
1324 if ((compression == FaxCompression) ||
1325 (compression == Group4Compression))
1326 {
1327 if (LocaleCompare(CCITTParam,"0") == 0)
1328 status=HuffmanEncodeImage(image_info,image,image,exception);
1329 else
1330 status=Huffman2DEncodeImage(image_info,image,image,exception);
1331 }
1332 else
1333 {
1334 status=SerializeImageChannel(image_info,image,&pixel_info,&length,
1335 exception);
1336 if (status == MagickFalse)
1337 {
1338 (void) CloseBlob(image);
1339 return(MagickFalse);
1340 }
1341 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1342 switch (compression)
1343 {
1344 case NoCompression:
1345 default:
1346 {
1347 Ascii85Initialize(image);
1348 for (i=0; i < (ssize_t) length; i++)
1349 Ascii85Encode(image,pixels[i]);
1350 Ascii85Flush(image);
1351 status=MagickTrue;
1352 break;
1353 }
1354 case LZWCompression:
1355 {
1356 status=LZWEncodeImage(image,length,pixels,exception);
1357 break;
1358 }
1359 case RLECompression:
1360 {
1361 status=PackbitsEncodeImage(image,length,pixels,exception);
1362 break;
1363 }
1364 case ZipCompression:
1365 {
1366 status=ZLIBEncodeImage(image,length,pixels,exception);
1367 break;
1368 }
1369 }
1370 pixel_info=RelinquishVirtualMemory(pixel_info);
1371 }
1372 }
1373 else
1374 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1375 (compression == JPEGCompression))
1376 {
1377 /*
1378 Truecolor image.
1379 */
1380 (void) WriteBlobString(image,PS3_DirectClass"\n");
1381 switch (compression)
1382 {
1383 case NoCompression:
1384 default:
1385 {
1386 (void) WriteBlobString(image,PS3_NoCompression"\n");
1387 break;
1388 }
1389 case RLECompression:
1390 {
1391 (void) WriteBlobString(image,PS3_RLECompression"\n");
1392 break;
1393 }
1394 case JPEGCompression:
1395 {
1396 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1397 break;
1398 }
1399 case LZWCompression:
1400 {
1401 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1402 break;
1403 }
1404 case ZipCompression:
1405 {
1406 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1407 break;
1408 }
1409 }
1410 /*
1411 Image data.
1412 */
1413 if (compression == JPEGCompression)
1414 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1415 else
1416 {
1417 /*
1418 Stream based compressions.
1419 */
1420 status=SerializeImage(image_info,image,&pixel_info,&length,
1421 exception);
1422 if (status == MagickFalse)
1423 {
1424 (void) CloseBlob(image);
1425 return(MagickFalse);
1426 }
1427 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1428 switch (compression)
1429 {
1430 case NoCompression:
1431 default:
1432 {
1433 Ascii85Initialize(image);
1434 for (i=0; i < (ssize_t) length; i++)
1435 Ascii85Encode(image,pixels[i]);
1436 Ascii85Flush(image);
1437 status=MagickTrue;
1438 break;
1439 }
1440 case RLECompression:
1441 {
1442 status=PackbitsEncodeImage(image,length,pixels,exception);
1443 break;
1444 }
1445 case LZWCompression:
1446 {
1447 status=LZWEncodeImage(image,length,pixels,exception);
1448 break;
1449 }
1450 case ZipCompression:
1451 {
1452 status=ZLIBEncodeImage(image,length,pixels,exception);
1453 break;
1454 }
1455 }
1456 pixel_info=RelinquishVirtualMemory(pixel_info);
1457 }
1458 }
1459 else
1460 {
1461 /*
1462 Colormapped images.
1463 */
1464 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1465 switch (compression)
1466 {
1467 case NoCompression:
1468 default:
1469 {
1470 (void) WriteBlobString(image,PS3_NoCompression"\n");
1471 break;
1472 }
1473 case RLECompression:
1474 {
1475 (void) WriteBlobString(image,PS3_RLECompression"\n");
1476 break;
1477 }
1478 case LZWCompression:
1479 {
1480 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1481 break;
1482 }
1483 case ZipCompression:
1484 {
1485 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1486 break;
1487 }
1488 }
1489 /*
1490 Number of colors in color map.
1491 */
1492 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",
1493 (double) image->colors);
1494 (void) WriteBlobString(image,buffer);
1495 /*
1496 Color map - uncompressed.
1497 */
1498 if ((compression != NoCompression) &&
1499 (compression != UndefinedCompression))
1500 {
1501 for (i=0; i < (ssize_t) image->colors; i++)
1502 {
1503 pixel=ScaleQuantumToChar(image->colormap[i].red);
1504 (void) WriteBlobByte(image,(unsigned char) pixel);
1505 pixel=ScaleQuantumToChar(image->colormap[i].green);
1506 (void) WriteBlobByte(image,(unsigned char) pixel);
1507 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1508 (void) WriteBlobByte(image,(unsigned char) pixel);
1509 }
1510 }
1511 else
1512 {
1513 Ascii85Initialize(image);
1514 for (i=0; i < (ssize_t) image->colors; i++)
1515 {
1516 pixel=ScaleQuantumToChar(image->colormap[i].red);
1517 Ascii85Encode(image,(unsigned char) pixel);
1518 pixel=ScaleQuantumToChar(image->colormap[i].green);
1519 Ascii85Encode(image,(unsigned char) pixel);
1520 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1521 Ascii85Encode(image,(unsigned char) pixel);
1522 }
1523 Ascii85Flush(image);
1524 }
1525 status=SerializeImageIndexes(image_info,image,&pixel_info,&length,
1526 exception);
1527 if (status == MagickFalse)
1528 {
1529 (void) CloseBlob(image);
1530 return(MagickFalse);
1531 }
1532 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1533 switch (compression)
1534 {
1535 case NoCompression:
1536 default:
1537 {
1538 Ascii85Initialize(image);
1539 for (i=0; i < (ssize_t) length; i++)
1540 Ascii85Encode(image,pixels[i]);
1541 Ascii85Flush(image);
1542 status=MagickTrue;
1543 break;
1544 }
1545 case RLECompression:
1546 {
1547 status=PackbitsEncodeImage(image,length,pixels,exception);
1548 break;
1549 }
1550 case LZWCompression:
1551 {
1552 status=LZWEncodeImage(image,length,pixels,exception);
1553 break;
1554 }
1555 case ZipCompression:
1556 {
1557 status=ZLIBEncodeImage(image,length,pixels,exception);
1558 break;
1559 }
1560 }
1561 pixel_info=RelinquishVirtualMemory(pixel_info);
1562 }
1563 (void) WriteBlobByte(image,'\n');
1564 if (status == MagickFalse)
1565 {
1566 (void) CloseBlob(image);
1567 return(MagickFalse);
1568 }
1569 /*
1570 Update BeginData now that we know the data size.
1571 */
1572 length=(size_t) (TellBlob(image)-stop);
1573 stop=TellBlob(image);
1574 if (stop < 0)
1575 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1576 offset=SeekBlob(image,start,SEEK_SET);
1577 if (offset < 0)
1578 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1579 (void) FormatLocaleString(buffer,MagickPathExtent,
1580 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1581 compression == NoCompression ? "ASCII" : "BINARY");
1582 (void) WriteBlobString(image,buffer);
1583 offset=SeekBlob(image,stop,SEEK_SET);
1584 (void) WriteBlobString(image,"%%EndData\n");
1585 /*
1586 End private dictionary if this an EPS.
1587 */
1588 if (LocaleCompare(image_info->magick,"PS3") != 0)
1589 (void) WriteBlobString(image,"end\n");
1590 (void) WriteBlobString(image,"%%PageTrailer\n");
1591 if (GetNextImageInList(image) == (Image *) NULL)
1592 break;
1593 image=SyncNextImageInList(image);
1594 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
1595 if (status == MagickFalse)
1596 break;
1597 } while (image_info->adjoin != MagickFalse);
1598 (void) WriteBlobString(image,"%%Trailer\n");
1599 if (page > 1)
1600 {
1601 (void) FormatLocaleString(buffer,MagickPathExtent,
1602 "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1603 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1604 (void) WriteBlobString(image,buffer);
1605 (void) FormatLocaleString(buffer,MagickPathExtent,
1606 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
1607 bounds.y2);
1608 (void) WriteBlobString(image,buffer);
1609 }
1610 (void) WriteBlobString(image,"%%EOF\n");
1611 (void) CloseBlob(image);
1612 return(MagickTrue);
1613 }
1614