blob: 5b5cd9f03006c415cf81450bb2d6549798e46156 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy80975862009-09-25 14:34:31 +000072
73/*
74 Define declarations.
75*/
cristy3ed852e2009-09-05 21:47:34 +000076#if defined(MAGICKCORE_TIFF_DELEGATE)
77#define CCITTParam "-1"
78#else
79#define CCITTParam "0"
80#endif
81
82/*
83 Forward declarations.
84*/
85static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000086 WritePS2Image(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000087
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%
cristybb503372010-05-27 20:51:26 +0000108% size_t RegisterPS2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000109%
110*/
cristybb503372010-05-27 20:51:26 +0000111ModuleExport size_t RegisterPS2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000112{
113 MagickInfo
114 *entry;
115
dirk06b627a2015-04-06 18:59:17 +0000116 entry=AcquireMagickInfo("PS2","EPS2","Level II Encapsulated PostScript");
cristy3ed852e2009-09-05 21:47:34 +0000117 entry->encoder=(EncodeImageHandler *) WritePS2Image;
dirk08e9a112015-02-22 01:51:41 +0000118 entry->flags^=CoderAdjoinFlag;
119 entry->flags|=CoderSeekableStreamFlag;
cristy5aefbeb2013-08-09 12:13:32 +0000120 entry->mime_type=ConstantString("application/postscript");
cristy3ed852e2009-09-05 21:47:34 +0000121 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000122 entry=AcquireMagickInfo("PS2","PS2","Level II PostScript");
cristy3ed852e2009-09-05 21:47:34 +0000123 entry->encoder=(EncodeImageHandler *) WritePS2Image;
dirk08e9a112015-02-22 01:51:41 +0000124 entry->flags|=CoderSeekableStreamFlag;
cristy5aefbeb2013-08-09 12:13:32 +0000125 entry->mime_type=ConstantString("application/postscript");
cristy3ed852e2009-09-05 21:47:34 +0000126 (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*/
149ModuleExport 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%
cristy1e178e72011-08-28 19:44:34 +0000173% MagickBooleanType WritePS2Image(const ImageInfo *image_info,
174% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000175%
176% A description of each parameter follows:
177%
178% o image_info: the image info.
179%
180% o image: the image.
181%
cristy1e178e72011-08-28 19:44:34 +0000182% o exception: return any errors or warnings in this structure.
183%
cristy3ed852e2009-09-05 21:47:34 +0000184*/
cristy47b838c2009-09-19 16:09:30 +0000185
186static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000187 Image *image,Image *inject_image,ExceptionInfo *exception)
cristy47b838c2009-09-19 16:09:30 +0000188{
cristy47b838c2009-09-19 16:09:30 +0000189 Image
cristy80975862009-09-25 14:34:31 +0000190 *group4_image;
cristy47b838c2009-09-19 16:09:30 +0000191
192 ImageInfo
193 *write_info;
194
cristy47b838c2009-09-19 16:09:30 +0000195 MagickBooleanType
196 status;
197
cristy80975862009-09-25 14:34:31 +0000198 size_t
199 length;
cristy47b838c2009-09-19 16:09:30 +0000200
201 unsigned char
cristy80975862009-09-25 14:34:31 +0000202 *group4;
cristy47b838c2009-09-19 16:09:30 +0000203
cristy42751fe2009-10-05 00:15:50 +0000204 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +0000205 write_info=CloneImageInfo(image_info);
cristy151b66d2015-04-15 10:50:31 +0000206 (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
207 (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
cristy018f07f2011-09-04 21:15:19 +0000208 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
cristy80975862009-09-25 14:34:31 +0000209 if (group4_image == (Image *) NULL)
210 return(MagickFalse);
211 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
cristy018f07f2011-09-04 21:15:19 +0000212 exception);
cristy80975862009-09-25 14:34:31 +0000213 group4_image=DestroyImage(group4_image);
214 if (group4 == (unsigned char *) NULL)
215 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +0000216 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +0000217 if (WriteBlob(image,length,group4) != (ssize_t) length)
218 status=MagickFalse;
219 group4=(unsigned char *) RelinquishMagickMemory(group4);
220 return(status);
cristy47b838c2009-09-19 16:09:30 +0000221}
222
cristy1e178e72011-08-28 19:44:34 +0000223static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image,
224 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000225{
226 static const char
Cristy629f8052015-09-14 07:48:08 -0400227 *const PostscriptProlog[]=
cristy3ed852e2009-09-05 21:47:34 +0000228 {
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",
cristy80975862009-09-25 14:34:31 +0000251 " { /DataSource pixel_stream %s }",
252 " { /DataSource pixel_stream %s } ifelse",
cristy3ed852e2009-09-05 21:47:34 +0000253 " >> 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",
cristy80975862009-09-25 14:34:31 +0000265 " { /DataSource pixel_stream %s }",
266 " { /DataSource pixel_stream %s } ifelse",
cristy3ed852e2009-09-05 21:47:34 +0000267 " >> 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",
cristy80975862009-09-25 14:34:31 +0000297 " { /DataSource pixel_stream %s }",
cristy3ed852e2009-09-05 21:47:34 +0000298 " {",
cristy80975862009-09-25 14:34:31 +0000299 " /DataSource pixel_stream %s",
cristy3ed852e2009-09-05 21:47:34 +0000300 " <<",
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",
cristy80975862009-09-25 14:34:31 +0000325 " { /DataSource pixel_stream %s }",
326 " { /DataSource pixel_stream %s } ifelse",
cristy3ed852e2009-09-05 21:47:34 +0000327 " >> 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",
Cristy629f8052015-09-14 07:48:08 -0400361 (const char *) NULL
cristy3ed852e2009-09-05 21:47:34 +0000362 },
Cristy629f8052015-09-14 07:48:08 -0400363 *const PostscriptEpilog[]=
cristy3ed852e2009-09-05 21:47:34 +0000364 {
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",
cristy8b4ff222012-03-02 13:01:39 +0000376 " grestore",
Cristy629f8052015-09-14 07:48:08 -0400377 (const char *) NULL
cristy3ed852e2009-09-05 21:47:34 +0000378 };
379
380 char
cristy151b66d2015-04-15 10:50:31 +0000381 buffer[MagickPathExtent],
382 date[MagickPathExtent],
383 page_geometry[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +0000384 **labels;
385
386 CompressionType
387 compression;
388
389 const char
Cristy629f8052015-09-14 07:48:08 -0400390 *const *q,
cristy3ed852e2009-09-05 21:47:34 +0000391 *value;
392
393 double
394 pointsize;
395
396 GeometryInfo
397 geometry_info;
398
cristy3ed852e2009-09-05 21:47:34 +0000399 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
cristy4c08aed2011-07-01 19:47:50 +0000427 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000428 *p;
429
cristybb503372010-05-27 20:51:26 +0000430 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000431 x;
432
cristybb503372010-05-27 20:51:26 +0000433 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000434 i;
435
436 SegmentInfo
437 bounds;
438
439 size_t
cristy802d3642011-04-27 02:02:41 +0000440 length,
441 page,
442 text_size;
443
444 ssize_t
445 j,
446 y;
cristy3ed852e2009-09-05 21:47:34 +0000447
448 time_t
449 timer;
450
451 unsigned char
452 *pixels;
453
cristy3ed852e2009-09-05 21:47:34 +0000454 /*
455 Open output image file.
456 */
457 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000458 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000459 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000460 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000461 if (image->debug != MagickFalse)
462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000463 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000464 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000465 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000466 if (status == MagickFalse)
467 return(status);
cristyaf8d3912014-02-21 14:50:33 +0000468 compression=image->compression;
cristy3ed852e2009-09-05 21:47:34 +0000469 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;
cristy1e178e72011-08-28 19:44:34 +0000477 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +0000478 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;
cristy2a11bef2011-10-28 18:33:11 +0000496 resolution.x=image->resolution.x;
497 resolution.y=image->resolution.y;
cristy3ed852e2009-09-05 21:47:34 +0000498 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 {
cristybb503372010-05-27 20:51:26 +0000516 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;
cristy3ed852e2009-09-05 21:47:34 +0000518 }
519 SetGeometry(image,&geometry);
cristy151b66d2015-04-15 10:50:31 +0000520 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
cristye8c25f92010-06-03 00:53:06 +0000521 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000522 if (image_info->page != (char *) NULL)
cristy151b66d2015-04-15 10:50:31 +0000523 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000524 else
525 if ((image->page.width != 0) && (image->page.height != 0))
cristy151b66d2015-04-15 10:50:31 +0000526 (void) FormatLocaleString(page_geometry,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000527 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
528 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +0000529 else
530 if ((image->gravity != UndefinedGravity) &&
531 (LocaleCompare(image_info->magick,"PS") == 0))
cristy151b66d2015-04-15 10:50:31 +0000532 (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent);
533 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000534 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
535 &geometry.width,&geometry.height);
536 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +0000537 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000538 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +0000539 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000540 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
cristy1e178e72011-08-28 19:44:34 +0000541 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000542 if (image->gravity != UndefinedGravity)
543 {
544 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +0000545 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000546 }
547 pointsize=12.0;
548 if (image_info->pointsize != 0.0)
549 pointsize=image_info->pointsize;
550 text_size=0;
cristyd15e6592011-10-15 00:13:06 +0000551 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000552 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +0000553 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +0000554 if (page == 1)
555 {
556 /*
557 Output Postscript header.
558 */
559 if (LocaleCompare(image_info->magick,"PS2") == 0)
cristy151b66d2015-04-15 10:50:31 +0000560 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000561 else
562 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
cristy151b66d2015-04-15 10:50:31 +0000563 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000564 (void) WriteBlobString(image,buffer);
565 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
cristy151b66d2015-04-15 10:50:31 +0000566 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
cristy3ed852e2009-09-05 21:47:34 +0000567 image->filename);
568 (void) WriteBlobString(image,buffer);
569 timer=time((time_t *) NULL);
cristy151b66d2015-04-15 10:50:31 +0000570 (void) FormatMagickTime(timer,MagickPathExtent,date);
571 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000572 "%%%%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",
cristy151b66d2015-04-15 10:50:31 +0000581 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000582 else
583 {
cristy151b66d2015-04-15 10:50:31 +0000584 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000585 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
cristy8071c472012-09-24 12:41:06 +0000586 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
cristy3ed852e2009-09-05 21:47:34 +0000587 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000588 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye7f51092010-01-17 00:39:37 +0000589 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
cristy8cd5b312010-01-07 01:10:24 +0000590 bounds.y1,bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +0000591 }
592 (void) WriteBlobString(image,buffer);
cristyd15e6592011-10-15 00:13:06 +0000593 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000594 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)
cristy151b66d2015-04-15 10:50:31 +0000605 (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000606 else
cristy151b66d2015-04-15 10:50:31 +0000607 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000608 "%%%%Pages: %.20g\n",(double) GetImageListLength(image));
cristy3ed852e2009-09-05 21:47:34 +0000609 (void) WriteBlobString(image,buffer);
610 }
cristy57219ff2014-01-29 21:06:24 +0000611 if (image->colorspace == CMYKColorspace)
612 (void) WriteBlobString(image,
613 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
cristy3ed852e2009-09-05 21:47:34 +0000614 (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 {
cristy151b66d2015-04-15 10:50:31 +0000626 (void) FormatLocaleString(buffer,MagickPathExtent,*q,
cristy80975862009-09-25 14:34:31 +0000627 "/ASCII85Decode filter");
cristy3ed852e2009-09-05 21:47:34 +0000628 break;
629 }
630 case JPEGCompression:
631 {
cristy151b66d2015-04-15 10:50:31 +0000632 (void) FormatLocaleString(buffer,MagickPathExtent,*q,
cristy80975862009-09-25 14:34:31 +0000633 "/DCTDecode filter");
cristy3ed852e2009-09-05 21:47:34 +0000634 break;
635 }
636 case LZWCompression:
637 {
cristy151b66d2015-04-15 10:50:31 +0000638 (void) FormatLocaleString(buffer,MagickPathExtent,*q,
cristy80975862009-09-25 14:34:31 +0000639 "/LZWDecode filter");
cristy3ed852e2009-09-05 21:47:34 +0000640 break;
641 }
642 case FaxCompression:
643 case Group4Compression:
644 {
cristy151b66d2015-04-15 10:50:31 +0000645 (void) FormatLocaleString(buffer,MagickPathExtent,*q," ");
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 default:
649 {
cristy151b66d2015-04-15 10:50:31 +0000650 (void) FormatLocaleString(buffer,MagickPathExtent,*q,
cristy80975862009-09-25 14:34:31 +0000651 "/RunLengthDecode filter");
cristy3ed852e2009-09-05 21:47:34 +0000652 break;
653 }
654 }
655 (void) WriteBlobString(image,buffer);
656 (void) WriteBlobByte(image,'\n');
657 }
cristyd15e6592011-10-15 00:13:06 +0000658 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000659 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +0000660 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
cristy3ed852e2009-09-05 21:47:34 +0000661 {
662 (void) WriteBlobString(image," /label 512 string def\n");
663 (void) WriteBlobString(image," currentfile label readline pop\n");
cristy151b66d2015-04-15 10:50:31 +0000664 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye7f51092010-01-17 00:39:37 +0000665 " 0 y %g add moveto label show pop\n",j*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +0000666 (void) WriteBlobString(image,buffer);
667 }
668 for (q=PostscriptEpilog; *q; q++)
669 {
cristy151b66d2015-04-15 10:50:31 +0000670 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*q);
cristy3ed852e2009-09-05 21:47:34 +0000671 (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 }
cristy151b66d2015-04-15 10:50:31 +0000678 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
cristye8c25f92010-06-03 00:53:06 +0000679 (double) page++);
cristy3ed852e2009-09-05 21:47:34 +0000680 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000681 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000682 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
683 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
cristy3ed852e2009-09-05 21:47:34 +0000684 (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;
cristyd15e6592011-10-15 00:13:06 +0000694 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000695 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);
cristy151b66d2015-04-15 10:50:31 +0000700 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000701 "%%%%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 */
cristy151b66d2015-04-15 10:50:31 +0000709 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
cristye8c25f92010-06-03 00:53:06 +0000710 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
cristy3ed852e2009-09-05 21:47:34 +0000711 (void) WriteBlobString(image,buffer);
712 labels=(char **) NULL;
cristyd15e6592011-10-15 00:13:06 +0000713 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000714 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 {
cristy151b66d2015-04-15 10:50:31 +0000720 (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",
cristy3ed852e2009-09-05 21:47:34 +0000721 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) &&
dirkf1d85482015-04-06 00:36:00 +0000732 (SetImageGray(image,exception) != MagickFalse)))
cristy3ed852e2009-09-05 21:47:34 +0000733 {
cristy151b66d2015-04-15 10:50:31 +0000734 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n1\n%d\n",
cristye8c25f92010-06-03 00:53:06 +0000735 (double) image->columns,(double) image->rows,(int)
cristy3ed852e2009-09-05 21:47:34 +0000736 (image->colorspace == CMYKColorspace));
737 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000738 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
cristy3ed852e2009-09-05 21:47:34 +0000739 (int) ((compression != FaxCompression) &&
740 (compression != Group4Compression)));
741 (void) WriteBlobString(image,buffer);
742 (void) WriteBlobString(image,"0\n");
cristy151b66d2015-04-15 10:50:31 +0000743 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
cristy3ed852e2009-09-05 21:47:34 +0000744 (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 {
cristy018f07f2011-09-04 21:15:19 +0000754 (void) HuffmanEncodeImage(image_info,image,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000755 break;
756 }
cristy018f07f2011-09-04 21:15:19 +0000757 (void) Huffman2DEncodeImage(image_info,image,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000758 break;
759 }
760 case JPEGCompression:
761 {
cristy1e178e72011-08-28 19:44:34 +0000762 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +0000763 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +0000764 {
765 (void) CloseBlob(image);
766 return(MagickFalse);
767 }
cristy3ed852e2009-09-05 21:47:34 +0000768 break;
769 }
770 case RLECompression:
771 default:
772 {
cristyb64823d2013-06-30 20:58:24 +0000773 MemoryInfo
774 *pixel_info;
775
cristy3ed852e2009-09-05 21:47:34 +0000776 register unsigned char
777 *q;
778
779 /*
780 Allocate pixel array.
781 */
782 length=(size_t) number_pixels;
cristyb64823d2013-06-30 20:58:24 +0000783 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
784 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000785 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000786 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000787 /*
cristyb64823d2013-06-30 20:58:24 +0000788 Dump runlength encoded pixels.
cristy3ed852e2009-09-05 21:47:34 +0000789 */
790 q=pixels;
cristybb503372010-05-27 20:51:26 +0000791 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000792 {
cristy1e178e72011-08-28 19:44:34 +0000793 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000794 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000795 break;
cristybb503372010-05-27 20:51:26 +0000796 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000797 {
cristyd0323222013-04-07 16:13:21 +0000798 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
cristyed231572011-07-14 02:18:59 +0000799 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000800 }
cristy802d3642011-04-27 02:02:41 +0000801 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
802 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000803 if (progress == MagickFalse)
804 break;
805 }
806 length=(size_t) (q-pixels);
807 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +0000808 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000809 else
cristy018f07f2011-09-04 21:15:19 +0000810 status=PackbitsEncodeImage(image,length,pixels,exception);
cristyb64823d2013-06-30 20:58:24 +0000811 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000812 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);
cristybb503372010-05-27 20:51:26 +0000825 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristy1e178e72011-08-28 19:44:34 +0000827 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000828 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000829 break;
cristybb503372010-05-27 20:51:26 +0000830 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
cristyd0323222013-04-07 16:13:21 +0000832 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
833 GetPixelLuma(image,p))));
cristyed231572011-07-14 02:18:59 +0000834 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000835 }
cristye8c25f92010-06-03 00:53:06 +0000836 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
837 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000838 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) ||
cristy17f11b02014-12-20 19:37:04 +0000848 (compression == JPEGCompression) || (image->alpha_trait != UndefinedPixelTrait))
cristy3ed852e2009-09-05 21:47:34 +0000849 {
cristy151b66d2015-04-15 10:50:31 +0000850 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n0\n%d\n",
cristye8c25f92010-06-03 00:53:06 +0000851 (double) image->columns,(double) image->rows,(int)
cristy3ed852e2009-09-05 21:47:34 +0000852 (image->colorspace == CMYKColorspace));
853 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000854 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
cristy3ed852e2009-09-05 21:47:34 +0000855 (int) (compression == NoCompression));
856 (void) WriteBlobString(image,buffer);
857 switch (compression)
858 {
859 case JPEGCompression:
860 {
cristy1e178e72011-08-28 19:44:34 +0000861 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +0000862 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +0000863 {
864 (void) CloseBlob(image);
865 return(MagickFalse);
866 }
cristy3ed852e2009-09-05 21:47:34 +0000867 break;
868 }
869 case RLECompression:
870 default:
871 {
cristyb64823d2013-06-30 20:58:24 +0000872 MemoryInfo
873 *pixel_info;
874
cristy3ed852e2009-09-05 21:47:34 +0000875 register unsigned char
876 *q;
877
878 /*
879 Allocate pixel array.
880 */
881 length=(size_t) number_pixels;
cristyb64823d2013-06-30 20:58:24 +0000882 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
883 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000884 ThrowWriterException(ResourceLimitError,
885 "MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000886 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000887 /*
cristyb64823d2013-06-30 20:58:24 +0000888 Dump runlength encoded pixels.
cristy3ed852e2009-09-05 21:47:34 +0000889 */
890 q=pixels;
cristybb503372010-05-27 20:51:26 +0000891 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000892 {
cristy1e178e72011-08-28 19:44:34 +0000893 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000894 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000895 break;
cristybb503372010-05-27 20:51:26 +0000896 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000897 {
cristy17f11b02014-12-20 19:37:04 +0000898 if ((image->alpha_trait != UndefinedPixelTrait) &&
cristy4c08aed2011-07-01 19:47:50 +0000899 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
cristy3ed852e2009-09-05 21:47:34 +0000900 {
cristy6e963d82012-06-19 15:23:24 +0000901 *q++=ScaleQuantumToChar(QuantumRange);
902 *q++=ScaleQuantumToChar(QuantumRange);
903 *q++=ScaleQuantumToChar(QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +0000904 }
905 else
906 if (image->colorspace != CMYKColorspace)
907 {
cristy4c08aed2011-07-01 19:47:50 +0000908 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
909 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
910 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
cristy3ed852e2009-09-05 21:47:34 +0000911 }
912 else
913 {
cristy4c08aed2011-07-01 19:47:50 +0000914 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
915 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
916 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
917 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
cristy3ed852e2009-09-05 21:47:34 +0000918 }
cristyed231572011-07-14 02:18:59 +0000919 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000920 }
cristy802d3642011-04-27 02:02:41 +0000921 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
922 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000923 if (progress == MagickFalse)
924 break;
925 }
926 length=(size_t) (q-pixels);
927 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +0000928 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000929 else
cristy018f07f2011-09-04 21:15:19 +0000930 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000931 if (status == MagickFalse)
932 {
933 (void) CloseBlob(image);
934 return(MagickFalse);
935 }
cristyb64823d2013-06-30 20:58:24 +0000936 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000937 break;
938 }
939 case NoCompression:
940 {
941 /*
942 Dump uncompressed DirectColor packets.
943 */
944 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +0000945 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000946 {
cristy1e178e72011-08-28 19:44:34 +0000947 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000948 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000949 break;
cristybb503372010-05-27 20:51:26 +0000950 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000951 {
cristy17f11b02014-12-20 19:37:04 +0000952 if ((image->alpha_trait != UndefinedPixelTrait) &&
cristy4c08aed2011-07-01 19:47:50 +0000953 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
cristy3ed852e2009-09-05 21:47:34 +0000954 {
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 {
cristy802d3642011-04-27 02:02:41 +0000965 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000966 GetPixelRed(image,p)));
cristy802d3642011-04-27 02:02:41 +0000967 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000968 GetPixelGreen(image,p)));
cristy802d3642011-04-27 02:02:41 +0000969 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000970 GetPixelBlue(image,p)));
cristy3ed852e2009-09-05 21:47:34 +0000971 }
972 else
973 {
cristy802d3642011-04-27 02:02:41 +0000974 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000975 GetPixelRed(image,p)));
cristy802d3642011-04-27 02:02:41 +0000976 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000977 GetPixelGreen(image,p)));
cristy802d3642011-04-27 02:02:41 +0000978 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000979 GetPixelBlue(image,p)));
cristy9fff7b42011-04-29 01:09:31 +0000980 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +0000981 GetPixelBlack(image,p)));
cristy3ed852e2009-09-05 21:47:34 +0000982 }
cristyed231572011-07-14 02:18:59 +0000983 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000984 }
cristy802d3642011-04-27 02:02:41 +0000985 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
986 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000987 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 */
cristy151b66d2015-04-15 10:50:31 +00001000 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n1\n%d\n",
cristye8c25f92010-06-03 00:53:06 +00001001 (double) image->columns,(double) image->rows,(int)
cristy3ed852e2009-09-05 21:47:34 +00001002 (image->colorspace == CMYKColorspace));
1003 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +00001004 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
cristy3ed852e2009-09-05 21:47:34 +00001005 (int) (compression == NoCompression));
1006 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +00001007 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001008 image->colors);
cristy3ed852e2009-09-05 21:47:34 +00001009 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001010 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001011 {
cristy151b66d2015-04-15 10:50:31 +00001012 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n",
cristy3ed852e2009-09-05 21:47:34 +00001013 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 {
cristyb64823d2013-06-30 20:58:24 +00001023 MemoryInfo
1024 *pixel_info;
1025
cristy3ed852e2009-09-05 21:47:34 +00001026 register unsigned char
1027 *q;
1028
1029 /*
1030 Allocate pixel array.
1031 */
1032 length=(size_t) number_pixels;
cristyb64823d2013-06-30 20:58:24 +00001033 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1034 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001035 ThrowWriterException(ResourceLimitError,
1036 "MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +00001037 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001038 /*
cristyb64823d2013-06-30 20:58:24 +00001039 Dump runlength encoded pixels.
cristy3ed852e2009-09-05 21:47:34 +00001040 */
1041 q=pixels;
cristybb503372010-05-27 20:51:26 +00001042 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001043 {
cristy1e178e72011-08-28 19:44:34 +00001044 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001045 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001046 break;
cristybb503372010-05-27 20:51:26 +00001047 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001048 {
1049 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001050 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001051 }
cristy802d3642011-04-27 02:02:41 +00001052 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1053 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001054 if (progress == MagickFalse)
1055 break;
1056 }
1057 length=(size_t) (q-pixels);
1058 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00001059 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001060 else
cristy018f07f2011-09-04 21:15:19 +00001061 status=PackbitsEncodeImage(image,length,pixels,exception);
cristyb64823d2013-06-30 20:58:24 +00001062 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001063 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);
cristybb503372010-05-27 20:51:26 +00001076 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001077 {
cristy1e178e72011-08-28 19:44:34 +00001078 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001079 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001080 break;
cristybb503372010-05-27 20:51:26 +00001081 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001082 {
1083 Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
cristyed231572011-07-14 02:18:59 +00001084 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001085 }
cristy802d3642011-04-27 02:02:41 +00001086 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1087 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001088 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");
cristy151b66d2015-04-15 10:50:31 +00001102 (void) FormatLocaleString(buffer,MagickPathExtent,
cristyf2faecf2010-05-28 19:19:36 +00001103 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
cristy3ed852e2009-09-05 21:47:34 +00001104 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 {
cristy151b66d2015-04-15 10:50:31 +00001122 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001123 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
cristy8071c472012-09-24 12:41:06 +00001124 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
cristy3ed852e2009-09-05 21:47:34 +00001125 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +00001126 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye7f51092010-01-17 00:39:37 +00001127 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +00001128 bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +00001129 (void) WriteBlobString(image,buffer);
1130 }
1131 (void) WriteBlobString(image,"%%EOF\n");
1132 (void) CloseBlob(image);
1133 return(MagickTrue);
1134}