blob: 659f8e07874a7edae803cc389c55dfdfe32e544f [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% PPPP SSSSS 33333 %
7% P P SS 33 %
8% PPPP SSS 333 %
9% P SS 33 %
10% P SSSSS 33333 %
11% %
12% %
13% Write Postscript Level III Format %
14% %
15% Software Design %
16% John Cristy %
17% Lars Ruben Skyum %
18% July 1992 %
19% %
20% %
cristy7e41fe82010-12-04 23:12:08 +000021% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000022% dedicated to making software imaging solutions freely available. %
23% %
24% You may not use this file except in compliance with the License. You may %
25% obtain a copy of the License at %
26% %
27% http://www.imagemagick.org/script/license.php %
28% %
29% Unless required by applicable law or agreed to in writing, software %
30% distributed under the License is distributed on an "AS IS" BASIS, %
31% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32% See the License for the specific language governing permissions and %
33% limitations under the License. %
34% %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/attribute.h"
45#include "MagickCore/blob.h"
46#include "MagickCore/blob-private.h"
47#include "MagickCore/cache.h"
48#include "MagickCore/color.h"
49#include "MagickCore/color-private.h"
50#include "MagickCore/compress.h"
51#include "MagickCore/constitute.h"
52#include "MagickCore/draw.h"
53#include "MagickCore/exception.h"
54#include "MagickCore/exception-private.h"
55#include "MagickCore/geometry.h"
56#include "MagickCore/image.h"
57#include "MagickCore/image-private.h"
58#include "MagickCore/list.h"
59#include "MagickCore/magick.h"
60#include "MagickCore/memory_.h"
61#include "MagickCore/monitor.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/token.h"
72#include "MagickCore/utility.h"
73#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000074
75/*
76 Define declarations.
77*/
78#define PS3_NoCompression "0"
79#define PS3_FaxCompression "1"
80#define PS3_JPEGCompression "2"
81#define PS3_LZWCompression "3"
82#define PS3_RLECompression "4"
83#define PS3_ZipCompression "5"
84
85#define PS3_RGBColorspace "0"
86#define PS3_CMYKColorspace "1"
87
88#define PS3_DirectClass "0"
89#define PS3_PseudoClass "1"
cristy80975862009-09-25 14:34:31 +000090
91#if defined(MAGICKCORE_TIFF_DELEGATE)
cristy80975862009-09-25 14:34:31 +000092#define CCITTParam "-1"
93#else
94#define CCITTParam "0"
95#endif
cristy3ed852e2009-09-05 21:47:34 +000096
97/*
98 Forward declarations.
99*/
100static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000101 WritePS3Image(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000102
103/*
104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105% %
106% %
107% %
108% R e g i s t e r P S 3 I m a g e %
109% %
110% %
111% %
112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113%
114% RegisterPS3Image() adds properties for the PS3 image format to the list of
115% supported formats. The properties include the image format tag, a method to
116% read and/or write the format, whether the format supports the saving of more
117% than one frame to the same file or blob, whether the format supports native
118% in-memory I/O, and a brief description of the format.
119%
120% The format of the RegisterPS3Image method is:
121%
cristybb503372010-05-27 20:51:26 +0000122% size_t RegisterPS3Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000123%
124*/
cristybb503372010-05-27 20:51:26 +0000125ModuleExport size_t RegisterPS3Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000126{
127 MagickInfo
128 *entry;
129
130 entry=SetMagickInfo("EPS3");
131 entry->encoder=(EncodeImageHandler *) WritePS3Image;
132 entry->description=ConstantString("Level III Encapsulated PostScript");
133 entry->module=ConstantString("PS3");
cristyffaf9782011-04-13 19:50:51 +0000134 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000135 (void) RegisterMagickInfo(entry);
136 entry=SetMagickInfo("PS3");
137 entry->encoder=(EncodeImageHandler *) WritePS3Image;
138 entry->description=ConstantString("Level III PostScript");
139 entry->module=ConstantString("PS3");
cristyffaf9782011-04-13 19:50:51 +0000140 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000141 (void) RegisterMagickInfo(entry);
142 return(MagickImageCoderSignature);
143}
144
145/*
146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147% %
148% %
149% %
150% U n r e g i s t e r P S 3 I m a g e %
151% %
152% %
153% %
154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155%
156% UnregisterPS3Image() removes format registrations made by the PS3 module
157% from the list of supported formats.
158%
159% The format of the UnregisterPS3Image method is:
160%
161% UnregisterPS3Image(void)
162%
163*/
164ModuleExport void UnregisterPS3Image(void)
165{
166 (void) UnregisterMagickInfo("EPS3");
167 (void) UnregisterMagickInfo("PS3");
168}
169
170/*
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172% %
173% %
174% %
175% W r i t e P S 3 I m a g e %
176% %
177% %
178% %
179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180%
181% WritePS3Image() translates an image to encapsulated Postscript Level III
182% for printing. If the supplied geometry is null, the image is centered on
183% the Postscript page. Otherwise, the image is positioned as specified by the
184% geometry.
185%
186% The format of the WritePS3Image method is:
187%
cristy1e178e72011-08-28 19:44:34 +0000188% MagickBooleanType WritePS3Image(const ImageInfo *image_info,
189% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000190%
191% A description of each parameter follows:
192%
193% o image_info: Specifies a pointer to a ImageInfo structure.
194%
195% o image: the image.
196%
cristy1e178e72011-08-28 19:44:34 +0000197% o exception: return any errors or warnings in this structure.
198%
cristy3ed852e2009-09-05 21:47:34 +0000199*/
200
cristy47b838c2009-09-19 16:09:30 +0000201static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000202 Image *image,Image *inject_image,ExceptionInfo *exception)
cristy47b838c2009-09-19 16:09:30 +0000203{
cristy47b838c2009-09-19 16:09:30 +0000204 Image
cristy80975862009-09-25 14:34:31 +0000205 *group4_image;
cristy47b838c2009-09-19 16:09:30 +0000206
207 ImageInfo
208 *write_info;
209
cristy47b838c2009-09-19 16:09:30 +0000210 MagickBooleanType
211 status;
212
cristy80975862009-09-25 14:34:31 +0000213 size_t
214 length;
cristy47b838c2009-09-19 16:09:30 +0000215
216 unsigned char
cristy80975862009-09-25 14:34:31 +0000217 *group4;
cristy47b838c2009-09-19 16:09:30 +0000218
cristy42751fe2009-10-05 00:15:50 +0000219 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +0000220 write_info=CloneImageInfo(image_info);
cristy80975862009-09-25 14:34:31 +0000221 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
222 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
cristy018f07f2011-09-04 21:15:19 +0000223 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
cristy80975862009-09-25 14:34:31 +0000224 if (group4_image == (Image *) NULL)
225 return(MagickFalse);
226 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
cristy018f07f2011-09-04 21:15:19 +0000227 exception);
cristy80975862009-09-25 14:34:31 +0000228 group4_image=DestroyImage(group4_image);
229 if (group4 == (unsigned char *) NULL)
230 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +0000231 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +0000232 if (WriteBlob(image,length,group4) != (ssize_t) length)
233 status=MagickFalse;
234 group4=(unsigned char *) RelinquishMagickMemory(group4);
235 return(status);
cristy47b838c2009-09-19 16:09:30 +0000236}
cristy80975862009-09-25 14:34:31 +0000237
cristy3ed852e2009-09-05 21:47:34 +0000238static MagickBooleanType SerializeImage(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000239 Image *image,unsigned char **pixels,size_t *length,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000240{
cristy3ed852e2009-09-05 21:47:34 +0000241 MagickBooleanType
242 status;
243
cristy4c08aed2011-07-01 19:47:50 +0000244 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000245 *p;
246
cristybb503372010-05-27 20:51:26 +0000247 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000248 x;
249
250 register unsigned char
251 *q;
252
cristy802d3642011-04-27 02:02:41 +0000253 ssize_t
254 y;
255
cristy3ed852e2009-09-05 21:47:34 +0000256 assert(image != (Image *) NULL);
257 assert(image->signature == MagickSignature);
258 if (image->debug != MagickFalse)
259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
260 status=MagickTrue;
cristy802d3642011-04-27 02:02:41 +0000261 *length=(image->colorspace == CMYKColorspace ? 4 : 3)*(size_t)
262 image->columns*image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000263 *pixels=(unsigned char *) AcquireQuantumMemory(*length,sizeof(**pixels));
264 if (*pixels == (unsigned char *) NULL)
265 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
266 q=(*pixels);
cristybb503372010-05-27 20:51:26 +0000267 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000268 {
269 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy4c08aed2011-07-01 19:47:50 +0000270 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000271 break;
cristy3ed852e2009-09-05 21:47:34 +0000272 if (image->colorspace != CMYKColorspace)
cristybb503372010-05-27 20:51:26 +0000273 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000274 {
cristy4c08aed2011-07-01 19:47:50 +0000275 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
276 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
277 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
cristyed231572011-07-14 02:18:59 +0000278 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000279 }
280 else
cristybb503372010-05-27 20:51:26 +0000281 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000282 {
cristy4c08aed2011-07-01 19:47:50 +0000283 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
284 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
285 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
286 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
cristyed231572011-07-14 02:18:59 +0000287 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000288 }
289 if (image->previous == (Image *) NULL)
290 {
cristycee97112010-05-28 00:44:52 +0000291 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy802d3642011-04-27 02:02:41 +0000292 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000293 if (status == MagickFalse)
294 break;
295 }
296 }
297 if (status == MagickFalse)
298 *pixels=(unsigned char *) RelinquishMagickMemory(*pixels);
299 return(status);
300}
301
302static MagickBooleanType SerializeImageChannel(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000303 Image *image,unsigned char **pixels,size_t *length,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000304{
cristy3ed852e2009-09-05 21:47:34 +0000305 MagickBooleanType
306 status;
307
cristy4c08aed2011-07-01 19:47:50 +0000308 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000309 *p;
310
cristybb503372010-05-27 20:51:26 +0000311 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000312 x;
313
314 register unsigned char
315 *q;
316
cristybb503372010-05-27 20:51:26 +0000317 size_t
cristy3ed852e2009-09-05 21:47:34 +0000318 pack,
319 padded_columns;
320
cristy802d3642011-04-27 02:02:41 +0000321 ssize_t
322 y;
323
324 unsigned char
325 code,
326 bit;
327
cristy3ed852e2009-09-05 21:47:34 +0000328 assert(image != (Image *) NULL);
329 assert(image->signature == MagickSignature);
330 if (image->debug != MagickFalse)
331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
332 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +0000333 pack=IsImageMonochrome(image,&image->exception) == MagickFalse ? 1UL : 8UL;
cristy3ed852e2009-09-05 21:47:34 +0000334 padded_columns=((image->columns+pack-1)/pack)*pack;
335 *length=(size_t) padded_columns*image->rows/pack;
336 *pixels=(unsigned char *) AcquireQuantumMemory(*length,sizeof(**pixels));
337 if (*pixels == (unsigned char *) NULL)
338 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
339 q=(*pixels);
cristybb503372010-05-27 20:51:26 +0000340 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000341 {
cristy018f07f2011-09-04 21:15:19 +0000342 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000343 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000344 break;
345 if (pack == 1)
cristybb503372010-05-27 20:51:26 +0000346 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000347 {
cristy4c08aed2011-07-01 19:47:50 +0000348 *q++=ScaleQuantumToChar(GetPixelIntensity(image,p));
cristyed231572011-07-14 02:18:59 +0000349 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000350 }
351 else
352 {
353 code='\0';
cristybb503372010-05-27 20:51:26 +0000354 for (x=0; x < (ssize_t) padded_columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000355 {
356 bit=(unsigned char) 0x00;
cristybb503372010-05-27 20:51:26 +0000357 if (x < (ssize_t) image->columns)
cristy4c08aed2011-07-01 19:47:50 +0000358 bit=(unsigned char) (GetPixelIntensity(image,p) == (Quantum)
359 TransparentAlpha ? 0x01 : 0x00);
cristy3ed852e2009-09-05 21:47:34 +0000360 code=(code << 1)+bit;
361 if (((x+1) % pack) == 0)
362 {
363 *q++=code;
364 code='\0';
365 }
cristyed231572011-07-14 02:18:59 +0000366 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000367 }
368 }
cristycee97112010-05-28 00:44:52 +0000369 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy802d3642011-04-27 02:02:41 +0000370 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000371 if (status == MagickFalse)
372 break;
373 }
374 if (status == MagickFalse)
375 *pixels=(unsigned char *) RelinquishMagickMemory(*pixels);
376 return(status);
377}
378
379static MagickBooleanType SerializeImageIndexes(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000380 Image *image,unsigned char **pixels,size_t *length,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000381{
cristy3ed852e2009-09-05 21:47:34 +0000382 MagickBooleanType
383 status;
384
cristy4c08aed2011-07-01 19:47:50 +0000385 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000386 *p;
387
cristybb503372010-05-27 20:51:26 +0000388 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000389 x;
390
391 register unsigned char
392 *q;
393
cristy802d3642011-04-27 02:02:41 +0000394 ssize_t
395 y;
396
cristy3ed852e2009-09-05 21:47:34 +0000397 assert(image != (Image *) NULL);
398 assert(image->signature == MagickSignature);
399 if (image->debug != MagickFalse)
400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
401 status=MagickTrue;
402 *length=(size_t) image->columns*image->rows;
403 *pixels=(unsigned char *) AcquireQuantumMemory(*length,sizeof(**pixels));
404 if (*pixels == (unsigned char *) NULL)
405 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
406 q=(*pixels);
cristybb503372010-05-27 20:51:26 +0000407 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000408 {
cristy018f07f2011-09-04 21:15:19 +0000409 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000410 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000411 break;
cristybb503372010-05-27 20:51:26 +0000412 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +0000413 {
414 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +0000415 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000416 }
cristy3ed852e2009-09-05 21:47:34 +0000417 if (image->previous == (Image *) NULL)
418 {
cristycee97112010-05-28 00:44:52 +0000419 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy802d3642011-04-27 02:02:41 +0000420 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000421 if (status == MagickFalse)
422 break;
423 }
424 }
425 if (status == MagickFalse)
426 *pixels=(unsigned char *) RelinquishMagickMemory(*pixels);
427 return(status);
428}
429
430static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000431 Image *image,const CompressionType compression,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000432{
cristybd5a96c2011-08-21 00:04:26 +0000433 ChannelType
434 channel_mask;
435
cristy3ed852e2009-09-05 21:47:34 +0000436 char
437 buffer[MaxTextExtent];
438
439 Image
440 *mask_image;
441
442 MagickBooleanType
443 status;
444
445 MagickOffsetType
446 offset,
447 start,
448 stop;
449
cristybb503372010-05-27 20:51:26 +0000450 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000451 i;
452
453 size_t
454 length;
455
456 unsigned char
457 *pixels;
458
459 assert(image_info != (ImageInfo *) NULL);
460 assert(image_info->signature == MagickSignature);
461 assert(image != (Image *) NULL);
462 assert(image->signature == MagickSignature);
463 if (image->debug != MagickFalse)
464 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
465 assert(image->matte != MagickFalse);
466 status=MagickTrue;
467 /*
468 Note BeginData DSC comment for update later.
469 */
470 start=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +0000471 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy802d3642011-04-27 02:02:41 +0000472 "%%%%BeginData:%13ld %s Bytes\n",0L,compression == NoCompression ?
473 "ASCII" : "BINARY");
cristy3ed852e2009-09-05 21:47:34 +0000474 (void) WriteBlobString(image,buffer);
475 stop=TellBlob(image);
476 /*
477 Only lossless compressions for the mask.
478 */
479 switch (compression)
480 {
481 case NoCompression:
482 default:
483 {
cristyb51dff52011-05-19 16:55:47 +0000484 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000485 "currentfile %.20g %.20g "PS3_NoCompression" ByteStreamDecodeFilter\n",
486 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000487 break;
488 }
489 case FaxCompression:
490 case Group4Compression:
491 {
cristyb51dff52011-05-19 16:55:47 +0000492 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000493 "currentfile %.20g %.20g "PS3_FaxCompression" ByteStreamDecodeFilter\n",
494 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000495 break;
496 }
497 case LZWCompression:
498 {
cristyb51dff52011-05-19 16:55:47 +0000499 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000500 "currentfile %.20g %.20g "PS3_LZWCompression" ByteStreamDecodeFilter\n",
501 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000502 break;
503 }
504 case RLECompression:
505 {
cristyb51dff52011-05-19 16:55:47 +0000506 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000507 "currentfile %.20g %.20g "PS3_RLECompression" ByteStreamDecodeFilter\n",
508 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000509 break;
510 }
511 case ZipCompression:
512 {
cristyb51dff52011-05-19 16:55:47 +0000513 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000514 "currentfile %.20g %.20g "PS3_ZipCompression" ByteStreamDecodeFilter\n",
515 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000516 break;
517 }
518 }
519 (void) WriteBlobString(image,buffer);
520 (void) WriteBlobString(image,"/ReusableStreamDecode filter\n");
521 mask_image=CloneImage(image,0,0,MagickTrue,&image->exception);
522 if (mask_image == (Image *) NULL)
523 ThrowWriterException(CoderError,image->exception.reason);
cristybd5a96c2011-08-21 00:04:26 +0000524 channel_mask=SetPixelChannelMask(mask_image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +0000525 status=SeparateImage(mask_image);
cristybd5a96c2011-08-21 00:04:26 +0000526 (void) SetPixelChannelMap(mask_image,channel_mask);
cristy3ed852e2009-09-05 21:47:34 +0000527 if (status == MagickFalse)
528 {
529 mask_image=DestroyImage(mask_image);
530 return(MagickFalse);
531 }
cristy018f07f2011-09-04 21:15:19 +0000532 (void) SetImageType(mask_image,BilevelType,exception);
533 (void) SetImageType(mask_image,PaletteType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000534 mask_image->matte=MagickFalse;
535 pixels=(unsigned char *) NULL;
536 length=0;
537 switch (compression)
538 {
539 case NoCompression:
540 default:
541 {
cristy018f07f2011-09-04 21:15:19 +0000542 status=SerializeImageChannel(image_info,mask_image,&pixels,&length,
543 exception);
cristy3ed852e2009-09-05 21:47:34 +0000544 if (status == MagickFalse)
545 break;
546 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +0000547 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +0000548 Ascii85Encode(image,pixels[i]);
549 Ascii85Flush(image);
550 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
551 break;
552 }
553 case FaxCompression:
554 case Group4Compression:
555 {
556 if ((compression == FaxCompression) ||
557 (LocaleCompare(CCITTParam,"0") == 0))
cristy018f07f2011-09-04 21:15:19 +0000558 status=HuffmanEncodeImage(image_info,image,mask_image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000559 else
cristy018f07f2011-09-04 21:15:19 +0000560 status=Huffman2DEncodeImage(image_info,image,mask_image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000561 break;
562 }
563 case LZWCompression:
564 {
cristy018f07f2011-09-04 21:15:19 +0000565 status=SerializeImageChannel(image_info,mask_image,&pixels,&length,
566 exception);
cristy3ed852e2009-09-05 21:47:34 +0000567 if (status == MagickFalse)
568 break;
cristy018f07f2011-09-04 21:15:19 +0000569 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000570 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
571 break;
572 }
573 case RLECompression:
574 {
cristy018f07f2011-09-04 21:15:19 +0000575 status=SerializeImageChannel(image_info,mask_image,&pixels,&length,
576 exception);
cristy3ed852e2009-09-05 21:47:34 +0000577 if (status == MagickFalse)
578 break;
cristy018f07f2011-09-04 21:15:19 +0000579 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000580 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
581 break;
582 }
583 case ZipCompression:
584 {
cristy018f07f2011-09-04 21:15:19 +0000585 status=SerializeImageChannel(image_info,mask_image,&pixels,&length,
586 exception);
cristy3ed852e2009-09-05 21:47:34 +0000587 if (status == MagickFalse)
588 break;
cristy018f07f2011-09-04 21:15:19 +0000589 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000590 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
591 break;
592 }
593 }
594 mask_image=DestroyImage(mask_image);
595 (void) WriteBlobByte(image,'\n');
596 length=(size_t) (TellBlob(image)-stop);
597 stop=TellBlob(image);
598 offset=SeekBlob(image,start,SEEK_SET);
599 if (offset < 0)
600 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
cristyb51dff52011-05-19 16:55:47 +0000601 (void) FormatLocaleString(buffer,MaxTextExtent,
cristyf2faecf2010-05-28 19:19:36 +0000602 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
cristy3ed852e2009-09-05 21:47:34 +0000603 compression == NoCompression ? "ASCII" : "BINARY");
604 (void) WriteBlobString(image,buffer);
605 offset=SeekBlob(image,stop,SEEK_SET);
606 if (offset < 0)
607 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
608 (void) WriteBlobString(image,"%%EndData\n");
609 (void) WriteBlobString(image, "/mask_stream exch def\n");
610 return(status);
611}
612
cristy1e178e72011-08-28 19:44:34 +0000613static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
614 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000615{
616 static const char
617 *PostscriptProlog[]=
618 {
619 "/ByteStreamDecodeFilter",
620 "{",
621 " /z exch def",
622 " /r exch def",
623 " /c exch def",
624 " z "PS3_NoCompression" eq { /ASCII85Decode filter } if",
625 " z "PS3_FaxCompression" eq",
626 " {",
627 " <<",
628 " /K "CCITTParam,
629 " /Columns c",
630 " /Rows r",
631 " >>",
632 " /CCITTFaxDecode filter",
633 " } if",
634 " z "PS3_JPEGCompression" eq { /DCTDecode filter } if",
635 " z "PS3_LZWCompression" eq { /LZWDecode filter } if",
636 " z "PS3_RLECompression" eq { /RunLengthDecode filter } if",
637 " z "PS3_ZipCompression" eq { /FlateDecode filter } if",
638 "} bind def",
639 "",
640 "/DirectClassImageDict",
641 "{",
642 " colorspace "PS3_RGBColorspace" eq",
643 " {",
644 " /DeviceRGB setcolorspace",
645 " <<",
646 " /ImageType 1",
647 " /Width columns",
648 " /Height rows",
649 " /BitsPerComponent 8",
650 " /DataSource pixel_stream",
651 " /MultipleDataSources false",
652 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
653 " /Decode [0 1 0 1 0 1]",
654 " >>",
655 " }",
656 " {",
657 " /DeviceCMYK setcolorspace",
658 " <<",
659 " /ImageType 1",
660 " /Width columns",
661 " /Height rows",
662 " /BitsPerComponent 8",
663 " /DataSource pixel_stream",
664 " /MultipleDataSources false",
665 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
666 " /Decode",
667 " compression "PS3_JPEGCompression" eq",
668 " { [1 0 1 0 1 0 1 0] }",
669 " { [0 1 0 1 0 1 0 1] }",
670 " ifelse",
671 " >>",
672 " }",
673 " ifelse",
674 "} bind def",
675 "",
676 "/PseudoClassImageDict",
677 "{",
678 " % Colors in colormap image.",
679 " currentfile buffer readline pop",
680 " token pop /colors exch def pop",
681 " colors 0 eq",
682 " {",
683 " % Depth of grayscale image.",
684 " currentfile buffer readline pop",
685 " token pop /bits exch def pop",
686 " /DeviceGray setcolorspace",
687 " <<",
688 " /ImageType 1",
689 " /Width columns",
690 " /Height rows",
691 " /BitsPerComponent bits",
692 " /Decode [0 1]",
693 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
694 " /DataSource pixel_stream",
695 " >>",
696 " }",
697 " {",
698 " % RGB colormap.",
699 " /colormap colors 3 mul string def",
700 " compression "PS3_NoCompression" eq",
701 " { currentfile /ASCII85Decode filter colormap readstring pop pop }",
702 " { currentfile colormap readstring pop pop }",
703 " ifelse",
704 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace",
705 " <<",
706 " /ImageType 1",
707 " /Width columns",
708 " /Height rows",
709 " /BitsPerComponent 8",
710 " /Decode [0 255]",
711 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
712 " /DataSource pixel_stream",
713 " >>",
714 " }",
715 " ifelse",
716 "} bind def",
717 "",
718 "/NonMaskedImageDict",
719 "{",
720 " class "PS3_PseudoClass" eq",
721 " { PseudoClassImageDict }",
722 " { DirectClassImageDict }",
723 " ifelse",
724 "} bind def",
725 "",
726 "/MaskedImageDict",
727 "{",
728 " <<",
729 " /ImageType 3",
730 " /InterleaveType 3",
731 " /DataDict NonMaskedImageDict",
732 " /MaskDict",
733 " <<",
734 " /ImageType 1",
735 " /Width columns",
736 " /Height rows",
737 " /BitsPerComponent 1",
738 " /DataSource mask_stream",
739 " /MultipleDataSources false",
740 " /ImageMatrix [ columns 0 0 rows neg 0 rows]",
741 " /Decode [ 0 1 ]",
742 " >>",
743 " >>",
744 "} bind def",
745 "",
746 "/ClipImage",
747 "{} def",
748 "",
749 "/DisplayImage",
750 "{",
751 " /buffer 512 string def",
752 " % Translation.",
753 " currentfile buffer readline pop",
754 " token pop /x exch def",
755 " token pop /y exch def pop",
756 " x y translate",
757 " % Image size and font size.",
758 " currentfile buffer readline pop",
759 " token pop /x exch def",
760 " token pop /y exch def pop",
761 " currentfile buffer readline pop",
762 " token pop /pointsize exch def pop",
763 (char *) NULL
764 },
765 *PostscriptEpilog[]=
766 {
767 " x y scale",
768 " % Clipping path.",
769 " currentfile buffer readline pop",
770 " token pop /clipped exch def pop",
771 " % Showpage.",
772 " currentfile buffer readline pop",
773 " token pop /sp exch def pop",
774 " % Image pixel size.",
775 " currentfile buffer readline pop",
776 " token pop /columns exch def",
777 " token pop /rows exch def pop",
778 " % Colorspace (RGB/CMYK).",
779 " currentfile buffer readline pop",
780 " token pop /colorspace exch def pop",
781 " % Transparency.",
782 " currentfile buffer readline pop",
783 " token pop /alpha exch def pop",
784 " % Stencil mask?",
785 " currentfile buffer readline pop",
786 " token pop /stencil exch def pop",
787 " % Image class (direct/pseudo).",
788 " currentfile buffer readline pop",
789 " token pop /class exch def pop",
790 " % Compression type.",
791 " currentfile buffer readline pop",
792 " token pop /compression exch def pop",
793 " % Clip and render.",
794 " /pixel_stream currentfile columns rows compression ByteStreamDecodeFilter def",
795 " clipped { ClipImage } if",
796 " alpha stencil not and",
797 " { MaskedImageDict mask_stream resetfile }",
798 " { NonMaskedImageDict }",
799 " ifelse",
800 " stencil { 0 setgray imagemask } { image } ifelse",
801 " sp { showpage } if",
802 "} bind def",
803 (char *) NULL
804 };
805
806 char
807 buffer[MaxTextExtent],
808 date[MaxTextExtent],
809 **labels,
810 page_geometry[MaxTextExtent];
811
812 CompressionType
813 compression;
814
815 const char
816 *option,
817 **q,
818 *value;
819
820 double
821 pointsize;
822
823 GeometryInfo
824 geometry_info;
825
cristy3ed852e2009-09-05 21:47:34 +0000826 MagickBooleanType
827 status;
828
829 MagickOffsetType
830 offset,
831 scene,
832 start,
833 stop;
834
835 MagickStatusType
836 flags;
837
838 PointInfo
839 delta,
840 resolution,
841 scale;
842
843 RectangleInfo
844 geometry,
845 media_info,
846 page_info;
847
cristybb503372010-05-27 20:51:26 +0000848 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000849 i;
850
851 SegmentInfo
852 bounds;
853
854 size_t
cristy802d3642011-04-27 02:02:41 +0000855 length,
856 page,
857 pixel,
858 text_size;
859
860 ssize_t
861 j;
cristy3ed852e2009-09-05 21:47:34 +0000862
863 time_t
864 timer;
865
866 unsigned char
867 *pixels;
868
cristy3ed852e2009-09-05 21:47:34 +0000869 /*
870 Open output image file.
871 */
872 assert(image_info != (const ImageInfo *) NULL);
873 assert(image_info->signature == MagickSignature);
874 assert(image != (Image *) NULL);
875 assert(image->signature == MagickSignature);
876 if (image->debug != MagickFalse)
877 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000878 assert(exception != (ExceptionInfo *) NULL);
879 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000880 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000881 if (status == MagickFalse)
882 return(MagickFalse);
883 compression=image->compression;
884 if (image_info->compression != UndefinedCompression)
885 compression=image_info->compression;
886 switch (compression)
887 {
888 case FaxCompression:
889 case Group4Compression:
890 {
cristy1e178e72011-08-28 19:44:34 +0000891 if ((IsImageMonochrome(image,exception) == MagickFalse) ||
cristy3ed852e2009-09-05 21:47:34 +0000892 (image->matte != MagickFalse))
893 compression=RLECompression;
894 break;
895 }
896#if !defined(MAGICKCORE_JPEG_DELEGATE)
897 case JPEGCompression:
898 {
899 compression=RLECompression;
cristy1e178e72011-08-28 19:44:34 +0000900 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +0000901 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
902 image->filename);
903 break;
904 }
905#endif
906#if !defined(MAGICKCORE_ZLIB_DELEGATE)
907 case ZipCompression:
908 {
909 compression=RLECompression;
cristy1e178e72011-08-28 19:44:34 +0000910 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +0000911 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
912 image->filename);
913 break;
914 }
915#endif
916 default:
917 break;
918 }
919 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
920 page=0;
921 scene=0;
922 do
923 {
924 /*
925 Scale relative to dots-per-inch.
926 */
927 delta.x=DefaultResolution;
928 delta.y=DefaultResolution;
929 resolution.x=image->x_resolution;
930 resolution.y=image->y_resolution;
931 if ((resolution.x == 0.0) || (resolution.y == 0.0))
932 {
933 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
934 resolution.x=geometry_info.rho;
935 resolution.y=geometry_info.sigma;
936 if ((flags & SigmaValue) == 0)
937 resolution.y=resolution.x;
938 }
939 if (image_info->density != (char *) NULL)
940 {
941 flags=ParseGeometry(image_info->density,&geometry_info);
942 resolution.x=geometry_info.rho;
943 resolution.y=geometry_info.sigma;
944 if ((flags & SigmaValue) == 0)
945 resolution.y=resolution.x;
946 }
947 if (image->units == PixelsPerCentimeterResolution)
948 {
cristybb503372010-05-27 20:51:26 +0000949 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
950 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000951 }
952 SetGeometry(image,&geometry);
cristyb51dff52011-05-19 16:55:47 +0000953 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
cristye8c25f92010-06-03 00:53:06 +0000954 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000955 if (image_info->page != (char *) NULL)
956 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
957 else
958 if ((image->page.width != 0) && (image->page.height != 0))
cristyb51dff52011-05-19 16:55:47 +0000959 (void) FormatLocaleString(page_geometry,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000960 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
961 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +0000962 else
963 if ((image->gravity != UndefinedGravity) &&
964 (LocaleCompare(image_info->magick,"PS") == 0))
965 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
966 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
967 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
968 &geometry.width,&geometry.height);
969 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +0000970 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000971 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +0000972 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000973 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
cristy1e178e72011-08-28 19:44:34 +0000974 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000975 if (image->gravity != UndefinedGravity)
976 {
977 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +0000978 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000979 }
980 pointsize=12.0;
981 if (image_info->pointsize != 0.0)
982 pointsize=image_info->pointsize;
983 text_size=0;
cristyd15e6592011-10-15 00:13:06 +0000984 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000985 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +0000986 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +0000987 page++;
988 if (page == 1)
989 {
990 /*
991 Postscript header on the first page.
992 */
993 if (LocaleCompare(image_info->magick,"PS3") == 0)
994 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
995 else
996 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
997 MaxTextExtent);
998 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +0000999 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00001000 "%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
1001 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001002 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: %s\n",
cristy3ed852e2009-09-05 21:47:34 +00001003 image->filename);
1004 (void) WriteBlobString(image,buffer);
1005 timer=time((time_t *) NULL);
1006 (void) FormatMagickTime(timer,MaxTextExtent,date);
cristyb51dff52011-05-19 16:55:47 +00001007 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00001008 "%%%%CreationDate: %s\n",date);
1009 (void) WriteBlobString(image,buffer);
1010 bounds.x1=(double) geometry.x;
1011 bounds.y1=(double) geometry.y;
1012 bounds.x2=(double) geometry.x+scale.x;
1013 bounds.y2=(double) geometry.y+scale.y+text_size;
1014 if ((image_info->adjoin != MagickFalse) &&
1015 (GetNextImageInList(image) != (Image *) NULL))
1016 {
1017 (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
1018 (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
1019 }
1020 else
1021 {
cristyb51dff52011-05-19 16:55:47 +00001022 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001023 "%%%%BoundingBox: %g %g %g %g\n",floor(bounds.x1+0.5),
cristy3ed852e2009-09-05 21:47:34 +00001024 floor(bounds.y1+0.5),ceil(bounds.x2-0.5),ceil(bounds.y2-0.5));
1025 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001026 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001027 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
cristy8cd5b312010-01-07 01:10:24 +00001028 bounds.y1,bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +00001029 (void) WriteBlobString(image,buffer);
1030 if (image->colorspace == CMYKColorspace)
1031 (void) WriteBlobString(image,
1032 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1033 else
cristy1e178e72011-08-28 19:44:34 +00001034 if (IsImageGray(image,exception) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001035 (void) WriteBlobString(image,
1036 "%%DocumentProcessColors: Black\n");
1037 }
1038 /*
1039 Font resources
1040 */
cristyd15e6592011-10-15 00:13:06 +00001041 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00001042 if (value != (const char *) NULL)
1043 (void) WriteBlobString(image,
1044 "%%DocumentNeededResources: font Helvetica\n");
1045 (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
1046 /*
1047 Pages, orientation and order.
1048 */
1049 if (LocaleCompare(image_info->magick,"PS3") != 0)
1050 (void) WriteBlobString(image,"%%Pages: 1\n");
1051 else
1052 {
1053 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1054 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1055 if (image_info->adjoin == MagickFalse)
1056 (void) CopyMagickString(buffer,"%%Pages: 1\n",MaxTextExtent);
1057 else
cristyb51dff52011-05-19 16:55:47 +00001058 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001059 "%%%%Pages: %.20g\n",(double) GetImageListLength(image));
cristy3ed852e2009-09-05 21:47:34 +00001060 (void) WriteBlobString(image,buffer);
1061 }
1062 (void) WriteBlobString(image,"%%EndComments\n");
1063 /*
1064 The static postscript procedures prolog.
1065 */
1066 (void)WriteBlobString(image,"%%BeginProlog\n");
1067 for (q=PostscriptProlog; *q; q++)
1068 {
1069 (void) WriteBlobString(image,*q);
1070 (void) WriteBlobByte(image,'\n');
1071 }
1072 /*
1073 One label line for each line in label string.
1074 */
cristyd15e6592011-10-15 00:13:06 +00001075 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00001076 if (value != (const char *) NULL)
1077 {
1078 (void) WriteBlobString(image,"\n %% Labels.\n /Helvetica "
1079 " findfont pointsize scalefont setfont\n");
cristybb503372010-05-27 20:51:26 +00001080 for (i=(ssize_t) MultilineCensus(value)-1; i >= 0; i--)
cristy3ed852e2009-09-05 21:47:34 +00001081 {
1082 (void) WriteBlobString(image,
1083 " currentfile buffer readline pop token pop\n");
cristyb51dff52011-05-19 16:55:47 +00001084 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001085 " 0 y %g add moveto show pop\n",i*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +00001086 (void) WriteBlobString(image,buffer);
1087 }
1088 }
1089 /*
1090 The static postscript procedures epilog.
1091 */
1092 for (q=PostscriptEpilog; *q; q++)
1093 {
1094 (void) WriteBlobString(image,*q);
1095 (void) WriteBlobByte(image,'\n');
1096 }
1097 (void)WriteBlobString(image,"%%EndProlog\n");
1098 }
cristyb51dff52011-05-19 16:55:47 +00001099 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001100 (double) page);
cristy3ed852e2009-09-05 21:47:34 +00001101 (void) WriteBlobString(image,buffer);
1102 /*
1103 Page bounding box.
1104 */
cristyb51dff52011-05-19 16:55:47 +00001105 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001106 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1107 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+
1108 (double) (geometry.height+text_size));
cristy3ed852e2009-09-05 21:47:34 +00001109 (void) WriteBlobString(image,buffer);
1110 /*
1111 Page process colors if not RGB.
1112 */
1113 if (image->colorspace == CMYKColorspace)
1114 (void) WriteBlobString(image,
1115 "%%PageProcessColors: Cyan Magenta Yellow Black\n");
1116 else
cristy1e178e72011-08-28 19:44:34 +00001117 if (IsImageGray(image,exception) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001118 (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
1119 /*
1120 Adjust document bounding box to bound page bounding box.
1121 */
1122 if ((double) geometry.x < bounds.x1)
1123 bounds.x1=(double) geometry.x;
1124 if ((double) geometry.y < bounds.y1)
1125 bounds.y1=(double) geometry.y;
1126 if ((double) (geometry.x+scale.x) > bounds.x2)
1127 bounds.x2=(double) geometry.x+scale.x;
1128 if ((double) (geometry.y+scale.y+text_size) > bounds.y2)
1129 bounds.y2=(double) geometry.y+scale.y+text_size;
1130 /*
1131 Page font resource if there's a label.
1132 */
cristyd15e6592011-10-15 00:13:06 +00001133 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00001134 if (value != (const char *) NULL)
1135 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
1136 /*
1137 PS clipping path from Photoshop clipping path.
1138 */
1139 if ((image->clip_mask == (Image *) NULL) ||
1140 (LocaleNCompare("8BIM:",image->clip_mask->magick_filename,5) != 0))
1141 (void) WriteBlobString(image,"/ClipImage {} def\n");
1142 else
1143 {
1144 const char
1145 *value;
1146
cristyd15e6592011-10-15 00:13:06 +00001147 value=GetImageProperty(image,image->clip_mask->magick_filename,
1148 exception);
cristy3ed852e2009-09-05 21:47:34 +00001149 if (value == (const char *) NULL)
1150 return(MagickFalse);
1151 (void) WriteBlobString(image,value);
1152 (void) WriteBlobByte(image,'\n');
1153 }
1154 /*
1155 Push a dictionary for our own def's if this an EPS.
1156 */
1157 if (LocaleCompare(image_info->magick,"PS3") != 0)
1158 (void) WriteBlobString(image,"userdict begin\n");
1159 /*
1160 Image mask.
1161 */
1162 if ((image->matte != MagickFalse) &&
cristy018f07f2011-09-04 21:15:19 +00001163 (WritePS3MaskImage(image_info,image,compression,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00001164 {
1165 (void) CloseBlob(image);
1166 return(MagickFalse);
1167 }
1168 /*
1169 Remember position of BeginData comment so we can update it.
1170 */
1171 start=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00001172 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00001173 "%%%%BeginData:%13ld %s Bytes\n",0L,
1174 compression == NoCompression ? "ASCII" : "BINARY");
1175 (void) WriteBlobString(image,buffer);
1176 stop=TellBlob(image);
1177 (void) WriteBlobString(image,"DisplayImage\n");
1178 /*
1179 Translate, scale, and font point size.
1180 */
cristyb51dff52011-05-19 16:55:47 +00001181 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
cristye8c25f92010-06-03 00:53:06 +00001182 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
cristy3ed852e2009-09-05 21:47:34 +00001183 (void) WriteBlobString(image,buffer);
1184 /*
1185 Output labels.
1186 */
1187 labels=(char **) NULL;
cristyd15e6592011-10-15 00:13:06 +00001188 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00001189 if (value != (const char *) NULL)
1190 labels=StringToList(value);
1191 if (labels != (char **) NULL)
1192 {
1193 for (i=0; labels[i] != (char *) NULL; i++)
1194 {
1195 if (compression != NoCompression)
1196 {
1197 for (j=0; labels[i][j] != '\0'; j++)
1198 (void) WriteBlobByte(image,(unsigned char) labels[i][j]);
1199 (void) WriteBlobByte(image,'\n');
1200 }
1201 else
1202 {
1203 (void) WriteBlobString(image,"<~");
1204 Ascii85Initialize(image);
1205 for (j=0; labels[i][j] != '\0'; j++)
1206 Ascii85Encode(image,(unsigned char) labels[i][j]);
1207 Ascii85Flush(image);
1208 }
1209 labels[i]=DestroyString(labels[i]);
1210 }
1211 labels=(char **) RelinquishMagickMemory(labels);
1212 }
1213 /*
1214 Photoshop clipping path active?
1215 */
1216 if ((image->clip_mask != (Image *) NULL) &&
1217 (LocaleNCompare("8BIM:",image->clip_mask->magick_filename,5) == 0))
1218 (void) WriteBlobString(image,"true\n");
1219 else
1220 (void) WriteBlobString(image,"false\n");
1221 /*
1222 Showpage for non-EPS.
1223 */
1224 (void) WriteBlobString(image, LocaleCompare(image_info->magick,"PS3") == 0 ?
1225 "true\n" : "false\n");
1226 /*
1227 Image columns, rows, and color space.
1228 */
cristyb51dff52011-05-19 16:55:47 +00001229 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%s\n",
cristy802d3642011-04-27 02:02:41 +00001230 (double) image->columns,(double) image->rows,image->colorspace ==
1231 CMYKColorspace ? PS3_CMYKColorspace : PS3_RGBColorspace);
cristy3ed852e2009-09-05 21:47:34 +00001232 (void) WriteBlobString(image,buffer);
1233 /*
1234 Masked image?
1235 */
1236 (void) WriteBlobString(image,image->matte != MagickFalse ?
1237 "true\n" : "false\n");
1238 /*
1239 Render with imagemask operator?
1240 */
1241 option=GetImageOption(image_info,"ps3:imagemask");
1242 (void) WriteBlobString(image,((option != (const char *) NULL) &&
cristy1e178e72011-08-28 19:44:34 +00001243 (IsImageMonochrome(image,exception) != MagickFalse)) ?
cristy3ed852e2009-09-05 21:47:34 +00001244 "true\n" : "false\n");
1245 /*
1246 Output pixel data.
1247 */
1248 pixels=(unsigned char *) NULL;
1249 length=0;
1250 if ((image_info->type != TrueColorType) &&
1251 (image_info->type != TrueColorMatteType) &&
1252 (image_info->type != ColorSeparationType) &&
1253 (image_info->type != ColorSeparationMatteType) &&
1254 (image->colorspace != CMYKColorspace) &&
cristy1e178e72011-08-28 19:44:34 +00001255 ((IsImageGray(image,exception) != MagickFalse) ||
1256 (IsImageMonochrome(image,exception) != MagickFalse)))
cristy3ed852e2009-09-05 21:47:34 +00001257 {
1258 /*
1259 Gray images.
1260 */
1261 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1262 switch (compression)
1263 {
1264 case NoCompression:
1265 default:
1266 {
1267 (void) WriteBlobString(image,PS3_NoCompression"\n");
1268 break;
1269 }
1270 case FaxCompression:
1271 case Group4Compression:
1272 {
1273 (void) WriteBlobString(image,PS3_FaxCompression"\n");
1274 break;
1275 }
1276 case JPEGCompression:
1277 {
1278 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1279 break;
1280 }
1281 case LZWCompression:
1282 {
1283 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1284 break;
1285 }
1286 case RLECompression:
1287 {
1288 (void) WriteBlobString(image,PS3_RLECompression"\n");
1289 break;
1290 }
1291 case ZipCompression:
1292 {
1293 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1294 break;
1295 }
1296 }
1297 /*
1298 Number of colors -- 0 for single component non-color mapped data.
1299 */
1300 (void) WriteBlobString(image,"0\n");
1301 /*
1302 1 bit or 8 bit components?
1303 */
cristyb51dff52011-05-19 16:55:47 +00001304 (void) FormatLocaleString(buffer,MaxTextExtent,"%d\n",
cristy1e178e72011-08-28 19:44:34 +00001305 IsImageMonochrome(image,exception) != MagickFalse ? 1 : 8);
cristy3ed852e2009-09-05 21:47:34 +00001306 (void) WriteBlobString(image,buffer);
1307 /*
1308 Image data.
1309 */
1310 if (compression == JPEGCompression)
cristy1e178e72011-08-28 19:44:34 +00001311 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +00001312 else
1313 if ((compression == FaxCompression) ||
1314 (compression == Group4Compression))
1315 {
1316 if (LocaleCompare(CCITTParam,"0") == 0)
cristy018f07f2011-09-04 21:15:19 +00001317 status=HuffmanEncodeImage(image_info,image,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001318 else
cristy018f07f2011-09-04 21:15:19 +00001319 status=Huffman2DEncodeImage(image_info,image,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001320 }
1321 else
1322 {
cristy018f07f2011-09-04 21:15:19 +00001323 status=SerializeImageChannel(image_info,image,&pixels,&length,
1324 exception);
cristy3ed852e2009-09-05 21:47:34 +00001325 if (status == MagickFalse)
1326 {
1327 (void) CloseBlob(image);
1328 return(MagickFalse);
1329 }
1330 switch (compression)
1331 {
1332 case NoCompression:
1333 default:
1334 {
1335 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001336 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00001337 Ascii85Encode(image,pixels[i]);
1338 Ascii85Flush(image);
1339 status=MagickTrue;
1340 break;
1341 }
1342 case LZWCompression:
1343 {
cristy018f07f2011-09-04 21:15:19 +00001344 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001345 break;
1346 }
1347 case RLECompression:
1348 {
cristy018f07f2011-09-04 21:15:19 +00001349 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001350 break;
1351 }
1352 case ZipCompression:
1353 {
cristy018f07f2011-09-04 21:15:19 +00001354 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001355 break;
1356 }
1357 }
1358 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1359 }
1360 }
1361 else
1362 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1363 (compression == JPEGCompression))
1364 {
1365 /*
1366 Truecolor image.
1367 */
1368 (void) WriteBlobString(image,PS3_DirectClass"\n");
1369 switch (compression)
1370 {
1371 case NoCompression:
1372 default:
1373 {
1374 (void) WriteBlobString(image,PS3_NoCompression"\n");
1375 break;
1376 }
1377 case RLECompression:
1378 {
1379 (void) WriteBlobString(image,PS3_RLECompression"\n");
1380 break;
1381 }
1382 case JPEGCompression:
1383 {
1384 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1385 break;
1386 }
1387 case LZWCompression:
1388 {
1389 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1390 break;
1391 }
1392 case ZipCompression:
1393 {
1394 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1395 break;
1396 }
1397 }
1398 /*
1399 Image data.
1400 */
1401 if (compression == JPEGCompression)
cristy1e178e72011-08-28 19:44:34 +00001402 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +00001403 else
1404 {
1405 /*
1406 Stream based compressions.
1407 */
cristy018f07f2011-09-04 21:15:19 +00001408 status=SerializeImage(image_info,image,&pixels,&length,exception);
cristy3ed852e2009-09-05 21:47:34 +00001409 if (status == MagickFalse)
1410 {
1411 (void) CloseBlob(image);
1412 return(MagickFalse);
1413 }
1414 switch (compression)
1415 {
1416 case NoCompression:
1417 default:
1418 {
1419 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001420 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00001421 Ascii85Encode(image,pixels[i]);
1422 Ascii85Flush(image);
1423 status=MagickTrue;
1424 break;
1425 }
1426 case RLECompression:
1427 {
cristy018f07f2011-09-04 21:15:19 +00001428 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001429 break;
1430 }
1431 case LZWCompression:
1432 {
cristy018f07f2011-09-04 21:15:19 +00001433 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001434 break;
1435 }
1436 case ZipCompression:
1437 {
cristy018f07f2011-09-04 21:15:19 +00001438 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001439 break;
1440 }
1441 }
1442 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1443 }
1444 }
1445 else
1446 {
1447 /*
1448 Colormapped images.
1449 */
1450 (void) WriteBlobString(image,PS3_PseudoClass"\n");
1451 switch (compression)
1452 {
1453 case NoCompression:
1454 default:
1455 {
1456 (void) WriteBlobString(image,PS3_NoCompression"\n");
1457 break;
1458 }
1459 case JPEGCompression:
1460 {
1461 (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1462 break;
1463 }
1464 case RLECompression:
1465 {
1466 (void) WriteBlobString(image,PS3_RLECompression"\n");
1467 break;
1468 }
1469 case LZWCompression:
1470 {
1471 (void) WriteBlobString(image,PS3_LZWCompression"\n");
1472 break;
1473 }
1474 case ZipCompression:
1475 {
1476 (void) WriteBlobString(image,PS3_ZipCompression"\n");
1477 break;
1478 }
1479 }
1480 /*
1481 Number of colors in color map.
1482 */
cristyb51dff52011-05-19 16:55:47 +00001483 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001484 (double) image->colors);
cristy3ed852e2009-09-05 21:47:34 +00001485 (void) WriteBlobString(image,buffer);
1486 /*
1487 Color map - uncompressed.
1488 */
1489 if ((compression != NoCompression) &&
1490 (compression != UndefinedCompression))
1491 {
cristybb503372010-05-27 20:51:26 +00001492 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001493 {
1494 pixel=ScaleQuantumToChar(image->colormap[i].red);
1495 (void) WriteBlobByte(image,(unsigned char) pixel);
1496 pixel=ScaleQuantumToChar(image->colormap[i].green);
1497 (void) WriteBlobByte(image,(unsigned char) pixel);
1498 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1499 (void) WriteBlobByte(image,(unsigned char) pixel);
1500 }
1501 }
1502 else
1503 {
1504 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001505 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001506 {
1507 pixel=ScaleQuantumToChar(image->colormap[i].red);
1508 Ascii85Encode(image,(unsigned char) pixel);
1509 pixel=ScaleQuantumToChar(image->colormap[i].green);
1510 Ascii85Encode(image,(unsigned char) pixel);
1511 pixel=ScaleQuantumToChar(image->colormap[i].blue);
1512 Ascii85Encode(image,(unsigned char) pixel);
1513 }
1514 Ascii85Flush(image);
1515 }
cristy018f07f2011-09-04 21:15:19 +00001516 status=SerializeImageIndexes(image_info,image,&pixels,&length,
1517 exception);
cristy3ed852e2009-09-05 21:47:34 +00001518 if (status == MagickFalse)
1519 {
1520 (void) CloseBlob(image);
1521 return(MagickFalse);
1522 }
1523 switch (compression)
1524 {
1525 case NoCompression:
1526 default:
1527 {
1528 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001529 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00001530 Ascii85Encode(image,pixels[i]);
1531 Ascii85Flush(image);
1532 status=MagickTrue;
1533 break;
1534 }
1535 case JPEGCompression:
1536 {
cristy1e178e72011-08-28 19:44:34 +00001537 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +00001538 break;
1539 }
1540 case RLECompression:
1541 {
cristy018f07f2011-09-04 21:15:19 +00001542 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001543 break;
1544 }
1545 case LZWCompression:
1546 {
cristy018f07f2011-09-04 21:15:19 +00001547 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001548 break;
1549 }
1550 case ZipCompression:
1551 {
cristy018f07f2011-09-04 21:15:19 +00001552 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001553 break;
1554 }
1555 }
1556 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1557 }
1558 (void) WriteBlobByte(image,'\n');
1559 if (status == MagickFalse)
1560 {
1561 (void) CloseBlob(image);
1562 return(MagickFalse);
1563 }
1564 /*
1565 Update BeginData now that we know the data size.
1566 */
1567 length=(size_t) (TellBlob(image)-stop);
1568 stop=TellBlob(image);
1569 offset=SeekBlob(image,start,SEEK_SET);
1570 if (offset < 0)
1571 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
cristyb51dff52011-05-19 16:55:47 +00001572 (void) FormatLocaleString(buffer,MaxTextExtent,
cristyf2faecf2010-05-28 19:19:36 +00001573 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
cristy3ed852e2009-09-05 21:47:34 +00001574 compression == NoCompression ? "ASCII" : "BINARY");
1575 (void) WriteBlobString(image,buffer);
1576 offset=SeekBlob(image,stop,SEEK_SET);
1577 (void) WriteBlobString(image,"%%EndData\n");
1578 /*
1579 End private dictionary if this an EPS.
1580 */
1581 if (LocaleCompare(image_info->magick,"PS3") != 0)
1582 (void) WriteBlobString(image,"end\n");
1583 (void) WriteBlobString(image,"%%PageTrailer\n");
1584 if (GetNextImageInList(image) == (Image *) NULL)
1585 break;
1586 image=SyncNextImageInList(image);
1587 status=SetImageProgress(image,SaveImagesTag,scene++,
1588 GetImageListLength(image));
1589 if (status == MagickFalse)
1590 break;
1591 } while (image_info->adjoin != MagickFalse);
1592 (void) WriteBlobString(image,"%%Trailer\n");
1593 if (page > 1)
1594 {
cristyb51dff52011-05-19 16:55:47 +00001595 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001596 "%%%%BoundingBox: %g %g %g %g\n",floor(bounds.x1+0.5),
cristy3ed852e2009-09-05 21:47:34 +00001597 floor(bounds.y1+0.5),ceil(bounds.x2-0.5),ceil(bounds.y2-0.5));
1598 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001599 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001600 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
cristy3ed852e2009-09-05 21:47:34 +00001601 bounds.x2,bounds.y2);
1602 (void) WriteBlobString(image,buffer);
1603 }
1604 (void) WriteBlobString(image,"%%EOF\n");
1605 (void) CloseBlob(image);
1606 return(MagickTrue);
1607}