1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            PPPP   DDDD   FFFFF                              %
7 %                            P   P  D   D  F                                  %
8 %                            PPPP   D   D  FFF                                %
9 %                            P      D   D  F                                  %
10 %                            P      DDDD   F                                  %
11 %                                                                             %
12 %                                                                             %
13 %                   Read/Write Portable Document Format                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/artifact.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/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/compress.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/delegate.h"
55 #include "MagickCore/delegate-private.h"
56 #include "MagickCore/draw.h"
57 #include "MagickCore/exception.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/image.h"
61 #include "MagickCore/image-private.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/magick.h"
64 #include "MagickCore/memory_.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/nt-base-private.h"
68 #include "MagickCore/option.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/profile.h"
71 #include "MagickCore/property.h"
72 #include "MagickCore/quantum-private.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/resize.h"
75 #include "MagickCore/signature.h"
76 #include "MagickCore/static.h"
77 #include "MagickCore/string_.h"
78 #include "MagickCore/module.h"
79 #include "MagickCore/token.h"
80 #include "MagickCore/transform.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/module.h"
83 
84 /*
85   Define declarations.
86 */
87 #if defined(MAGICKCORE_TIFF_DELEGATE)
88 #define CCITTParam  "-1"
89 #else
90 #define CCITTParam  "0"
91 #endif
92 
93 /*
94   Forward declarations.
95 */
96 static MagickBooleanType
97   WritePDFImage(const ImageInfo *,Image *,ExceptionInfo *);
98 
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %   I n v o k e P D F D e l e g a t e                                         %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  InvokePDFDelegate() executes the PDF interpreter with the specified command.
111 %
112 %  The format of the InvokePDFDelegate method is:
113 %
114 %      MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
115 %        const char *command,ExceptionInfo *exception)
116 %
117 %  A description of each parameter follows:
118 %
119 %    o verbose: A value other than zero displays the command prior to
120 %      executing it.
121 %
122 %    o command: the address of a character string containing the command to
123 %      execute.
124 %
125 %    o exception: return any errors or warnings in this structure.
126 %
127 */
128 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
PDFDelegateMessage(void * handle,const char * message,int length)129 static int MagickDLLCall PDFDelegateMessage(void *handle,const char *message,
130   int length)
131 {
132   char
133     **messages;
134 
135   ssize_t
136     offset;
137 
138   offset=0;
139   messages=(char **) handle;
140   if (*messages == (char *) NULL)
141     *messages=(char *) AcquireQuantumMemory(length+1,sizeof(char *));
142   else
143     {
144       offset=strlen(*messages);
145       *messages=(char *) ResizeQuantumMemory(*messages,offset+length+1,
146         sizeof(char *));
147     }
148   (void) memcpy(*messages+offset,message,length);
149   (*messages)[length+offset] ='\0';
150   return(length);
151 }
152 #endif
153 
InvokePDFDelegate(const MagickBooleanType verbose,const char * command,char * message,ExceptionInfo * exception)154 static MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
155   const char *command,char *message,ExceptionInfo *exception)
156 {
157   int
158     status;
159 
160 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
161 #define SetArgsStart(command,args_start) \
162   if (args_start == (const char *) NULL) \
163     { \
164       if (*command != '"') \
165         args_start=strchr(command,' '); \
166       else \
167         { \
168           args_start=strchr(command+1,'"'); \
169           if (args_start != (const char *) NULL) \
170             args_start++; \
171         } \
172     }
173 
174 #define ExecuteGhostscriptCommand(command,status) \
175 { \
176   status=ExternalDelegateCommand(MagickFalse,verbose,command,message, \
177     exception); \
178   if (status == 0) \
179     return(MagickTrue); \
180   if (status < 0) \
181     return(MagickFalse); \
182   (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, \
183     "FailedToExecuteCommand","`%s' (%d)",command,status); \
184   return(MagickFalse); \
185 }
186 
187   char
188     **argv,
189     *errors;
190 
191   const char
192     *args_start = (const char *) NULL;
193 
194   const GhostInfo
195     *ghost_info;
196 
197   gs_main_instance
198     *interpreter;
199 
200   gsapi_revision_t
201     revision;
202 
203   int
204     argc,
205     code;
206 
207   register ssize_t
208     i;
209 
210 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
211   ghost_info=NTGhostscriptDLLVectors();
212 #else
213   GhostInfo
214     ghost_info_struct;
215 
216   ghost_info=(&ghost_info_struct);
217   (void) ResetMagickMemory(&ghost_info_struct,0,sizeof(ghost_info_struct));
218   ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
219     gsapi_delete_instance;
220   ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
221   ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
222     gsapi_new_instance;
223   ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
224     gsapi_init_with_args;
225   ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
226     int *)) gsapi_run_string;
227   ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int(*)(void *,char *,
228     int),int(*)(void *,const char *,int),int(*)(void *, const char *, int)))
229     gsapi_set_stdio;
230   ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision;
231 #endif
232   if (ghost_info == (GhostInfo *) NULL)
233     ExecuteGhostscriptCommand(command,status);
234   if ((ghost_info->revision)(&revision,sizeof(revision)) != 0)
235     revision.revision=0;
236   if (verbose != MagickFalse)
237     {
238       (void) fprintf(stdout,"[ghostscript library %.2f]",(double)
239         revision.revision/100.0);
240       SetArgsStart(command,args_start);
241       (void) fputs(args_start,stdout);
242     }
243   errors=(char *) NULL;
244   status=(ghost_info->new_instance)(&interpreter,(void *) &errors);
245   if (status < 0)
246     ExecuteGhostscriptCommand(command,status);
247   code=0;
248   argv=StringToArgv(command,&argc);
249   if (argv == (char **) NULL)
250     {
251       (ghost_info->delete_instance)(interpreter);
252       return(MagickFalse);
253     }
254   (void) (ghost_info->set_stdio)(interpreter,(int(MagickDLLCall *)(void *,
255     char *,int)) NULL,PDFDelegateMessage,PDFDelegateMessage);
256   status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
257   if (status == 0)
258     status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
259       0,&code);
260   (ghost_info->exit)(interpreter);
261   (ghost_info->delete_instance)(interpreter);
262   for (i=0; i < (ssize_t) argc; i++)
263     argv[i]=DestroyString(argv[i]);
264   argv=(char **) RelinquishMagickMemory(argv);
265   if (status != 0)
266     {
267       SetArgsStart(command,args_start);
268       if (status == -101) /* quit */
269         (void) FormatLocaleString(message,MagickPathExtent,
270           "[ghostscript library %.2f]%s: %s",(double)revision.revision / 100,
271           args_start,errors);
272       else
273         {
274           (void) ThrowMagickException(exception,GetMagickModule(),
275             DelegateError,"PDFDelegateFailed",
276             "`[ghostscript library %.2f]%s': %s",
277             (double)revision.revision / 100,args_start,errors);
278           if (errors != (char *) NULL)
279             errors=DestroyString(errors);
280           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
281             "Ghostscript returns status %d, exit code %d",status,code);
282           return(MagickFalse);
283         }
284     }
285   if (errors != (char *) NULL)
286     errors=DestroyString(errors);
287   return(MagickTrue);
288 #else
289   status=ExternalDelegateCommand(MagickFalse,verbose,command,message,exception);
290   return(status == 0 ? MagickTrue : MagickFalse);
291 #endif
292 }
293 
294 /*
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 %                                                                             %
297 %                                                                             %
298 %                                                                             %
299 %   I s P D F                                                                 %
300 %                                                                             %
301 %                                                                             %
302 %                                                                             %
303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304 %
305 %  IsPDF() returns MagickTrue if the image format type, identified by the
306 %  magick string, is PDF.
307 %
308 %  The format of the IsPDF method is:
309 %
310 %      MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
311 %
312 %  A description of each parameter follows:
313 %
314 %    o magick: compare image format pattern against these bytes.
315 %
316 %    o offset: Specifies the offset of the magick string.
317 %
318 */
IsPDF(const unsigned char * magick,const size_t offset)319 static MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
320 {
321   if (offset < 5)
322     return(MagickFalse);
323   if (LocaleNCompare((const char *) magick,"%PDF-",5) == 0)
324     return(MagickTrue);
325   return(MagickFalse);
326 }
327 
328 /*
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 %                                                                             %
331 %                                                                             %
332 %                                                                             %
333 %   R e a d P D F I m a g e                                                   %
334 %                                                                             %
335 %                                                                             %
336 %                                                                             %
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338 %
339 %  ReadPDFImage() reads a Portable Document Format image file and
340 %  returns it.  It allocates the memory necessary for the new Image structure
341 %  and returns a pointer to the new image.
342 %
343 %  The format of the ReadPDFImage method is:
344 %
345 %      Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
346 %
347 %  A description of each parameter follows:
348 %
349 %    o image_info: the image info.
350 %
351 %    o exception: return any errors or warnings in this structure.
352 %
353 */
354 
IsPDFRendered(const char * path)355 static MagickBooleanType IsPDFRendered(const char *path)
356 {
357   MagickBooleanType
358     status;
359 
360   struct stat
361     attributes;
362 
363   if ((path == (const char *) NULL) || (*path == '\0'))
364     return(MagickFalse);
365   status=GetPathAttributes(path,&attributes);
366   if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
367       (attributes.st_size > 0))
368     return(MagickTrue);
369   return(MagickFalse);
370 }
371 
ReadPDFImage(const ImageInfo * image_info,ExceptionInfo * exception)372 static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
373 {
374 #define CMYKProcessColor  "CMYKProcessColor"
375 #define CropBox  "CropBox"
376 #define DefaultCMYK  "DefaultCMYK"
377 #define DeviceCMYK  "DeviceCMYK"
378 #define MediaBox  "MediaBox"
379 #define RenderPostscriptText  "Rendering Postscript...  "
380 #define PDFRotate  "Rotate"
381 #define SpotColor  "Separation"
382 #define TrimBox  "TrimBox"
383 #define PDFVersion  "PDF-"
384 
385   char
386     command[MagickPathExtent],
387     *density,
388     filename[MagickPathExtent],
389     geometry[MagickPathExtent],
390     input_filename[MagickPathExtent],
391     message[MagickPathExtent],
392     *options,
393     postscript_filename[MagickPathExtent];
394 
395   const char
396     *option;
397 
398   const DelegateInfo
399     *delegate_info;
400 
401   double
402     angle;
403 
404   GeometryInfo
405     geometry_info;
406 
407   Image
408     *image,
409     *next,
410     *pdf_image;
411 
412   ImageInfo
413     *read_info;
414 
415   int
416     c,
417     file;
418 
419   MagickBooleanType
420     cmyk,
421     cropbox,
422     fitPage,
423     status,
424     stop_on_error,
425     trimbox;
426 
427   MagickStatusType
428     flags;
429 
430   PointInfo
431     delta;
432 
433   RectangleInfo
434     bounding_box,
435     page;
436 
437   register char
438     *p;
439 
440   register ssize_t
441     i;
442 
443   SegmentInfo
444     bounds,
445     hires_bounds;
446 
447   size_t
448     scene,
449     spotcolor;
450 
451   ssize_t
452     count;
453 
454   assert(image_info != (const ImageInfo *) NULL);
455   assert(image_info->signature == MagickCoreSignature);
456   if (image_info->debug != MagickFalse)
457     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
458       image_info->filename);
459   assert(exception != (ExceptionInfo *) NULL);
460   assert(exception->signature == MagickCoreSignature);
461   /*
462     Open image file.
463   */
464   image=AcquireImage(image_info,exception);
465   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
466   if (status == MagickFalse)
467     {
468       image=DestroyImageList(image);
469       return((Image *) NULL);
470     }
471   status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
472   if (status == MagickFalse)
473     {
474       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
475         image_info->filename);
476       image=DestroyImageList(image);
477       return((Image *) NULL);
478     }
479   /*
480     Set the page density.
481   */
482   delta.x=DefaultResolution;
483   delta.y=DefaultResolution;
484   if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
485     {
486       flags=ParseGeometry(PSDensityGeometry,&geometry_info);
487       image->resolution.x=geometry_info.rho;
488       image->resolution.y=geometry_info.sigma;
489       if ((flags & SigmaValue) == 0)
490         image->resolution.y=image->resolution.x;
491     }
492   if (image_info->density != (char *) NULL)
493     {
494       flags=ParseGeometry(image_info->density,&geometry_info);
495       image->resolution.x=geometry_info.rho;
496       image->resolution.y=geometry_info.sigma;
497       if ((flags & SigmaValue) == 0)
498         image->resolution.y=image->resolution.x;
499     }
500   (void) ResetMagickMemory(&page,0,sizeof(page));
501   (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
502   if (image_info->page != (char *) NULL)
503     (void) ParseAbsoluteGeometry(image_info->page,&page);
504   page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)-
505     0.5);
506   page.height=(size_t) ceil((double) (page.height*image->resolution.y/delta.y)-
507     0.5);
508   /*
509     Determine page geometry from the PDF media box.
510   */
511   cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
512   cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
513   stop_on_error=IsStringTrue(GetImageOption(image_info,"pdf:stop-on-error"));
514   trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
515   count=0;
516   spotcolor=0;
517   (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
518   (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
519   (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
520   (void) ResetMagickMemory(command,0,sizeof(command));
521   angle=0.0;
522   p=command;
523   for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
524   {
525     /*
526       Note PDF elements.
527     */
528     if (c == '\n')
529       c=' ';
530     *p++=(char) c;
531     if ((c != (int) '/') && (c != (int) '%') &&
532         ((size_t) (p-command) < (MagickPathExtent-1)))
533       continue;
534     *(--p)='\0';
535     p=command;
536     if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
537       count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
538     /*
539       Is this a CMYK document?
540     */
541     if (LocaleNCompare(DefaultCMYK,command,strlen(DefaultCMYK)) == 0)
542       cmyk=MagickTrue;
543     if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
544       cmyk=MagickTrue;
545     if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
546       cmyk=MagickTrue;
547     if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)
548       {
549         char
550           name[MagickPathExtent],
551           property[MagickPathExtent],
552           *value;
553 
554         /*
555           Note spot names.
556         */
557         (void) FormatLocaleString(property,MagickPathExtent,
558           "pdf:SpotColor-%.20g",(double) spotcolor++);
559         i=0;
560         for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
561         {
562           if ((isspace(c) != 0) || (c == '/') || ((i+1) == MagickPathExtent))
563             break;
564           name[i++]=(char) c;
565         }
566         name[i]='\0';
567         value=AcquireString(name);
568         (void) SubstituteString(&value,"#20"," ");
569         (void) SetImageProperty(image,property,value,exception);
570         value=DestroyString(value);
571         continue;
572       }
573     if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0)
574       (void) SetImageProperty(image,"pdf:Version",command,exception);
575     if (image_info->page != (char *) NULL)
576       continue;
577     count=0;
578     if (cropbox != MagickFalse)
579       {
580         if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
581           {
582             /*
583               Note region defined by crop box.
584             */
585             count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
586               &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
587             if (count != 4)
588               count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
589                 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
590           }
591       }
592     else
593       if (trimbox != MagickFalse)
594         {
595           if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0)
596             {
597               /*
598                 Note region defined by trim box.
599               */
600               count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf",
601                 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
602               if (count != 4)
603                 count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf",
604                   &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
605             }
606         }
607       else
608         if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
609           {
610             /*
611               Note region defined by media box.
612             */
613             count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
614               &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
615             if (count != 4)
616               count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
617                 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
618           }
619     if (count != 4)
620       continue;
621     if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
622         (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
623       continue;
624     hires_bounds=bounds;
625   }
626   if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
627       (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
628     {
629       /*
630         Set PDF render geometry.
631       */
632       (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+.15g%+.15g",
633         hires_bounds.x2-bounds.x1,hires_bounds.y2-hires_bounds.y1,
634         hires_bounds.x1,hires_bounds.y1);
635       (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry,exception);
636       page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
637         image->resolution.x/delta.x)-0.5);
638       page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
639         image->resolution.y/delta.y)-0.5);
640     }
641   fitPage=MagickFalse;
642   option=GetImageOption(image_info,"pdf:fit-page");
643   if (option != (char *) NULL)
644   {
645     char
646       *page_geometry;
647 
648     page_geometry=GetPageGeometry(option);
649     flags=ParseMetaGeometry(page_geometry,&page.x,&page.y,&page.width,
650       &page.height);
651     page_geometry=DestroyString(page_geometry);
652     if (flags == NoValue)
653       {
654         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
655           "InvalidGeometry","`%s'",option);
656         image=DestroyImage(image);
657         return((Image *) NULL);
658       }
659     page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)
660       -0.5);
661     page.height=(size_t) ceil((double) (page.height*image->resolution.y/
662       delta.y) -0.5);
663     fitPage=MagickTrue;
664   }
665   (void) CloseBlob(image);
666   if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0))
667     {
668       size_t
669         swap;
670 
671       swap=page.width;
672       page.width=page.height;
673       page.height=swap;
674     }
675   if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
676     cmyk=MagickFalse;
677   /*
678     Create Ghostscript control file.
679   */
680   file=AcquireUniqueFileResource(postscript_filename);
681   if (file == -1)
682     {
683       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
684         image_info->filename);
685       image=DestroyImage(image);
686       return((Image *) NULL);
687     }
688   count=write(file," ",1);
689   file=close(file)-1;
690   /*
691     Render Postscript with the Ghostscript delegate.
692   */
693   if (image_info->monochrome != MagickFalse)
694     delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
695   else
696      if (cmyk != MagickFalse)
697        delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
698      else
699        delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
700   if (delegate_info == (const DelegateInfo *) NULL)
701     {
702       (void) RelinquishUniqueFileResource(postscript_filename);
703       image=DestroyImage(image);
704       return((Image *) NULL);
705     }
706   density=AcquireString("");
707   options=AcquireString("");
708   (void) FormatLocaleString(density,MagickPathExtent,"%gx%g",
709     image->resolution.x,image->resolution.y);
710   if ((image_info->page != (char *) NULL) || (fitPage != MagickFalse))
711     (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double)
712       page.width,(double) page.height);
713   if (fitPage != MagickFalse)
714     (void) ConcatenateMagickString(options,"-dPSFitPage ",MagickPathExtent);
715   if (cmyk != MagickFalse)
716     (void) ConcatenateMagickString(options,"-dUseCIEColor ",MagickPathExtent);
717   if (cropbox != MagickFalse)
718     (void) ConcatenateMagickString(options,"-dUseCropBox ",MagickPathExtent);
719   if (stop_on_error != MagickFalse)
720     (void) ConcatenateMagickString(options,"-dPDFSTOPONERROR ",
721       MagickPathExtent);
722   if (trimbox != MagickFalse)
723     (void) ConcatenateMagickString(options,"-dUseTrimBox ",MagickPathExtent);
724   read_info=CloneImageInfo(image_info);
725   *read_info->magick='\0';
726   if (read_info->number_scenes != 0)
727     {
728       char
729         pages[MagickPathExtent];
730 
731       (void) FormatLocaleString(pages,MagickPathExtent,"-dFirstPage=%.20g "
732         "-dLastPage=%.20g",(double) read_info->scene+1,(double)
733         (read_info->scene+read_info->number_scenes));
734       (void) ConcatenateMagickString(options,pages,MagickPathExtent);
735       read_info->number_scenes=0;
736       if (read_info->scenes != (char *) NULL)
737         *read_info->scenes='\0';
738     }
739   (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
740   (void) AcquireUniqueFilename(filename);
741   (void) RelinquishUniqueFileResource(filename);
742   (void) ConcatenateMagickString(filename,"%d",MagickPathExtent);
743   (void) FormatLocaleString(command,MagickPathExtent,
744     GetDelegateCommands(delegate_info),
745     read_info->antialias != MagickFalse ? 4 : 1,
746     read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
747     postscript_filename,input_filename);
748   options=DestroyString(options);
749   density=DestroyString(density);
750   *message='\0';
751   status=InvokePDFDelegate(read_info->verbose,command,message,exception);
752   (void) RelinquishUniqueFileResource(postscript_filename);
753   (void) RelinquishUniqueFileResource(input_filename);
754   pdf_image=(Image *) NULL;
755   if (status == MagickFalse)
756     for (i=1; ; i++)
757     {
758       (void) InterpretImageFilename(image_info,image,filename,(int) i,
759         read_info->filename,exception);
760       if (IsPDFRendered(read_info->filename) == MagickFalse)
761         break;
762       (void) RelinquishUniqueFileResource(read_info->filename);
763     }
764   else
765     for (i=1; ; i++)
766     {
767       (void) InterpretImageFilename(image_info,image,filename,(int) i,
768         read_info->filename,exception);
769       if (IsPDFRendered(read_info->filename) == MagickFalse)
770         break;
771       read_info->blob=NULL;
772       read_info->length=0;
773       next=ReadImage(read_info,exception);
774       (void) RelinquishUniqueFileResource(read_info->filename);
775       if (next == (Image *) NULL)
776         break;
777       AppendImageToList(&pdf_image,next);
778     }
779   read_info=DestroyImageInfo(read_info);
780   if (pdf_image == (Image *) NULL)
781     {
782       if (*message != '\0')
783         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
784           "PDFDelegateFailed","`%s'",message);
785       image=DestroyImage(image);
786       return((Image *) NULL);
787     }
788   if (LocaleCompare(pdf_image->magick,"BMP") == 0)
789     {
790       Image
791         *cmyk_image;
792 
793       cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
794       if (cmyk_image != (Image *) NULL)
795         {
796           pdf_image=DestroyImageList(pdf_image);
797           pdf_image=cmyk_image;
798         }
799     }
800   if (image_info->number_scenes != 0)
801     {
802       Image
803         *clone_image;
804 
805       /*
806         Add place holder images to meet the subimage specification requirement.
807       */
808       for (i=0; i < (ssize_t) image_info->scene; i++)
809       {
810         clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
811         if (clone_image != (Image *) NULL)
812           PrependImageToList(&pdf_image,clone_image);
813       }
814     }
815   do
816   {
817     (void) CopyMagickString(pdf_image->filename,filename,MagickPathExtent);
818     (void) CopyMagickString(pdf_image->magick,image->magick,MagickPathExtent);
819     pdf_image->page=page;
820     (void) CloneImageProfiles(pdf_image,image);
821     (void) CloneImageProperties(pdf_image,image);
822     next=SyncNextImageInList(pdf_image);
823     if (next != (Image *) NULL)
824       pdf_image=next;
825   } while (next != (Image *) NULL);
826   image=DestroyImage(image);
827   scene=0;
828   for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
829   {
830     next->scene=scene++;
831     next=GetNextImageInList(next);
832   }
833   return(GetFirstImageInList(pdf_image));
834 }
835 
836 /*
837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 %                                                                             %
839 %                                                                             %
840 %                                                                             %
841 %   R e g i s t e r P D F I m a g e                                           %
842 %                                                                             %
843 %                                                                             %
844 %                                                                             %
845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
846 %
847 %  RegisterPDFImage() adds properties for the PDF image format to
848 %  the list of supported formats.  The properties include the image format
849 %  tag, a method to read and/or write the format, whether the format
850 %  supports the saving of more than one frame to the same file or blob,
851 %  whether the format supports native in-memory I/O, and a brief
852 %  description of the format.
853 %
854 %  The format of the RegisterPDFImage method is:
855 %
856 %      size_t RegisterPDFImage(void)
857 %
858 */
RegisterPDFImage(void)859 ModuleExport size_t RegisterPDFImage(void)
860 {
861   MagickInfo
862     *entry;
863 
864   entry=AcquireMagickInfo("PDF","AI","Adobe Illustrator CS2");
865   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
866   entry->encoder=(EncodeImageHandler *) WritePDFImage;
867   entry->flags^=CoderAdjoinFlag;
868   entry->flags^=CoderBlobSupportFlag;
869   entry->flags|=CoderSeekableStreamFlag;
870   entry->mime_type=ConstantString("application/pdf");
871   (void) RegisterMagickInfo(entry);
872   entry=AcquireMagickInfo("PDF","EPDF",
873     "Encapsulated Portable Document Format");
874   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
875   entry->encoder=(EncodeImageHandler *) WritePDFImage;
876   entry->flags^=CoderAdjoinFlag;
877   entry->flags^=CoderBlobSupportFlag;
878   entry->flags|=CoderSeekableStreamFlag;
879   entry->mime_type=ConstantString("application/pdf");
880   (void) RegisterMagickInfo(entry);
881   entry=AcquireMagickInfo("PDF","PDF","Portable Document Format");
882   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
883   entry->encoder=(EncodeImageHandler *) WritePDFImage;
884   entry->magick=(IsImageFormatHandler *) IsPDF;
885   entry->flags^=CoderBlobSupportFlag;
886   entry->flags|=CoderSeekableStreamFlag;
887   entry->mime_type=ConstantString("application/pdf");
888   (void) RegisterMagickInfo(entry);
889   entry=AcquireMagickInfo("PDF","PDFA","Portable Document Archive Format");
890   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
891   entry->encoder=(EncodeImageHandler *) WritePDFImage;
892   entry->magick=(IsImageFormatHandler *) IsPDF;
893   entry->flags^=CoderBlobSupportFlag;
894   entry->flags|=CoderSeekableStreamFlag;
895   entry->mime_type=ConstantString("application/pdf");
896   (void) RegisterMagickInfo(entry);
897   return(MagickImageCoderSignature);
898 }
899 
900 /*
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 %                                                                             %
903 %                                                                             %
904 %                                                                             %
905 %   U n r e g i s t e r P D F I m a g e                                       %
906 %                                                                             %
907 %                                                                             %
908 %                                                                             %
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 %
911 %  UnregisterPDFImage() removes format registrations made by the
912 %  PDF module from the list of supported formats.
913 %
914 %  The format of the UnregisterPDFImage method is:
915 %
916 %      UnregisterPDFImage(void)
917 %
918 */
UnregisterPDFImage(void)919 ModuleExport void UnregisterPDFImage(void)
920 {
921   (void) UnregisterMagickInfo("AI");
922   (void) UnregisterMagickInfo("EPDF");
923   (void) UnregisterMagickInfo("PDF");
924   (void) UnregisterMagickInfo("PDFA");
925 }
926 
927 /*
928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 %                                                                             %
930 %                                                                             %
931 %                                                                             %
932 %   W r i t e P D F I m a g e                                                 %
933 %                                                                             %
934 %                                                                             %
935 %                                                                             %
936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937 %
938 %  WritePDFImage() writes an image in the Portable Document image
939 %  format.
940 %
941 %  The format of the WritePDFImage method is:
942 %
943 %      MagickBooleanType WritePDFImage(const ImageInfo *image_info,
944 %        Image *image,ExceptionInfo *exception)
945 %
946 %  A description of each parameter follows.
947 %
948 %    o image_info: the image info.
949 %
950 %    o image:  The image.
951 %
952 %    o exception: return any errors or warnings in this structure.
953 %
954 */
955 
EscapeParenthesis(const char * source)956 static char *EscapeParenthesis(const char *source)
957 {
958   char
959     *destination;
960 
961   register char
962     *q;
963 
964   register const char
965     *p;
966 
967   size_t
968     length;
969 
970   assert(source != (const char *) NULL);
971   length=0;
972   for (p=source; *p != '\0'; p++)
973   {
974     if ((*p == '\\') || (*p == '(') || (*p == ')'))
975       {
976         if (~length < 1)
977           ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
978         length++;
979       }
980     length++;
981   }
982   destination=(char *) NULL;
983   if (~length >= (MagickPathExtent-1))
984     destination=(char *) AcquireQuantumMemory(length+MagickPathExtent,
985       sizeof(*destination));
986   if (destination == (char *) NULL)
987     ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
988   *destination='\0';
989   q=destination;
990   for (p=source; *p != '\0'; p++)
991   {
992     if ((*p == '\\') || (*p == '(') || (*p == ')'))
993       *q++='\\';
994     *q++=(*p);
995   }
996   *q='\0';
997   return(destination);
998 }
999 
UTF8ToUTF16(const unsigned char * utf8,wchar_t * utf16)1000 static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16)
1001 {
1002   register const unsigned char
1003     *p;
1004 
1005   if (utf16 != (wchar_t *) NULL)
1006     {
1007       register wchar_t
1008         *q;
1009 
1010       wchar_t
1011         c;
1012 
1013       /*
1014         Convert UTF-8 to UTF-16.
1015       */
1016       q=utf16;
1017       for (p=utf8; *p != '\0'; p++)
1018       {
1019         if ((*p & 0x80) == 0)
1020           *q=(*p);
1021         else
1022           if ((*p & 0xE0) == 0xC0)
1023             {
1024               c=(*p);
1025               *q=(c & 0x1F) << 6;
1026               p++;
1027               if ((*p & 0xC0) != 0x80)
1028                 return(0);
1029               *q|=(*p & 0x3F);
1030             }
1031           else
1032             if ((*p & 0xF0) == 0xE0)
1033               {
1034                 c=(*p);
1035                 *q=c << 12;
1036                 p++;
1037                 if ((*p & 0xC0) != 0x80)
1038                   return(0);
1039                 c=(*p);
1040                 *q|=(c & 0x3F) << 6;
1041                 p++;
1042                 if ((*p & 0xC0) != 0x80)
1043                   return(0);
1044                 *q|=(*p & 0x3F);
1045               }
1046             else
1047               return(0);
1048         q++;
1049       }
1050       *q++='\0';
1051       return(q-utf16);
1052     }
1053   /*
1054     Compute UTF-16 string length.
1055   */
1056   for (p=utf8; *p != '\0'; p++)
1057   {
1058     if ((*p & 0x80) == 0)
1059       ;
1060     else
1061       if ((*p & 0xE0) == 0xC0)
1062         {
1063           p++;
1064           if ((*p & 0xC0) != 0x80)
1065             return(0);
1066         }
1067       else
1068         if ((*p & 0xF0) == 0xE0)
1069           {
1070             p++;
1071             if ((*p & 0xC0) != 0x80)
1072               return(0);
1073             p++;
1074             if ((*p & 0xC0) != 0x80)
1075               return(0);
1076          }
1077        else
1078          return(0);
1079   }
1080   return(p-utf8);
1081 }
1082 
ConvertUTF8ToUTF16(const unsigned char * source,size_t * length)1083 static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source,size_t *length)
1084 {
1085   wchar_t
1086     *utf16;
1087 
1088   *length=UTF8ToUTF16(source,(wchar_t *) NULL);
1089   if (*length == 0)
1090     {
1091       register ssize_t
1092         i;
1093 
1094       /*
1095         Not UTF-8, just copy.
1096       */
1097       *length=strlen((const char *) source);
1098       utf16=(wchar_t *) AcquireQuantumMemory(*length+1,sizeof(*utf16));
1099       if (utf16 == (wchar_t *) NULL)
1100         return((wchar_t *) NULL);
1101       for (i=0; i <= (ssize_t) *length; i++)
1102         utf16[i]=source[i];
1103       return(utf16);
1104     }
1105   utf16=(wchar_t *) AcquireQuantumMemory(*length+1,sizeof(*utf16));
1106   if (utf16 == (wchar_t *) NULL)
1107     return((wchar_t *) NULL);
1108   *length=UTF8ToUTF16(source,utf16);
1109   return(utf16);
1110 }
1111 
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image,Image * inject_image,ExceptionInfo * exception)1112 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
1113   Image *image,Image *inject_image,ExceptionInfo *exception)
1114 {
1115   Image
1116     *group4_image;
1117 
1118   ImageInfo
1119     *write_info;
1120 
1121   MagickBooleanType
1122     status;
1123 
1124   size_t
1125     length;
1126 
1127   unsigned char
1128     *group4;
1129 
1130   status=MagickTrue;
1131   write_info=CloneImageInfo(image_info);
1132   (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
1133   (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
1134   group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
1135   if (group4_image == (Image *) NULL)
1136     return(MagickFalse);
1137   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
1138     exception);
1139   group4_image=DestroyImage(group4_image);
1140   if (group4 == (unsigned char *) NULL)
1141     return(MagickFalse);
1142   write_info=DestroyImageInfo(write_info);
1143   if (WriteBlob(image,length,group4) != (ssize_t) length)
1144     status=MagickFalse;
1145   group4=(unsigned char *) RelinquishMagickMemory(group4);
1146   return(status);
1147 }
1148 
WritePDFImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1149 static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image,
1150   ExceptionInfo *exception)
1151 {
1152 #define CFormat  "/Filter [ /%s ]\n"
1153 #define ObjectsPerImage  14
1154 
1155 DisableMSCWarning(4310)
1156   static const char
1157     XMPProfile[]=
1158     {
1159       "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
1160       "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 4.0-c316 44.253921, Sun Oct 01 2006 17:08:23\">\n"
1161       "   <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
1162       "      <rdf:Description rdf:about=\"\"\n"
1163       "            xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
1164       "         <xap:ModifyDate>%s</xap:ModifyDate>\n"
1165       "         <xap:CreateDate>%s</xap:CreateDate>\n"
1166       "         <xap:MetadataDate>%s</xap:MetadataDate>\n"
1167       "         <xap:CreatorTool>%s</xap:CreatorTool>\n"
1168       "      </rdf:Description>\n"
1169       "      <rdf:Description rdf:about=\"\"\n"
1170       "            xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
1171       "         <dc:format>application/pdf</dc:format>\n"
1172       "         <dc:title>\n"
1173       "           <rdf:Alt>\n"
1174       "              <rdf:li xml:lang=\"x-default\">%s</rdf:li>\n"
1175       "           </rdf:Alt>\n"
1176       "         </dc:title>\n"
1177       "      </rdf:Description>\n"
1178       "      <rdf:Description rdf:about=\"\"\n"
1179       "            xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
1180       "         <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
1181       "         <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
1182       "      </rdf:Description>\n"
1183       "      <rdf:Description rdf:about=\"\"\n"
1184       "            xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
1185       "         <pdf:Producer>%s</pdf:Producer>\n"
1186       "      </rdf:Description>\n"
1187       "      <rdf:Description rdf:about=\"\"\n"
1188       "            xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
1189       "         <pdfaid:part>3</pdfaid:part>\n"
1190       "         <pdfaid:conformance>B</pdfaid:conformance>\n"
1191       "      </rdf:Description>\n"
1192       "   </rdf:RDF>\n"
1193       "</x:xmpmeta>\n"
1194       "<?xpacket end=\"w\"?>\n"
1195     },
1196     XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
1197 RestoreMSCWarning
1198 
1199   char
1200     basename[MagickPathExtent],
1201     buffer[MagickPathExtent],
1202     date[MagickPathExtent],
1203     **labels,
1204     page_geometry[MagickPathExtent];
1205 
1206   CompressionType
1207     compression;
1208 
1209   const char
1210     *option,
1211     *value;
1212 
1213   double
1214     pointsize;
1215 
1216   GeometryInfo
1217     geometry_info;
1218 
1219   Image
1220     *next,
1221     *tile_image;
1222 
1223   MagickBooleanType
1224     status;
1225 
1226   MagickOffsetType
1227     offset,
1228     scene,
1229     *xref;
1230 
1231   MagickSizeType
1232     number_pixels;
1233 
1234   MagickStatusType
1235     flags;
1236 
1237   PointInfo
1238     delta,
1239     resolution,
1240     scale;
1241 
1242   RectangleInfo
1243     geometry,
1244     media_info,
1245     page_info;
1246 
1247   register const Quantum
1248     *p;
1249 
1250   register unsigned char
1251     *q;
1252 
1253   register ssize_t
1254     i,
1255     x;
1256 
1257   size_t
1258     info_id,
1259     length,
1260     object,
1261     pages_id,
1262     root_id,
1263     text_size,
1264     version;
1265 
1266   ssize_t
1267     count,
1268     y;
1269 
1270   struct tm
1271     local_time;
1272 
1273   time_t
1274     seconds;
1275 
1276   unsigned char
1277     *pixels;
1278 
1279   wchar_t
1280     *utf16;
1281 
1282   /*
1283     Open output image file.
1284   */
1285   assert(image_info != (const ImageInfo *) NULL);
1286   assert(image_info->signature == MagickCoreSignature);
1287   assert(image != (Image *) NULL);
1288   assert(image->signature == MagickCoreSignature);
1289   if (image->debug != MagickFalse)
1290     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1291   assert(exception != (ExceptionInfo *) NULL);
1292   assert(exception->signature == MagickCoreSignature);
1293   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1294   if (status == MagickFalse)
1295     return(status);
1296   /*
1297     Allocate X ref memory.
1298   */
1299   xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1300   if (xref == (MagickOffsetType *) NULL)
1301     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1302   (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1303   /*
1304     Write Info object.
1305   */
1306   object=0;
1307   version=3;
1308   if (image_info->compression == JPEG2000Compression)
1309     version=(size_t) MagickMax(version,5);
1310   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1311     if (next->alpha_trait != UndefinedPixelTrait)
1312       version=(size_t) MagickMax(version,4);
1313   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1314     version=(size_t) MagickMax(version,6);
1315   (void) FormatLocaleString(buffer,MagickPathExtent,"%%PDF-1.%.20g \n",(double)
1316     version);
1317   (void) WriteBlobString(image,buffer);
1318   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1319     {
1320       (void) WriteBlobByte(image,'%');
1321       (void) WriteBlobByte(image,0xe2);
1322       (void) WriteBlobByte(image,0xe3);
1323       (void) WriteBlobByte(image,0xcf);
1324       (void) WriteBlobByte(image,0xd3);
1325       (void) WriteBlobByte(image,'\n');
1326     }
1327   /*
1328     Write Catalog object.
1329   */
1330   xref[object++]=TellBlob(image);
1331   root_id=object;
1332   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1333     object);
1334   (void) WriteBlobString(image,buffer);
1335   (void) WriteBlobString(image,"<<\n");
1336   if (LocaleCompare(image_info->magick,"PDFA") != 0)
1337     (void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n",
1338       (double) object+1);
1339   else
1340     {
1341       (void) FormatLocaleString(buffer,MagickPathExtent,"/Metadata %.20g 0 R\n",
1342         (double) object+1);
1343       (void) WriteBlobString(image,buffer);
1344       (void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n",
1345         (double) object+2);
1346     }
1347   (void) WriteBlobString(image,buffer);
1348   (void) WriteBlobString(image,"/Type /Catalog");
1349   option=GetImageOption(image_info,"pdf:page-direction");
1350   if ((option != (const char *) NULL) &&
1351       (LocaleCompare(option,"right-to-left") != MagickFalse))
1352     (void) WriteBlobString(image,"/ViewerPreferences<</PageDirection/R2L>>\n");
1353   (void) WriteBlobString(image,"\n");
1354   (void) WriteBlobString(image,">>\n");
1355   (void) WriteBlobString(image,"endobj\n");
1356   GetPathComponent(image->filename,BasePath,basename);
1357   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1358     {
1359       char
1360         create_date[MagickPathExtent],
1361         modify_date[MagickPathExtent],
1362         timestamp[MagickPathExtent],
1363         xmp_profile[MagickPathExtent];
1364 
1365       /*
1366         Write XMP object.
1367       */
1368       xref[object++]=TellBlob(image);
1369       (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1370         object);
1371       (void) WriteBlobString(image,buffer);
1372       (void) WriteBlobString(image,"<<\n");
1373       (void) WriteBlobString(image,"/Subtype /XML\n");
1374       *modify_date='\0';
1375       value=GetImageProperty(image,"date:modify",exception);
1376       if (value != (const char *) NULL)
1377         (void) CopyMagickString(modify_date,value,MagickPathExtent);
1378       *create_date='\0';
1379       value=GetImageProperty(image,"date:create",exception);
1380       if (value != (const char *) NULL)
1381         (void) CopyMagickString(create_date,value,MagickPathExtent);
1382       (void) FormatMagickTime(time((time_t *) NULL),MagickPathExtent,timestamp);
1383       i=FormatLocaleString(xmp_profile,MagickPathExtent,XMPProfile,
1384         XMPProfileMagick,modify_date,create_date,timestamp,
1385         GetMagickVersion(&version),EscapeParenthesis(basename),
1386         GetMagickVersion(&version));
1387       (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g\n",
1388         (double) i);
1389       (void) WriteBlobString(image,buffer);
1390       (void) WriteBlobString(image,"/Type /Metadata\n");
1391       (void) WriteBlobString(image,">>\nstream\n");
1392       (void) WriteBlobString(image,xmp_profile);
1393       (void) WriteBlobString(image,"\nendstream\n");
1394       (void) WriteBlobString(image,"endobj\n");
1395     }
1396   /*
1397     Write Pages object.
1398   */
1399   xref[object++]=TellBlob(image);
1400   pages_id=object;
1401   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1402     object);
1403   (void) WriteBlobString(image,buffer);
1404   (void) WriteBlobString(image,"<<\n");
1405   (void) WriteBlobString(image,"/Type /Pages\n");
1406   (void) FormatLocaleString(buffer,MagickPathExtent,"/Kids [ %.20g 0 R ",
1407     (double) object+1);
1408   (void) WriteBlobString(image,buffer);
1409   count=(ssize_t) (pages_id+ObjectsPerImage+1);
1410   if (image_info->adjoin != MagickFalse)
1411     {
1412       Image
1413         *kid_image;
1414 
1415       /*
1416         Predict page object id's.
1417       */
1418       kid_image=image;
1419       for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1420       {
1421         (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 R ",(double)
1422           count);
1423         (void) WriteBlobString(image,buffer);
1424         kid_image=GetNextImageInList(kid_image);
1425       }
1426       xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1427         sizeof(*xref));
1428       if (xref == (MagickOffsetType *) NULL)
1429         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1430     }
1431   (void) WriteBlobString(image,"]\n");
1432   (void) FormatLocaleString(buffer,MagickPathExtent,"/Count %.20g\n",(double)
1433     ((count-pages_id)/ObjectsPerImage));
1434   (void) WriteBlobString(image,buffer);
1435   (void) WriteBlobString(image,">>\n");
1436   (void) WriteBlobString(image,"endobj\n");
1437   scene=0;
1438   do
1439   {
1440     compression=image->compression;
1441     if (image_info->compression != UndefinedCompression)
1442       compression=image_info->compression;
1443     switch (compression)
1444     {
1445       case FaxCompression:
1446       case Group4Compression:
1447       {
1448         if ((SetImageMonochrome(image,exception) == MagickFalse) ||
1449             (image->alpha_trait != UndefinedPixelTrait))
1450           compression=RLECompression;
1451         break;
1452       }
1453 #if !defined(MAGICKCORE_JPEG_DELEGATE)
1454       case JPEGCompression:
1455       {
1456         compression=RLECompression;
1457         (void) ThrowMagickException(exception,GetMagickModule(),
1458           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1459           image->filename);
1460         break;
1461       }
1462 #endif
1463 #if !defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
1464       case JPEG2000Compression:
1465       {
1466         compression=RLECompression;
1467         (void) ThrowMagickException(exception,GetMagickModule(),
1468           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1469           image->filename);
1470         break;
1471       }
1472 #endif
1473 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1474       case ZipCompression:
1475       {
1476         compression=RLECompression;
1477         (void) ThrowMagickException(exception,GetMagickModule(),
1478           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1479           image->filename);
1480         break;
1481       }
1482 #endif
1483       case LZWCompression:
1484       {
1485         if (LocaleCompare(image_info->magick,"PDFA") == 0)
1486           compression=RLECompression;  /* LZW compression is forbidden */
1487         break;
1488       }
1489       case NoCompression:
1490       {
1491         if (LocaleCompare(image_info->magick,"PDFA") == 0)
1492           compression=RLECompression; /* ASCII 85 compression is forbidden */
1493         break;
1494       }
1495       default:
1496         break;
1497     }
1498     if (compression == JPEG2000Compression)
1499       (void) TransformImageColorspace(image,sRGBColorspace,exception);
1500     /*
1501       Scale relative to dots-per-inch.
1502     */
1503     delta.x=DefaultResolution;
1504     delta.y=DefaultResolution;
1505     resolution.x=image->resolution.x;
1506     resolution.y=image->resolution.y;
1507     if ((resolution.x == 0.0) || (resolution.y == 0.0))
1508       {
1509         flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1510         resolution.x=geometry_info.rho;
1511         resolution.y=geometry_info.sigma;
1512         if ((flags & SigmaValue) == 0)
1513           resolution.y=resolution.x;
1514       }
1515     if (image_info->density != (char *) NULL)
1516       {
1517         flags=ParseGeometry(image_info->density,&geometry_info);
1518         resolution.x=geometry_info.rho;
1519         resolution.y=geometry_info.sigma;
1520         if ((flags & SigmaValue) == 0)
1521           resolution.y=resolution.x;
1522       }
1523     if (image->units == PixelsPerCentimeterResolution)
1524       {
1525         resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1526         resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1527       }
1528     SetGeometry(image,&geometry);
1529     (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
1530       (double) image->columns,(double) image->rows);
1531     if (image_info->page != (char *) NULL)
1532       (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
1533     else
1534       if ((image->page.width != 0) && (image->page.height != 0))
1535         (void) FormatLocaleString(page_geometry,MagickPathExtent,
1536           "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1537           image->page.height,(double) image->page.x,(double) image->page.y);
1538       else
1539         if ((image->gravity != UndefinedGravity) &&
1540             (LocaleCompare(image_info->magick,"PDF") == 0))
1541           (void) CopyMagickString(page_geometry,PSPageGeometry,
1542             MagickPathExtent);
1543     (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
1544     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1545       &geometry.width,&geometry.height);
1546     scale.x=(double) (geometry.width*delta.x)/resolution.x;
1547     geometry.width=(size_t) floor(scale.x+0.5);
1548     scale.y=(double) (geometry.height*delta.y)/resolution.y;
1549     geometry.height=(size_t) floor(scale.y+0.5);
1550     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1551     (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1552     if (image->gravity != UndefinedGravity)
1553       {
1554         geometry.x=(-page_info.x);
1555         geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1556       }
1557     pointsize=12.0;
1558     if (image_info->pointsize != 0.0)
1559       pointsize=image_info->pointsize;
1560     text_size=0;
1561     value=GetImageProperty(image,"label",exception);
1562     if (value != (const char *) NULL)
1563       text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1564     (void) text_size;
1565     /*
1566       Write Page object.
1567     */
1568     xref[object++]=TellBlob(image);
1569     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1570       object);
1571     (void) WriteBlobString(image,buffer);
1572     (void) WriteBlobString(image,"<<\n");
1573     (void) WriteBlobString(image,"/Type /Page\n");
1574     (void) FormatLocaleString(buffer,MagickPathExtent,"/Parent %.20g 0 R\n",
1575       (double) pages_id);
1576     (void) WriteBlobString(image,buffer);
1577     (void) WriteBlobString(image,"/Resources <<\n");
1578     labels=(char **) NULL;
1579     value=GetImageProperty(image,"label",exception);
1580     if (value != (const char *) NULL)
1581       labels=StringToList(value);
1582     if (labels != (char **) NULL)
1583       {
1584         (void) FormatLocaleString(buffer,MagickPathExtent,
1585           "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1586           object+4);
1587         (void) WriteBlobString(image,buffer);
1588       }
1589     (void) FormatLocaleString(buffer,MagickPathExtent,
1590       "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1591       object+5);
1592     (void) WriteBlobString(image,buffer);
1593     (void) FormatLocaleString(buffer,MagickPathExtent,"/ProcSet %.20g 0 R >>\n",
1594       (double) object+3);
1595     (void) WriteBlobString(image,buffer);
1596     (void) FormatLocaleString(buffer,MagickPathExtent,
1597       "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1598       72.0*media_info.height/resolution.y);
1599     (void) WriteBlobString(image,buffer);
1600     (void) FormatLocaleString(buffer,MagickPathExtent,
1601       "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1602       72.0*media_info.height/resolution.y);
1603     (void) WriteBlobString(image,buffer);
1604     (void) FormatLocaleString(buffer,MagickPathExtent,"/Contents %.20g 0 R\n",
1605       (double) object+1);
1606     (void) WriteBlobString(image,buffer);
1607     (void) FormatLocaleString(buffer,MagickPathExtent,"/Thumb %.20g 0 R\n",(double)
1608       object+8);
1609     (void) WriteBlobString(image,buffer);
1610     (void) WriteBlobString(image,">>\n");
1611     (void) WriteBlobString(image,"endobj\n");
1612     /*
1613       Write Contents object.
1614     */
1615     xref[object++]=TellBlob(image);
1616     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1617       object);
1618     (void) WriteBlobString(image,buffer);
1619     (void) WriteBlobString(image,"<<\n");
1620     (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
1621       (double) object+1);
1622     (void) WriteBlobString(image,buffer);
1623     (void) WriteBlobString(image,">>\n");
1624     (void) WriteBlobString(image,"stream\n");
1625     offset=TellBlob(image);
1626     (void) WriteBlobString(image,"q\n");
1627     if (labels != (char **) NULL)
1628       for (i=0; labels[i] != (char *) NULL; i++)
1629       {
1630         (void) WriteBlobString(image,"BT\n");
1631         (void) FormatLocaleString(buffer,MagickPathExtent,"/F%.20g %g Tf\n",
1632           (double) image->scene,pointsize);
1633         (void) WriteBlobString(image,buffer);
1634         (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g Td\n",
1635           (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+
1636           12));
1637         (void) WriteBlobString(image,buffer);
1638         (void) FormatLocaleString(buffer,MagickPathExtent,"(%s) Tj\n",
1639            labels[i]);
1640         (void) WriteBlobString(image,buffer);
1641         (void) WriteBlobString(image,"ET\n");
1642         labels[i]=DestroyString(labels[i]);
1643       }
1644     (void) FormatLocaleString(buffer,MagickPathExtent,
1645       "%g 0 0 %g %.20g %.20g cm\n",scale.x,scale.y,(double) geometry.x,
1646       (double) geometry.y);
1647     (void) WriteBlobString(image,buffer);
1648     (void) FormatLocaleString(buffer,MagickPathExtent,"/Im%.20g Do\n",(double)
1649       image->scene);
1650     (void) WriteBlobString(image,buffer);
1651     (void) WriteBlobString(image,"Q\n");
1652     offset=TellBlob(image)-offset;
1653     (void) WriteBlobString(image,"\nendstream\n");
1654     (void) WriteBlobString(image,"endobj\n");
1655     /*
1656       Write Length object.
1657     */
1658     xref[object++]=TellBlob(image);
1659     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1660       object);
1661     (void) WriteBlobString(image,buffer);
1662     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",
1663       (double) offset);
1664     (void) WriteBlobString(image,buffer);
1665     (void) WriteBlobString(image,"endobj\n");
1666     /*
1667       Write Procset object.
1668     */
1669     xref[object++]=TellBlob(image);
1670     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1671       object);
1672     (void) WriteBlobString(image,buffer);
1673     if ((image->storage_class == DirectClass) || (image->colors > 256))
1674       (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MagickPathExtent);
1675     else
1676       if ((compression == FaxCompression) || (compression == Group4Compression))
1677         (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MagickPathExtent);
1678       else
1679         (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MagickPathExtent);
1680     (void) WriteBlobString(image,buffer);
1681     (void) WriteBlobString(image," ]\n");
1682     (void) WriteBlobString(image,"endobj\n");
1683     /*
1684       Write Font object.
1685     */
1686     xref[object++]=TellBlob(image);
1687     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1688       object);
1689     (void) WriteBlobString(image,buffer);
1690     (void) WriteBlobString(image,"<<\n");
1691     if (labels != (char **) NULL)
1692       {
1693         (void) WriteBlobString(image,"/Type /Font\n");
1694         (void) WriteBlobString(image,"/Subtype /Type1\n");
1695         (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /F%.20g\n",
1696           (double) image->scene);
1697         (void) WriteBlobString(image,buffer);
1698         (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1699         (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1700         labels=(char **) RelinquishMagickMemory(labels);
1701       }
1702     (void) WriteBlobString(image,">>\n");
1703     (void) WriteBlobString(image,"endobj\n");
1704     /*
1705       Write XObject object.
1706     */
1707     xref[object++]=TellBlob(image);
1708     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1709       object);
1710     (void) WriteBlobString(image,buffer);
1711     (void) WriteBlobString(image,"<<\n");
1712     (void) WriteBlobString(image,"/Type /XObject\n");
1713     (void) WriteBlobString(image,"/Subtype /Image\n");
1714     (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Im%.20g\n",(double)
1715       image->scene);
1716     (void) WriteBlobString(image,buffer);
1717     switch (compression)
1718     {
1719       case NoCompression:
1720       {
1721         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"ASCII85Decode");
1722         break;
1723       }
1724       case JPEGCompression:
1725       {
1726         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode");
1727         if (image->colorspace != CMYKColorspace)
1728           break;
1729         (void) WriteBlobString(image,buffer);
1730         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1731           MagickPathExtent);
1732         break;
1733       }
1734       case JPEG2000Compression:
1735       {
1736         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode");
1737         if (image->colorspace != CMYKColorspace)
1738           break;
1739         (void) WriteBlobString(image,buffer);
1740         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1741           MagickPathExtent);
1742         break;
1743       }
1744       case LZWCompression:
1745       {
1746         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode");
1747         break;
1748       }
1749       case ZipCompression:
1750       {
1751         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1752           "FlateDecode");
1753         break;
1754       }
1755       case FaxCompression:
1756       case Group4Compression:
1757       {
1758         (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1759           MagickPathExtent);
1760         (void) WriteBlobString(image,buffer);
1761         (void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << "
1762           "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1763           (double) image->columns,(double) image->rows);
1764         break;
1765       }
1766       default:
1767       {
1768         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1769           "RunLengthDecode");
1770         break;
1771       }
1772     }
1773     (void) WriteBlobString(image,buffer);
1774     (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double)
1775       image->columns);
1776     (void) WriteBlobString(image,buffer);
1777     (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double)
1778       image->rows);
1779     (void) WriteBlobString(image,buffer);
1780     (void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n",
1781       (double) object+2);
1782     (void) WriteBlobString(image,buffer);
1783     (void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n",
1784       (compression == FaxCompression) || (compression == Group4Compression) ?
1785       1 : 8);
1786     (void) WriteBlobString(image,buffer);
1787     if (image->alpha_trait != UndefinedPixelTrait)
1788       {
1789         (void) FormatLocaleString(buffer,MagickPathExtent,"/SMask %.20g 0 R\n",
1790           (double) object+7);
1791         (void) WriteBlobString(image,buffer);
1792       }
1793     (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
1794       (double) object+1);
1795     (void) WriteBlobString(image,buffer);
1796     (void) WriteBlobString(image,">>\n");
1797     (void) WriteBlobString(image,"stream\n");
1798     offset=TellBlob(image);
1799     number_pixels=(MagickSizeType) image->columns*image->rows;
1800     if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1801       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1802     if ((compression == FaxCompression) || (compression == Group4Compression) ||
1803         ((image_info->type != TrueColorType) &&
1804          (SetImageGray(image,exception) != MagickFalse)))
1805       {
1806         switch (compression)
1807         {
1808           case FaxCompression:
1809           case Group4Compression:
1810           {
1811             if (LocaleCompare(CCITTParam,"0") == 0)
1812               {
1813                 (void) HuffmanEncodeImage(image_info,image,image,exception);
1814                 break;
1815               }
1816             (void) Huffman2DEncodeImage(image_info,image,image,exception);
1817             break;
1818           }
1819           case JPEGCompression:
1820           {
1821             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1822             if (status == MagickFalse)
1823               {
1824                 (void) CloseBlob(image);
1825                 return(MagickFalse);
1826               }
1827             break;
1828           }
1829           case JPEG2000Compression:
1830           {
1831             status=InjectImageBlob(image_info,image,image,"jp2",exception);
1832             if (status == MagickFalse)
1833               {
1834                 (void) CloseBlob(image);
1835                 return(MagickFalse);
1836               }
1837             break;
1838           }
1839           case RLECompression:
1840           default:
1841           {
1842             MemoryInfo
1843               *pixel_info;
1844 
1845             /*
1846               Allocate pixel array.
1847             */
1848             length=(size_t) number_pixels;
1849             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1850             if (pixel_info == (MemoryInfo *) NULL)
1851               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1852             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1853             /*
1854               Dump Runlength encoded pixels.
1855             */
1856             q=pixels;
1857             for (y=0; y < (ssize_t) image->rows; y++)
1858             {
1859               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1860               if (p == (const Quantum *) NULL)
1861                 break;
1862               for (x=0; x < (ssize_t) image->columns; x++)
1863               {
1864                 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
1865                 p+=GetPixelChannels(image);
1866               }
1867               if (image->previous == (Image *) NULL)
1868                 {
1869                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1870                     y,image->rows);
1871                   if (status == MagickFalse)
1872                     break;
1873                 }
1874             }
1875 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1876             if (compression == ZipCompression)
1877               status=ZLIBEncodeImage(image,length,pixels,exception);
1878             else
1879 #endif
1880               if (compression == LZWCompression)
1881                 status=LZWEncodeImage(image,length,pixels,exception);
1882               else
1883                 status=PackbitsEncodeImage(image,length,pixels,exception);
1884             pixel_info=RelinquishVirtualMemory(pixel_info);
1885             if (status == MagickFalse)
1886               {
1887                 (void) CloseBlob(image);
1888                 return(MagickFalse);
1889               }
1890             break;
1891           }
1892           case NoCompression:
1893           {
1894             /*
1895               Dump uncompressed PseudoColor packets.
1896             */
1897             Ascii85Initialize(image);
1898             for (y=0; y < (ssize_t) image->rows; y++)
1899             {
1900               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1901               if (p == (const Quantum *) NULL)
1902                 break;
1903               for (x=0; x < (ssize_t) image->columns; x++)
1904               {
1905                 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
1906                   GetPixelLuma(image,p))));
1907                 p+=GetPixelChannels(image);
1908               }
1909               if (image->previous == (Image *) NULL)
1910                 {
1911                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1912                     y,image->rows);
1913                   if (status == MagickFalse)
1914                     break;
1915                 }
1916             }
1917             Ascii85Flush(image);
1918             break;
1919           }
1920         }
1921       }
1922     else
1923       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1924           (compression == JPEGCompression) ||
1925           (compression == JPEG2000Compression))
1926         switch (compression)
1927         {
1928           case JPEGCompression:
1929           {
1930             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1931             if (status == MagickFalse)
1932               {
1933                 (void) CloseBlob(image);
1934                 return(MagickFalse);
1935               }
1936             break;
1937           }
1938           case JPEG2000Compression:
1939           {
1940             status=InjectImageBlob(image_info,image,image,"jp2",exception);
1941             if (status == MagickFalse)
1942               {
1943                 (void) CloseBlob(image);
1944                 return(MagickFalse);
1945               }
1946             break;
1947           }
1948           case RLECompression:
1949           default:
1950           {
1951             MemoryInfo
1952               *pixel_info;
1953 
1954             /*
1955               Allocate pixel array.
1956             */
1957             length=(size_t) number_pixels;
1958             length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1959             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1960             if (pixel_info == (MemoryInfo *) NULL)
1961               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1962             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1963             /*
1964               Dump runoffset encoded pixels.
1965             */
1966             q=pixels;
1967             for (y=0; y < (ssize_t) image->rows; y++)
1968             {
1969               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1970               if (p == (const Quantum *) NULL)
1971                 break;
1972               for (x=0; x < (ssize_t) image->columns; x++)
1973               {
1974                 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1975                 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1976                 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1977                 if (image->colorspace == CMYKColorspace)
1978                   *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
1979                 p+=GetPixelChannels(image);
1980               }
1981               if (image->previous == (Image *) NULL)
1982                 {
1983                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1984                     y,image->rows);
1985                   if (status == MagickFalse)
1986                     break;
1987                 }
1988             }
1989 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1990             if (compression == ZipCompression)
1991               status=ZLIBEncodeImage(image,length,pixels,exception);
1992             else
1993 #endif
1994               if (compression == LZWCompression)
1995                 status=LZWEncodeImage(image,length,pixels,exception);
1996               else
1997                 status=PackbitsEncodeImage(image,length,pixels,exception);
1998             pixel_info=RelinquishVirtualMemory(pixel_info);
1999             if (status == MagickFalse)
2000               {
2001                 (void) CloseBlob(image);
2002                 return(MagickFalse);
2003               }
2004             break;
2005           }
2006           case NoCompression:
2007           {
2008             /*
2009               Dump uncompressed DirectColor packets.
2010             */
2011             Ascii85Initialize(image);
2012             for (y=0; y < (ssize_t) image->rows; y++)
2013             {
2014               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2015               if (p == (const Quantum *) NULL)
2016                 break;
2017               for (x=0; x < (ssize_t) image->columns; x++)
2018               {
2019                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelRed(image,p)));
2020                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
2021                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
2022                 if (image->colorspace == CMYKColorspace)
2023                   Ascii85Encode(image,ScaleQuantumToChar(
2024                     GetPixelBlack(image,p)));
2025                 p+=GetPixelChannels(image);
2026               }
2027               if (image->previous == (Image *) NULL)
2028                 {
2029                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
2030                     y,image->rows);
2031                   if (status == MagickFalse)
2032                     break;
2033                 }
2034             }
2035             Ascii85Flush(image);
2036             break;
2037           }
2038         }
2039       else
2040         {
2041           /*
2042             Dump number of colors and colormap.
2043           */
2044           switch (compression)
2045           {
2046             case RLECompression:
2047             default:
2048             {
2049               MemoryInfo
2050                 *pixel_info;
2051 
2052               /*
2053                 Allocate pixel array.
2054               */
2055               length=(size_t) number_pixels;
2056               pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2057               if (pixel_info == (MemoryInfo *) NULL)
2058                 ThrowWriterException(ResourceLimitError,
2059                   "MemoryAllocationFailed");
2060               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2061               /*
2062                 Dump Runlength encoded pixels.
2063               */
2064               q=pixels;
2065               for (y=0; y < (ssize_t) image->rows; y++)
2066               {
2067                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2068                 if (p == (const Quantum *) NULL)
2069                   break;
2070                 for (x=0; x < (ssize_t) image->columns; x++)
2071                 {
2072                   *q++=(unsigned char) GetPixelIndex(image,p);
2073                   p+=GetPixelChannels(image);
2074                 }
2075                 if (image->previous == (Image *) NULL)
2076                   {
2077                     status=SetImageProgress(image,SaveImageTag,
2078                       (MagickOffsetType) y,image->rows);
2079                     if (status == MagickFalse)
2080                       break;
2081                   }
2082               }
2083 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2084               if (compression == ZipCompression)
2085                 status=ZLIBEncodeImage(image,length,pixels,exception);
2086               else
2087 #endif
2088                 if (compression == LZWCompression)
2089                   status=LZWEncodeImage(image,length,pixels,exception);
2090                 else
2091                   status=PackbitsEncodeImage(image,length,pixels,exception);
2092               pixel_info=RelinquishVirtualMemory(pixel_info);
2093               if (status == MagickFalse)
2094                 {
2095                   (void) CloseBlob(image);
2096                   return(MagickFalse);
2097                 }
2098               break;
2099             }
2100             case NoCompression:
2101             {
2102               /*
2103                 Dump uncompressed PseudoColor packets.
2104               */
2105               Ascii85Initialize(image);
2106               for (y=0; y < (ssize_t) image->rows; y++)
2107               {
2108                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2109                 if (p == (const Quantum *) NULL)
2110                   break;
2111                 for (x=0; x < (ssize_t) image->columns; x++)
2112                 {
2113                   Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
2114                   p+=GetPixelChannels(image);
2115                 }
2116                 if (image->previous == (Image *) NULL)
2117                   {
2118                     status=SetImageProgress(image,SaveImageTag,
2119                       (MagickOffsetType) y,image->rows);
2120                     if (status == MagickFalse)
2121                       break;
2122                   }
2123               }
2124               Ascii85Flush(image);
2125               break;
2126             }
2127           }
2128         }
2129     offset=TellBlob(image)-offset;
2130     (void) WriteBlobString(image,"\nendstream\n");
2131     (void) WriteBlobString(image,"endobj\n");
2132     /*
2133       Write Length object.
2134     */
2135     xref[object++]=TellBlob(image);
2136     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2137       object);
2138     (void) WriteBlobString(image,buffer);
2139     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2140       offset);
2141     (void) WriteBlobString(image,buffer);
2142     (void) WriteBlobString(image,"endobj\n");
2143     /*
2144       Write Colorspace object.
2145     */
2146     xref[object++]=TellBlob(image);
2147     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2148       object);
2149     (void) WriteBlobString(image,buffer);
2150     if (image->colorspace == CMYKColorspace)
2151       (void) CopyMagickString(buffer,"/DeviceCMYK\n",MagickPathExtent);
2152     else
2153       if ((compression == FaxCompression) ||
2154           (compression == Group4Compression) ||
2155           ((image_info->type != TrueColorType) &&
2156            (SetImageGray(image,exception) != MagickFalse)))
2157           (void) CopyMagickString(buffer,"/DeviceGray\n",MagickPathExtent);
2158       else
2159         if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2160             (compression == JPEGCompression) ||
2161             (compression == JPEG2000Compression))
2162           (void) CopyMagickString(buffer,"/DeviceRGB\n",MagickPathExtent);
2163         else
2164           (void) FormatLocaleString(buffer,MagickPathExtent,
2165             "[ /Indexed /DeviceRGB %.20g %.20g 0 R ]\n",(double) image->colors-
2166             1,(double) object+3);
2167     (void) WriteBlobString(image,buffer);
2168     (void) WriteBlobString(image,"endobj\n");
2169     /*
2170       Write Thumb object.
2171     */
2172     SetGeometry(image,&geometry);
2173     (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
2174       &geometry.width,&geometry.height);
2175     tile_image=ThumbnailImage(image,geometry.width,geometry.height,exception);
2176     if (tile_image == (Image *) NULL)
2177       return(MagickFalse);
2178     xref[object++]=TellBlob(image);
2179     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2180       object);
2181     (void) WriteBlobString(image,buffer);
2182     (void) WriteBlobString(image,"<<\n");
2183     switch (compression)
2184     {
2185       case NoCompression:
2186       {
2187         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2188           "ASCII85Decode");
2189         break;
2190       }
2191       case JPEGCompression:
2192       {
2193         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode");
2194         if (image->colorspace != CMYKColorspace)
2195           break;
2196         (void) WriteBlobString(image,buffer);
2197         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2198           MagickPathExtent);
2199         break;
2200       }
2201       case JPEG2000Compression:
2202       {
2203         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode");
2204         if (image->colorspace != CMYKColorspace)
2205           break;
2206         (void) WriteBlobString(image,buffer);
2207         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2208           MagickPathExtent);
2209         break;
2210       }
2211       case LZWCompression:
2212       {
2213         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode");
2214         break;
2215       }
2216       case ZipCompression:
2217       {
2218         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2219           "FlateDecode");
2220         break;
2221       }
2222       case FaxCompression:
2223       case Group4Compression:
2224       {
2225         (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
2226           MagickPathExtent);
2227         (void) WriteBlobString(image,buffer);
2228         (void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << "
2229           "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
2230           (double) tile_image->columns,(double) tile_image->rows);
2231         break;
2232       }
2233       default:
2234       {
2235         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2236           "RunLengthDecode");
2237         break;
2238       }
2239     }
2240     (void) WriteBlobString(image,buffer);
2241     (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double)
2242       tile_image->columns);
2243     (void) WriteBlobString(image,buffer);
2244     (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double)
2245       tile_image->rows);
2246     (void) WriteBlobString(image,buffer);
2247     (void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n",
2248       (double) object-1);
2249     (void) WriteBlobString(image,buffer);
2250     (void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n",
2251       (compression == FaxCompression) || (compression == Group4Compression) ?
2252       1 : 8);
2253     (void) WriteBlobString(image,buffer);
2254     (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2255       (double) object+1);
2256     (void) WriteBlobString(image,buffer);
2257     (void) WriteBlobString(image,">>\n");
2258     (void) WriteBlobString(image,"stream\n");
2259     offset=TellBlob(image);
2260     number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
2261     if ((compression == FaxCompression) ||
2262         (compression == Group4Compression) ||
2263         ((image_info->type != TrueColorType) &&
2264          (SetImageGray(tile_image,exception) != MagickFalse)))
2265       {
2266         switch (compression)
2267         {
2268           case FaxCompression:
2269           case Group4Compression:
2270           {
2271             if (LocaleCompare(CCITTParam,"0") == 0)
2272               {
2273                 (void) HuffmanEncodeImage(image_info,image,tile_image,
2274                   exception);
2275                 break;
2276               }
2277             (void) Huffman2DEncodeImage(image_info,image,tile_image,exception);
2278             break;
2279           }
2280           case JPEGCompression:
2281           {
2282             status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2283               exception);
2284             if (status == MagickFalse)
2285               {
2286                 (void) CloseBlob(image);
2287                 return(MagickFalse);
2288               }
2289             break;
2290           }
2291           case JPEG2000Compression:
2292           {
2293             status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
2294             if (status == MagickFalse)
2295               {
2296                 (void) CloseBlob(image);
2297                 return(MagickFalse);
2298               }
2299             break;
2300           }
2301           case RLECompression:
2302           default:
2303           {
2304             MemoryInfo
2305               *pixel_info;
2306 
2307             /*
2308               Allocate pixel array.
2309             */
2310             length=(size_t) number_pixels;
2311             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2312             if (pixel_info == (MemoryInfo *) NULL)
2313               {
2314                 tile_image=DestroyImage(tile_image);
2315                 ThrowWriterException(ResourceLimitError,
2316                   "MemoryAllocationFailed");
2317               }
2318             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2319             /*
2320               Dump runlength encoded pixels.
2321             */
2322             q=pixels;
2323             for (y=0; y < (ssize_t) tile_image->rows; y++)
2324             {
2325               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2326                 exception);
2327               if (p == (const Quantum *) NULL)
2328                 break;
2329               for (x=0; x < (ssize_t) tile_image->columns; x++)
2330               {
2331                 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2332                   tile_image,p)));
2333                 p+=GetPixelChannels(tile_image);
2334               }
2335             }
2336 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2337             if (compression == ZipCompression)
2338               status=ZLIBEncodeImage(image,length,pixels,exception);
2339             else
2340 #endif
2341               if (compression == LZWCompression)
2342                 status=LZWEncodeImage(image,length,pixels,exception);
2343               else
2344                 status=PackbitsEncodeImage(image,length,pixels,exception);
2345             pixel_info=RelinquishVirtualMemory(pixel_info);
2346             if (status == MagickFalse)
2347               {
2348                 (void) CloseBlob(image);
2349                 return(MagickFalse);
2350               }
2351             break;
2352           }
2353           case NoCompression:
2354           {
2355             /*
2356               Dump uncompressed PseudoColor packets.
2357             */
2358             Ascii85Initialize(image);
2359             for (y=0; y < (ssize_t) tile_image->rows; y++)
2360             {
2361               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2362                 exception);
2363               if (p == (const Quantum *) NULL)
2364                 break;
2365               for (x=0; x < (ssize_t) tile_image->columns; x++)
2366               {
2367                 Ascii85Encode(tile_image,ScaleQuantumToChar(ClampToQuantum(
2368                   GetPixelLuma(tile_image,p))));
2369                 p+=GetPixelChannels(tile_image);
2370               }
2371             }
2372             Ascii85Flush(image);
2373             break;
2374           }
2375         }
2376       }
2377     else
2378       if ((tile_image->storage_class == DirectClass) ||
2379           (tile_image->colors > 256) || (compression == JPEGCompression) ||
2380           (compression == JPEG2000Compression))
2381         switch (compression)
2382         {
2383           case JPEGCompression:
2384           {
2385             status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2386               exception);
2387             if (status == MagickFalse)
2388               {
2389                 (void) CloseBlob(image);
2390                 return(MagickFalse);
2391               }
2392             break;
2393           }
2394           case JPEG2000Compression:
2395           {
2396             status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
2397             if (status == MagickFalse)
2398               {
2399                 (void) CloseBlob(image);
2400                 return(MagickFalse);
2401               }
2402             break;
2403           }
2404           case RLECompression:
2405           default:
2406           {
2407             MemoryInfo
2408               *pixel_info;
2409 
2410             /*
2411               Allocate pixel array.
2412             */
2413             length=(size_t) number_pixels;
2414             length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2415             pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2416             if (pixel_info == (MemoryInfo *) NULL)
2417               {
2418                 tile_image=DestroyImage(tile_image);
2419                 ThrowWriterException(ResourceLimitError,
2420                   "MemoryAllocationFailed");
2421               }
2422             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2423             /*
2424               Dump runlength encoded pixels.
2425             */
2426             q=pixels;
2427             for (y=0; y < (ssize_t) tile_image->rows; y++)
2428             {
2429               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2430                 exception);
2431               if (p == (const Quantum *) NULL)
2432                 break;
2433               for (x=0; x < (ssize_t) tile_image->columns; x++)
2434               {
2435                 *q++=ScaleQuantumToChar(GetPixelRed(tile_image,p));
2436                 *q++=ScaleQuantumToChar(GetPixelGreen(tile_image,p));
2437                 *q++=ScaleQuantumToChar(GetPixelBlue(tile_image,p));
2438                 if (tile_image->colorspace == CMYKColorspace)
2439                   *q++=ScaleQuantumToChar(GetPixelBlack(tile_image,p));
2440                 p+=GetPixelChannels(tile_image);
2441               }
2442             }
2443 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2444             if (compression == ZipCompression)
2445               status=ZLIBEncodeImage(image,length,pixels,exception);
2446             else
2447 #endif
2448               if (compression == LZWCompression)
2449                 status=LZWEncodeImage(image,length,pixels,exception);
2450               else
2451                 status=PackbitsEncodeImage(image,length,pixels,exception);
2452             pixel_info=RelinquishVirtualMemory(pixel_info);
2453             if (status == MagickFalse)
2454               {
2455                 (void) CloseBlob(image);
2456                 return(MagickFalse);
2457               }
2458             break;
2459           }
2460           case NoCompression:
2461           {
2462             /*
2463               Dump uncompressed DirectColor packets.
2464             */
2465             Ascii85Initialize(image);
2466             for (y=0; y < (ssize_t) tile_image->rows; y++)
2467             {
2468               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2469                 exception);
2470               if (p == (const Quantum *) NULL)
2471                 break;
2472               for (x=0; x < (ssize_t) tile_image->columns; x++)
2473               {
2474                 Ascii85Encode(image,ScaleQuantumToChar(
2475                   GetPixelRed(tile_image,p)));
2476                 Ascii85Encode(image,ScaleQuantumToChar(
2477                   GetPixelGreen(tile_image,p)));
2478                 Ascii85Encode(image,ScaleQuantumToChar(
2479                   GetPixelBlue(tile_image,p)));
2480                 if (image->colorspace == CMYKColorspace)
2481                   Ascii85Encode(image,ScaleQuantumToChar(
2482                     GetPixelBlack(tile_image,p)));
2483                 p+=GetPixelChannels(tile_image);
2484               }
2485             }
2486             Ascii85Flush(image);
2487             break;
2488           }
2489         }
2490       else
2491         {
2492           /*
2493             Dump number of colors and colormap.
2494           */
2495           switch (compression)
2496           {
2497             case RLECompression:
2498             default:
2499             {
2500               MemoryInfo
2501                 *pixel_info;
2502 
2503               /*
2504                 Allocate pixel array.
2505               */
2506               length=(size_t) number_pixels;
2507               pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2508               if (pixel_info == (MemoryInfo *) NULL)
2509                 {
2510                   tile_image=DestroyImage(tile_image);
2511                   ThrowWriterException(ResourceLimitError,
2512                     "MemoryAllocationFailed");
2513                 }
2514               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2515               /*
2516                 Dump runlength encoded pixels.
2517               */
2518               q=pixels;
2519               for (y=0; y < (ssize_t) tile_image->rows; y++)
2520               {
2521                 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2522                   exception);
2523                 if (p == (const Quantum *) NULL)
2524                   break;
2525                 for (x=0; x < (ssize_t) tile_image->columns; x++)
2526                 {
2527                   *q++=(unsigned char) GetPixelIndex(tile_image,p);
2528                   p+=GetPixelChannels(tile_image);
2529                 }
2530               }
2531 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2532               if (compression == ZipCompression)
2533                 status=ZLIBEncodeImage(image,length,pixels,exception);
2534               else
2535 #endif
2536                 if (compression == LZWCompression)
2537                   status=LZWEncodeImage(image,length,pixels,exception);
2538                 else
2539                   status=PackbitsEncodeImage(image,length,pixels,exception);
2540               pixel_info=RelinquishVirtualMemory(pixel_info);
2541               if (status == MagickFalse)
2542                 {
2543                   (void) CloseBlob(image);
2544                   return(MagickFalse);
2545                 }
2546               break;
2547             }
2548             case NoCompression:
2549             {
2550               /*
2551                 Dump uncompressed PseudoColor packets.
2552               */
2553               Ascii85Initialize(image);
2554               for (y=0; y < (ssize_t) tile_image->rows; y++)
2555               {
2556                 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2557                   exception);
2558                 if (p == (const Quantum *) NULL)
2559                   break;
2560                 for (x=0; x < (ssize_t) tile_image->columns; x++)
2561                 {
2562                   Ascii85Encode(image,(unsigned char)
2563                     GetPixelIndex(tile_image,p));
2564                   p+=GetPixelChannels(image);
2565                 }
2566               }
2567               Ascii85Flush(image);
2568               break;
2569             }
2570           }
2571         }
2572     tile_image=DestroyImage(tile_image);
2573     offset=TellBlob(image)-offset;
2574     (void) WriteBlobString(image,"\nendstream\n");
2575     (void) WriteBlobString(image,"endobj\n");
2576     /*
2577       Write Length object.
2578     */
2579     xref[object++]=TellBlob(image);
2580     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2581       object);
2582     (void) WriteBlobString(image,buffer);
2583     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2584       offset);
2585     (void) WriteBlobString(image,buffer);
2586     (void) WriteBlobString(image,"endobj\n");
2587     xref[object++]=TellBlob(image);
2588     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2589       object);
2590     (void) WriteBlobString(image,buffer);
2591     (void) WriteBlobString(image,"<<\n");
2592     if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2593         (compression == FaxCompression) || (compression == Group4Compression))
2594       (void) WriteBlobString(image,">>\n");
2595     else
2596       {
2597         /*
2598           Write Colormap object.
2599         */
2600         if (compression == NoCompression)
2601           (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
2602         (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2603           (double) object+1);
2604         (void) WriteBlobString(image,buffer);
2605         (void) WriteBlobString(image,">>\n");
2606         (void) WriteBlobString(image,"stream\n");
2607         offset=TellBlob(image);
2608         if (compression == NoCompression)
2609           Ascii85Initialize(image);
2610         for (i=0; i < (ssize_t) image->colors; i++)
2611         {
2612           if (compression == NoCompression)
2613             {
2614               Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2615                 image->colormap[i].red)));
2616               Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2617                 image->colormap[i].green)));
2618               Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2619                 image->colormap[i].blue)));
2620               continue;
2621             }
2622           (void) WriteBlobByte(image,ScaleQuantumToChar(
2623              ClampToQuantum(image->colormap[i].red)));
2624           (void) WriteBlobByte(image,ScaleQuantumToChar(
2625              ClampToQuantum(image->colormap[i].green)));
2626           (void) WriteBlobByte(image,ScaleQuantumToChar(
2627              ClampToQuantum(image->colormap[i].blue)));
2628         }
2629         if (compression == NoCompression)
2630           Ascii85Flush(image);
2631        offset=TellBlob(image)-offset;
2632        (void) WriteBlobString(image,"\nendstream\n");
2633       }
2634     (void) WriteBlobString(image,"endobj\n");
2635     /*
2636       Write Length object.
2637     */
2638     xref[object++]=TellBlob(image);
2639     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2640       object);
2641     (void) WriteBlobString(image,buffer);
2642     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2643       offset);
2644     (void) WriteBlobString(image,buffer);
2645     (void) WriteBlobString(image,"endobj\n");
2646     /*
2647       Write softmask object.
2648     */
2649     xref[object++]=TellBlob(image);
2650     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2651       object);
2652     (void) WriteBlobString(image,buffer);
2653     (void) WriteBlobString(image,"<<\n");
2654     if (image->alpha_trait == UndefinedPixelTrait)
2655       (void) WriteBlobString(image,">>\n");
2656     else
2657       {
2658         (void) WriteBlobString(image,"/Type /XObject\n");
2659         (void) WriteBlobString(image,"/Subtype /Image\n");
2660         (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Ma%.20g\n",
2661           (double) image->scene);
2662         (void) WriteBlobString(image,buffer);
2663         switch (compression)
2664         {
2665           case NoCompression:
2666           {
2667             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2668               "ASCII85Decode");
2669             break;
2670           }
2671           case LZWCompression:
2672           {
2673             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2674               "LZWDecode");
2675             break;
2676           }
2677           case ZipCompression:
2678           {
2679             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2680               "FlateDecode");
2681             break;
2682           }
2683           default:
2684           {
2685             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2686               "RunLengthDecode");
2687             break;
2688           }
2689         }
2690         (void) WriteBlobString(image,buffer);
2691         (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",
2692           (double) image->columns);
2693         (void) WriteBlobString(image,buffer);
2694         (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",
2695           (double) image->rows);
2696         (void) WriteBlobString(image,buffer);
2697         (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2698         (void) FormatLocaleString(buffer,MagickPathExtent,
2699           "/BitsPerComponent %d\n",(compression == FaxCompression) ||
2700           (compression == Group4Compression) ? 1 : 8);
2701         (void) WriteBlobString(image,buffer);
2702         (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2703           (double) object+1);
2704         (void) WriteBlobString(image,buffer);
2705         (void) WriteBlobString(image,">>\n");
2706         (void) WriteBlobString(image,"stream\n");
2707         offset=TellBlob(image);
2708         number_pixels=(MagickSizeType) image->columns*image->rows;
2709         switch (compression)
2710         {
2711           case RLECompression:
2712           default:
2713           {
2714             MemoryInfo
2715               *pixel_info;
2716 
2717             /*
2718               Allocate pixel array.
2719             */
2720             length=(size_t) number_pixels;
2721             pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2722             if (pixel_info == (MemoryInfo *) NULL)
2723               {
2724                 image=DestroyImage(image);
2725                 ThrowWriterException(ResourceLimitError,
2726                   "MemoryAllocationFailed");
2727               }
2728             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2729             /*
2730               Dump Runlength encoded pixels.
2731             */
2732             q=pixels;
2733             for (y=0; y < (ssize_t) image->rows; y++)
2734             {
2735               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2736               if (p == (const Quantum *) NULL)
2737                 break;
2738               for (x=0; x < (ssize_t) image->columns; x++)
2739               {
2740                 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
2741                 p+=GetPixelChannels(image);
2742               }
2743             }
2744 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2745             if (compression == ZipCompression)
2746               status=ZLIBEncodeImage(image,length,pixels,exception);
2747             else
2748 #endif
2749               if (compression == LZWCompression)
2750                 status=LZWEncodeImage(image,length,pixels,exception);
2751               else
2752                 status=PackbitsEncodeImage(image,length,pixels,exception);
2753             pixel_info=RelinquishVirtualMemory(pixel_info);
2754             if (status == MagickFalse)
2755               {
2756                 (void) CloseBlob(image);
2757                 return(MagickFalse);
2758               }
2759             break;
2760           }
2761           case NoCompression:
2762           {
2763             /*
2764               Dump uncompressed PseudoColor packets.
2765             */
2766             Ascii85Initialize(image);
2767             for (y=0; y < (ssize_t) image->rows; y++)
2768             {
2769               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2770               if (p == (const Quantum *) NULL)
2771                 break;
2772               for (x=0; x < (ssize_t) image->columns; x++)
2773               {
2774                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
2775                 p+=GetPixelChannels(image);
2776               }
2777             }
2778             Ascii85Flush(image);
2779             break;
2780           }
2781         }
2782         offset=TellBlob(image)-offset;
2783         (void) WriteBlobString(image,"\nendstream\n");
2784       }
2785     (void) WriteBlobString(image,"endobj\n");
2786     /*
2787       Write Length object.
2788     */
2789     xref[object++]=TellBlob(image);
2790     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2791       object);
2792     (void) WriteBlobString(image,buffer);
2793     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2794       offset);
2795     (void) WriteBlobString(image,buffer);
2796     (void) WriteBlobString(image,"endobj\n");
2797     if (GetNextImageInList(image) == (Image *) NULL)
2798       break;
2799     image=SyncNextImageInList(image);
2800     status=SetImageProgress(image,SaveImagesTag,scene++,
2801       GetImageListLength(image));
2802     if (status == MagickFalse)
2803       break;
2804   } while (image_info->adjoin != MagickFalse);
2805   /*
2806     Write Metadata object.
2807   */
2808   xref[object++]=TellBlob(image);
2809   info_id=object;
2810   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2811     object);
2812   (void) WriteBlobString(image,buffer);
2813   (void) WriteBlobString(image,"<<\n");
2814   utf16=ConvertUTF8ToUTF16((unsigned char *) basename,&length);
2815   if (utf16 != (wchar_t *) NULL)
2816     {
2817       (void) FormatLocaleString(buffer,MagickPathExtent,"/Title (\xfe\xff");
2818       (void) WriteBlobString(image,buffer);
2819       for (i=0; i < (ssize_t) length; i++)
2820         WriteBlobMSBShort(image,(unsigned short) utf16[i]);
2821       (void) FormatLocaleString(buffer,MagickPathExtent,")\n");
2822       (void) WriteBlobString(image,buffer);
2823       utf16=(wchar_t *) RelinquishMagickMemory(utf16);
2824     }
2825   seconds=time((time_t *) NULL);
2826 #if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2827   (void) localtime_r(&seconds,&local_time);
2828 #else
2829   (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2830 #endif
2831   (void) FormatLocaleString(date,MagickPathExtent,"D:%04d%02d%02d%02d%02d%02d",
2832     local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2833     local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2834   (void) FormatLocaleString(buffer,MagickPathExtent,"/CreationDate (%s)\n",
2835     date);
2836   (void) WriteBlobString(image,buffer);
2837   (void) FormatLocaleString(buffer,MagickPathExtent,"/ModDate (%s)\n",date);
2838   (void) WriteBlobString(image,buffer);
2839   (void) FormatLocaleString(buffer,MagickPathExtent,"/Producer (%s)\n",
2840     EscapeParenthesis(GetMagickVersion((size_t *) NULL)));
2841   (void) WriteBlobString(image,buffer);
2842   (void) WriteBlobString(image,">>\n");
2843   (void) WriteBlobString(image,"endobj\n");
2844   /*
2845     Write Xref object.
2846   */
2847   offset=TellBlob(image)-xref[0]+
2848    (LocaleCompare(image_info->magick,"PDFA") == 0 ? 6 : 0)+10;
2849   (void) WriteBlobString(image,"xref\n");
2850   (void) FormatLocaleString(buffer,MagickPathExtent,"0 %.20g\n",(double)
2851     object+1);
2852   (void) WriteBlobString(image,buffer);
2853   (void) WriteBlobString(image,"0000000000 65535 f \n");
2854   for (i=0; i < (ssize_t) object; i++)
2855   {
2856     (void) FormatLocaleString(buffer,MagickPathExtent,"%010lu 00000 n \n",
2857       (unsigned long) xref[i]);
2858     (void) WriteBlobString(image,buffer);
2859   }
2860   (void) WriteBlobString(image,"trailer\n");
2861   (void) WriteBlobString(image,"<<\n");
2862   (void) FormatLocaleString(buffer,MagickPathExtent,"/Size %.20g\n",(double)
2863     object+1);
2864   (void) WriteBlobString(image,buffer);
2865   (void) FormatLocaleString(buffer,MagickPathExtent,"/Info %.20g 0 R\n",(double)
2866     info_id);
2867   (void) WriteBlobString(image,buffer);
2868   (void) FormatLocaleString(buffer,MagickPathExtent,"/Root %.20g 0 R\n",(double)
2869     root_id);
2870   (void) WriteBlobString(image,buffer);
2871   (void) SignatureImage(image,exception);
2872   (void) FormatLocaleString(buffer,MagickPathExtent,"/ID [<%s> <%s>]\n",
2873     GetImageProperty(image,"signature",exception),
2874     GetImageProperty(image,"signature",exception));
2875   (void) WriteBlobString(image,buffer);
2876   (void) WriteBlobString(image,">>\n");
2877   (void) WriteBlobString(image,"startxref\n");
2878   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) offset);
2879   (void) WriteBlobString(image,buffer);
2880   (void) WriteBlobString(image,"%%EOF\n");
2881   xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2882   (void) CloseBlob(image);
2883   return(MagickTrue);
2884 }
2885