1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % PPPP SSSSS 22222 %
7 % P P SS 22 %
8 % PPPP SSS 222 %
9 % P SS 22 %
10 % P SSSSS 22222 %
11 % %
12 % %
13 % Write Postscript Level II Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2020 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/compress.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/module.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/monitor-private.h"
64 #include "MagickCore/option.h"
65 #include "MagickCore/pixel-accessor.h"
66 #include "MagickCore/property.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/string_.h"
71 #include "MagickCore/timer-private.h"
72 #include "MagickCore/utility.h"
73
74 /*
75 Define declarations.
76 */
77 #if defined(MAGICKCORE_TIFF_DELEGATE)
78 #define CCITTParam "-1"
79 #else
80 #define CCITTParam "0"
81 #endif
82
83 /*
84 Forward declarations.
85 */
86 static MagickBooleanType
87 WritePS2Image(const ImageInfo *,Image *,ExceptionInfo *);
88
89 /*
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 % %
92 % %
93 % %
94 % R e g i s t e r P S 2 I m a g e %
95 % %
96 % %
97 % %
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 %
100 % RegisterPS2Image() adds properties for the PS2 image format to
101 % the list of supported formats. The properties include the image format
102 % tag, a method to read and/or write the format, whether the format
103 % supports the saving of more than one frame to the same file or blob,
104 % whether the format supports native in-memory I/O, and a brief
105 % description of the format.
106 %
107 % The format of the RegisterPS2Image method is:
108 %
109 % size_t RegisterPS2Image(void)
110 %
111 */
RegisterPS2Image(void)112 ModuleExport size_t RegisterPS2Image(void)
113 {
114 MagickInfo
115 *entry;
116
117 entry=AcquireMagickInfo("PS2","EPS2","Level II Encapsulated PostScript");
118 entry->encoder=(EncodeImageHandler *) WritePS2Image;
119 entry->flags^=CoderAdjoinFlag;
120 entry->flags|=CoderEncoderSeekableStreamFlag;
121 entry->flags^=CoderBlobSupportFlag;
122 entry->mime_type=ConstantString("application/postscript");
123 (void) RegisterMagickInfo(entry);
124 entry=AcquireMagickInfo("PS2","PS2","Level II PostScript");
125 entry->encoder=(EncodeImageHandler *) WritePS2Image;
126 entry->flags|=CoderEncoderSeekableStreamFlag;
127 entry->flags^=CoderBlobSupportFlag;
128 entry->mime_type=ConstantString("application/postscript");
129 (void) RegisterMagickInfo(entry);
130 return(MagickImageCoderSignature);
131 }
132
133 /*
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 % %
136 % %
137 % %
138 % U n r e g i s t e r P S 2 I m a g e %
139 % %
140 % %
141 % %
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 %
144 % UnregisterPS2Image() removes format registrations made by the
145 % PS2 module from the list of supported formats.
146 %
147 % The format of the UnregisterPS2Image method is:
148 %
149 % UnregisterPS2Image(void)
150 %
151 */
UnregisterPS2Image(void)152 ModuleExport void UnregisterPS2Image(void)
153 {
154 (void) UnregisterMagickInfo("EPS2");
155 (void) UnregisterMagickInfo("PS2");
156 }
157
158 /*
159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % %
161 % %
162 % %
163 % W r i t e P S 2 I m a g e %
164 % %
165 % %
166 % %
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168 %
169 % WritePS2Image translates an image to encapsulated Postscript
170 % Level II for printing. If the supplied geometry is null, the image is
171 % centered on the Postscript page. Otherwise, the image is positioned as
172 % specified by the geometry.
173 %
174 % The format of the WritePS2Image method is:
175 %
176 % MagickBooleanType WritePS2Image(const ImageInfo *image_info,
177 % Image *image,ExceptionInfo *exception)
178 %
179 % A description of each parameter follows:
180 %
181 % o image_info: the image info.
182 %
183 % o image: the image.
184 %
185 % o exception: return any errors or warnings in this structure.
186 %
187 */
188
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image,Image * inject_image,ExceptionInfo * exception)189 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
190 Image *image,Image *inject_image,ExceptionInfo *exception)
191 {
192 Image
193 *group4_image;
194
195 ImageInfo
196 *write_info;
197
198 MagickBooleanType
199 status;
200
201 size_t
202 length;
203
204 unsigned char
205 *group4;
206
207 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
208 if (group4_image == (Image *) NULL)
209 return(MagickFalse);
210 write_info=CloneImageInfo(image_info);
211 (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
212 (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
213 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
214 exception);
215 write_info=DestroyImageInfo(write_info);
216 group4_image=DestroyImage(group4_image);
217 if (group4 == (unsigned char *) NULL)
218 return(MagickFalse);
219 status=MagickTrue;
220 if (WriteBlob(image,length,group4) != (ssize_t) length)
221 status=MagickFalse;
222 group4=(unsigned char *) RelinquishMagickMemory(group4);
223 return(status);
224 }
225
WritePS2Image(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)226 static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image,
227 ExceptionInfo *exception)
228 {
229 static const char
230 PostscriptProlog[] =
231 "%%%%BeginProlog\n"
232 "%%\n"
233 "%% Display a color image. The image is displayed in color on\n"
234 "%% Postscript viewers or printers that support color, otherwise\n"
235 "%% it is displayed as grayscale.\n"
236 "%%\n"
237 "/DirectClassImage\n"
238 "{\n"
239 " %%\n"
240 " %% Display a DirectClass image.\n"
241 " %%\n"
242 " colorspace 0 eq\n"
243 " {\n"
244 " /DeviceRGB setcolorspace\n"
245 " <<\n"
246 " /ImageType 1\n"
247 " /Width columns\n"
248 " /Height rows\n"
249 " /BitsPerComponent 8\n"
250 " /Decode [0 1 0 1 0 1]\n"
251 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
252 " compression 0 gt\n"
253 " { /DataSource pixel_stream %s }\n"
254 " { /DataSource pixel_stream %s } ifelse\n"
255 " >> image\n"
256 " }\n"
257 " {\n"
258 " /DeviceCMYK setcolorspace\n"
259 " <<\n"
260 " /ImageType 1\n"
261 " /Width columns\n"
262 " /Height rows\n"
263 " /BitsPerComponent 8\n"
264 " /Decode [1 0 1 0 1 0 1 0]\n"
265 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
266 " compression 0 gt\n"
267 " { /DataSource pixel_stream %s }\n"
268 " { /DataSource pixel_stream %s } ifelse\n"
269 " >> image\n"
270 " } ifelse\n"
271 "} bind def\n"
272 "\n"
273 "/PseudoClassImage\n"
274 "{\n"
275 " %%\n"
276 " %% Display a PseudoClass image.\n"
277 " %%\n"
278 " %% Parameters:\n"
279 " %% colors: number of colors in the colormap.\n"
280 " %%\n"
281 " currentfile buffer readline pop\n"
282 " token pop /colors exch def pop\n"
283 " colors 0 eq\n"
284 " {\n"
285 " %%\n"
286 " %% Image is grayscale.\n"
287 " %%\n"
288 " currentfile buffer readline pop\n"
289 " token pop /bits exch def pop\n"
290 " /DeviceGray setcolorspace\n"
291 " <<\n"
292 " /ImageType 1\n"
293 " /Width columns\n"
294 " /Height rows\n"
295 " /BitsPerComponent bits\n"
296 " /Decode [0 1]\n"
297 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
298 " compression 0 gt\n"
299 " { /DataSource pixel_stream %s }\n"
300 " {\n"
301 " /DataSource pixel_stream %s\n"
302 " <<\n"
303 " /K " CCITTParam "\n"
304 " /Columns columns\n"
305 " /Rows rows\n"
306 " >> /CCITTFaxDecode filter\n"
307 " } ifelse\n"
308 " >> image\n"
309 " }\n"
310 " {\n"
311 " %%\n"
312 " %% Parameters:\n"
313 " %% colormap: red, green, blue color packets.\n"
314 " %%\n"
315 " /colormap colors 3 mul string def\n"
316 " currentfile colormap readhexstring pop pop\n"
317 " currentfile buffer readline pop\n"
318 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace\n"
319 " <<\n"
320 " /ImageType 1\n"
321 " /Width columns\n"
322 " /Height rows\n"
323 " /BitsPerComponent 8\n"
324 " /Decode [0 255]\n"
325 " /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
326 " compression 0 gt\n"
327 " { /DataSource pixel_stream %s }\n"
328 " { /DataSource pixel_stream %s } ifelse\n"
329 " >> image\n"
330 " } ifelse\n"
331 "} bind def\n"
332 "\n"
333 "/DisplayImage\n"
334 "{\n"
335 " %%\n"
336 " %% Display a DirectClass or PseudoClass image.\n"
337 " %%\n"
338 " %% Parameters:\n"
339 " %% x & y translation.\n"
340 " %% x & y scale.\n"
341 " %% label pointsize.\n"
342 " %% image label.\n"
343 " %% image columns & rows.\n"
344 " %% class: 0-DirectClass or 1-PseudoClass.\n"
345 " %% colorspace: 0-RGB or 1-CMYK.\n"
346 " %% compression: 0-RLECompression or 1-NoCompression.\n"
347 " %% hex color packets.\n"
348 " %%\n"
349 " gsave\n"
350 " /buffer 512 string def\n"
351 " /pixel_stream currentfile def\n"
352 "\n"
353 " currentfile buffer readline pop\n"
354 " token pop /x exch def\n"
355 " token pop /y exch def pop\n"
356 " x y translate\n"
357 " currentfile buffer readline pop\n"
358 " token pop /x exch def\n"
359 " token pop /y exch def pop\n"
360 " currentfile buffer readline pop\n"
361 " token pop /pointsize exch def pop\n",
362 PostscriptEpilog[] =
363 " x y scale\n"
364 " currentfile buffer readline pop\n"
365 " token pop /columns exch def\n"
366 " token pop /rows exch def pop\n"
367 " currentfile buffer readline pop\n"
368 " token pop /class exch def pop\n"
369 " currentfile buffer readline pop\n"
370 " token pop /colorspace exch def pop\n"
371 " currentfile buffer readline pop\n"
372 " token pop /compression exch def pop\n"
373 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse\n"
374 " grestore\n";
375
376 char
377 buffer[MagickPathExtent],
378 date[MagickPathExtent],
379 page_geometry[MagickPathExtent],
380 **labels;
381
382 CompressionType
383 compression;
384
385 const char
386 *filter,
387 *value;
388
389 double
390 pointsize;
391
392 GeometryInfo
393 geometry_info;
394
395 MagickOffsetType
396 scene,
397 start,
398 stop;
399
400 MagickBooleanType
401 progress,
402 status;
403
404 MagickOffsetType
405 offset;
406
407 MagickSizeType
408 number_pixels;
409
410 MagickStatusType
411 flags;
412
413 PointInfo
414 delta,
415 resolution,
416 scale;
417
418 RectangleInfo
419 geometry,
420 media_info,
421 page_info;
422
423 register const Quantum
424 *p;
425
426 register ssize_t
427 x;
428
429 register ssize_t
430 i;
431
432 SegmentInfo
433 bounds;
434
435 size_t
436 imageListLength,
437 length,
438 page,
439 text_size;
440
441 ssize_t
442 j,
443 y;
444
445 time_t
446 timer;
447
448 unsigned char
449 *pixels;
450
451 /*
452 Open output image file.
453 */
454 assert(image_info != (const ImageInfo *) NULL);
455 assert(image_info->signature == MagickCoreSignature);
456 assert(image != (Image *) NULL);
457 assert(image->signature == MagickCoreSignature);
458 if (image->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
460 assert(exception != (ExceptionInfo *) NULL);
461 assert(exception->signature == MagickCoreSignature);
462 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
463 if (status == MagickFalse)
464 return(status);
465 compression=image->compression;
466 if (image_info->compression != UndefinedCompression)
467 compression=image_info->compression;
468 switch (compression)
469 {
470 #if !defined(MAGICKCORE_JPEG_DELEGATE)
471 case JPEGCompression:
472 {
473 compression=RLECompression;
474 (void) ThrowMagickException(exception,GetMagickModule(),
475 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
476 image->filename);
477 break;
478 }
479 #endif
480 default:
481 break;
482 }
483 (void) memset(&bounds,0,sizeof(bounds));
484 page=1;
485 scene=0;
486 imageListLength=GetImageListLength(image);
487 do
488 {
489 /*
490 Scale relative to dots-per-inch.
491 */
492 delta.x=DefaultResolution;
493 delta.y=DefaultResolution;
494 resolution.x=image->resolution.x;
495 resolution.y=image->resolution.y;
496 if ((resolution.x == 0.0) || (resolution.y == 0.0))
497 {
498 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
499 resolution.x=geometry_info.rho;
500 resolution.y=geometry_info.sigma;
501 if ((flags & SigmaValue) == 0)
502 resolution.y=resolution.x;
503 }
504 if (image_info->density != (char *) NULL)
505 {
506 flags=ParseGeometry(image_info->density,&geometry_info);
507 resolution.x=geometry_info.rho;
508 resolution.y=geometry_info.sigma;
509 if ((flags & SigmaValue) == 0)
510 resolution.y=resolution.x;
511 }
512 if (image->units == PixelsPerCentimeterResolution)
513 {
514 resolution.x=(double) (100.0*2.54*resolution.x+0.5)/100.0;
515 resolution.y=(double) (100.0*2.54*resolution.y+0.5)/100.0;
516 }
517 SetGeometry(image,&geometry);
518 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
519 (double) image->columns,(double) image->rows);
520 if (image_info->page != (char *) NULL)
521 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
522 else
523 if ((image->page.width != 0) && (image->page.height != 0))
524 (void) FormatLocaleString(page_geometry,MagickPathExtent,
525 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
526 image->page.height,(double) image->page.x,(double) image->page.y);
527 else
528 if ((image->gravity != UndefinedGravity) &&
529 (LocaleCompare(image_info->magick,"PS") == 0))
530 (void) CopyMagickString(page_geometry,PSPageGeometry,
531 MagickPathExtent);
532 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
533 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
534 &geometry.width,&geometry.height);
535 scale.x=PerceptibleReciprocal(resolution.x)*geometry.width*delta.x;
536 geometry.width=(size_t) floor(scale.x+0.5);
537 scale.y=PerceptibleReciprocal(resolution.y)*geometry.height*delta.y;
538 geometry.height=(size_t) floor(scale.y+0.5);
539 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
540 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
541 if (image->gravity != UndefinedGravity)
542 {
543 geometry.x=(-page_info.x);
544 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
545 }
546 pointsize=12.0;
547 if (image_info->pointsize != 0.0)
548 pointsize=image_info->pointsize;
549 text_size=0;
550 value=GetImageProperty(image,"label",exception);
551 if (value != (const char *) NULL)
552 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
553 if (page == 1)
554 {
555 /*
556 Output Postscript header.
557 */
558 if (LocaleCompare(image_info->magick,"PS2") == 0)
559 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
560 else
561 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
562 MagickPathExtent);
563 (void) WriteBlobString(image,buffer);
564 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
565 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
566 image->filename);
567 (void) WriteBlobString(image,buffer);
568 timer=GetMagickTime();
569 (void) FormatMagickTime(timer,MagickPathExtent,date);
570 (void) FormatLocaleString(buffer,MagickPathExtent,
571 "%%%%CreationDate: (%s)\n",date);
572 (void) WriteBlobString(image,buffer);
573 bounds.x1=(double) geometry.x;
574 bounds.y1=(double) geometry.y;
575 bounds.x2=(double) geometry.x+geometry.width;
576 bounds.y2=(double) geometry.y+geometry.height+text_size;
577 if ((image_info->adjoin != MagickFalse) &&
578 (GetNextImageInList(image) != (Image *) NULL))
579 (void) CopyMagickString(buffer,"%%BoundingBox: (atend)\n",
580 MagickPathExtent);
581 else
582 {
583 (void) FormatLocaleString(buffer,MagickPathExtent,
584 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
585 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
586 (void) WriteBlobString(image,buffer);
587 (void) FormatLocaleString(buffer,MagickPathExtent,
588 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
589 bounds.y1,bounds.x2,bounds.y2);
590 }
591 (void) WriteBlobString(image,buffer);
592 value=GetImageProperty(image,"label",exception);
593 if (value != (const char *) NULL)
594 (void) WriteBlobString(image,
595 "%%DocumentNeededResources: font Helvetica\n");
596 (void) WriteBlobString(image,"%%LanguageLevel: 2\n");
597 if (LocaleCompare(image_info->magick,"PS2") != 0)
598 (void) WriteBlobString(image,"%%Pages: 1\n");
599 else
600 {
601 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
602 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
603 if (image_info->adjoin == MagickFalse)
604 (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
605 else
606 (void) FormatLocaleString(buffer,MagickPathExtent,
607 "%%%%Pages: %.20g\n",(double) imageListLength);
608 (void) WriteBlobString(image,buffer);
609 }
610 if (image->colorspace == CMYKColorspace)
611 (void) WriteBlobString(image,
612 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
613 (void) WriteBlobString(image,"%%EndComments\n");
614 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
615 (void) WriteBlobString(image,"%%EndDefaults\n\n");
616 /*
617 Output Postscript commands.
618 */
619 switch (compression)
620 {
621 case NoCompression:
622 {
623 filter="/ASCII85Decode filter";
624 break;
625 }
626 case JPEGCompression:
627 {
628 filter="/DCTDecode filter";
629 break;
630 }
631 case LZWCompression:
632 {
633 filter="/LZWDecode filter";
634 break;
635 }
636 case FaxCompression:
637 case Group4Compression:
638 {
639 filter=" ";
640 break;
641 }
642 default:
643 {
644 filter="/RunLengthDecode filter";
645 break;
646 }
647 }
648 (void) FormatLocaleString(buffer,MagickPathExtent,PostscriptProlog,
649 filter,filter,filter,filter,filter,filter,filter,filter);
650 (void) WriteBlob(image,strlen(buffer),buffer);
651 value=GetImageProperty(image,"label",exception);
652 if (value != (const char *) NULL)
653 {
654 (void) WriteBlobString(image,
655 " /Helvetica findfont pointsize scalefont setfont\n");
656 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
657 {
658 (void) WriteBlobString(image," /label 512 string def\n");
659 (void) WriteBlobString(image,
660 " currentfile label readline pop\n");
661 (void) FormatLocaleString(buffer,MagickPathExtent,
662 " 0 y %g add moveto label show pop\n",j*pointsize+12);
663 (void) WriteBlobString(image,buffer);
664 }
665 }
666 (void) WriteBlob(image,sizeof(PostscriptEpilog)-1,
667 (const unsigned char *) PostscriptEpilog);
668 if (LocaleCompare(image_info->magick,"PS2") == 0)
669 (void) WriteBlobString(image," showpage\n");
670 (void) WriteBlobString(image,"} bind def\n");
671 (void) WriteBlobString(image,"%%EndProlog\n");
672 }
673 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
674 (double) page++);
675 (void) WriteBlobString(image,buffer);
676 (void) FormatLocaleString(buffer,MagickPathExtent,
677 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
678 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
679 (geometry.height+text_size));
680 (void) WriteBlobString(image,buffer);
681 if ((double) geometry.x < bounds.x1)
682 bounds.x1=(double) geometry.x;
683 if ((double) geometry.y < bounds.y1)
684 bounds.y1=(double) geometry.y;
685 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
686 bounds.x2=(double) geometry.x+geometry.width-1;
687 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
688 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
689 value=GetImageProperty(image,"label",exception);
690 if (value != (const char *) NULL)
691 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
692 if (LocaleCompare(image_info->magick,"PS2") != 0)
693 (void) WriteBlobString(image,"userdict begin\n");
694 start=TellBlob(image);
695 (void) FormatLocaleString(buffer,MagickPathExtent,
696 "%%%%BeginData:%13ld %s Bytes\n",0L,
697 compression == NoCompression ? "ASCII" : "Binary");
698 (void) WriteBlobString(image,buffer);
699 stop=TellBlob(image);
700 (void) WriteBlobString(image,"DisplayImage\n");
701 /*
702 Output image data.
703 */
704 (void) FormatLocaleString(buffer,MagickPathExtent,
705 "%.20g %.20g\n%g %g\n%g\n",(double) geometry.x,(double) geometry.y,
706 scale.x,scale.y,pointsize);
707 (void) WriteBlobString(image,buffer);
708 labels=(char **) NULL;
709 value=GetImageProperty(image,"label",exception);
710 if (value != (const char *) NULL)
711 labels=StringToList(value);
712 if (labels != (char **) NULL)
713 {
714 for (i=0; labels[i] != (char *) NULL; i++)
715 {
716 (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",
717 labels[i]);
718 (void) WriteBlobString(image,buffer);
719 labels[i]=DestroyString(labels[i]);
720 }
721 labels=(char **) RelinquishMagickMemory(labels);
722 }
723 number_pixels=(MagickSizeType) image->columns*image->rows;
724 if (number_pixels != (MagickSizeType) ((size_t) number_pixels))
725 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
726 if ((compression == FaxCompression) || (compression == Group4Compression) ||
727 ((image_info->type != TrueColorType) &&
728 (SetImageGray(image,exception) != MagickFalse)))
729 {
730 (void) FormatLocaleString(buffer,MagickPathExtent,
731 "%.20g %.20g\n1\n%d\n",(double) image->columns,(double) image->rows,
732 (int) (image->colorspace == CMYKColorspace));
733 (void) WriteBlobString(image,buffer);
734 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",(int)
735 ((compression != FaxCompression) &&
736 (compression != Group4Compression)));
737 (void) WriteBlobString(image,buffer);
738 (void) WriteBlobString(image,"0\n");
739 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
740 (compression == FaxCompression) ||
741 (compression == Group4Compression) ? 1 : 8);
742 (void) WriteBlobString(image,buffer);
743 switch (compression)
744 {
745 case FaxCompression:
746 case Group4Compression:
747 {
748 if (LocaleCompare(CCITTParam,"0") == 0)
749 {
750 (void) HuffmanEncodeImage(image_info,image,image,exception);
751 break;
752 }
753 (void) Huffman2DEncodeImage(image_info,image,image,exception);
754 break;
755 }
756 case JPEGCompression:
757 {
758 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
759 if (status == MagickFalse)
760 {
761 (void) CloseBlob(image);
762 return(MagickFalse);
763 }
764 break;
765 }
766 case RLECompression:
767 default:
768 {
769 MemoryInfo
770 *pixel_info;
771
772 register unsigned char
773 *q;
774
775 /*
776 Allocate pixel array.
777 */
778 length=(size_t) number_pixels;
779 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
780 if (pixel_info == (MemoryInfo *) NULL)
781 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
782 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
783 /*
784 Dump runlength encoded pixels.
785 */
786 q=pixels;
787 for (y=0; y < (ssize_t) image->rows; y++)
788 {
789 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
790 if (p == (const Quantum *) NULL)
791 break;
792 for (x=0; x < (ssize_t) image->columns; x++)
793 {
794 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
795 p+=GetPixelChannels(image);
796 }
797 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
798 image->rows);
799 if (progress == MagickFalse)
800 break;
801 }
802 length=(size_t) (q-pixels);
803 if (compression == LZWCompression)
804 status=LZWEncodeImage(image,length,pixels,exception);
805 else
806 status=PackbitsEncodeImage(image,length,pixels,exception);
807 pixel_info=RelinquishVirtualMemory(pixel_info);
808 if (status == MagickFalse)
809 {
810 (void) CloseBlob(image);
811 return(MagickFalse);
812 }
813 break;
814 }
815 case NoCompression:
816 {
817 /*
818 Dump uncompressed PseudoColor packets.
819 */
820 Ascii85Initialize(image);
821 for (y=0; y < (ssize_t) image->rows; y++)
822 {
823 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
824 if (p == (const Quantum *) NULL)
825 break;
826 for (x=0; x < (ssize_t) image->columns; x++)
827 {
828 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
829 GetPixelLuma(image,p))));
830 p+=GetPixelChannels(image);
831 }
832 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
833 y,image->rows);
834 if (progress == MagickFalse)
835 break;
836 }
837 Ascii85Flush(image);
838 break;
839 }
840 }
841 }
842 else
843 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
844 (compression == JPEGCompression) || (image->alpha_trait != UndefinedPixelTrait))
845 {
846 (void) FormatLocaleString(buffer,MagickPathExtent,
847 "%.20g %.20g\n0\n%d\n",(double) image->columns,(double) image->rows,
848 (int) (image->colorspace == CMYKColorspace));
849 (void) WriteBlobString(image,buffer);
850 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
851 (int) (compression == NoCompression));
852 (void) WriteBlobString(image,buffer);
853 switch (compression)
854 {
855 case JPEGCompression:
856 {
857 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
858 if (status == MagickFalse)
859 {
860 (void) CloseBlob(image);
861 return(MagickFalse);
862 }
863 break;
864 }
865 case RLECompression:
866 default:
867 {
868 MemoryInfo
869 *pixel_info;
870
871 register unsigned char
872 *q;
873
874 /*
875 Allocate pixel array.
876 */
877 length=(size_t) number_pixels;
878 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
879 if (pixel_info == (MemoryInfo *) NULL)
880 ThrowWriterException(ResourceLimitError,
881 "MemoryAllocationFailed");
882 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
883 /*
884 Dump runlength encoded pixels.
885 */
886 q=pixels;
887 for (y=0; y < (ssize_t) image->rows; y++)
888 {
889 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
890 if (p == (const Quantum *) NULL)
891 break;
892 for (x=0; x < (ssize_t) image->columns; x++)
893 {
894 if ((image->alpha_trait != UndefinedPixelTrait) &&
895 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
896 {
897 *q++=ScaleQuantumToChar(QuantumRange);
898 *q++=ScaleQuantumToChar(QuantumRange);
899 *q++=ScaleQuantumToChar(QuantumRange);
900 }
901 else
902 if (image->colorspace != CMYKColorspace)
903 {
904 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
905 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
906 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
907 }
908 else
909 {
910 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
911 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
912 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
913 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
914 }
915 p+=GetPixelChannels(image);
916 }
917 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
918 y,image->rows);
919 if (progress == MagickFalse)
920 break;
921 }
922 length=(size_t) (q-pixels);
923 if (compression == LZWCompression)
924 status=LZWEncodeImage(image,length,pixels,exception);
925 else
926 status=PackbitsEncodeImage(image,length,pixels,exception);
927 if (status == MagickFalse)
928 {
929 (void) CloseBlob(image);
930 return(MagickFalse);
931 }
932 pixel_info=RelinquishVirtualMemory(pixel_info);
933 break;
934 }
935 case NoCompression:
936 {
937 /*
938 Dump uncompressed DirectColor packets.
939 */
940 Ascii85Initialize(image);
941 for (y=0; y < (ssize_t) image->rows; y++)
942 {
943 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
944 if (p == (const Quantum *) NULL)
945 break;
946 for (x=0; x < (ssize_t) image->columns; x++)
947 {
948 if ((image->alpha_trait != UndefinedPixelTrait) &&
949 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
950 {
951 Ascii85Encode(image,ScaleQuantumToChar((Quantum)
952 QuantumRange));
953 Ascii85Encode(image,ScaleQuantumToChar((Quantum)
954 QuantumRange));
955 Ascii85Encode(image,ScaleQuantumToChar((Quantum)
956 QuantumRange));
957 }
958 else
959 if (image->colorspace != CMYKColorspace)
960 {
961 Ascii85Encode(image,ScaleQuantumToChar(
962 GetPixelRed(image,p)));
963 Ascii85Encode(image,ScaleQuantumToChar(
964 GetPixelGreen(image,p)));
965 Ascii85Encode(image,ScaleQuantumToChar(
966 GetPixelBlue(image,p)));
967 }
968 else
969 {
970 Ascii85Encode(image,ScaleQuantumToChar(
971 GetPixelRed(image,p)));
972 Ascii85Encode(image,ScaleQuantumToChar(
973 GetPixelGreen(image,p)));
974 Ascii85Encode(image,ScaleQuantumToChar(
975 GetPixelBlue(image,p)));
976 Ascii85Encode(image,ScaleQuantumToChar(
977 GetPixelBlack(image,p)));
978 }
979 p+=GetPixelChannels(image);
980 }
981 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
982 y,image->rows);
983 if (progress == MagickFalse)
984 break;
985 }
986 Ascii85Flush(image);
987 break;
988 }
989 }
990 }
991 else
992 {
993 /*
994 Dump number of colors and colormap.
995 */
996 (void) FormatLocaleString(buffer,MagickPathExtent,
997 "%.20g %.20g\n1\n%d\n",(double) image->columns,(double) image->rows,
998 (int) (image->colorspace == CMYKColorspace));
999 (void) WriteBlobString(image,buffer);
1000 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
1001 (int) (compression == NoCompression));
1002 (void) WriteBlobString(image,buffer);
1003 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
1004 image->colors);
1005 (void) WriteBlobString(image,buffer);
1006 for (i=0; i < (ssize_t) image->colors; i++)
1007 {
1008 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n",
1009 ScaleQuantumToChar(image->colormap[i].red),
1010 ScaleQuantumToChar(image->colormap[i].green),
1011 ScaleQuantumToChar(image->colormap[i].blue));
1012 (void) WriteBlobString(image,buffer);
1013 }
1014 switch (compression)
1015 {
1016 case RLECompression:
1017 default:
1018 {
1019 MemoryInfo
1020 *pixel_info;
1021
1022 register unsigned char
1023 *q;
1024
1025 /*
1026 Allocate pixel array.
1027 */
1028 length=(size_t) number_pixels;
1029 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1030 if (pixel_info == (MemoryInfo *) NULL)
1031 ThrowWriterException(ResourceLimitError,
1032 "MemoryAllocationFailed");
1033 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1034 /*
1035 Dump runlength encoded pixels.
1036 */
1037 q=pixels;
1038 for (y=0; y < (ssize_t) image->rows; y++)
1039 {
1040 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1041 if (p == (const Quantum *) NULL)
1042 break;
1043 for (x=0; x < (ssize_t) image->columns; x++)
1044 {
1045 *q++=(unsigned char) GetPixelIndex(image,p);
1046 p+=GetPixelChannels(image);
1047 }
1048 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1049 y,image->rows);
1050 if (progress == MagickFalse)
1051 break;
1052 }
1053 length=(size_t) (q-pixels);
1054 if (compression == LZWCompression)
1055 status=LZWEncodeImage(image,length,pixels,exception);
1056 else
1057 status=PackbitsEncodeImage(image,length,pixels,exception);
1058 pixel_info=RelinquishVirtualMemory(pixel_info);
1059 if (status == MagickFalse)
1060 {
1061 (void) CloseBlob(image);
1062 return(MagickFalse);
1063 }
1064 break;
1065 }
1066 case NoCompression:
1067 {
1068 /*
1069 Dump uncompressed PseudoColor packets.
1070 */
1071 Ascii85Initialize(image);
1072 for (y=0; y < (ssize_t) image->rows; y++)
1073 {
1074 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1075 if (p == (const Quantum *) NULL)
1076 break;
1077 for (x=0; x < (ssize_t) image->columns; x++)
1078 {
1079 Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
1080 p+=GetPixelChannels(image);
1081 }
1082 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1083 y,image->rows);
1084 if (progress == MagickFalse)
1085 break;
1086 }
1087 Ascii85Flush(image);
1088 break;
1089 }
1090 }
1091 }
1092 (void) WriteBlobByte(image,'\n');
1093 length=(size_t) (TellBlob(image)-stop);
1094 stop=TellBlob(image);
1095 offset=SeekBlob(image,start,SEEK_SET);
1096 if (offset < 0)
1097 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1098 (void) FormatLocaleString(buffer,MagickPathExtent,
1099 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1100 compression == NoCompression ? "ASCII" : "Binary");
1101 (void) WriteBlobString(image,buffer);
1102 offset=SeekBlob(image,stop,SEEK_SET);
1103 (void) WriteBlobString(image,"%%EndData\n");
1104 if (LocaleCompare(image_info->magick,"PS2") != 0)
1105 (void) WriteBlobString(image,"end\n");
1106 (void) WriteBlobString(image,"%%PageTrailer\n");
1107 if (GetNextImageInList(image) == (Image *) NULL)
1108 break;
1109 image=SyncNextImageInList(image);
1110 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
1111 if (status == MagickFalse)
1112 break;
1113 } while (image_info->adjoin != MagickFalse);
1114 (void) WriteBlobString(image,"%%Trailer\n");
1115 if (page > 1)
1116 {
1117 (void) FormatLocaleString(buffer,MagickPathExtent,
1118 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1119 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1120 (void) WriteBlobString(image,buffer);
1121 (void) FormatLocaleString(buffer,MagickPathExtent,
1122 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
1123 bounds.x2,bounds.y2);
1124 (void) WriteBlobString(image,buffer);
1125 }
1126 (void) WriteBlobString(image,"%%EOF\n");
1127 (void) CloseBlob(image);
1128 return(MagickTrue);
1129 }
1130