blob: cb342243943566571c509c2280b8e7e26338bffd [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% PPPP SSSSS %
7% P P SS %
8% PPPP SSS %
9% P SS %
10% P SSSSS %
11% %
12% %
13% Read/Write Postscript Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000050#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000051#include "MagickCore/constitute.h"
52#include "MagickCore/delegate.h"
53#include "MagickCore/delegate-private.h"
54#include "MagickCore/draw.h"
55#include "MagickCore/exception.h"
56#include "MagickCore/exception-private.h"
57#include "MagickCore/geometry.h"
58#include "MagickCore/image.h"
59#include "MagickCore/image-private.h"
60#include "MagickCore/list.h"
61#include "MagickCore/magick.h"
62#include "MagickCore/memory_.h"
63#include "MagickCore/monitor.h"
64#include "MagickCore/monitor-private.h"
65#include "MagickCore/option.h"
66#include "MagickCore/profile.h"
67#include "MagickCore/resource_.h"
68#include "MagickCore/pixel-accessor.h"
69#include "MagickCore/property.h"
70#include "MagickCore/quantum-private.h"
71#include "MagickCore/static.h"
72#include "MagickCore/string_.h"
73#include "MagickCore/module.h"
74#include "MagickCore/token.h"
75#include "MagickCore/transform.h"
76#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000077
78/*
79 Forward declarations.
80*/
81static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000082 WritePSImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000083
84/*
85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86% %
87% %
88% %
89% I n v o k e P o s t s r i p t D e l e g a t e %
90% %
91% %
92% %
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94%
cristydefb3f02009-09-10 02:18:35 +000095% InvokePostscriptDelegate() executes the Postscript interpreter with the
cristy3ed852e2009-09-05 21:47:34 +000096% specified command.
97%
98% The format of the InvokePostscriptDelegate method is:
99%
100% MagickBooleanType InvokePostscriptDelegate(
cristyb32b90a2009-09-07 21:45:48 +0000101% const MagickBooleanType verbose,const char *command,
102% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000103%
104% A description of each parameter follows:
105%
106% o verbose: A value other than zero displays the command prior to
107% executing it.
108%
109% o command: the address of a character string containing the command to
110% execute.
111%
cristyb32b90a2009-09-07 21:45:48 +0000112% o exception: return any errors or warnings in this structure.
113%
cristy3ed852e2009-09-05 21:47:34 +0000114*/
115static MagickBooleanType InvokePostscriptDelegate(
cristyb32b90a2009-09-07 21:45:48 +0000116 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000117{
cristyb32b90a2009-09-07 21:45:48 +0000118 int
119 status;
120
cristy0157aea2010-04-24 21:12:18 +0000121#if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000122 char
123 **argv;
124
cristydefb3f02009-09-10 02:18:35 +0000125 const GhostInfo
126 *ghost_info;
cristy3ed852e2009-09-05 21:47:34 +0000127
128 gs_main_instance
129 *interpreter;
130
131 int
132 argc,
cristyb32b90a2009-09-07 21:45:48 +0000133 code;
cristy3ed852e2009-09-05 21:47:34 +0000134
cristybb503372010-05-27 20:51:26 +0000135 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000136 i;
137
cristy0157aea2010-04-24 21:12:18 +0000138#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristydefb3f02009-09-10 02:18:35 +0000139 ghost_info=NTGhostscriptDLLVectors();
cristy3ed852e2009-09-05 21:47:34 +0000140#else
cristydefb3f02009-09-10 02:18:35 +0000141 GhostInfo
142 ghost_info_struct;
cristy3ed852e2009-09-05 21:47:34 +0000143
cristydefb3f02009-09-10 02:18:35 +0000144 ghost_info=(&ghost_info_struct);
145 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
146 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
cristy3ed852e2009-09-05 21:47:34 +0000147 gsapi_new_instance;
cristydefb3f02009-09-10 02:18:35 +0000148 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
cristy3ed852e2009-09-05 21:47:34 +0000149 gsapi_init_with_args;
cristydefb3f02009-09-10 02:18:35 +0000150 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
151 int *)) gsapi_run_string;
152 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
cristy3ed852e2009-09-05 21:47:34 +0000153 gsapi_delete_instance;
cristydefb3f02009-09-10 02:18:35 +0000154 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
cristy3ed852e2009-09-05 21:47:34 +0000155#endif
cristydefb3f02009-09-10 02:18:35 +0000156 if (ghost_info == (GhostInfo *) NULL)
cristyb32b90a2009-09-07 21:45:48 +0000157 {
cristy6de4bc22010-01-12 17:10:35 +0000158 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000159 return(status == 0 ? MagickTrue : MagickFalse);
cristyb32b90a2009-09-07 21:45:48 +0000160 }
cristy3ed852e2009-09-05 21:47:34 +0000161 if (verbose != MagickFalse)
162 {
163 (void) fputs("[ghostscript library]",stdout);
164 (void) fputs(strchr(command,' '),stdout);
165 }
cristydefb3f02009-09-10 02:18:35 +0000166 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000167 if (status < 0)
cristyb32b90a2009-09-07 21:45:48 +0000168 {
cristy6de4bc22010-01-12 17:10:35 +0000169 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000170 return(status == 0 ? MagickTrue : MagickFalse);
cristyb32b90a2009-09-07 21:45:48 +0000171 }
cristya73c0f82010-12-20 15:57:05 +0000172 code=0;
cristy3ed852e2009-09-05 21:47:34 +0000173 argv=StringToArgv(command,&argc);
cristydefb3f02009-09-10 02:18:35 +0000174 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
cristy3ed852e2009-09-05 21:47:34 +0000175 if (status == 0)
cristydefb3f02009-09-10 02:18:35 +0000176 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
177 0,&code);
178 (ghost_info->exit)(interpreter);
179 (ghost_info->delete_instance)(interpreter);
cristy0157aea2010-04-24 21:12:18 +0000180#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000181 NTGhostscriptUnLoadDLL();
182#endif
cristybb503372010-05-27 20:51:26 +0000183 for (i=0; i < (ssize_t) argc; i++)
cristy3ed852e2009-09-05 21:47:34 +0000184 argv[i]=DestroyString(argv[i]);
185 argv=(char **) RelinquishMagickMemory(argv);
cristy41083a42009-09-07 23:47:59 +0000186 if ((status != 0) && (status != -101))
187 {
188 char
189 *message;
cristyb32b90a2009-09-07 21:45:48 +0000190
cristy41083a42009-09-07 23:47:59 +0000191 message=GetExceptionMessage(errno);
192 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
193 "`%s': %s",command,message);
194 message=DestroyString(message);
195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
196 "Ghostscript returns status %d, exit code %d",status,code);
197 return(MagickFalse);
198 }
cristy3ed852e2009-09-05 21:47:34 +0000199 return(MagickTrue);
200#else
cristy6de4bc22010-01-12 17:10:35 +0000201 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000202 return(status == 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000203#endif
204}
205
206/*
207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208% %
209% %
210% %
211% I s P S %
212% %
213% %
214% %
215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216%
217% IsPS() returns MagickTrue if the image format type, identified by the
218% magick string, is PS.
219%
220% The format of the IsPS method is:
221%
222% MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
223%
224% A description of each parameter follows:
225%
226% o magick: compare image format pattern against these bytes.
227%
228% o length: Specifies the length of the magick string.
229%
230*/
231static MagickBooleanType IsPS(const unsigned char *magick,const size_t length)
232{
233 if (length < 4)
234 return(MagickFalse);
235 if (memcmp(magick,"%!",2) == 0)
236 return(MagickTrue);
237 if (memcmp(magick,"\004%!",3) == 0)
238 return(MagickTrue);
239 return(MagickFalse);
240}
241
242/*
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244% %
245% %
246% %
247% R e a d P S I m a g e %
248% %
249% %
250% %
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252%
253% ReadPSImage() reads a Postscript image file and returns it. It allocates
254% the memory necessary for the new Image structure and returns a pointer
255% to the new image.
256%
257% The format of the ReadPSImage method is:
258%
259% Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
260%
261% A description of each parameter follows:
262%
263% o image_info: the image info.
264%
265% o exception: return any errors or warnings in this structure.
266%
267*/
268
269static MagickBooleanType IsPostscriptRendered(const char *path)
270{
271 MagickBooleanType
272 status;
273
274 struct stat
275 attributes;
276
277 if ((path == (const char *) NULL) || (*path == '\0'))
278 return(MagickFalse);
279 status=GetPathAttributes(path,&attributes);
280 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
281 (attributes.st_size > 0))
282 return(MagickTrue);
283 return(MagickFalse);
284}
285
286static inline int ProfileInteger(Image *image,short int *hex_digits)
287{
288 int
289 c,
290 l,
291 value;
292
cristybb503372010-05-27 20:51:26 +0000293 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000294 i;
295
296 l=0;
297 value=0;
298 for (i=0; i < 2; )
299 {
300 c=ReadBlobByte(image);
301 if ((c == EOF) || ((c == '%') && (l == '%')))
302 {
303 value=(-1);
304 break;
305 }
306 l=c;
307 c&=0xff;
308 if (isxdigit(c) == MagickFalse)
309 continue;
cristybb503372010-05-27 20:51:26 +0000310 value=(int) ((size_t) value << 4)+hex_digits[c];
cristy3ed852e2009-09-05 21:47:34 +0000311 i++;
312 }
313 return(value);
314}
315
316static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
317{
318#define BoundingBox "BoundingBox:"
319#define BeginDocument "BeginDocument:"
320#define BeginXMPPacket "<?xpacket begin="
321#define EndXMPPacket "<?xpacket end="
322#define ICCProfile "BeginICCProfile:"
323#define CMYKCustomColor "CMYKCustomColor:"
cristy01ca8922010-03-17 12:20:37 +0000324#define CMYKProcessColor "CMYKProcessColor:"
cristy3ed852e2009-09-05 21:47:34 +0000325#define DocumentMedia "DocumentMedia:"
326#define DocumentCustomColors "DocumentCustomColors:"
327#define DocumentProcessColors "DocumentProcessColors:"
328#define EndDocument "EndDocument:"
329#define HiResBoundingBox "HiResBoundingBox:"
330#define ImageData "ImageData:"
331#define PageBoundingBox "PageBoundingBox:"
332#define LanguageLevel "LanguageLevel:"
333#define PageMedia "PageMedia:"
334#define Pages "Pages:"
335#define PhotoshopProfile "BeginPhotoshop:"
336#define PostscriptLevel "!PS-"
337#define RenderPostscriptText " Rendering Postscript... "
338#define SpotColor "+ "
339
340 char
341 command[MaxTextExtent],
342 density[MaxTextExtent],
343 filename[MaxTextExtent],
344 geometry[MaxTextExtent],
345 input_filename[MaxTextExtent],
346 options[MaxTextExtent],
cristyc39e3d62010-10-14 16:52:01 +0000347 postscript_filename[MaxTextExtent];
cristy3ed852e2009-09-05 21:47:34 +0000348
349 const char
350 *option;
351
352 const DelegateInfo
353 *delegate_info;
354
355 GeometryInfo
356 geometry_info;
357
358 Image
359 *image,
360 *next,
361 *postscript_image;
362
363 ImageInfo
364 *read_info;
365
366 int
367 c,
368 file;
369
370 MagickBooleanType
371 cmyk,
372 skip,
373 status;
374
375 MagickStatusType
376 flags;
377
378 PointInfo
379 delta;
380
381 RectangleInfo
382 page;
383
384 register char
385 *p;
386
cristybb503372010-05-27 20:51:26 +0000387 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000388 i;
389
390 SegmentInfo
391 bounds,
392 hires_bounds;
393
394 short int
395 hex_digits[256];
396
397 size_t
398 length;
399
400 ssize_t
401 count;
402
403 StringInfo
404 *profile;
405
cristyf2faecf2010-05-28 19:19:36 +0000406 unsigned long
cristy3ed852e2009-09-05 21:47:34 +0000407 columns,
408 extent,
409 language_level,
410 pages,
411 rows,
412 scene,
413 spotcolor;
414
415 /*
416 Open image file.
417 */
418 assert(image_info != (const ImageInfo *) NULL);
419 assert(image_info->signature == MagickSignature);
420 if (image_info->debug != MagickFalse)
421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
422 image_info->filename);
423 assert(exception != (ExceptionInfo *) NULL);
424 assert(exception->signature == MagickSignature);
425 image=AcquireImage(image_info);
426 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
427 if (status == MagickFalse)
428 {
429 image=DestroyImageList(image);
430 return((Image *) NULL);
431 }
432 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
433 if (status == MagickFalse)
434 {
435 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
436 image_info->filename);
437 image=DestroyImageList(image);
438 return((Image *) NULL);
439 }
440 /*
441 Initialize hex values.
442 */
443 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits));
444 hex_digits[(int) '0']=0;
445 hex_digits[(int) '1']=1;
446 hex_digits[(int) '2']=2;
447 hex_digits[(int) '3']=3;
448 hex_digits[(int) '4']=4;
449 hex_digits[(int) '5']=5;
450 hex_digits[(int) '6']=6;
451 hex_digits[(int) '7']=7;
452 hex_digits[(int) '8']=8;
453 hex_digits[(int) '9']=9;
454 hex_digits[(int) 'a']=10;
455 hex_digits[(int) 'b']=11;
456 hex_digits[(int) 'c']=12;
457 hex_digits[(int) 'd']=13;
458 hex_digits[(int) 'e']=14;
459 hex_digits[(int) 'f']=15;
460 hex_digits[(int) 'A']=10;
461 hex_digits[(int) 'B']=11;
462 hex_digits[(int) 'C']=12;
463 hex_digits[(int) 'D']=13;
464 hex_digits[(int) 'E']=14;
465 hex_digits[(int) 'F']=15;
466 /*
467 Set the page density.
468 */
469 delta.x=DefaultResolution;
470 delta.y=DefaultResolution;
471 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
472 {
473 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
474 image->x_resolution=geometry_info.rho;
475 image->y_resolution=geometry_info.sigma;
476 if ((flags & SigmaValue) == 0)
477 image->y_resolution=image->x_resolution;
478 }
479 /*
480 Determine page geometry from the Postscript bounding box.
481 */
482 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
483 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
484 (void) ResetMagickMemory(&page,0,sizeof(page));
485 (void) ResetMagickMemory(command,0,sizeof(command));
486 hires_bounds.x2=0.0;
487 hires_bounds.y2=0.0;
488 columns=0;
489 rows=0;
490 extent=0;
491 spotcolor=0;
492 language_level=1;
493 skip=MagickFalse;
494 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
495 pages=(~0UL);
496 p=command;
497 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
498 {
499 /*
500 Note document structuring comments.
501 */
502 *p++=(char) c;
503 if ((strchr("\n\r%",c) == (char *) NULL) &&
504 ((size_t) (p-command) < (MaxTextExtent-1)))
505 continue;
506 *p='\0';
507 p=command;
508 /*
509 Skip %%BeginDocument thru %%EndDocument.
510 */
511 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0)
512 skip=MagickTrue;
513 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0)
514 skip=MagickFalse;
515 if (skip != MagickFalse)
516 continue;
517 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0)
518 {
519 (void) SetImageProperty(image,"ps:Level",command+4);
520 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse)
521 pages=1;
522 }
523 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0)
524 (void) sscanf(command,LanguageLevel " %lu",&language_level);
525 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0)
526 (void) sscanf(command,Pages " %lu",&pages);
cristy97841ba2010-09-02 15:48:08 +0000527 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000528 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows);
cristy97841ba2010-09-02 15:48:08 +0000529 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000530 {
531 unsigned char
532 *datum;
533
534 /*
535 Read ICC profile.
536 */
537 profile=AcquireStringInfo(65536);
538 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++)
539 {
540 SetStringInfoLength(profile,(size_t) i+1);
541 datum=GetStringInfoDatum(profile);
542 datum[i]=(unsigned char) c;
543 }
544 (void) SetImageProfile(image,"icc",profile);
545 profile=DestroyStringInfo(profile);
546 continue;
547 }
548 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0)
549 {
550 unsigned char
551 *p;
552
553 /*
554 Read Photoshop profile.
555 */
556 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
557 if (count != 1)
558 continue;
559 length=extent;
cristy8723e4b2011-09-01 13:11:19 +0000560 profile=BlobToStringInfo((const void *) NULL,length);
cristy3ed852e2009-09-05 21:47:34 +0000561 p=GetStringInfoDatum(profile);
cristybb503372010-05-27 20:51:26 +0000562 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +0000563 *p++=(unsigned char) ProfileInteger(image,hex_digits);
564 (void) SetImageProfile(image,"8bim",profile);
565 profile=DestroyStringInfo(profile);
566 continue;
567 }
568 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
569 {
570 register size_t
571 i;
572
573 /*
574 Read XMP profile.
575 */
576 p=command;
577 profile=StringToStringInfo(command);
578 for (i=GetStringInfoLength(profile)-1; c != EOF; i++)
579 {
580 SetStringInfoLength(profile,i+1);
581 c=ReadBlobByte(image);
582 GetStringInfoDatum(profile)[i]=(unsigned char) c;
583 *p++=(char) c;
584 if ((strchr("\n\r%",c) == (char *) NULL) &&
585 ((size_t) (p-command) < (MaxTextExtent-1)))
586 continue;
587 *p='\0';
588 p=command;
589 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
590 break;
591 }
592 SetStringInfoLength(profile,i);
593 (void) SetImageProfile(image,"xmp",profile);
594 profile=DestroyStringInfo(profile);
595 continue;
596 }
597 /*
598 Is this a CMYK document?
599 */
600 length=strlen(DocumentProcessColors);
601 if (LocaleNCompare(DocumentProcessColors,command,length) == 0)
602 {
603 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) ||
604 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) ||
605 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse))
606 cmyk=MagickTrue;
607 }
608 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0)
609 cmyk=MagickTrue;
cristy01ca8922010-03-17 12:20:37 +0000610 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
611 cmyk=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000612 length=strlen(DocumentCustomColors);
613 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) ||
614 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) ||
615 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0))
616 {
617 char
618 property[MaxTextExtent],
619 *value;
620
621 register char
622 *p;
623
624 /*
625 Note spot names.
626 */
cristyb51dff52011-05-19 16:55:47 +0000627 (void) FormatLocaleString(property,MaxTextExtent,"ps:SpotColor-%.20g",
cristye8c25f92010-06-03 00:53:06 +0000628 (double) (spotcolor++));
cristy3ed852e2009-09-05 21:47:34 +0000629 for (p=command; *p != '\0'; p++)
630 if (isspace((int) (unsigned char) *p) != 0)
631 break;
632 value=AcquireString(p);
633 (void) SubstituteString(&value,"(","");
634 (void) SubstituteString(&value,")","");
635 (void) StripString(value);
636 (void) SetImageProperty(image,property,value);
637 value=DestroyString(value);
638 continue;
639 }
640 /*
641 Note region defined by bounding box.
642 */
643 count=0;
644 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
645 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf",&bounds.x1,
646 &bounds.y1,&bounds.x2,&bounds.y2);
647 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
648 count=(ssize_t) sscanf(command,DocumentMedia " %*s %lf %lf",&bounds.x2,
649 &bounds.y2)+2;
650 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0)
651 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf",
652 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
653 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
654 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf",
655 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
656 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0)
657 count=(ssize_t) sscanf(command,PageMedia " %*s %lf %lf",&bounds.x2,
658 &bounds.y2)+2;
659 if (count != 4)
660 continue;
661 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
662 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
663 {
664 /*
665 Set Postscript render geometry.
666 */
cristyb51dff52011-05-19 16:55:47 +0000667 (void) FormatLocaleString(geometry,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +0000668 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +0000669 bounds.x1,bounds.y1);
cristy3ed852e2009-09-05 21:47:34 +0000670 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry);
cristybb503372010-05-27 20:51:26 +0000671 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
672 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000673 hires_bounds=bounds;
674 }
675 }
676 (void) CloseBlob(image);
cristy510d06a2011-07-06 23:43:54 +0000677 if (IsRGBColorspace(image_info->colorspace) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000678 cmyk=MagickFalse;
679 /*
680 Create Ghostscript control file.
681 */
682 file=AcquireUniqueFileResource(postscript_filename);
683 if (file == -1)
684 {
685 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
686 image_info->filename);
687 image=DestroyImageList(image);
688 return((Image *) NULL);
689 }
690 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
691 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n"
692 "<</UseCIEColor true>>setpagedevice\n",MaxTextExtent);
693 count=write(file,command,(unsigned int) strlen(command));
cristyc39e3d62010-10-14 16:52:01 +0000694 if (image_info->page == (char *) NULL)
695 {
696 char
697 translate_geometry[MaxTextExtent];
698
cristyb51dff52011-05-19 16:55:47 +0000699 (void) FormatLocaleString(translate_geometry,MaxTextExtent,
cristyc39e3d62010-10-14 16:52:01 +0000700 "%g %g translate\n",-bounds.x1,-bounds.y1);
701 count=write(file,translate_geometry,(unsigned int)
702 strlen(translate_geometry));
703 }
cristy3ed852e2009-09-05 21:47:34 +0000704 file=close(file)-1;
705 /*
706 Render Postscript with the Ghostscript delegate.
707 */
708 if (image_info->monochrome != MagickFalse)
709 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
710 else
711 if (cmyk != MagickFalse)
712 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
713 else
cristya97426c2011-02-04 01:41:27 +0000714 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000715 if (delegate_info == (const DelegateInfo *) NULL)
716 {
717 (void) RelinquishUniqueFileResource(postscript_filename);
718 image=DestroyImageList(image);
719 return((Image *) NULL);
720 }
721 *options='\0';
722 if ((page.width == 0) || (page.height == 0))
723 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
cristydba40d42010-03-25 18:31:50 +0000724 if (image_info->density != (char *) NULL)
725 {
726 flags=ParseGeometry(image_info->density,&geometry_info);
727 image->x_resolution=geometry_info.rho;
728 image->y_resolution=geometry_info.sigma;
729 if ((flags & SigmaValue) == 0)
730 image->y_resolution=image->x_resolution;
731 }
cristyb51dff52011-05-19 16:55:47 +0000732 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",
cristy8cd5b312010-01-07 01:10:24 +0000733 image->x_resolution,image->y_resolution);
cristydba40d42010-03-25 18:31:50 +0000734 if (image_info->page != (char *) NULL)
735 (void) ParseAbsoluteGeometry(image_info->page,&page);
cristya97426c2011-02-04 01:41:27 +0000736 page.width=(size_t) floor((double) (page.width*image->x_resolution/delta.x)+
737 0.5);
738 page.height=(size_t) floor((double) (page.height*image->y_resolution/delta.y)+
cristy06609ee2010-03-17 20:21:27 +0000739 0.5);
cristyb51dff52011-05-19 16:55:47 +0000740 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
cristye8c25f92010-06-03 00:53:06 +0000741 page.width,(double) page.height);
cristy3ed852e2009-09-05 21:47:34 +0000742 read_info=CloneImageInfo(image_info);
743 *read_info->magick='\0';
744 if (read_info->number_scenes != 0)
745 {
746 char
747 pages[MaxTextExtent];
748
cristyb51dff52011-05-19 16:55:47 +0000749 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
cristye8c25f92010-06-03 00:53:06 +0000750 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
cristyf2faecf2010-05-28 19:19:36 +0000751 (read_info->scene+read_info->number_scenes));
cristy3ed852e2009-09-05 21:47:34 +0000752 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
753 read_info->number_scenes=0;
754 if (read_info->scenes != (char *) NULL)
755 *read_info->scenes='\0';
756 }
757 option=GetImageOption(image_info,"ps:use-cropbox");
758 if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse))
759 (void) ConcatenateMagickString(options,"-dEPSCrop ",MaxTextExtent);
760 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
cristya97426c2011-02-04 01:41:27 +0000761 (void) AcquireUniqueFilename(filename);
762 (void) ConcatenateMagickString(filename,"-%08d",MaxTextExtent);
cristyb51dff52011-05-19 16:55:47 +0000763 (void) FormatLocaleString(command,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000764 GetDelegateCommands(delegate_info),
765 read_info->antialias != MagickFalse ? 4 : 1,
cristya97426c2011-02-04 01:41:27 +0000766 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
767 postscript_filename,input_filename);
cristyb32b90a2009-09-07 21:45:48 +0000768 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
cristya97426c2011-02-04 01:41:27 +0000769 (void) InterpretImageFilename(image_info,image,filename,1,
770 read_info->filename);
cristy41083a42009-09-07 23:47:59 +0000771 if ((status == MagickFalse) ||
cristy3ed852e2009-09-05 21:47:34 +0000772 (IsPostscriptRendered(read_info->filename) == MagickFalse))
773 {
774 (void) ConcatenateMagickString(command," -c showpage",MaxTextExtent);
cristyb32b90a2009-09-07 21:45:48 +0000775 status=InvokePostscriptDelegate(read_info->verbose,command,exception);
cristy3ed852e2009-09-05 21:47:34 +0000776 }
cristy3ed852e2009-09-05 21:47:34 +0000777 (void) RelinquishUniqueFileResource(postscript_filename);
cristy3ed852e2009-09-05 21:47:34 +0000778 (void) RelinquishUniqueFileResource(input_filename);
cristya97426c2011-02-04 01:41:27 +0000779 postscript_image=(Image *) NULL;
780 if (status == MagickFalse)
781 for (i=1; ; i++)
782 {
cristya97426c2011-02-04 01:41:27 +0000783 (void) InterpretImageFilename(image_info,image,filename,(int) i,
784 read_info->filename);
785 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
786 break;
787 (void) RelinquishUniqueFileResource(read_info->filename);
788 }
789 else
790 for (i=1; ; i++)
791 {
cristya97426c2011-02-04 01:41:27 +0000792 (void) InterpretImageFilename(image_info,image,filename,(int) i,
793 read_info->filename);
794 if (IsPostscriptRendered(read_info->filename) == MagickFalse)
795 break;
796 next=ReadImage(read_info,exception);
797 (void) RelinquishUniqueFileResource(read_info->filename);
798 if (next == (Image *) NULL)
799 break;
800 AppendImageToList(&postscript_image,next);
801 }
802 (void) RelinquishUniqueFileResource(read_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000803 read_info=DestroyImageInfo(read_info);
804 if (postscript_image == (Image *) NULL)
805 {
806 image=DestroyImageList(image);
807 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
808 image_info->filename);
809 return((Image *) NULL);
810 }
811 if (LocaleCompare(postscript_image->magick,"BMP") == 0)
812 {
813 Image
814 *cmyk_image;
815
816 cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
817 if (cmyk_image != (Image *) NULL)
818 {
819 postscript_image=DestroyImageList(postscript_image);
820 postscript_image=cmyk_image;
821 }
822 }
823 if (image_info->number_scenes != 0)
824 {
825 Image
826 *clone_image;
827
cristybb503372010-05-27 20:51:26 +0000828 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000829 i;
830
831 /*
832 Add place holder images to meet the subimage specification requirement.
833 */
cristybb503372010-05-27 20:51:26 +0000834 for (i=0; i < (ssize_t) image_info->scene; i++)
cristy3ed852e2009-09-05 21:47:34 +0000835 {
836 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
837 if (clone_image != (Image *) NULL)
838 PrependImageToList(&postscript_image,clone_image);
839 }
840 }
841 do
842 {
843 (void) CopyMagickString(postscript_image->filename,filename,MaxTextExtent);
844 if (columns != 0)
845 postscript_image->magick_columns=columns;
846 if (rows != 0)
847 postscript_image->magick_rows=rows;
848 postscript_image->page=page;
849 (void) CloneImageProfiles(postscript_image,image);
850 (void) CloneImageProperties(postscript_image,image);
851 next=SyncNextImageInList(postscript_image);
852 if (next != (Image *) NULL)
853 postscript_image=next;
854 } while (next != (Image *) NULL);
855 image=DestroyImageList(image);
856 scene=0;
857 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
858 {
859 next->scene=scene++;
860 next=GetNextImageInList(next);
861 }
862 return(GetFirstImageInList(postscript_image));
863}
864
865/*
866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867% %
868% %
869% %
870% R e g i s t e r P S I m a g e %
871% %
872% %
873% %
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875%
876% RegisterPSImage() adds properties for the PS image format to
877% the list of supported formats. The properties include the image format
878% tag, a method to read and/or write the format, whether the format
879% supports the saving of more than one frame to the same file or blob,
880% whether the format supports native in-memory I/O, and a brief
881% description of the format.
882%
883% The format of the RegisterPSImage method is:
884%
cristybb503372010-05-27 20:51:26 +0000885% size_t RegisterPSImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000886%
887*/
cristybb503372010-05-27 20:51:26 +0000888ModuleExport size_t RegisterPSImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000889{
890 MagickInfo
891 *entry;
892
893 entry=SetMagickInfo("EPI");
894 entry->decoder=(DecodeImageHandler *) ReadPSImage;
895 entry->encoder=(EncodeImageHandler *) WritePSImage;
896 entry->magick=(IsImageFormatHandler *) IsPS;
897 entry->adjoin=MagickFalse;
898 entry->blob_support=MagickFalse;
899 entry->seekable_stream=MagickTrue;
900 entry->thread_support=EncoderThreadSupport;
901 entry->description=ConstantString(
902 "Encapsulated PostScript Interchange format");
903 entry->module=ConstantString("PS");
904 (void) RegisterMagickInfo(entry);
905 entry=SetMagickInfo("EPS");
906 entry->decoder=(DecodeImageHandler *) ReadPSImage;
907 entry->encoder=(EncodeImageHandler *) WritePSImage;
908 entry->magick=(IsImageFormatHandler *) IsPS;
909 entry->adjoin=MagickFalse;
910 entry->blob_support=MagickFalse;
911 entry->seekable_stream=MagickTrue;
912 entry->thread_support=EncoderThreadSupport;
913 entry->description=ConstantString("Encapsulated PostScript");
914 entry->module=ConstantString("PS");
915 (void) RegisterMagickInfo(entry);
916 entry=SetMagickInfo("EPSF");
917 entry->decoder=(DecodeImageHandler *) ReadPSImage;
918 entry->encoder=(EncodeImageHandler *) WritePSImage;
919 entry->magick=(IsImageFormatHandler *) IsPS;
920 entry->adjoin=MagickFalse;
921 entry->blob_support=MagickFalse;
922 entry->seekable_stream=MagickTrue;
923 entry->description=ConstantString("Encapsulated PostScript");
924 entry->module=ConstantString("PS");
925 (void) RegisterMagickInfo(entry);
926 entry=SetMagickInfo("EPSI");
927 entry->decoder=(DecodeImageHandler *) ReadPSImage;
928 entry->encoder=(EncodeImageHandler *) WritePSImage;
929 entry->magick=(IsImageFormatHandler *) IsPS;
930 entry->adjoin=MagickFalse;
931 entry->blob_support=MagickFalse;
932 entry->seekable_stream=MagickTrue;
933 entry->thread_support=EncoderThreadSupport;
934 entry->description=ConstantString(
935 "Encapsulated PostScript Interchange format");
936 entry->module=ConstantString("PS");
937 (void) RegisterMagickInfo(entry);
938 entry=SetMagickInfo("PS");
939 entry->decoder=(DecodeImageHandler *) ReadPSImage;
940 entry->encoder=(EncodeImageHandler *) WritePSImage;
941 entry->magick=(IsImageFormatHandler *) IsPS;
942 entry->module=ConstantString("PS");
943 entry->blob_support=MagickFalse;
944 entry->seekable_stream=MagickTrue;
945 entry->thread_support=EncoderThreadSupport;
946 entry->description=ConstantString("PostScript");
947 (void) RegisterMagickInfo(entry);
948 return(MagickImageCoderSignature);
949}
950
951/*
952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953% %
954% %
955% %
956% U n r e g i s t e r P S I m a g e %
957% %
958% %
959% %
960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961%
962% UnregisterPSImage() removes format registrations made by the
963% PS module from the list of supported formats.
964%
965% The format of the UnregisterPSImage method is:
966%
967% UnregisterPSImage(void)
968%
969*/
970ModuleExport void UnregisterPSImage(void)
971{
972 (void) UnregisterMagickInfo("EPI");
973 (void) UnregisterMagickInfo("EPS");
974 (void) UnregisterMagickInfo("EPSF");
975 (void) UnregisterMagickInfo("EPSI");
976 (void) UnregisterMagickInfo("PS");
977}
978
979/*
980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981% %
982% %
983% %
984% W r i t e P S I m a g e %
985% %
986% %
987% %
988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
989%
990% WritePSImage translates an image to encapsulated Postscript
991% Level I for printing. If the supplied geometry is null, the image is
992% centered on the Postscript page. Otherwise, the image is positioned as
993% specified by the geometry.
994%
995% The format of the WritePSImage method is:
996%
cristy1e178e72011-08-28 19:44:34 +0000997% MagickBooleanType WritePSImage(const ImageInfo *image_info,
998% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000999%
1000% A description of each parameter follows:
1001%
1002% o image_info: the image info.
1003%
1004% o image: the image.
1005%
cristy1e178e72011-08-28 19:44:34 +00001006% o exception: return any errors or warnings in this structure.
1007%
cristy3ed852e2009-09-05 21:47:34 +00001008*/
1009
1010static inline size_t MagickMin(const size_t x,const size_t y)
1011{
1012 if (x < y)
1013 return(x);
1014 return(y);
1015}
1016
1017static inline unsigned char *PopHexPixel(const char **hex_digits,
cristybb503372010-05-27 20:51:26 +00001018 const size_t pixel,unsigned char *pixels)
cristy3ed852e2009-09-05 21:47:34 +00001019{
1020 register const char
1021 *hex;
1022
1023 hex=hex_digits[pixel];
1024 *pixels++=(unsigned char) (*hex++);
1025 *pixels++=(unsigned char) (*hex);
1026 return(pixels);
1027}
1028
cristy1e178e72011-08-28 19:44:34 +00001029static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
1030 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001031{
1032#define WriteRunlengthPacket(image,pixel,length,p) \
1033{ \
1034 if ((image->matte != MagickFalse) && \
cristy4c08aed2011-07-01 19:47:50 +00001035 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \
cristy3ed852e2009-09-05 21:47:34 +00001036 { \
1037 q=PopHexPixel(hex_digits,0xff,q); \
1038 q=PopHexPixel(hex_digits,0xff,q); \
1039 q=PopHexPixel(hex_digits,0xff,q); \
1040 } \
1041 else \
1042 { \
1043 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.red),q); \
1044 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.green),q); \
1045 q=PopHexPixel(hex_digits,ScaleQuantumToChar(pixel.blue),q); \
1046 } \
cristy9f027d12011-09-21 01:17:17 +00001047 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \
cristy3ed852e2009-09-05 21:47:34 +00001048}
1049
1050 static const char
1051 *hex_digits[] =
1052 {
1053 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B",
1054 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17",
1055 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23",
1056 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
1057 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B",
1058 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
1059 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53",
1060 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
1061 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B",
1062 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77",
1063 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83",
1064 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
1065 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
1066 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
1067 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3",
1068 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
1069 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
1070 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
1071 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3",
1072 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
1073 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB",
1074 "FC", "FD", "FE", "FF", (char *) NULL
1075 },
1076 *PostscriptProlog[]=
1077 {
1078 "%%BeginProlog",
1079 "%",
1080 "% Display a color image. The image is displayed in color on",
1081 "% Postscript viewers or printers that support color, otherwise",
1082 "% it is displayed as grayscale.",
1083 "%",
1084 "/DirectClassPacket",
1085 "{",
1086 " %",
1087 " % Get a DirectClass packet.",
1088 " %",
1089 " % Parameters:",
1090 " % red.",
1091 " % green.",
1092 " % blue.",
1093 " % length: number of pixels minus one of this color (optional).",
1094 " %",
1095 " currentfile color_packet readhexstring pop pop",
1096 " compression 0 eq",
1097 " {",
1098 " /number_pixels 3 def",
1099 " }",
1100 " {",
1101 " currentfile byte readhexstring pop 0 get",
1102 " /number_pixels exch 1 add 3 mul def",
1103 " } ifelse",
1104 " 0 3 number_pixels 1 sub",
1105 " {",
1106 " pixels exch color_packet putinterval",
1107 " } for",
1108 " pixels 0 number_pixels getinterval",
1109 "} bind def",
1110 "",
1111 "/DirectClassImage",
1112 "{",
1113 " %",
1114 " % Display a DirectClass image.",
1115 " %",
1116 " systemdict /colorimage known",
1117 " {",
1118 " columns rows 8",
1119 " [",
1120 " columns 0 0",
1121 " rows neg 0 rows",
1122 " ]",
1123 " { DirectClassPacket } false 3 colorimage",
1124 " }",
1125 " {",
1126 " %",
1127 " % No colorimage operator; convert to grayscale.",
1128 " %",
1129 " columns rows 8",
1130 " [",
1131 " columns 0 0",
1132 " rows neg 0 rows",
1133 " ]",
1134 " { GrayDirectClassPacket } image",
1135 " } ifelse",
1136 "} bind def",
1137 "",
1138 "/GrayDirectClassPacket",
1139 "{",
1140 " %",
1141 " % Get a DirectClass packet; convert to grayscale.",
1142 " %",
1143 " % Parameters:",
1144 " % red",
1145 " % green",
1146 " % blue",
1147 " % length: number of pixels minus one of this color (optional).",
1148 " %",
1149 " currentfile color_packet readhexstring pop pop",
1150 " color_packet 0 get 0.299 mul",
1151 " color_packet 1 get 0.587 mul add",
1152 " color_packet 2 get 0.114 mul add",
1153 " cvi",
1154 " /gray_packet exch def",
1155 " compression 0 eq",
1156 " {",
1157 " /number_pixels 1 def",
1158 " }",
1159 " {",
1160 " currentfile byte readhexstring pop 0 get",
1161 " /number_pixels exch 1 add def",
1162 " } ifelse",
1163 " 0 1 number_pixels 1 sub",
1164 " {",
1165 " pixels exch gray_packet put",
1166 " } for",
1167 " pixels 0 number_pixels getinterval",
1168 "} bind def",
1169 "",
1170 "/GrayPseudoClassPacket",
1171 "{",
1172 " %",
1173 " % Get a PseudoClass packet; convert to grayscale.",
1174 " %",
1175 " % Parameters:",
1176 " % index: index into the colormap.",
1177 " % length: number of pixels minus one of this color (optional).",
1178 " %",
1179 " currentfile byte readhexstring pop 0 get",
1180 " /offset exch 3 mul def",
1181 " /color_packet colormap offset 3 getinterval def",
1182 " color_packet 0 get 0.299 mul",
1183 " color_packet 1 get 0.587 mul add",
1184 " color_packet 2 get 0.114 mul add",
1185 " cvi",
1186 " /gray_packet exch def",
1187 " compression 0 eq",
1188 " {",
1189 " /number_pixels 1 def",
1190 " }",
1191 " {",
1192 " currentfile byte readhexstring pop 0 get",
1193 " /number_pixels exch 1 add def",
1194 " } ifelse",
1195 " 0 1 number_pixels 1 sub",
1196 " {",
1197 " pixels exch gray_packet put",
1198 " } for",
1199 " pixels 0 number_pixels getinterval",
1200 "} bind def",
1201 "",
1202 "/PseudoClassPacket",
1203 "{",
1204 " %",
1205 " % Get a PseudoClass packet.",
1206 " %",
1207 " % Parameters:",
1208 " % index: index into the colormap.",
1209 " % length: number of pixels minus one of this color (optional).",
1210 " %",
1211 " currentfile byte readhexstring pop 0 get",
1212 " /offset exch 3 mul def",
1213 " /color_packet colormap offset 3 getinterval def",
1214 " compression 0 eq",
1215 " {",
1216 " /number_pixels 3 def",
1217 " }",
1218 " {",
1219 " currentfile byte readhexstring pop 0 get",
1220 " /number_pixels exch 1 add 3 mul def",
1221 " } ifelse",
1222 " 0 3 number_pixels 1 sub",
1223 " {",
1224 " pixels exch color_packet putinterval",
1225 " } for",
1226 " pixels 0 number_pixels getinterval",
1227 "} bind def",
1228 "",
1229 "/PseudoClassImage",
1230 "{",
1231 " %",
1232 " % Display a PseudoClass image.",
1233 " %",
1234 " % Parameters:",
1235 " % class: 0-PseudoClass or 1-Grayscale.",
1236 " %",
1237 " currentfile buffer readline pop",
1238 " token pop /class exch def pop",
1239 " class 0 gt",
1240 " {",
1241 " currentfile buffer readline pop",
1242 " token pop /depth exch def pop",
1243 " /grays columns 8 add depth sub depth mul 8 idiv string def",
1244 " columns rows depth",
1245 " [",
1246 " columns 0 0",
1247 " rows neg 0 rows",
1248 " ]",
1249 " { currentfile grays readhexstring pop } image",
1250 " }",
1251 " {",
1252 " %",
1253 " % Parameters:",
1254 " % colors: number of colors in the colormap.",
1255 " % colormap: red, green, blue color packets.",
1256 " %",
1257 " currentfile buffer readline pop",
1258 " token pop /colors exch def pop",
1259 " /colors colors 3 mul def",
1260 " /colormap colors string def",
1261 " currentfile colormap readhexstring pop pop",
1262 " systemdict /colorimage known",
1263 " {",
1264 " columns rows 8",
1265 " [",
1266 " columns 0 0",
1267 " rows neg 0 rows",
1268 " ]",
1269 " { PseudoClassPacket } false 3 colorimage",
1270 " }",
1271 " {",
1272 " %",
1273 " % No colorimage operator; convert to grayscale.",
1274 " %",
1275 " columns rows 8",
1276 " [",
1277 " columns 0 0",
1278 " rows neg 0 rows",
1279 " ]",
1280 " { GrayPseudoClassPacket } image",
1281 " } ifelse",
1282 " } ifelse",
1283 "} bind def",
1284 "",
1285 "/DisplayImage",
1286 "{",
1287 " %",
1288 " % Display a DirectClass or PseudoClass image.",
1289 " %",
1290 " % Parameters:",
1291 " % x & y translation.",
1292 " % x & y scale.",
1293 " % label pointsize.",
1294 " % image label.",
1295 " % image columns & rows.",
1296 " % class: 0-DirectClass or 1-PseudoClass.",
1297 " % compression: 0-none or 1-RunlengthEncoded.",
1298 " % hex color packets.",
1299 " %",
1300 " gsave",
1301 " /buffer 512 string def",
1302 " /byte 1 string def",
1303 " /color_packet 3 string def",
1304 " /pixels 768 string def",
1305 "",
1306 " currentfile buffer readline pop",
1307 " token pop /x exch def",
1308 " token pop /y exch def pop",
1309 " x y translate",
1310 " currentfile buffer readline pop",
1311 " token pop /x exch def",
1312 " token pop /y exch def pop",
1313 " currentfile buffer readline pop",
1314 " token pop /pointsize exch def pop",
1315 " /Times-Roman findfont pointsize scalefont setfont",
1316 (char *) NULL
1317 },
1318 *PostscriptEpilog[]=
1319 {
1320 " x y scale",
1321 " currentfile buffer readline pop",
1322 " token pop /columns exch def",
1323 " token pop /rows exch def pop",
1324 " currentfile buffer readline pop",
1325 " token pop /class exch def pop",
1326 " currentfile buffer readline pop",
1327 " token pop /compression exch def pop",
1328 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
1329 (char *) NULL
1330 };
1331
1332 char
1333 buffer[MaxTextExtent],
1334 date[MaxTextExtent],
1335 **labels,
1336 page_geometry[MaxTextExtent];
1337
1338 const char
1339 **s,
1340 *value;
1341
1342 const StringInfo
1343 *profile;
1344
1345 double
1346 pointsize;
1347
1348 GeometryInfo
1349 geometry_info;
1350
cristy3ed852e2009-09-05 21:47:34 +00001351 MagickBooleanType
1352 status;
1353
1354 MagickOffsetType
1355 scene;
1356
1357 MagickStatusType
1358 flags;
1359
1360 PixelPacket
1361 pixel;
1362
1363 PointInfo
1364 delta,
1365 resolution,
1366 scale;
1367
cristy4c08aed2011-07-01 19:47:50 +00001368 Quantum
1369 index;
1370
cristy3ed852e2009-09-05 21:47:34 +00001371 RectangleInfo
1372 geometry,
1373 media_info,
1374 page_info;
1375
cristy4c08aed2011-07-01 19:47:50 +00001376 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001377 *p;
1378
cristybb503372010-05-27 20:51:26 +00001379 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001380 i,
1381 x;
1382
1383 register unsigned char
1384 *q;
1385
1386 SegmentInfo
1387 bounds;
1388
1389 size_t
cristy802d3642011-04-27 02:02:41 +00001390 bit,
1391 byte,
1392 length,
1393 page,
1394 text_size;
1395
1396 ssize_t
1397 j,
1398 y;
cristy3ed852e2009-09-05 21:47:34 +00001399
1400 time_t
1401 timer;
1402
1403 unsigned char
1404 pixels[2048];
1405
cristy3ed852e2009-09-05 21:47:34 +00001406 /*
1407 Open output image file.
1408 */
1409 assert(image_info != (const ImageInfo *) NULL);
1410 assert(image_info->signature == MagickSignature);
1411 assert(image != (Image *) NULL);
1412 assert(image->signature == MagickSignature);
1413 if (image->debug != MagickFalse)
1414 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001415 assert(exception != (ExceptionInfo *) NULL);
1416 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001417 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001418 if (status == MagickFalse)
1419 return(status);
1420 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
1421 page=1;
1422 scene=0;
1423 do
1424 {
1425 /*
1426 Scale relative to dots-per-inch.
1427 */
cristy510d06a2011-07-06 23:43:54 +00001428 if ((IsRGBColorspace(image->colorspace) == MagickFalse) &&
cristy3ed852e2009-09-05 21:47:34 +00001429 (image->colorspace != CMYKColorspace))
1430 (void) TransformImageColorspace(image,RGBColorspace);
1431 delta.x=DefaultResolution;
1432 delta.y=DefaultResolution;
1433 resolution.x=image->x_resolution;
1434 resolution.y=image->y_resolution;
1435 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1436 {
1437 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1438 resolution.x=geometry_info.rho;
1439 resolution.y=geometry_info.sigma;
1440 if ((flags & SigmaValue) == 0)
1441 resolution.y=resolution.x;
1442 }
1443 if (image_info->density != (char *) NULL)
1444 {
1445 flags=ParseGeometry(image_info->density,&geometry_info);
1446 resolution.x=geometry_info.rho;
1447 resolution.y=geometry_info.sigma;
1448 if ((flags & SigmaValue) == 0)
1449 resolution.y=resolution.x;
1450 }
1451 if (image->units == PixelsPerCentimeterResolution)
1452 {
cristya97426c2011-02-04 01:41:27 +00001453 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1454 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
cristy3ed852e2009-09-05 21:47:34 +00001455 }
1456 SetGeometry(image,&geometry);
cristyb51dff52011-05-19 16:55:47 +00001457 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
cristye8c25f92010-06-03 00:53:06 +00001458 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001459 if (image_info->page != (char *) NULL)
1460 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1461 else
1462 if ((image->page.width != 0) && (image->page.height != 0))
cristyb51dff52011-05-19 16:55:47 +00001463 (void) FormatLocaleString(page_geometry,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00001464 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
cristye8c25f92010-06-03 00:53:06 +00001465 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001466 else
1467 if ((image->gravity != UndefinedGravity) &&
1468 (LocaleCompare(image_info->magick,"PS") == 0))
1469 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1470 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1471 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1472 &geometry.width,&geometry.height);
1473 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +00001474 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001475 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +00001476 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001477 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
cristy1e178e72011-08-28 19:44:34 +00001478 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001479 if (image->gravity != UndefinedGravity)
1480 {
1481 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +00001482 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001483 }
1484 pointsize=12.0;
1485 if (image_info->pointsize != 0.0)
1486 pointsize=image_info->pointsize;
1487 text_size=0;
1488 value=GetImageProperty(image,"label");
1489 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +00001490 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +00001491 if (page == 1)
1492 {
1493 /*
1494 Output Postscript header.
1495 */
1496 if (LocaleCompare(image_info->magick,"PS") == 0)
1497 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
1498 else
1499 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1500 MaxTextExtent);
1501 (void) WriteBlobString(image,buffer);
1502 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
cristyb51dff52011-05-19 16:55:47 +00001503 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
cristy3ed852e2009-09-05 21:47:34 +00001504 image->filename);
1505 (void) WriteBlobString(image,buffer);
1506 timer=time((time_t *) NULL);
1507 (void) FormatMagickTime(timer,MaxTextExtent,date);
cristyb51dff52011-05-19 16:55:47 +00001508 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00001509 "%%%%CreationDate: (%s)\n",date);
1510 (void) WriteBlobString(image,buffer);
1511 bounds.x1=(double) geometry.x;
1512 bounds.y1=(double) geometry.y;
1513 bounds.x2=(double) geometry.x+scale.x;
1514 bounds.y2=(double) geometry.y+(geometry.height+text_size);
1515 if ((image_info->adjoin != MagickFalse) &&
1516 (GetNextImageInList(image) != (Image *) NULL))
1517 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n",
1518 MaxTextExtent);
1519 else
1520 {
cristyb51dff52011-05-19 16:55:47 +00001521 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001522 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1523 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
cristy3ed852e2009-09-05 21:47:34 +00001524 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001525 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001526 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
cristy8cd5b312010-01-07 01:10:24 +00001527 bounds.y1,bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +00001528 }
1529 (void) WriteBlobString(image,buffer);
1530 profile=GetImageProfile(image,"8bim");
1531 if (profile != (StringInfo *) NULL)
1532 {
1533 /*
1534 Embed Photoshop profile.
1535 */
cristyb51dff52011-05-19 16:55:47 +00001536 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001537 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00001538 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001539 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
cristy3ed852e2009-09-05 21:47:34 +00001540 {
1541 if ((i % 32) == 0)
1542 (void) WriteBlobString(image,"\n% ");
cristyb51dff52011-05-19 16:55:47 +00001543 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X",
cristy3ed852e2009-09-05 21:47:34 +00001544 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff));
1545 (void) WriteBlobString(image,buffer);
1546 }
1547 (void) WriteBlobString(image,"\n%EndPhotoshop\n");
1548 }
1549 profile=GetImageProfile(image,"xmp");
cristy2b2eb912010-03-03 14:56:40 +00001550 if (0 && (profile != (StringInfo *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001551 {
1552 /*
1553 Embed XML profile.
1554 */
1555 (void) WriteBlobString(image,"\n%begin_xml_code\n");
cristyb51dff52011-05-19 16:55:47 +00001556 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001557 "\n%%begin_xml_packet: %.20g\n",(double)
cristyeec18db2010-03-03 21:15:45 +00001558 GetStringInfoLength(profile));
cristy2b2eb912010-03-03 14:56:40 +00001559 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001560 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
cristy3ed852e2009-09-05 21:47:34 +00001561 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]);
cristy2b2eb912010-03-03 14:56:40 +00001562 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n");
cristy3ed852e2009-09-05 21:47:34 +00001563 }
1564 value=GetImageProperty(image,"label");
1565 if (value != (const char *) NULL)
1566 (void) WriteBlobString(image,
1567 "%%DocumentNeededResources: font Times-Roman\n");
1568 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
1569 (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
1570 if (LocaleCompare(image_info->magick,"PS") != 0)
1571 (void) WriteBlobString(image,"%%Pages: 1\n");
1572 else
1573 {
1574 /*
1575 Compute the number of pages.
1576 */
1577 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1578 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
cristyb51dff52011-05-19 16:55:47 +00001579 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Pages: %.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001580 image_info->adjoin != MagickFalse ? (double)
1581 GetImageListLength(image) : 1.0);
cristy3ed852e2009-09-05 21:47:34 +00001582 (void) WriteBlobString(image,buffer);
1583 }
1584 (void) WriteBlobString(image,"%%EndComments\n");
1585 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
1586 (void) WriteBlobString(image,"%%EndDefaults\n\n");
1587 if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
1588 (LocaleCompare(image_info->magick,"EPSI") == 0) ||
1589 (LocaleCompare(image_info->magick,"EPT") == 0))
1590 {
1591 Image
1592 *preview_image;
1593
cristy3ed852e2009-09-05 21:47:34 +00001594 Quantum
1595 pixel;
1596
cristybb503372010-05-27 20:51:26 +00001597 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001598 x;
1599
cristy802d3642011-04-27 02:02:41 +00001600 ssize_t
1601 y;
1602
cristy3ed852e2009-09-05 21:47:34 +00001603 /*
1604 Create preview image.
1605 */
cristy1e178e72011-08-28 19:44:34 +00001606 preview_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00001607 if (preview_image == (Image *) NULL)
1608 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1609 /*
1610 Dump image as bitmap.
1611 */
cristyb51dff52011-05-19 16:55:47 +00001612 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001613 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double)
1614 preview_image->columns,(double) preview_image->rows,1.0,
1615 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+
1616 35)/36));
cristy3ed852e2009-09-05 21:47:34 +00001617 (void) WriteBlobString(image,buffer);
1618 q=pixels;
cristybb503372010-05-27 20:51:26 +00001619 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001620 {
1621 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00001622 exception);
cristy4c08aed2011-07-01 19:47:50 +00001623 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001624 break;
cristy3ed852e2009-09-05 21:47:34 +00001625 bit=0;
1626 byte=0;
cristybb503372010-05-27 20:51:26 +00001627 for (x=0; x < (ssize_t) preview_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001628 {
1629 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001630 pixel=GetPixelIntensity(preview_image,p);
cristy3ed852e2009-09-05 21:47:34 +00001631 if (pixel >= (Quantum) (QuantumRange/2))
1632 byte|=0x01;
1633 bit++;
1634 if (bit == 8)
1635 {
1636 q=PopHexPixel(hex_digits,byte,q);
1637 if ((q-pixels+8) >= 80)
1638 {
1639 *q++='\n';
1640 (void) WriteBlob(image,q-pixels,pixels);
1641 q=pixels;
1642 (void) WriteBlobString(image,"% ");
1643 };
1644 bit=0;
1645 byte=0;
1646 }
1647 }
1648 if (bit != 0)
1649 {
1650 byte<<=(8-bit);
1651 q=PopHexPixel(hex_digits,byte,q);
1652 if ((q-pixels+8) >= 80)
1653 {
1654 *q++='\n';
1655 (void) WriteBlob(image,q-pixels,pixels);
1656 q=pixels;
1657 (void) WriteBlobString(image,"% ");
1658 };
1659 };
1660 }
1661 if (q != pixels)
1662 {
1663 *q++='\n';
1664 (void) WriteBlob(image,q-pixels,pixels);
1665 }
1666 (void) WriteBlobString(image,"\n%%EndPreview\n");
1667 preview_image=DestroyImage(preview_image);
1668 }
1669 /*
1670 Output Postscript commands.
1671 */
1672 for (s=PostscriptProlog; *s != (char *) NULL; s++)
1673 {
cristyb51dff52011-05-19 16:55:47 +00001674 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
cristy3ed852e2009-09-05 21:47:34 +00001675 (void) WriteBlobString(image,buffer);
1676 }
1677 value=GetImageProperty(image,"label");
1678 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +00001679 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
cristy3ed852e2009-09-05 21:47:34 +00001680 {
1681 (void) WriteBlobString(image," /label 512 string def\n");
1682 (void) WriteBlobString(image," currentfile label readline pop\n");
cristyb51dff52011-05-19 16:55:47 +00001683 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001684 " 0 y %g add moveto label show pop\n",j*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +00001685 (void) WriteBlobString(image,buffer);
1686 }
1687 for (s=PostscriptEpilog; *s != (char *) NULL; s++)
1688 {
cristyb51dff52011-05-19 16:55:47 +00001689 (void) FormatLocaleString(buffer,MaxTextExtent,"%s\n",*s);
cristy3ed852e2009-09-05 21:47:34 +00001690 (void) WriteBlobString(image,buffer);
1691 }
1692 if (LocaleCompare(image_info->magick,"PS") == 0)
1693 (void) WriteBlobString(image," showpage\n");
1694 (void) WriteBlobString(image,"} bind def\n");
1695 (void) WriteBlobString(image,"%%EndProlog\n");
1696 }
cristyb51dff52011-05-19 16:55:47 +00001697 (void) FormatLocaleString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001698 (double) (page++));
cristy3ed852e2009-09-05 21:47:34 +00001699 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001700 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001701 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1702 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
cristyf2faecf2010-05-28 19:19:36 +00001703 (geometry.height+text_size));
cristy3ed852e2009-09-05 21:47:34 +00001704 (void) WriteBlobString(image,buffer);
1705 if ((double) geometry.x < bounds.x1)
1706 bounds.x1=(double) geometry.x;
1707 if ((double) geometry.y < bounds.y1)
1708 bounds.y1=(double) geometry.y;
1709 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
1710 bounds.x2=(double) geometry.x+geometry.width-1;
1711 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
1712 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
1713 value=GetImageProperty(image,"label");
1714 if (value != (const char *) NULL)
1715 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1716 if (LocaleCompare(image_info->magick,"PS") != 0)
1717 (void) WriteBlobString(image,"userdict begin\n");
1718 (void) WriteBlobString(image,"DisplayImage\n");
1719 /*
1720 Output image data.
1721 */
cristyb51dff52011-05-19 16:55:47 +00001722 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
cristye8c25f92010-06-03 00:53:06 +00001723 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
cristy3ed852e2009-09-05 21:47:34 +00001724 (void) WriteBlobString(image,buffer);
1725 labels=(char **) NULL;
1726 value=GetImageProperty(image,"label");
1727 if (value != (const char *) NULL)
1728 labels=StringToList(value);
1729 if (labels != (char **) NULL)
1730 {
1731 for (i=0; labels[i] != (char *) NULL; i++)
1732 {
cristyb51dff52011-05-19 16:55:47 +00001733 (void) FormatLocaleString(buffer,MaxTextExtent,"%s \n",
cristy3ed852e2009-09-05 21:47:34 +00001734 labels[i]);
1735 (void) WriteBlobString(image,buffer);
1736 labels[i]=DestroyString(labels[i]);
1737 }
1738 labels=(char **) RelinquishMagickMemory(labels);
1739 }
1740 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
cristy4c08aed2011-07-01 19:47:50 +00001741 pixel.alpha=(Quantum) TransparentAlpha;
1742 index=0;
cristy3ed852e2009-09-05 21:47:34 +00001743 x=0;
1744 if ((image_info->type != TrueColorType) &&
cristy1e178e72011-08-28 19:44:34 +00001745 (IsImageGray(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00001746 {
cristy1e178e72011-08-28 19:44:34 +00001747 if (IsImageMonochrome(image,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001748 {
1749 Quantum
1750 pixel;
1751
1752 /*
1753 Dump image as grayscale.
1754 */
cristyb51dff52011-05-19 16:55:47 +00001755 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001756 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double)
1757 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001758 (void) WriteBlobString(image,buffer);
1759 q=pixels;
cristybb503372010-05-27 20:51:26 +00001760 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001761 {
cristy1e178e72011-08-28 19:44:34 +00001762 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001763 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001764 break;
cristybb503372010-05-27 20:51:26 +00001765 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001766 {
cristy4c08aed2011-07-01 19:47:50 +00001767 pixel=(Quantum) ScaleQuantumToChar(GetPixelIntensity(image,p));
cristya97426c2011-02-04 01:41:27 +00001768 q=PopHexPixel(hex_digits,(size_t) pixel,q);
cristy3ed852e2009-09-05 21:47:34 +00001769 i++;
1770 if ((q-pixels+8) >= 80)
1771 {
1772 *q++='\n';
1773 (void) WriteBlob(image,q-pixels,pixels);
1774 q=pixels;
1775 }
cristyed231572011-07-14 02:18:59 +00001776 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001777 }
1778 if (image->previous == (Image *) NULL)
1779 {
cristya97426c2011-02-04 01:41:27 +00001780 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1781 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001782 if (status == MagickFalse)
1783 break;
1784 }
1785 }
1786 if (q != pixels)
1787 {
1788 *q++='\n';
1789 (void) WriteBlob(image,q-pixels,pixels);
1790 }
1791 }
1792 else
1793 {
cristybb503372010-05-27 20:51:26 +00001794 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001795 y;
1796
1797 Quantum
1798 pixel;
1799
1800 /*
1801 Dump image as bitmap.
1802 */
cristyb51dff52011-05-19 16:55:47 +00001803 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001804 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double)
1805 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001806 (void) WriteBlobString(image,buffer);
1807 q=pixels;
cristybb503372010-05-27 20:51:26 +00001808 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001809 {
cristy1e178e72011-08-28 19:44:34 +00001810 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001811 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001812 break;
cristy3ed852e2009-09-05 21:47:34 +00001813 bit=0;
1814 byte=0;
cristybb503372010-05-27 20:51:26 +00001815 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001816 {
1817 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001818 pixel=GetPixelIntensity(image,p);
cristy3ed852e2009-09-05 21:47:34 +00001819 if (pixel >= (Quantum) (QuantumRange/2))
1820 byte|=0x01;
1821 bit++;
1822 if (bit == 8)
1823 {
1824 q=PopHexPixel(hex_digits,byte,q);
1825 if ((q-pixels+2) >= 80)
1826 {
1827 *q++='\n';
1828 (void) WriteBlob(image,q-pixels,pixels);
1829 q=pixels;
1830 };
1831 bit=0;
1832 byte=0;
1833 }
cristyed231572011-07-14 02:18:59 +00001834 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001835 }
1836 if (bit != 0)
1837 {
1838 byte<<=(8-bit);
1839 q=PopHexPixel(hex_digits,byte,q);
1840 if ((q-pixels+2) >= 80)
1841 {
1842 *q++='\n';
1843 (void) WriteBlob(image,q-pixels,pixels);
1844 q=pixels;
1845 }
1846 };
1847 if (image->previous == (Image *) NULL)
1848 {
cristy802d3642011-04-27 02:02:41 +00001849 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1850 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001851 if (status == MagickFalse)
1852 break;
1853 }
1854 }
1855 if (q != pixels)
1856 {
1857 *q++='\n';
1858 (void) WriteBlob(image,q-pixels,pixels);
1859 }
1860 }
1861 }
1862 else
1863 if ((image->storage_class == DirectClass) ||
1864 (image->colors > 256) || (image->matte != MagickFalse))
1865 {
1866 /*
1867 Dump DirectClass image.
1868 */
cristyb51dff52011-05-19 16:55:47 +00001869 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
cristye8c25f92010-06-03 00:53:06 +00001870 (double) image->columns,(double) image->rows,
cristy3ed852e2009-09-05 21:47:34 +00001871 image_info->compression == RLECompression ? 1 : 0);
1872 (void) WriteBlobString(image,buffer);
1873 switch (image_info->compression)
1874 {
1875 case RLECompression:
1876 {
1877 /*
1878 Dump runlength-encoded DirectColor packets.
1879 */
1880 q=pixels;
cristybb503372010-05-27 20:51:26 +00001881 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001882 {
cristy1e178e72011-08-28 19:44:34 +00001883 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001884 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001885 break;
cristy4c08aed2011-07-01 19:47:50 +00001886 GetPixelPacket(image,p,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00001887 length=255;
cristybb503372010-05-27 20:51:26 +00001888 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001889 {
cristy4c08aed2011-07-01 19:47:50 +00001890 if ((GetPixelRed(image,p) == pixel.red) &&
1891 (GetPixelGreen(image,p) == pixel.green) &&
1892 (GetPixelBlue(image,p) == pixel.blue) &&
1893 (GetPixelAlpha(image,p) == pixel.alpha) &&
cristy802d3642011-04-27 02:02:41 +00001894 (length < 255) && (x < (ssize_t) (image->columns-1)))
cristy3ed852e2009-09-05 21:47:34 +00001895 length++;
1896 else
1897 {
1898 if (x > 0)
1899 {
1900 WriteRunlengthPacket(image,pixel,length,p);
1901 if ((q-pixels+10) >= 80)
1902 {
1903 *q++='\n';
1904 (void) WriteBlob(image,q-pixels,pixels);
1905 q=pixels;
1906 }
1907 }
1908 length=0;
1909 }
cristy4c08aed2011-07-01 19:47:50 +00001910 GetPixelPacket(image,p,&pixel);
cristyed231572011-07-14 02:18:59 +00001911 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001912 }
1913 WriteRunlengthPacket(image,pixel,length,p);
1914 if ((q-pixels+10) >= 80)
1915 {
1916 *q++='\n';
1917 (void) WriteBlob(image,q-pixels,pixels);
1918 q=pixels;
1919 }
1920 if (image->previous == (Image *) NULL)
1921 {
cristy802d3642011-04-27 02:02:41 +00001922 status=SetImageProgress(image,SaveImageTag,
1923 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001924 if (status == MagickFalse)
1925 break;
1926 }
1927 }
1928 if (q != pixels)
1929 {
1930 *q++='\n';
1931 (void) WriteBlob(image,q-pixels,pixels);
1932 }
1933 break;
1934 }
1935 case NoCompression:
1936 default:
1937 {
1938 /*
1939 Dump uncompressed DirectColor packets.
1940 */
1941 q=pixels;
cristybb503372010-05-27 20:51:26 +00001942 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001943 {
cristy1e178e72011-08-28 19:44:34 +00001944 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001945 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001946 break;
cristybb503372010-05-27 20:51:26 +00001947 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001948 {
1949 if ((image->matte != MagickFalse) &&
cristy4c08aed2011-07-01 19:47:50 +00001950 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha))
cristy3ed852e2009-09-05 21:47:34 +00001951 {
1952 q=PopHexPixel(hex_digits,0xff,q);
1953 q=PopHexPixel(hex_digits,0xff,q);
1954 q=PopHexPixel(hex_digits,0xff,q);
1955 }
1956 else
1957 {
cristy802d3642011-04-27 02:02:41 +00001958 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00001959 GetPixelRed(image,p)),q);
cristy802d3642011-04-27 02:02:41 +00001960 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00001961 GetPixelGreen(image,p)),q);
cristy802d3642011-04-27 02:02:41 +00001962 q=PopHexPixel(hex_digits,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00001963 GetPixelBlue(image,p)),q);
cristy3ed852e2009-09-05 21:47:34 +00001964 }
1965 if ((q-pixels+6) >= 80)
1966 {
1967 *q++='\n';
1968 (void) WriteBlob(image,q-pixels,pixels);
1969 q=pixels;
1970 }
cristyed231572011-07-14 02:18:59 +00001971 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001972 }
1973 if (image->previous == (Image *) NULL)
1974 {
cristy802d3642011-04-27 02:02:41 +00001975 status=SetImageProgress(image,SaveImageTag,
1976 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001977 if (status == MagickFalse)
1978 break;
1979 }
1980 }
1981 if (q != pixels)
1982 {
1983 *q++='\n';
1984 (void) WriteBlob(image,q-pixels,pixels);
1985 }
1986 break;
1987 }
1988 }
1989 (void) WriteBlobByte(image,'\n');
1990 }
1991 else
1992 {
1993 /*
1994 Dump PseudoClass image.
1995 */
cristyb51dff52011-05-19 16:55:47 +00001996 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001997 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double)
1998 image->rows,image->storage_class == PseudoClass ? 1 : 0,
cristy3ed852e2009-09-05 21:47:34 +00001999 image_info->compression == RLECompression ? 1 : 0);
2000 (void) WriteBlobString(image,buffer);
2001 /*
2002 Dump number of colors and colormap.
2003 */
cristyb51dff52011-05-19 16:55:47 +00002004 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002005 image->colors);
cristy3ed852e2009-09-05 21:47:34 +00002006 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00002007 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002008 {
cristyb51dff52011-05-19 16:55:47 +00002009 (void) FormatLocaleString(buffer,MaxTextExtent,"%02X%02X%02X\n",
cristy3ed852e2009-09-05 21:47:34 +00002010 ScaleQuantumToChar(image->colormap[i].red),
2011 ScaleQuantumToChar(image->colormap[i].green),
2012 ScaleQuantumToChar(image->colormap[i].blue));
2013 (void) WriteBlobString(image,buffer);
2014 }
2015 switch (image_info->compression)
2016 {
2017 case RLECompression:
2018 {
2019 /*
2020 Dump runlength-encoded PseudoColor packets.
2021 */
2022 q=pixels;
cristybb503372010-05-27 20:51:26 +00002023 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002024 {
cristy1e178e72011-08-28 19:44:34 +00002025 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002026 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002027 break;
cristy4c08aed2011-07-01 19:47:50 +00002028 index=GetPixelIndex(image,p);
cristy3ed852e2009-09-05 21:47:34 +00002029 length=255;
cristybb503372010-05-27 20:51:26 +00002030 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002031 {
cristy4c08aed2011-07-01 19:47:50 +00002032 if ((index == GetPixelIndex(image,p)) &&
cristy802d3642011-04-27 02:02:41 +00002033 (length < 255) && (x < ((ssize_t) image->columns-1)))
cristy3ed852e2009-09-05 21:47:34 +00002034 length++;
2035 else
2036 {
2037 if (x > 0)
2038 {
cristya97426c2011-02-04 01:41:27 +00002039 q=PopHexPixel(hex_digits,(size_t) index,q);
cristybb503372010-05-27 20:51:26 +00002040 q=PopHexPixel(hex_digits,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00002041 MagickMin(length,0xff),q);
2042 i++;
2043 if ((q-pixels+6) >= 80)
2044 {
2045 *q++='\n';
2046 (void) WriteBlob(image,q-pixels,pixels);
2047 q=pixels;
2048 }
2049 }
2050 length=0;
2051 }
cristy4c08aed2011-07-01 19:47:50 +00002052 index=GetPixelIndex(image,p);
2053 pixel.red=GetPixelRed(image,p);
2054 pixel.green=GetPixelGreen(image,p);
2055 pixel.blue=GetPixelBlue(image,p);
2056 pixel.alpha=GetPixelAlpha(image,p);
cristyed231572011-07-14 02:18:59 +00002057 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002058 }
cristya97426c2011-02-04 01:41:27 +00002059 q=PopHexPixel(hex_digits,(size_t) index,q);
cristybb503372010-05-27 20:51:26 +00002060 q=PopHexPixel(hex_digits,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00002061 MagickMin(length,0xff),q);
2062 if (image->previous == (Image *) NULL)
2063 {
cristya97426c2011-02-04 01:41:27 +00002064 status=SetImageProgress(image,SaveImageTag,
2065 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002066 if (status == MagickFalse)
2067 break;
2068 }
2069 }
2070 if (q != pixels)
2071 {
2072 *q++='\n';
2073 (void) WriteBlob(image,q-pixels,pixels);
2074 }
2075 break;
2076 }
2077 case NoCompression:
2078 default:
2079 {
2080 /*
2081 Dump uncompressed PseudoColor packets.
2082 */
2083 q=pixels;
cristybb503372010-05-27 20:51:26 +00002084 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002085 {
cristy1e178e72011-08-28 19:44:34 +00002086 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002087 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002088 break;
cristybb503372010-05-27 20:51:26 +00002089 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002090 {
cristy4c08aed2011-07-01 19:47:50 +00002091 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +00002092 if ((q-pixels+4) >= 80)
2093 {
2094 *q++='\n';
2095 (void) WriteBlob(image,q-pixels,pixels);
2096 q=pixels;
2097 }
cristyed231572011-07-14 02:18:59 +00002098 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002099 }
2100 if (image->previous == (Image *) NULL)
2101 {
cristya97426c2011-02-04 01:41:27 +00002102 status=SetImageProgress(image,SaveImageTag,
2103 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002104 if (status == MagickFalse)
2105 break;
2106 }
2107 }
2108 if (q != pixels)
2109 {
2110 *q++='\n';
2111 (void) WriteBlob(image,q-pixels,pixels);
2112 }
2113 break;
2114 }
2115 }
2116 (void) WriteBlobByte(image,'\n');
2117 }
2118 if (LocaleCompare(image_info->magick,"PS") != 0)
2119 (void) WriteBlobString(image,"end\n");
2120 (void) WriteBlobString(image,"%%PageTrailer\n");
2121 if (GetNextImageInList(image) == (Image *) NULL)
2122 break;
2123 image=SyncNextImageInList(image);
2124 status=SetImageProgress(image,SaveImagesTag,scene++,
2125 GetImageListLength(image));
2126 if (status == MagickFalse)
2127 break;
2128 } while (image_info->adjoin != MagickFalse);
2129 (void) WriteBlobString(image,"%%Trailer\n");
2130 if (page > 2)
2131 {
cristyb51dff52011-05-19 16:55:47 +00002132 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00002133 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
2134 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
cristy3ed852e2009-09-05 21:47:34 +00002135 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002136 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00002137 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +00002138 bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +00002139 (void) WriteBlobString(image,buffer);
2140 }
2141 (void) WriteBlobString(image,"%%EOF\n");
2142 (void) CloseBlob(image);
2143 return(MagickTrue);
2144}