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