1 /*
2 % Copyright (C) 2003 - 2020 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
5 %
6 % This program is covered by multiple licenses, which are described in
7 % Copyright.txt. You should have received a copy of Copyright.txt with this
8 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9 %
10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 % %
12 % %
13 % %
14 % PPPP SSSSS 33333 %
15 % P P SS 33 %
16 % PPPP SSS 333 %
17 % P SS 33 %
18 % P SSSSS 33333 %
19 % %
20 % %
21 % Write Postscript Level III Format. %
22 % %
23 % %
24 % Software Design %
25 % John Cristy %
26 % July 1992 %
27 % %
28 % %
29 % %
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31 %
32 %
33 */
34
35 /*
36 Include declarations.
37 */
38 #include "magick/studio.h"
39 #include "magick/analyze.h"
40 #include "magick/attribute.h"
41 #include "magick/blob.h"
42 #include "magick/pixel_cache.h"
43 #include "magick/channel.h"
44 #include "magick/color.h"
45 #include "magick/compress.h"
46 #include "magick/constitute.h"
47 #include "magick/enum_strings.h"
48 #include "magick/magick.h"
49 #include "magick/map.h"
50 #include "magick/monitor.h"
51 #include "magick/tempfile.h"
52 #include "magick/utility.h"
53 #include "magick/version.h"
54 #if defined(HasTIFF)
55 #define CCITTParam "-1"
56 #else
57 #define CCITTParam "0"
58 #endif
59
60 /* For consistent PS and C code usage */
61 #define PS3_NoCompression "0"
62 #define PS3_FaxCompression "1"
63 #define PS3_RLECompression "2"
64 #define PS3_LZWCompression "3"
65 #define PS3_ZipCompression "4"
66 #define PS3_JPEGCompression "5"
67
68 #define PS3_RGBColorspace "0"
69 #define PS3_CMYKColorspace "1"
70
71 #define PS3_DirectClass "0"
72 #define PS3_PseudoClass "1"
73
74 /*
75 Forward declarations.
76 */
77 static unsigned int
78 WritePS3Image(const ImageInfo *,Image *),
79 ZLIBEncode2Image(Image *,const size_t,const unsigned long,unsigned char *,
80 WriteByteHook,void *);
81
82 #if defined(HasTIFF)
83 #if defined(HAVE_TIFFCONF_H)
84 #include "tiffconf.h"
85 #endif
86 #include "tiffio.h"
87 /*
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 % %
90 % %
91 % %
92 % H u f f m a n 2 D E n c o d e I m a g e %
93 % %
94 % %
95 % %
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %
98 % Method Huffman2DEncodeImage compresses an image via two-dimensional
99 % Huffman-coding.
100 %
101 % The format of the Huffman2DEncodeImage method is:
102 %
103 % unsigned int Huffman2DEncodeImage(const ImageInfo *image_info,
104 % Image *image)
105 %
106 % A description of each parameter follows:
107 %
108 % o status: Method Huffman2DEncodeImage returns True if all the pixels are
109 % compressed without error, otherwise False.
110 %
111 % o image_info: The image info..
112 %
113 % o image: The image.
114 %
115 */
SerializeHuffman2DImage(const ImageInfo * image_info,Image * image,unsigned char ** pixels,size_t * length)116 static unsigned int SerializeHuffman2DImage(const ImageInfo *image_info,
117 Image *image, unsigned char **pixels, size_t *length)
118 {
119 char
120 filename[MaxTextExtent];
121
122 Image
123 *huffman_image;
124
125 ImageInfo
126 *clone_info;
127
128 long
129 count,
130 j;
131
132 register long
133 i;
134
135 TIFF
136 *tiff;
137
138 uint16
139 fillorder;
140
141 unsigned char
142 *buffer,
143 *p;
144
145 unsigned int
146 status;
147
148 unsigned long
149 *byte_count,
150 strip_size;
151
152 /*
153 Write image as CCITTFax4 TIFF image to a temporary file.
154 */
155 assert(image_info != (ImageInfo *) NULL);
156 assert(image_info->signature == MagickSignature);
157 assert(image != (Image *) NULL);
158 assert(image->signature == MagickSignature);
159 if(!AcquireTemporaryFileName(filename))
160 {
161 ThrowBinaryException(FileOpenError,UnableToCreateTemporaryFile,
162 filename)
163 }
164 huffman_image=CloneImage(image,0,0,True,&image->exception);
165 if (huffman_image == (Image *) NULL)
166 return(False);
167 /*
168 TODO: If (image, then) huffman_image->compression is JPEG, huffman_image
169 is changed to DirectClass in WriteTIFFImage and the huffman_image ends up
170 broken. Change WriteTIFFIMage to not alter bilevel image to directclass
171 when clone_info is G4 compression. Until then, set
172 huffman_image->compression here:
173 */
174 huffman_image->compression=Group4Compression;
175
176 (void) SetImageType(huffman_image,BilevelType);
177 FormatString(huffman_image->filename,"tiff:%s",filename);
178 clone_info=CloneImageInfo(image_info);
179 clone_info->compression=Group4Compression;
180 clone_info->type=BilevelType;
181 (void) AddDefinitions(clone_info,"tiff:fill-order=msb2lsb",
182 &image->exception);
183 status=WriteImage(clone_info,huffman_image);
184 DestroyImageInfo(clone_info);
185 DestroyImage(huffman_image);
186 if (status == False)
187 {
188 (void) LiberateTemporaryFile(filename);
189 return(False);
190 }
191 tiff=TIFFOpen(filename,"rb");
192 if (tiff == (TIFF *) NULL)
193 {
194 (void) LiberateTemporaryFile(filename);
195 ThrowBinaryException(FileOpenError,UnableToOpenFile,
196 image_info->filename)
197 }
198 /*
199 Allocate raw strip buffer.
200 */
201 (void) TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count);
202 *length=strip_size=byte_count[0];
203 for (i=1; i < (long) TIFFNumberOfStrips(tiff); i++)
204 {
205 if (byte_count[i] > strip_size)
206 strip_size=byte_count[i];
207 *length+=byte_count[i];
208 }
209 buffer=MagickAllocateResourceLimitedMemory(unsigned char *,strip_size);
210 if (buffer == (unsigned char *) NULL)
211 {
212 TIFFClose(tiff);
213 (void) LiberateTemporaryFile(filename);
214 ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
215 (char *) NULL)
216 }
217 *pixels=MagickAllocateResourceLimitedMemory(unsigned char *,*length);
218 if (*pixels == (unsigned char *) NULL)
219 {
220 MagickFreeResourceLimitedMemory(buffer);
221 TIFFClose(tiff);
222 (void) LiberateTemporaryFile(filename);
223 ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
224 (char *) NULL)
225 }
226
227 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fillorder);
228 p=(*pixels);
229 for (i=0; i < (long) TIFFNumberOfStrips(tiff); i++)
230 {
231 count=TIFFReadRawStrip(tiff,(uint32) i,buffer,(long) byte_count[i]);
232 if (fillorder == FILLORDER_LSB2MSB)
233 TIFFReverseBits(buffer,count);
234 for (j=0; j < count; j++)
235 *p++=buffer[j];
236 }
237 MagickFreeResourceLimitedMemory(buffer);
238 TIFFClose(tiff);
239 (void) LiberateTemporaryFile(filename);
240 return(True);
241 }
242
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image)243 static unsigned int Huffman2DEncodeImage(const ImageInfo *image_info,
244 Image *image)
245 {
246 size_t
247 length;
248
249 register unsigned long
250 i;
251
252 unsigned char
253 *pixels;
254
255 unsigned int
256 status;
257
258 assert(image_info != (ImageInfo *) NULL);
259 assert(image_info->signature == MagickSignature);
260 assert(image != (Image *) NULL);
261 assert(image->signature == MagickSignature);
262
263 status=SerializeHuffman2DImage(image_info,image,&pixels,&length);
264 if (!status)
265 return False;
266
267 Ascii85Initialize(image);
268 for (i=0; i < length; i++)
269 Ascii85Encode(image,(unsigned long) pixels[i]);
270 Ascii85Flush(image);
271 MagickFreeResourceLimitedMemory(pixels);
272 return(True);
273 }
274
275 #else
276
SerializeHuffman2DImage(const ImageInfo * image_info,Image * image,unsigned char ** pixels,size_t * length)277 static unsigned int SerializeHuffman2DImage(const ImageInfo *image_info,
278 Image *image, unsigned char **pixels, size_t *length)
279 {
280 ARG_NOT_USED(image_info);
281 ARG_NOT_USED(pixels);
282 ARG_NOT_USED(length);
283 assert(image != (Image *) NULL);
284 assert(image->signature == MagickSignature);
285 ThrowBinaryException(MissingDelegateError,TIFFLibraryIsNotAvailable,image->filename)
286 }
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image)287 static unsigned int Huffman2DEncodeImage(const ImageInfo *image_info,
288 Image *image)
289 {
290 ARG_NOT_USED(image_info);
291 assert(image != (Image *) NULL);
292 assert(image->signature == MagickSignature);
293 ThrowBinaryException(MissingDelegateError,TIFFLibraryIsNotAvailable,image->filename)
294 }
295 #endif
296
297 /*
298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299 % %
300 % %
301 % %
302 % J P E G E n c o d e I m a g e %
303 % %
304 % %
305 % %
306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307 %
308 % Method JPEGEncodeImage compresses an image via JPEG compression.
309 %
310 % The format of the JPEGEncodeImage method is:
311 %
312 % unsigned int JPEGEncodeImage(const ImageInfo *image_info,
313 % Image *image)
314 %
315 % A description of each parameter follows:
316 %
317 % o status: Method JPEGEncodeImage returns True if all the pixels are
318 % compressed without error, otherwise False.
319 %
320 % o image_info: The image info.
321 %
322 % o image: The image.
323 %
324 */
JPEGEncodeImage(const ImageInfo * image_info,Image * image)325 static MagickPassFail JPEGEncodeImage(const ImageInfo *image_info,
326 Image *image)
327 {
328 unsigned char
329 *blob;
330
331 size_t
332 length;
333
334 MagickPassFail
335 status=MagickFail;
336
337 blob=ImageToJPEGBlob(image,image_info,&length,&image->exception);
338 if (blob != (unsigned char *) NULL)
339 {
340 register const unsigned char
341 *p;
342
343 register size_t
344 i;
345
346 Ascii85Initialize(image);
347 for (p=(const unsigned char*) blob,i=0; i < length; i++)
348 Ascii85Encode(image,(unsigned long) p[i]);
349 Ascii85Flush(image);
350 MagickFreeMemory(blob);
351 status=MagickPass;
352 }
353 return status;
354 }
355
356 /*
357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 % %
359 % %
360 % %
361 % R e g i s t e r P S 3 I m a g e %
362 % %
363 % %
364 % %
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 %
367 % Method RegisterPS3Image adds attributes for the PS3 image format to
368 % the list of supported formats. The attributes include the image format
369 % tag, a method to read and/or write the format, whether the format
370 % supports the saving of more than one frame to the same file or blob,
371 % whether the format supports native in-memory I/O, and a brief
372 % description of the format.
373 %
374 % The format of the RegisterPS3Image method is:
375 %
376 % RegisterPS3Image(void)
377 %
378 */
RegisterPS3Image(void)379 ModuleExport void RegisterPS3Image(void)
380 {
381 MagickInfo
382 *entry;
383
384 entry=SetMagickInfo("EPS3");
385 entry->encoder=(EncoderHandler) WritePS3Image;
386 entry->description="Adobe Level III Encapsulated PostScript";
387 entry->seekable_stream=MagickTrue;
388 entry->module="PS3";
389 entry->coder_class=PrimaryCoderClass;
390 (void) RegisterMagickInfo(entry);
391
392 entry=SetMagickInfo("PS3");
393 entry->encoder=(EncoderHandler) WritePS3Image;
394 entry->description="Adobe Level III PostScript";
395 entry->seekable_stream=MagickTrue;
396 entry->module="PS3";
397 entry->coder_class=PrimaryCoderClass;
398 (void) RegisterMagickInfo(entry);
399 }
400
401 /*
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 % %
404 % %
405 % %
406 % S e r i a l i z e P s e u d o C l a s s I m a g e %
407 % %
408 % %
409 % %
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 %
412 % Convert the indexes of a color mapped image to a stream of bytes.
413 %
414 % The format of the SerializePseudoClassImage method is:
415 %
416 % unsigned int SerializePseudoClassImage(const ImageInfo *image_info,
417 % Image *image, unsigned char **pixels, size_t *length)
418 %
419 % A description of each parameter follows:
420 %
421 % o image_info: Specifies a pointer to a ImageInfo structure. required by
422 % exception handlers.
423 %
424 % o image: The image for which the color map indexes should be serialized.
425 %
426 % o pixels: the serialized indexes.
427 %
428 % o length: the length of the pixels mamory area.
429 %
430 */
SerializePseudoClassImage(const ImageInfo * image_info,Image * image,unsigned char ** pixels,size_t * length)431 static unsigned int SerializePseudoClassImage(const ImageInfo *image_info,
432 Image *image, unsigned char **pixels, size_t *length)
433 {
434 long
435 x,
436 y;
437
438 register unsigned char
439 *q;
440
441 const PixelPacket
442 *p;
443
444 int
445 status;
446
447 register const IndexPacket
448 *indexes;
449
450 assert(image != (Image *) NULL);
451 assert(image->signature == MagickSignature);
452 status=True;
453 *length=MagickArraySize(image->columns,image->rows);
454 *pixels=MagickAllocateResourceLimitedMemory(unsigned char *, *length);
455 if (*pixels == (unsigned char *) NULL)
456 ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
457 q=(*pixels);
458 for (y=0; y < (long) image->rows; y++)
459 {
460 p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
461 if (p == (const PixelPacket *) NULL)
462 break;
463 indexes=AccessImmutableIndexes(image);
464 for (x=0; x < (long) image->columns; x++)
465 *q++=indexes[x];
466 if (image->previous == (Image *) NULL)
467 if (QuantumTick(y,image->rows))
468 {
469 status=MagickMonitorFormatted(y,image->rows,&image->exception,
470 SaveImageText,image->filename,
471 image->columns,image->rows);
472 if (status == False)
473 break;
474 }
475 }
476 if (status == False)
477 MagickFreeResourceLimitedMemory(*pixels);
478 return(status);
479 }
480
481 /*
482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 % %
484 % %
485 % %
486 % S e r i a l i z e M u l t i C h a n n e l I m a g e %
487 % %
488 % %
489 % %
490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491 %
492 % Convert three and four channel images to a stream of bytes.
493 %
494 % The format of the SerializeMultiChannelImage method is:
495 %
496 % unsigned int SerializeMultiChannelImage(const ImageInfo *image_info,
497 % Image *image, unsigned char **pixels, size_t *length)
498 %
499 % A description of each parameter follows:
500 %
501 % o image_info: Specifies a pointer to a ImageInfo structure. required by
502 % exception handlers.
503 %
504 % o image: The image for which the RGB or CMYK channels should be
505 % serialized.
506 %
507 % o pixels: the serialized image channels.
508 %
509 % o length: the length of the pixels mamory area.
510 %
511 */
SerializeMultiChannelImage(const ImageInfo * image_info,Image * image,unsigned char ** pixels,size_t * length)512 static unsigned int SerializeMultiChannelImage(const ImageInfo *image_info,
513 Image *image, unsigned char **pixels, size_t *length)
514 {
515 long
516 x,
517 y;
518
519 register unsigned char
520 *q;
521
522 const PixelPacket
523 *p;
524
525 int
526 status;
527
528 assert(image != (Image *) NULL);
529 assert(image->signature == MagickSignature);
530 status=True;
531 *length=(size_t) (image->colorspace == CMYKColorspace ? 4U : 3U)*MagickArraySize(image->columns,image->rows);
532 *pixels=MagickAllocateResourceLimitedMemory(unsigned char *, *length);
533 if (*pixels == (unsigned char *) NULL)
534 ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
535
536 q=(*pixels);
537 for (y=0; y < (long) image->rows; y++)
538 {
539 p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
540 if (p == (const PixelPacket *) NULL)
541 break;
542 if (image->colorspace == CMYKColorspace)
543 for (x=0; x < (long) image->columns; x++)
544 {
545 *q++=ScaleQuantumToChar(p->red);
546 *q++=ScaleQuantumToChar(p->green);
547 *q++=ScaleQuantumToChar(p->blue);
548 *q++=ScaleQuantumToChar(p->opacity);
549 p++;
550 }
551 else
552 for (x=0; x < (long) image->columns; x++)
553 {
554 *q++=ScaleQuantumToChar(p->red);
555 *q++=ScaleQuantumToChar(p->green);
556 *q++=ScaleQuantumToChar(p->blue);
557 p++;
558 }
559 if (image->previous == (Image *) NULL)
560 if (QuantumTick(y,image->rows))
561 {
562 status=MagickMonitorFormatted(y,image->rows,&image->exception,
563 SaveImageText,image->filename,
564 image->columns,image->rows);
565 if (status == False)
566 break;
567 }
568 }
569 if (status == False)
570 MagickFreeResourceLimitedMemory(*pixels);
571 return(status);
572 }
573
574 /*
575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576 % %
577 % %
578 % %
579 % S e r i a l i z e S i n g l e C h a n n e l I m a g e %
580 % %
581 % %
582 % %
583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 %
585 % Convert 1 and 8 bit single channel images to a stream of bytes. Bilevel
586 % image pixels are packed 8 pixels in a byte.
587 %
588 % The format of the SerializeSingleChannelImage method is:
589 %
590 % unsigned int SerializeSingleChannelImage(const ImageInfo *image_info,
591 % Image *image, unsigned char **pixels, size_t *length)
592 %
593 % A description of each parameter follows:
594 %
595 % o image_info: Specifies a pointer to an ImageInfo structure. Required by
596 % exception handlers.
597 %
598 % o image: The image for which the RGB or CMYK channels should be
599 % serialized.
600 %
601 % o characteristics: Already populated image characteristics.
602 %
603 % o pixels: the serialized image channels.
604 %
605 % o length: the length of the pixels mamory area.
606 %
607 */
SerializeSingleChannelImage(const ImageInfo * image_info,Image * image,unsigned char ** pixels,size_t * length)608 static unsigned int SerializeSingleChannelImage(const ImageInfo *image_info,
609 Image *image,unsigned char **pixels, size_t *length)
610 {
611 unsigned long
612 x,
613 y;
614
615 register unsigned char
616 *q;
617
618 const PixelPacket
619 *p;
620
621 unsigned long
622 pack,
623 padded_columns;
624
625 unsigned char
626 code,
627 bit;
628
629 int
630 status;
631
632 assert(image != (Image *) NULL);
633 assert(image->signature == MagickSignature);
634 status=True;
635 pack=IsMonochromeImage(image,&image->exception) ? 8 : 1;
636 /* Padded columns are padded to byte boundary */
637 padded_columns=((image->columns+pack-1)/pack)*pack;
638 *length=padded_columns*image->rows/pack;
639 *pixels=MagickAllocateResourceLimitedMemory(unsigned char *, *length);
640 if (*pixels == (unsigned char *) NULL)
641 ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
642 image);
643
644 q=(*pixels);
645 for (y=0; y < image->rows; y++)
646 {
647 p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
648 if (p == (const PixelPacket *) NULL)
649 break;
650 if (pack == 1)
651 {
652 for (x=0; x < image->columns; x++)
653 {
654 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
655 p++;
656 }
657 }
658 else
659 {
660 code=0;
661 for (x=0; x < padded_columns; x++)
662 {
663 bit=0x00;
664 if (x < image->columns)
665 bit=PixelIntensityToQuantum(p) == TransparentOpacity ? 0x01 : 0x00;
666 code=(code << 1)+bit;
667 if ((x+1) % pack == 0)
668 {
669 *q++=code;
670 code=0;
671 }
672 p++;
673 }
674 }
675 if (image->previous == (Image *) NULL)
676 if (QuantumTick(y,image->rows))
677 {
678 status=MagickMonitorFormatted(y,image->rows,
679 &image->exception,SaveImageText,
680 image->filename,
681 image->columns,image->rows);
682 if (status == False)
683 break;
684 }
685 }
686 if (status == False)
687 MagickFreeResourceLimitedMemory(*pixels);
688 return(status);
689 }
690 /*
691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 % %
693 % %
694 % %
695 % U n r e g i s t e r P S 3 I m a g e %
696 % %
697 % %
698 % %
699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 %
701 % Method UnregisterPS3Image removes format registrations made by the
702 % PS3 module from the list of supported formats.
703 %
704 % The format of the UnregisterPS3Image method is:
705 %
706 % UnregisterPS3Image(void)
707 %
708 */
UnregisterPS3Image(void)709 ModuleExport void UnregisterPS3Image(void)
710 {
711 (void) UnregisterMagickInfo("EPS3");
712 (void) UnregisterMagickInfo("PS3");
713 }
714
715 /*
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 % %
718 % %
719 % %
720 % W r i t e P S 3 M a s k I m a g e %
721 % %
722 % %
723 % %
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725 %
726 % Method WritePS3ImageMask writes the alpha channel of an image as an
727 % Encapsulated Postscript Level III image mask. The mask is written as a
728 % bilevel image, converted from the grayscale alpha channel using dithering
729 % options supplied in image_info.
730 %
731 % The format of the WritePS3MaskImage method is:
732 %
733 % unsigned int WritePS3MaskImage(const ImageInfo *image_info,Image *image)
734 %
735 % A description of each parameter follows:
736 %
737 % o status: Method WritePS3MaskImage return True if the mask is printed.
738 % False is returned on errors like out-of-memory.
739 %
740 % o image_info: Specifies a pointer to a ImageInfo structure.
741 %
742 % o image: The address of a structure of type Image.
743 %
744 %
745 */
746 typedef struct WriteByteHookInfo_
747 {
748 Image
749 *image;
750 } WriteByteHookInfo;
751
MaskWriteByteHook(Image * mask_image,const magick_uint8_t code,void * info)752 static unsigned int MaskWriteByteHook(Image *mask_image,
753 const magick_uint8_t code, void *info)
754 {
755 ARG_NOT_USED(mask_image);
756 Ascii85Encode(((WriteByteHookInfo *)info)->image, (unsigned long)code);
757 return(True);
758 }
759
WritePS3MaskImage(const ImageInfo * image_info,Image * image)760 static MagickPassFail WritePS3MaskImage(const ImageInfo *image_info,Image *image)
761 {
762 char
763 buffer[MaxTextExtent];
764
765 Image
766 *mask_image;
767
768 size_t
769 i,
770 length;
771
772 CompressionType
773 compression;
774
775 unsigned char
776 *pixels;
777
778 MagickPassFail
779 status;
780
781 magick_off_t
782 here,
783 start,
784 stop;
785
786 assert(image_info != (ImageInfo *) NULL);
787 assert(image_info->signature == MagickSignature);
788 assert(image != (Image *) NULL);
789 assert(image->signature == MagickSignature);
790 assert(image->matte);
791 status=MagickPass;
792 compression=image->compression;
793 if (image_info->compression != UndefinedCompression)
794 compression=image_info->compression;
795
796 /* Keep position of BeginData DSC comment for update later */
797 start=TellBlob(image);
798 if (start < 0)
799 return MagickFail;
800 FormatString(buffer,"%%%%BeginData:%13ld ASCII Bytes\n",0L);
801 (void) WriteBlobString(image,buffer);
802 stop=TellBlob(image);
803 if (stop < 0)
804 return MagickFail;
805
806 /* Only lossless compressions for the mask */
807 switch (compression)
808 {
809 case NoCompression:
810 FormatString(buffer,
811 "currentfile %lu %lu "PS3_NoCompression" ByteStreamDecodeFilter\n",
812 image->columns, image->rows);
813 break;
814 case FaxCompression:
815 default:
816 FormatString(buffer,
817 "currentfile %lu %lu "PS3_FaxCompression" ByteStreamDecodeFilter\n",
818 image->columns, image->rows);
819 break;
820 case RLECompression:
821 FormatString(buffer,
822 "currentfile %lu %lu "PS3_RLECompression" ByteStreamDecodeFilter\n",
823 image->columns, image->rows);
824 break;
825 case LZWCompression:
826 FormatString(buffer,
827 "currentfile %lu %lu "PS3_LZWCompression" ByteStreamDecodeFilter\n",
828 image->columns, image->rows);
829 break;
830 case ZipCompression:
831 FormatString(buffer,
832 "currentfile %lu %lu "PS3_ZipCompression" ByteStreamDecodeFilter\n",
833 image->columns, image->rows);
834 break;
835 }
836 (void)WriteBlobString(image, buffer);
837 (void)WriteBlobString(image, "/ReusableStreamDecode filter\n");
838
839 mask_image=CloneImage(image,0,0,True,&image->exception);
840 if (mask_image == (Image *) NULL)
841 return MagickFail;
842 status=ChannelImage(mask_image, OpacityChannel);
843 if (!status)
844 {
845 CopyException(&image->exception,&mask_image->exception);
846 DestroyImage(mask_image);
847 return(MagickFail);
848 }
849 (void) SetImageType(mask_image, BilevelType);
850 mask_image->matte=False;
851
852 /* Only lossless compressions for the mask */
853 switch (compression)
854 {
855 case NoCompression:
856 status=SerializeSingleChannelImage(image_info,mask_image,&pixels,&length);
857 if (status)
858 {
859 Ascii85Initialize(image);
860 for (i=0; i < length; i++)
861 Ascii85Encode(image, (unsigned long)pixels[i]);
862 Ascii85Flush(image);
863 MagickFreeResourceLimitedMemory(pixels);
864 }
865 break;
866 case FaxCompression:
867 default:
868 if (LocaleCompare(CCITTParam,"0") == 0)
869 {
870 WriteByteHookInfo
871 info;
872 info.image=image;
873 /* Read bytes from mask and write them ASCII85 encoded to image */
874 Ascii85Initialize(image);
875 status=HuffmanEncode2Image(image_info,mask_image,MaskWriteByteHook,(void *)&info);
876 Ascii85Flush(image);
877 }
878 else
879 {
880 status=SerializeHuffman2DImage(image_info,mask_image,&pixels,&length);
881 if (status)
882 {
883 Ascii85Initialize(image);
884 for (i=0; i < length; i++)
885 Ascii85Encode(image,(unsigned long) pixels[i]);
886 Ascii85Flush(image);
887 MagickFreeResourceLimitedMemory(pixels);
888 }
889 }
890 break;
891 case RLECompression:
892 status=SerializeSingleChannelImage(image_info,mask_image,&pixels,&length);
893 if (status)
894 {
895 Ascii85Initialize(image);
896 status=PackbitsEncode2Image(image,length,pixels,
897 Ascii85WriteByteHook,(void *)NULL);
898 Ascii85Flush(image);
899 MagickFreeResourceLimitedMemory(pixels);
900 }
901 break;
902 case LZWCompression:
903 status=SerializeSingleChannelImage(image_info,mask_image,&pixels,&length);
904 if (status)
905 {
906 Ascii85Initialize(image);
907 status=LZWEncode2Image(image,length,pixels,Ascii85WriteByteHook,(void*)NULL);
908 Ascii85Flush(image);
909 MagickFreeResourceLimitedMemory(pixels);
910 }
911 break;
912 case ZipCompression:
913 status=SerializeSingleChannelImage(image_info,mask_image,&pixels,&length);
914 if (status)
915 {
916 Ascii85Initialize(image);
917 status=ZLIBEncode2Image(image,length,image_info->quality,pixels,
918 Ascii85WriteByteHook,(void*)NULL);
919 Ascii85Flush(image);
920 MagickFreeResourceLimitedMemory(pixels);
921 }
922 break;
923 }
924 DestroyImage(mask_image);
925 here=TellBlob(image);
926 if (here < 0)
927 return MagickFail;
928 length=here-stop;
929 stop=TellBlob(image);
930 if (stop < 0)
931 return MagickFail;
932 if (SeekBlob(image,start,SEEK_SET) != start)
933 ThrowWriterException(BlobError,UnableToSeekToOffset,image);
934 FormatString(buffer,"%%%%BeginData:%13ld ASCII Bytes\n",(long) length);
935 (void) WriteBlobString(image,buffer);
936 if (SeekBlob(image,stop,SEEK_SET) != stop)
937 ThrowWriterException(BlobError,UnableToSeekToOffset,image);
938 (void) WriteBlobString(image,"%%EndData\n");
939 (void)WriteBlobString(image, "/mask_stream exch def\n");
940 return(status);
941 }
942
943 /*
944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
945 % %
946 % %
947 % %
948 % W r i t e P S 3 I m a g e %
949 % %
950 % %
951 % %
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953 %
954 % Method WritePS3Image translates an image to encapsulated Postscript
955 % Level III for printing. If the supplied geometry is null, the image is
956 % centered on the Postscript page. Otherwise, the image is positioned as
957 % specified by the geometry.
958 %
959 % The format of the WritePS3Image method is:
960 %
961 % MagickPassFail WritePS3Image(const ImageInfo *image_info,Image *image)
962 %
963 % A description of each parameter follows:
964 %
965 % o status: Method WritePS3Image return MagickPass if the image is printed.
966 % MagickFail is returned if the image file cannot be opened for printing.
967 %
968 % o image_info: Specifies a pointer to a ImageInfo structure.
969 %
970 % o image: The address of a structure of type Image; returned from
971 % ReadImage.
972 %
973 %
974 */
WritePS3Image(const ImageInfo * image_info,Image * image)975 static MagickPassFail WritePS3Image(const ImageInfo *image_info,Image *image)
976 {
977 static const char PostscriptProlog[]=
978 "/ByteStreamDecodeFilter\n"
979 "{\n"
980 " /z exch def\n"
981 " /r exch def\n"
982 " /c exch def\n"
983 " /ASCII85Decode filter\n"
984 " z "PS3_FaxCompression" eq\n"
985 " {\n"
986 " <<\n"
987 " /K "CCITTParam"\n"
988 " /Columns c\n"
989 " /Rows r\n"
990 " >>\n"
991 " /CCITTFaxDecode filter\n"
992 " } if\n"
993 " z "PS3_RLECompression" eq {/RunLengthDecode filter} if\n"
994 " z "PS3_LZWCompression" eq {/LZWDecode filter} if\n"
995 " z "PS3_ZipCompression" eq {/FlateDecode filter} if\n"
996 " z "PS3_JPEGCompression" eq {/DCTDecode filter} if\n"
997 "} bind def\n"
998 "\n"
999 "/DirectClassImageDict\n"
1000 "{\n"
1001 " colorspace "PS3_RGBColorspace" eq\n"
1002 " {\n"
1003 " /DeviceRGB setcolorspace\n"
1004 " <<\n"
1005 " /ImageType 1\n"
1006 " /Width columns\n"
1007 " /Height rows\n"
1008 " /BitsPerComponent 8\n"
1009 " /DataSource pixel_stream\n"
1010 " /MultipleDataSources false\n"
1011 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
1012 " /Decode [0 1 0 1 0 1]\n"
1013 " >>\n"
1014 " }\n"
1015 " {\n"
1016 " /DeviceCMYK setcolorspace\n"
1017 " <<\n"
1018 " /ImageType 1\n"
1019 " /Width columns\n"
1020 " /Height rows\n"
1021 " /BitsPerComponent 8\n"
1022 " /DataSource pixel_stream\n"
1023 " /MultipleDataSources false\n"
1024 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
1025 " /Decode\n"
1026 /*
1027 JPEG coder is used for JPEG compression. It compensates
1028 for inverted CMYK, so use an inverted decode matrix for
1029 JPEG compressed CMYK images.
1030 */
1031 " compression "PS3_JPEGCompression" eq\n"
1032 " {[1 0 1 0 1 0 1 0]}\n"
1033 " {[0 1 0 1 0 1 0 1]}\n"
1034 " ifelse\n"
1035 " >>\n"
1036 " }\n"
1037 " ifelse\n"
1038 "} bind def\n"
1039 "\n"
1040 "/PseudoClassImageDict\n"
1041 "{\n"
1042 " % COLORS IN PSEUDO CLASS IMAGE\n"
1043 " currentfile buffer readline pop\n"
1044 " token pop /colors exch def pop\n"
1045 " colors 0 eq\n"
1046 " {\n"
1047 " % DEPTH OF GRAYSCALE\n"
1048 " currentfile buffer readline pop\n"
1049 " token pop /bits exch def pop\n"
1050 " /DeviceGray setcolorspace\n"
1051 " <<\n"
1052 " /ImageType 1\n"
1053 " /Width columns\n"
1054 " /Height rows\n"
1055 " /BitsPerComponent bits\n"
1056 " /Decode [0 1]\n"
1057 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
1058 " /DataSource pixel_stream\n"
1059 " >>\n"
1060 " }\n"
1061 " {\n"
1062 " % RGB COLORMAP\n"
1063 " /colormap colors 3 mul string def\n"
1064 " % INDEXES\n"
1065 " currentfile /ASCII85Decode filter colormap readstring pop pop\n"
1066 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace\n"
1067 " <<\n"
1068 " /ImageType 1\n"
1069 " /Width columns\n"
1070 " /Height rows\n"
1071 " /BitsPerComponent 8\n"
1072 " /Decode [0 255]\n"
1073 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
1074 " /DataSource pixel_stream\n"
1075 " >>\n"
1076 " }\n"
1077 " ifelse\n"
1078 "} bind def\n"
1079 "\n"
1080 "/NonMaskedImageDict\n"
1081 "{\n"
1082 " class "PS3_PseudoClass" eq\n"
1083 " { PseudoClassImageDict }\n"
1084 " { DirectClassImageDict }\n"
1085 " ifelse\n"
1086 "} bind def\n"
1087 "\n"
1088 "/MaskedImageDict\n"
1089 "{\n"
1090 " <<\n"
1091 " /ImageType 3\n"
1092 " /InterleaveType 3\n"
1093 " /DataDict NonMaskedImageDict\n"
1094 " /MaskDict\n"
1095 " <<\n"
1096 " /ImageType 1\n"
1097 " /Width columns\n"
1098 " /Height rows\n"
1099 " /BitsPerComponent 1\n"
1100 " /DataSource mask_stream\n"
1101 " /MultipleDataSources false\n"
1102 " /ImageMatrix [ columns 0 0 rows neg 0 rows]\n"
1103 " /Decode [ 0 1 ]\n"
1104 " >>\n"
1105 " >>\n"
1106 "} bind def\n"
1107 "\n"
1108 /*
1109 Default procedure for image clipping does nothing. Image
1110 will provide overriding ClipPath procdure if relevant.
1111 */
1112 "/ClipImage\n"
1113 "{} def\n"
1114 "\n"
1115 "/DisplayImage\n"
1116 "{\n"
1117 " /buffer 512 string def\n"
1118 "\n"
1119 " % TRANSLATION\n"
1120 " currentfile buffer readline pop\n"
1121 " token pop /x exch def\n"
1122 " token pop /y exch def pop\n"
1123 " x y translate\n"
1124 "\n"
1125 " % IMAGE SIZE AND FONT SIZE\n"
1126 " currentfile buffer readline pop\n"
1127 " token pop /x exch def\n"
1128 " token pop /y exch def pop\n"
1129 " currentfile buffer readline pop\n"
1130 " token pop /pointsize exch def pop\n";
1131
1132 /*
1133 This hole in the PS prolog is for labels.
1134 */
1135 static const char PostscriptEpilog[]=
1136 " x y scale\n"
1137 "\n"
1138 " % CLIPPING PATH\n"
1139 " currentfile buffer readline pop\n"
1140 " token pop /clipped exch def pop\n"
1141 "\n"
1142 " % EPS\n"
1143 " currentfile buffer readline pop\n"
1144 " token pop /sp exch def pop\n"
1145 "\n"
1146 " % IMAGE PIXEL SIZE\n"
1147 " currentfile buffer readline pop\n"
1148 " token pop /columns exch def\n"
1149 " token pop /rows exch def pop\n"
1150 "\n"
1151 " % COLORSPACE (RGB/CMYK)\n"
1152 " currentfile buffer readline pop\n"
1153 " token pop /colorspace exch def pop\n"
1154 "\n"
1155 " % TRANSPARENCY\n"
1156 " currentfile buffer readline pop\n"
1157 " token pop /alpha exch def pop\n"
1158 "\n"
1159 " % STENCIL MASK?\n"
1160 " currentfile buffer readline pop\n"
1161 " token pop /stencil exch def pop\n"
1162 "\n"
1163 " % IMAGE CLASS (DIRECT/PSEUDO)\n"
1164 " currentfile buffer readline pop\n"
1165 " token pop /class exch def pop\n"
1166 "\n"
1167 " % COMPRESSION\n"
1168 " currentfile buffer readline pop\n"
1169 " token pop /compression exch def pop\n"
1170 "\n"
1171 " % CLIP AND RENDER\n"
1172 " /pixel_stream currentfile columns rows compression\n"
1173 " ByteStreamDecodeFilter def\n"
1174 " clipped {ClipImage} if\n"
1175 " alpha stencil not and\n"
1176 " { MaskedImageDict mask_stream resetfile }\n"
1177 " { NonMaskedImageDict }\n"
1178 " ifelse\n"
1179 " stencil {0 setgray imagemask} {image} ifelse\n"
1180 " grestore\n"
1181 " sp {showpage} if\n"
1182 "} bind def\n";
1183
1184 char
1185 buffer[MaxTextExtent],
1186 date[MaxTextExtent],
1187 density[MaxTextExtent],
1188 page_geometry[MaxTextExtent],
1189 **labels;
1190
1191 CompressionType
1192 compression;
1193
1194 const ImageAttribute
1195 *attribute;
1196
1197 double
1198 dx_resolution,
1199 dy_resolution,
1200 x_resolution,
1201 x_scale,
1202 y_resolution,
1203 y_scale;
1204
1205 magick_off_t
1206 current,
1207 start,
1208 stop;
1209
1210 int
1211 count,
1212 status;
1213
1214 RectangleInfo
1215 geometry;
1216
1217 register unsigned int
1218 i,
1219 j;
1220
1221 SegmentInfo
1222 bounds={0.0,0.0,0.0,0.0};
1223
1224 size_t
1225 length;
1226
1227 time_t
1228 timer;
1229
1230 unsigned char
1231 *pixels;
1232
1233 unsigned long
1234 page,
1235 scene,
1236 text_size;
1237
1238 size_t
1239 image_list_length;
1240
1241 Image
1242 *clip_mask;
1243
1244 /*
1245 Open output image file.
1246 */
1247 assert(image_info != (const ImageInfo *) NULL);
1248 assert(image_info->signature == MagickSignature);
1249 assert(image != (Image *) NULL);
1250 assert(image->signature == MagickSignature);
1251 image_list_length=GetImageListLength(image);
1252 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1253 if (status == False)
1254 ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1255 compression=image->compression;
1256 if (image_info->compression != UndefinedCompression)
1257 compression=image_info->compression;
1258 switch (compression)
1259 {
1260 #if !defined(HasJPEG)
1261 case JPEGCompression:
1262 {
1263 compression=RLECompression;
1264 ThrowException(&image->exception,MissingDelegateError,JPEGLibraryIsNotAvailable,image->filename);
1265 break;
1266 }
1267 #endif
1268 #if !defined(HasZLIB)
1269 case ZipCompression:
1270 {
1271 compression=RLECompression;
1272 ThrowException(&image->exception,MissingDelegateError,ZipLibraryIsNotAvailable,image->filename);
1273 break;
1274 }
1275 #endif
1276 default:
1277 break;
1278 }
1279 page=0;
1280 scene=0;
1281 clip_mask = *ImageGetClipMask(image);
1282 do
1283 {
1284 page++;
1285 /*
1286 Scale image to size of Postscript page.
1287 */
1288 text_size=0;
1289 attribute=GetImageAttribute(image,"label");
1290 if (attribute != (const ImageAttribute *) NULL)
1291 text_size=(unsigned int)(MultilineCensus(attribute->value)*
1292 image_info->pointsize+12);
1293 SetGeometry(image,&geometry);
1294 geometry.y=(long) text_size;
1295 FormatString(page_geometry,"%lux%lu",image->columns,image->rows);
1296 if (image_info->page != (char *) NULL)
1297 {
1298 (void) strlcpy(page_geometry,image_info->page,MaxTextExtent);
1299 }
1300 else
1301 {
1302 if ((image->page.width != 0) && (image->page.height != 0))
1303 (void) FormatString(page_geometry,"%lux%lu%+ld%+ld",
1304 image->page.width,image->page.height,image->page.x,
1305 image->page.y);
1306 else
1307 if (LocaleCompare(image_info->magick,"PS3") == 0)
1308 (void) strlcpy(page_geometry,PSPageGeometry,sizeof(page_geometry));
1309 }
1310 (void) GetMagickGeometry(page_geometry,&geometry.x,&geometry.y,
1311 &geometry.width,&geometry.height);
1312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1313 "Image Resolution: %gx%g %s",
1314 image->x_resolution,
1315 image->y_resolution,
1316 ResolutionTypeToString(image->units));
1317 /*
1318 Scale relative to dots-per-inch. First whatever resolution passed
1319 in image_info. Then resolution from the image. Last default PS
1320 resolution.
1321 */
1322 dx_resolution=72.0;
1323 dy_resolution=72.0;
1324 x_resolution=72.0;
1325 (void) strlcpy(density,PSDensityGeometry,sizeof(density));
1326 count=GetMagickDimension(density,&x_resolution,&y_resolution,NULL,NULL);
1327 if (count != 2)
1328 y_resolution=x_resolution;
1329 /*
1330 Use override resolution information if it appears to be valid.
1331 */
1332 if ((image_info->density != (char *) NULL) &&
1333 ((image_info->units == PixelsPerInchResolution) ||
1334 (image_info->units == PixelsPerCentimeterResolution)))
1335 {
1336 count=GetMagickDimension(image_info->density,&x_resolution,
1337 &y_resolution,NULL,NULL);
1338 if (count != 2)
1339 y_resolution=x_resolution;
1340 if (image_info->units == PixelsPerCentimeterResolution)
1341 {
1342 x_resolution *= 2.54;
1343 y_resolution *= 2.54;
1344 }
1345 }
1346 /*
1347 Use image resolution information if it appears to be valid.
1348 */
1349 else if ((image->x_resolution > 0.0) && (image->y_resolution > 0.0) &&
1350 ((image->units == PixelsPerInchResolution) ||
1351 (image->units == PixelsPerCentimeterResolution)))
1352 {
1353 x_resolution = image->x_resolution;
1354 y_resolution = image->y_resolution;
1355 if (image->units == PixelsPerCentimeterResolution)
1356 {
1357 x_resolution *= 2.54;
1358 y_resolution *= 2.54;
1359 }
1360 }
1361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1362 "Postscript Resolution: %gx%g DPI",
1363 x_resolution,y_resolution);
1364 x_scale=(geometry.width*dx_resolution)/x_resolution;
1365 geometry.width=(unsigned long) (x_scale+0.5);
1366 y_scale=(geometry.height*dy_resolution)/y_resolution;
1367 geometry.height=(unsigned long) (y_scale+0.5);
1368
1369 /*
1370 Postscript header on the first page
1371 */
1372 if (page == 1)
1373 {
1374 #if defined(HAVE_CTIME_R)
1375 char time_buf[26];
1376 #endif /* defined(HAVE_CTIME_R) */
1377 /* Postscript magic */
1378 if (LocaleCompare(image_info->magick,"PS3") == 0)
1379 (void) strlcpy(buffer,"%!PS-Adobe-3.0\n", sizeof(buffer));
1380 else
1381 (void) strlcpy(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n", sizeof(buffer));
1382 (void) WriteBlobString(image,buffer);
1383
1384 /* Creator */
1385 FormatString(buffer,"%%%%Creator: GraphicsMagick %s\n",
1386 MagickLibVersionText);
1387 (void) WriteBlobString(image,buffer);
1388
1389 /* Title */
1390 FormatString(buffer,"%%%%Title: %.1024s\n",image->filename);
1391 (void) WriteBlobString(image,buffer);
1392
1393 /* File creation timestamp */
1394 timer=time((time_t *) NULL);
1395 #if defined(HAVE_CTIME_R)
1396 (void) strlcpy(date,ctime_r(&timer,time_buf),MaxTextExtent);
1397 #else
1398 (void) strlcpy(date,ctime(&timer),MaxTextExtent); /* Thread-unsafe version */
1399 #endif /* defined(HAVE_CTIME_R) */
1400 date[strlen(date)-1]='\0';
1401 FormatString(buffer,"%%%%CreationDate: %.1024s\n",date);
1402 (void) WriteBlobString(image,buffer);
1403
1404 /* Bounding box and process colors if not RGB */
1405 bounds.x1=geometry.x;
1406 bounds.y1=geometry.y;
1407 bounds.x2=geometry.x+x_scale;
1408 bounds.y2=geometry.y+y_scale+text_size;
1409 if (image_info->adjoin && (image->next != (Image *) NULL))
1410 {
1411 (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
1412 (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
1413 /* No document process colors if there's more than one page */
1414 }
1415 else
1416 {
1417 FormatString(buffer,"%%%%BoundingBox: %g %g %g %g\n",
1418 floor(bounds.x1+0.5),floor(bounds.y1+0.5),ceil(bounds.x2-0.5),
1419 ceil(bounds.y2-0.5));
1420 (void) WriteBlobString(image,buffer);
1421 FormatString(buffer,"%%%%HiResBoundingBox: %.7g %.7g %.7g %.7g\n",
1422 bounds.x1,bounds.y1,bounds.x2,bounds.y2);
1423 (void) WriteBlobString(image,buffer);
1424
1425 if (image->colorspace == CMYKColorspace)
1426 (void) WriteBlobString(image,
1427 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1428 else
1429 if (IsGrayImage(image,&image->exception))
1430 (void) WriteBlobString(image,
1431 "%%DocumentProcessColors: Black\n");
1432 }
1433
1434 /* Font resources */
1435 attribute=GetImageAttribute(image,"label");
1436 if (attribute != (const ImageAttribute *) NULL)
1437 (void) WriteBlobString(image,
1438 "%%DocumentNeededResources: font Helvetica\n");
1439
1440 /* Language level */
1441 (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
1442
1443 /* Pages, orientation, and page order */
1444 if (LocaleCompare(image_info->magick,"PS3") != 0)
1445 {
1446 (void) WriteBlobString(image,"%%Pages: 1\n");
1447 }
1448 else
1449 {
1450 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1451 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1452 if (!image_info->adjoin)
1453 (void) strlcpy(buffer,"%%Pages: 1\n",sizeof(buffer));
1454 else
1455 FormatString(buffer,"%%%%Pages: %lu\n",(unsigned long)
1456 image_list_length);
1457 (void) WriteBlobString(image,buffer);
1458 }
1459 (void) WriteBlobString(image,"%%EndComments\n");
1460
1461 /* The static postscript procedures prolog. */
1462 (void)WriteBlobString(image,"%%BeginProlog\n");
1463 (void) WriteBlob(image,sizeof(PostscriptProlog)-1,PostscriptProlog);
1464
1465 /* One label line for each line in label string */
1466 attribute=GetImageAttribute(image,"label");
1467 if (attribute != (const ImageAttribute *) NULL)
1468 {
1469 long
1470 si;
1471
1472 (void) WriteBlobString(image,"\n % LABELS\n /Helvetica "
1473 "findfont pointsize scalefont setfont\n");
1474 for (si=(long) MultilineCensus(attribute->value)-1; si >= 0; si--)
1475 {
1476 (void) WriteBlobString(image,
1477 " currentfile buffer readline pop token pop\n");
1478 FormatString(buffer," 0 y %g add moveto show pop\n",
1479 si*image_info->pointsize+12);
1480 (void) WriteBlobString(image,buffer);
1481 }
1482 }
1483
1484 /* The static postscript procedures epilog. */
1485 (void) WriteBlob(image,sizeof(PostscriptEpilog)-1,PostscriptEpilog);
1486 (void)WriteBlobString(image,"%%EndProlog\n");
1487 }
1488
1489 /* Page number */
1490 FormatString(buffer,"%%%%Page: 1 %lu\n",page);
1491 (void) WriteBlobString(image,buffer);
1492
1493 /* Page bounding box */
1494 FormatString(buffer,"%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x,
1495 geometry.y,geometry.x+(long) geometry.width,geometry.y+(long)
1496 (geometry.height+text_size));
1497 (void) WriteBlobString(image,buffer);
1498
1499 /* Page process colors if not RGB */
1500 if (image->colorspace == CMYKColorspace)
1501 (void) WriteBlobString(image,
1502 "%%PageProcessColors: Cyan Magenta Yellow Black\n");
1503 else
1504 if (IsGrayImage(image,&image->exception))
1505 (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
1506
1507 /*
1508 Adjust document bounding box to bound page bounding
1509 box if page bounding box is the larger
1510 */
1511 if (geometry.x < bounds.x1)
1512 bounds.x1=geometry.x;
1513 if (geometry.y < bounds.y1)
1514 bounds.y1=geometry.y;
1515 if ((geometry.x+x_scale) > bounds.x2)
1516 bounds.x2=geometry.x+x_scale;
1517 if ((geometry.y+y_scale+text_size) > bounds.y2)
1518 bounds.y2=geometry.y+y_scale+text_size;
1519
1520 /* Page font resource if there's a label */
1521 attribute=GetImageAttribute(image,"label");
1522 if (attribute != (const ImageAttribute *) NULL)
1523 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
1524
1525 /* PS clipping path from Photoshop clipping path */
1526 if ((clip_mask != (Image *) NULL) &&
1527 (LocaleNCompare("8BIM:",clip_mask->magick_filename,5) == 0))
1528 {
1529 const ImageAttribute
1530 *attribute;
1531
1532 attribute=GetImageAttribute(image,clip_mask->magick_filename);
1533 if (attribute == (const ImageAttribute *) NULL)
1534 return(False);
1535 (void) WriteBlobString(image,attribute->value);
1536 (void) WriteBlobByte(image,'\n');
1537 }
1538 else
1539 {
1540 /* Reset definition in case previous image had a clipping path.*/
1541 (void)WriteBlobString(image,"/ClipImage {} def\n");
1542 }
1543
1544 /* Push a dictionary for our own def's if this is an EPS */
1545 if (LocaleCompare(image_info->magick,"PS3") != 0)
1546 (void) WriteBlobString(image,"userdict begin\n");
1547
1548 /* Image mask */
1549 if (image->matte)
1550 if (!WritePS3MaskImage(image_info, image))
1551 {
1552 CloseBlob(image);
1553 return(False);
1554 }
1555
1556 /*
1557 Remember position of BeginData comment so we can update
1558 it when we know how many ascii85 encoded bytes we have
1559 in the blob.
1560 */
1561 start=TellBlob(image);
1562 if (start < 0)
1563 ThrowWriterException(BlobError,UnableToObtainOffset,image);
1564 FormatString(buffer,"%%%%BeginData:%13ld ASCII Bytes\n",0L);
1565 (void) WriteBlobString(image,buffer);
1566 stop=TellBlob(image);
1567 if (stop < 0)
1568 ThrowWriterException(BlobError,UnableToObtainOffset,image);
1569
1570 /* Call to image display procedure */
1571 (void) WriteBlobString(image,"DisplayImage\n");
1572
1573 /* Translate, scale, and font point size */
1574 FormatString(buffer,"%ld %ld\n%.7g %.7g\n%f\n",geometry.x,geometry.y,
1575 x_scale,y_scale,image_info->pointsize);
1576 (void) WriteBlobString(image,buffer);
1577
1578 /* Output labels */
1579 labels=(char **) NULL;
1580 attribute=GetImageAttribute(image,"label");
1581 if (attribute != (const ImageAttribute *) NULL)
1582 labels=StringToList(attribute->value);
1583 if (labels != (char **) NULL)
1584 {
1585 for (i=0; labels[i] != (char *) NULL; i++)
1586 {
1587 Ascii85Initialize(image);
1588 (void) WriteBlobString(image,"<~");
1589 for (j=0; labels[i][j] != '\0'; j++)
1590 Ascii85Encode(image, (unsigned long)labels[i][j]);
1591 Ascii85Flush(image);
1592 MagickFreeMemory(labels[i]);
1593 }
1594 MagickFreeMemory(labels);
1595 }
1596
1597 /* Photoshop clipping path active? */
1598 if ((clip_mask != (Image *) NULL) &&
1599 (LocaleNCompare("8BIM:",clip_mask->magick_filename,5) == 0))
1600 (void) WriteBlobString(image,"true\n");
1601 else
1602 (void) WriteBlobString(image,"false\n");
1603
1604 /* Compression seems to take precedence over anyting */
1605 if (compression == FaxCompression)
1606 (void) SetImageType(image, BilevelType);
1607
1608 /* Showpage for non-EPS. */
1609 (void) WriteBlobString(image,
1610 LocaleCompare(image_info->magick,"PS3") == 0 ? "true\n" : "false\n");
1611
1612 /* Image columns and rows; color space */
1613 FormatString(buffer,"%lu %lu\n%.1024s\n",
1614 image->columns,image->rows,image->colorspace == CMYKColorspace ?
1615 PS3_CMYKColorspace : PS3_RGBColorspace);
1616 (void) WriteBlobString(image,buffer);
1617
1618 /* Masked image? */
1619 (void) WriteBlobString(image,image->matte ? "true\n" : "false\n");
1620
1621 /* Render with imagemask operator? */
1622 if (((AccessDefinition(image_info,"ps","imagemask")) != 0) &&
1623 IsMonochromeImage(image,&image->exception))
1624 (void) WriteBlobString(image,"true\n");
1625 else
1626 (void) WriteBlobString(image,"false\n");
1627
1628 /*
1629 Output data in one of three ways:
1630 1) 1 bit and 8 bit single channel direct color image data.
1631 2) 3 and 4 channel direct color image data
1632 3) 8 bit color mapped image data
1633 */
1634
1635 /*
1636 Output 1 bit and 8 bit single channel image data. IsGray and IsMono
1637 may return true for both direct class RGB and CMYK colors, so we need
1638 to test that these were not requested explicitly.
1639 */
1640 if ((image_info->type != TrueColorType) &&
1641 (image_info->type != TrueColorMatteType) &&
1642 (image_info->type != ColorSeparationType) &&
1643 (image_info->type != ColorSeparationMatteType) &&
1644 (image->colorspace != CMYKColorspace) &&
1645 (IsGrayImage(image,&image->exception) ||
1646 IsMonochromeImage(image,&image->exception)))
1647 {
1648 /* Image class */
1649 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1650
1651 /* Compression scheme - any */
1652 switch (compression)
1653 {
1654 case NoCompression:
1655 default:
1656 (void) WriteBlobString(image,PS3_NoCompression"\n");
1657 break;
1658 case FaxCompression:
1659 (void) WriteBlobString(image,PS3_FaxCompression"\n");
1660 break;
1661 case RLECompression:
1662 (void) WriteBlobString(image,PS3_RLECompression"\n");
1663 break;
1664 case LZWCompression:
1665 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1666 break;
1667 case ZipCompression:
1668 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1669 break;
1670 case JPEGCompression:
1671 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1672 break;
1673 }
1674
1675 /* Number of colors -- 0 for single component non-color mapped data */
1676 (void) WriteBlobString(image,"0\n");
1677
1678 /* 1 bit or 8 bit components? */
1679 FormatString(buffer,"%d\n",
1680 IsMonochromeImage(image,&image->exception) ? 1 : 8);
1681 (void) WriteBlobString(image,buffer);
1682
1683 /* Image data. Always ASCII85 encoded. */
1684 if (compression == JPEGCompression)
1685 {
1686 status=JPEGEncodeImage(image_info,image);
1687 }
1688 else
1689 if (compression == FaxCompression)
1690 {
1691 if (LocaleCompare(CCITTParam,"0") == 0)
1692 status=HuffmanEncodeImage(image_info,image);
1693 else
1694 status=Huffman2DEncodeImage(image_info,image);
1695 }
1696 else
1697 {
1698 status=SerializeSingleChannelImage(image_info,image,&pixels,
1699 &length);
1700 if (!status)
1701 {
1702 CloseBlob(image);
1703 return(False);
1704 }
1705 Ascii85Initialize(image);
1706 switch (compression)
1707 {
1708 case NoCompression:
1709 default:
1710 for (i=0; i < length; i++)
1711 Ascii85Encode(image, (unsigned long)pixels[i]);
1712 break;
1713 case RLECompression:
1714 status=PackbitsEncode2Image(image,length,pixels,
1715 Ascii85WriteByteHook,(void*)NULL);
1716 break;
1717 case LZWCompression:
1718 status=LZWEncode2Image(image,length,pixels,
1719 Ascii85WriteByteHook,(void*)NULL);
1720 break;
1721 case ZipCompression:
1722 status=ZLIBEncode2Image(image,length,image_info->quality,
1723 pixels,Ascii85WriteByteHook,(void*)NULL);
1724 break;
1725 }
1726 Ascii85Flush(image);
1727 MagickFreeResourceLimitedMemory(pixels);
1728 }
1729 }
1730 else
1731 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1732 (compression == JPEGCompression))
1733 {
1734 /* Image class */
1735 (void) WriteBlobString(image,PS3_DirectClass"\n");
1736
1737 /* Compression scheme - fax is only for bilevel images */
1738 switch (compression)
1739 {
1740 case NoCompression:
1741 default:
1742 (void) WriteBlobString(image,PS3_NoCompression"\n");
1743 break;
1744 case RLECompression:
1745 (void) WriteBlobString(image,PS3_RLECompression"\n");
1746 break;
1747 case LZWCompression:
1748 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1749 break;
1750 case ZipCompression:
1751 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1752 break;
1753 case JPEGCompression:
1754 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1755 break;
1756 }
1757
1758 /* Image data. Always ASCII85 encoded. */
1759 if (compression == JPEGCompression)
1760 {
1761 status=JPEGEncodeImage(image_info,image);
1762 }
1763 else
1764 {
1765 /* Stream based compressions */
1766 status=SerializeMultiChannelImage(image_info,image,&pixels,
1767 &length);
1768 if (!status)
1769 {
1770 CloseBlob(image);
1771 return(False);
1772 }
1773 Ascii85Initialize(image);
1774 switch (compression)
1775 {
1776 case NoCompression:
1777 default:
1778 for (i=0; i < length; i++)
1779 Ascii85Encode(image, (unsigned long)pixels[i]);
1780 status=True;
1781 break;
1782 case RLECompression:
1783 status=PackbitsEncode2Image(image,length,pixels,
1784 Ascii85WriteByteHook,(void*)NULL);
1785 break;
1786 case LZWCompression:
1787 status=LZWEncode2Image(image,length,pixels,
1788 Ascii85WriteByteHook,(void*)NULL);
1789 break;
1790 case ZipCompression:
1791 status=ZLIBEncode2Image(image,length,image_info->quality,
1792 pixels,Ascii85WriteByteHook,(void*)NULL);
1793 break;
1794 }
1795 Ascii85Flush(image);
1796 MagickFreeResourceLimitedMemory(pixels);
1797 }
1798 }
1799 else
1800 {
1801 /*
1802 Color mapped images.
1803
1804 Image class.
1805 */
1806 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1807
1808 /*
1809 Compression scheme - fax is only for bilevel images,
1810 JPEG for true color (single channel) images.
1811 */
1812 switch (compression)
1813 {
1814 case NoCompression:
1815 default:
1816 (void) WriteBlobString(image,PS3_NoCompression"\n");
1817 break;
1818 case RLECompression:
1819 (void) WriteBlobString(image,PS3_RLECompression"\n");
1820 break;
1821 case LZWCompression:
1822 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1823 break;
1824 case ZipCompression:
1825 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1826 break;
1827 }
1828
1829 /* Number of colors in color map */
1830 FormatString(buffer,"%u\n",image->colors);
1831 (void) WriteBlobString(image,buffer);
1832
1833 /* Color map - uncompressed, ascii85 encoded */
1834 Ascii85Initialize(image);
1835 for (i=0; i < image->colors; i++)
1836 {
1837 Ascii85Encode(image, (unsigned long)image->colormap[i].red);
1838 Ascii85Encode(image, (unsigned long)image->colormap[i].green);
1839 Ascii85Encode(image, (unsigned long)image->colormap[i].blue);
1840 }
1841 Ascii85Flush(image);
1842
1843 status=SerializePseudoClassImage(image_info,image,&pixels,&length);
1844 if (!status)
1845 {
1846 CloseBlob(image);
1847 return(False);
1848 }
1849 Ascii85Initialize(image);
1850 switch (compression)
1851 {
1852 case NoCompression:
1853 default:
1854 for (i=0; i < length; i++)
1855 Ascii85Encode(image, (unsigned long)pixels[i]);
1856 status=True;
1857 break;
1858 case RLECompression:
1859 status=PackbitsEncode2Image(image,length,pixels,
1860 Ascii85WriteByteHook,(void *)NULL);
1861 break;
1862 case LZWCompression:
1863 status=LZWEncode2Image(image,length,pixels,Ascii85WriteByteHook,
1864 (void *)NULL);
1865 break;
1866 case ZipCompression:
1867 status=ZLIBEncode2Image(image,length,image_info->quality,pixels,
1868 Ascii85WriteByteHook,(void *)NULL);
1869 break;
1870 }
1871 Ascii85Flush(image);
1872 MagickFreeResourceLimitedMemory(pixels);
1873 }
1874
1875 if (!status)
1876 {
1877 CloseBlob(image);
1878 return(False);
1879 }
1880
1881 /* Update BeginData now that we know the data size */
1882 current=TellBlob(image);
1883 if (current < 0)
1884 ThrowWriterException(BlobError,UnableToObtainOffset,image);
1885 length=current-stop;
1886 stop=TellBlob(image);
1887 if (stop < 0)
1888 ThrowWriterException(BlobError,UnableToObtainOffset,image);
1889 if (SeekBlob(image,start,SEEK_SET) != start)
1890 ThrowWriterException(BlobError,UnableToSeekToOffset,image);
1891 FormatString(buffer,"%%%%BeginData:%13ld ASCII Bytes\n",(long) length);
1892 (void) WriteBlobString(image,buffer);
1893 if (SeekBlob(image,stop,SEEK_SET) != stop)
1894 ThrowWriterException(BlobError,UnableToSeekToOffset,image);
1895 (void) WriteBlobString(image,"%%EndData\n");
1896
1897 /* End private dictionary if this is an EPS */
1898 if (LocaleCompare(image_info->magick,"PS3") != 0)
1899 (void) WriteBlobString(image,"end\n");
1900
1901 (void) WriteBlobString(image,"%%PageTrailer\n");
1902 if (image->next == (Image *) NULL)
1903 break;
1904 image=SyncNextImageInList(image);
1905 status=MagickMonitorFormatted(scene,image_list_length,
1906 &image->exception,SaveImagesText,
1907 image->filename);
1908 if (status == False)
1909 break;
1910 scene++;
1911 } while (image_info->adjoin);
1912 if (image_info->adjoin)
1913 while (image->previous != (Image *) NULL)
1914 image=image->previous;
1915 (void) WriteBlobString(image,"%%Trailer\n");
1916 if (page > 1)
1917 {
1918 FormatString(buffer,"%%%%BoundingBox: %g %g %g %g\n",
1919 floor(bounds.x1+0.5),floor(bounds.y1+0.5),ceil(bounds.x2-0.5),
1920 ceil(bounds.y2-0.5));
1921 (void) WriteBlobString(image,buffer);
1922 FormatString(buffer,"%%%%HiResBoundingBox: %.7g %.7g %.7g %.7g\n",
1923 bounds.x1,bounds.y1,bounds.x2,bounds.y2);
1924 (void) WriteBlobString(image,buffer);
1925 }
1926 (void) WriteBlobString(image,"%%EOF\n");
1927 CloseBlob(image);
1928 return(True);
1929 }
1930
1931 #if defined(HasZLIB)
1932 #include "zlib.h"
1933 /*
1934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935 % %
1936 % %
1937 % %
1938 % Z L I B E n c o d e 2 I m a g e %
1939 % %
1940 % %
1941 % %
1942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943 %
1944 % Method ZLIBEncode2Image compresses an image via ZLIB-coding specific to
1945 % Postscript Level II or Portable Document Format. To ensure portability, the
1946 % binary ZLIB bytes are encoded as ASCII base-85.
1947 %
1948 % The format of the ZLIBEncode2Image method is:
1949 %
1950 % unsigned int ZLIBEncode2Image(Image *image,const size_t length,
1951 % const unsigned long quality,unsigned char *pixels,
1952 % WriteByteHook write_byte,void *info)
1953 %
1954 % A description of each parameter follows:
1955 %
1956 % o image: The address of a structure of type Image; returned from
1957 % ReadImage.
1958 %
1959 % o length: A value that specifies the number of pixels to compress.
1960 %
1961 % o quality: the compression level (0-100).
1962 %
1963 % o pixels: The address of an unsigned array of characters containing the
1964 % pixels to compress.
1965 %
1966 % o write_byte: function (hook) to call for writing each byte of compressed
1967 % data.
1968 %
1969 % o info: information block to pass along when calling write_byte
1970 % function.
1971 %
1972 %
1973 */
1974
1975 static voidpf ZLIBAllocFunc(voidpf opaque, uInt items, uInt size) MAGICK_FUNC_MALLOC;
ZLIBAllocFunc(voidpf opaque,uInt items,uInt size)1976 static voidpf ZLIBAllocFunc(voidpf opaque, uInt items, uInt size)
1977 {
1978 ARG_NOT_USED(opaque);
1979 return MagickMallocCleared(MagickArraySize(items,size));
1980 }
ZLIBFreeFunc(voidpf opaque,voidpf address)1981 static void ZLIBFreeFunc(voidpf opaque, voidpf address)
1982 {
1983 ARG_NOT_USED(opaque);
1984 MagickFree(address);
1985 }
1986
ZLIBEncode2Image(Image * image,const size_t length,const unsigned long quality,unsigned char * pixels,WriteByteHook write_byte,void * info)1987 static unsigned int ZLIBEncode2Image(Image *image,const size_t length,
1988 const unsigned long quality,unsigned char *pixels,WriteByteHook write_byte,
1989 void *info)
1990 {
1991 int
1992 status;
1993
1994 register long
1995 i;
1996
1997 unsigned char
1998 *compressed_pixels;
1999
2000 unsigned long
2001 compressed_packets;
2002
2003 z_stream
2004 stream;
2005
2006 assert(image != (Image *) NULL);
2007 assert(image->signature == MagickSignature);
2008 compressed_packets=(unsigned long) (1.001*length+12);
2009 compressed_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,compressed_packets);
2010 if (compressed_pixels == (unsigned char *) NULL)
2011 ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
2012 (char *) NULL);
2013 stream.next_in=pixels;
2014 stream.avail_in=(unsigned int) length;
2015 stream.next_out=compressed_pixels;
2016 stream.avail_out=(unsigned int) compressed_packets;
2017 stream.zalloc=ZLIBAllocFunc;
2018 stream.zfree=ZLIBFreeFunc;
2019 stream.opaque=(voidpf) NULL;
2020 status=deflateInit(&stream,(int) Min(quality/10,9));
2021 if (status == Z_OK)
2022 {
2023 status=deflate(&stream,Z_FINISH);
2024 if (status == Z_STREAM_END)
2025 status=deflateEnd(&stream);
2026 else
2027 (void) deflateEnd(&stream);
2028 compressed_packets=stream.total_out;
2029 }
2030 if (status)
2031 ThrowBinaryException(CoderError,UnableToZipCompressImage,(char *) NULL)
2032 else
2033 for (i=0; i < (long) compressed_packets; i++)
2034 (void) (*write_byte)(image,(magick_uint8_t)compressed_pixels[i],info);
2035 MagickFreeResourceLimitedMemory(compressed_pixels);
2036 return(!status);
2037 }
2038 #else
ZLIBEncode2Image(Image * image,const size_t length,const unsigned long quality,unsigned char * pixels,WriteByteHook write_byte,void * info)2039 static unsigned int ZLIBEncode2Image(Image *image,const size_t length,
2040 const unsigned long quality,unsigned char *pixels,WriteByteHook write_byte,
2041 void *info)
2042 {
2043 ARG_NOT_USED(length);
2044 ARG_NOT_USED(quality);
2045 ARG_NOT_USED(pixels);
2046 ARG_NOT_USED(write_byte);
2047 ARG_NOT_USED(info);
2048
2049 assert(image != (Image *) NULL);
2050 assert(image->signature == MagickSignature);
2051 ThrowBinaryException(MissingDelegateError,ZipLibraryIsNotAvailable,image->filename);
2052 return(False);
2053 }
2054 #endif
2055