]> granicus.if.org Git - imagemagick/blob - coders/pdf.c
Fix improper cast that could cause an overflow as demonstrated in #347.
[imagemagick] / coders / pdf.c
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-2017 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 \f
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 \f
84 /*
85   Define declarations.
86 */
87 #if defined(MAGICKCORE_TIFF_DELEGATE)
88 #define CCITTParam  "-1"
89 #else
90 #define CCITTParam  "0"
91 #endif
92 \f
93 /*
94   Forward declarations.
95 */
96 static MagickBooleanType
97   WritePDFImage(const ImageInfo *,Image *,ExceptionInfo *);
98 \f
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)
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
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 \f
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 */
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 \f
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
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
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 \f
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 */
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 \f
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 */
919 ModuleExport void UnregisterPDFImage(void)
920 {
921   (void) UnregisterMagickInfo("AI");
922   (void) UnregisterMagickInfo("EPDF");
923   (void) UnregisterMagickInfo("PDF");
924   (void) UnregisterMagickInfo("PDFA");
925 }
926 \f
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
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
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
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
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
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     *url;
1206
1207   CompressionType
1208     compression;
1209
1210   const char
1211     *option,
1212     *value;
1213
1214   double
1215     pointsize;
1216
1217   GeometryInfo
1218     geometry_info;
1219
1220   Image
1221     *next,
1222     *tile_image;
1223
1224   MagickBooleanType
1225     status;
1226
1227   MagickOffsetType
1228     offset,
1229     scene,
1230     *xref;
1231
1232   MagickSizeType
1233     number_pixels;
1234
1235   MagickStatusType
1236     flags;
1237
1238   PointInfo
1239     delta,
1240     resolution,
1241     scale;
1242
1243   RectangleInfo
1244     geometry,
1245     media_info,
1246     page_info;
1247
1248   register const Quantum
1249     *p;
1250
1251   register unsigned char
1252     *q;
1253
1254   register ssize_t
1255     i,
1256     x;
1257
1258   size_t
1259     info_id,
1260     length,
1261     object,
1262     pages_id,
1263     root_id,
1264     text_size,
1265     version;
1266
1267   ssize_t
1268     count,
1269     y;
1270
1271   struct tm
1272     local_time;
1273
1274   time_t
1275     seconds;
1276
1277   unsigned char
1278     *pixels;
1279
1280   wchar_t
1281     *utf16;
1282
1283   /*
1284     Open output image file.
1285   */
1286   assert(image_info != (const ImageInfo *) NULL);
1287   assert(image_info->signature == MagickCoreSignature);
1288   assert(image != (Image *) NULL);
1289   assert(image->signature == MagickCoreSignature);
1290   if (image->debug != MagickFalse)
1291     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1292   assert(exception != (ExceptionInfo *) NULL);
1293   assert(exception->signature == MagickCoreSignature);
1294   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1295   if (status == MagickFalse)
1296     return(status);
1297   /*
1298     Allocate X ref memory.
1299   */
1300   xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1301   if (xref == (MagickOffsetType *) NULL)
1302     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1303   (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1304   /*
1305     Write Info object.
1306   */
1307   object=0;
1308   version=3;
1309   if (image_info->compression == JPEG2000Compression)
1310     version=(size_t) MagickMax(version,5);
1311   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1312     if (next->alpha_trait != UndefinedPixelTrait)
1313       version=(size_t) MagickMax(version,4);
1314   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1315     version=(size_t) MagickMax(version,6);
1316   (void) FormatLocaleString(buffer,MagickPathExtent,"%%PDF-1.%.20g \n",(double)
1317     version);
1318   (void) WriteBlobString(image,buffer);
1319   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1320     {
1321       (void) WriteBlobByte(image,'%');
1322       (void) WriteBlobByte(image,0xe2);
1323       (void) WriteBlobByte(image,0xe3);
1324       (void) WriteBlobByte(image,0xcf);
1325       (void) WriteBlobByte(image,0xd3);
1326       (void) WriteBlobByte(image,'\n');
1327     }
1328   /*
1329     Write Catalog object.
1330   */
1331   xref[object++]=TellBlob(image);
1332   root_id=object;
1333   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1334     object);
1335   (void) WriteBlobString(image,buffer);
1336   (void) WriteBlobString(image,"<<\n");
1337   if (LocaleCompare(image_info->magick,"PDFA") != 0)
1338     (void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n",
1339       (double) object+1);
1340   else
1341     {
1342       (void) FormatLocaleString(buffer,MagickPathExtent,"/Metadata %.20g 0 R\n",
1343         (double) object+1);
1344       (void) WriteBlobString(image,buffer);
1345       (void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n",
1346         (double) object+2);
1347     }
1348   (void) WriteBlobString(image,buffer);
1349   (void) WriteBlobString(image,"/Type /Catalog");
1350   option=GetImageOption(image_info,"pdf:page-direction");
1351   if ((option != (const char *) NULL) &&
1352       (LocaleCompare(option,"right-to-left") != MagickFalse))
1353     (void) WriteBlobString(image,"/ViewerPreferences<</PageDirection/R2L>>\n");
1354   (void) WriteBlobString(image,"\n");
1355   (void) WriteBlobString(image,">>\n");
1356   (void) WriteBlobString(image,"endobj\n");
1357   GetPathComponent(image->filename,BasePath,basename);
1358   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1359     {
1360       char
1361         create_date[MagickPathExtent],
1362         modify_date[MagickPathExtent],
1363         timestamp[MagickPathExtent],
1364         *url,
1365         xmp_profile[MagickPathExtent];
1366
1367       /*
1368         Write XMP object.
1369       */
1370       xref[object++]=TellBlob(image);
1371       (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1372         object);
1373       (void) WriteBlobString(image,buffer);
1374       (void) WriteBlobString(image,"<<\n");
1375       (void) WriteBlobString(image,"/Subtype /XML\n");
1376       *modify_date='\0';
1377       value=GetImageProperty(image,"date:modify",exception);
1378       if (value != (const char *) NULL)
1379         (void) CopyMagickString(modify_date,value,MagickPathExtent);
1380       *create_date='\0';
1381       value=GetImageProperty(image,"date:create",exception);
1382       if (value != (const char *) NULL)
1383         (void) CopyMagickString(create_date,value,MagickPathExtent);
1384       (void) FormatMagickTime(time((time_t *) NULL),MagickPathExtent,timestamp);
1385       url=GetMagickHomeURL();
1386       i=FormatLocaleString(xmp_profile,MagickPathExtent,XMPProfile,
1387         XMPProfileMagick,modify_date,create_date,timestamp,url,
1388         EscapeParenthesis(basename),url);
1389       url=DestroyString(url);
1390       (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g\n",
1391         (double) i);
1392       (void) WriteBlobString(image,buffer);
1393       (void) WriteBlobString(image,"/Type /Metadata\n");
1394       (void) WriteBlobString(image,">>\nstream\n");
1395       (void) WriteBlobString(image,xmp_profile);
1396       (void) WriteBlobString(image,"\nendstream\n");
1397       (void) WriteBlobString(image,"endobj\n");
1398     }
1399   /*
1400     Write Pages object.
1401   */
1402   xref[object++]=TellBlob(image);
1403   pages_id=object;
1404   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1405     object);
1406   (void) WriteBlobString(image,buffer);
1407   (void) WriteBlobString(image,"<<\n");
1408   (void) WriteBlobString(image,"/Type /Pages\n");
1409   (void) FormatLocaleString(buffer,MagickPathExtent,"/Kids [ %.20g 0 R ",
1410     (double) object+1);
1411   (void) WriteBlobString(image,buffer);
1412   count=(ssize_t) (pages_id+ObjectsPerImage+1);
1413   if (image_info->adjoin != MagickFalse)
1414     {
1415       Image
1416         *kid_image;
1417
1418       /*
1419         Predict page object id's.
1420       */
1421       kid_image=image;
1422       for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1423       {
1424         (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 R ",(double)
1425           count);
1426         (void) WriteBlobString(image,buffer);
1427         kid_image=GetNextImageInList(kid_image);
1428       }
1429       xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1430         sizeof(*xref));
1431       if (xref == (MagickOffsetType *) NULL)
1432         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1433     }
1434   (void) WriteBlobString(image,"]\n");
1435   (void) FormatLocaleString(buffer,MagickPathExtent,"/Count %.20g\n",(double)
1436     ((count-pages_id)/ObjectsPerImage));
1437   (void) WriteBlobString(image,buffer);
1438   (void) WriteBlobString(image,">>\n");
1439   (void) WriteBlobString(image,"endobj\n");
1440   scene=0;
1441   do
1442   {
1443     compression=image->compression;
1444     if (image_info->compression != UndefinedCompression)
1445       compression=image_info->compression;
1446     switch (compression)
1447     {
1448       case FaxCompression:
1449       case Group4Compression:
1450       {
1451         if ((SetImageMonochrome(image,exception) == MagickFalse) ||
1452             (image->alpha_trait != UndefinedPixelTrait))
1453           compression=RLECompression;
1454         break;
1455       }
1456 #if !defined(MAGICKCORE_JPEG_DELEGATE)
1457       case JPEGCompression:
1458       {
1459         compression=RLECompression;
1460         (void) ThrowMagickException(exception,GetMagickModule(),
1461           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1462           image->filename);
1463         break;
1464       }
1465 #endif
1466 #if !defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
1467       case JPEG2000Compression:
1468       {
1469         compression=RLECompression;
1470         (void) ThrowMagickException(exception,GetMagickModule(),
1471           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1472           image->filename);
1473         break;
1474       }
1475 #endif
1476 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1477       case ZipCompression:
1478       {
1479         compression=RLECompression;
1480         (void) ThrowMagickException(exception,GetMagickModule(),
1481           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1482           image->filename);
1483         break;
1484       }
1485 #endif
1486       case LZWCompression:
1487       {
1488         if (LocaleCompare(image_info->magick,"PDFA") == 0)
1489           compression=RLECompression;  /* LZW compression is forbidden */
1490         break;
1491       }
1492       case NoCompression:
1493       {
1494         if (LocaleCompare(image_info->magick,"PDFA") == 0)
1495           compression=RLECompression; /* ASCII 85 compression is forbidden */
1496         break;
1497       }
1498       default:
1499         break;
1500     }
1501     if (compression == JPEG2000Compression)
1502       (void) TransformImageColorspace(image,sRGBColorspace,exception);
1503     /*
1504       Scale relative to dots-per-inch.
1505     */
1506     delta.x=DefaultResolution;
1507     delta.y=DefaultResolution;
1508     resolution.x=image->resolution.x;
1509     resolution.y=image->resolution.y;
1510     if ((resolution.x == 0.0) || (resolution.y == 0.0))
1511       {
1512         flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1513         resolution.x=geometry_info.rho;
1514         resolution.y=geometry_info.sigma;
1515         if ((flags & SigmaValue) == 0)
1516           resolution.y=resolution.x;
1517       }
1518     if (image_info->density != (char *) NULL)
1519       {
1520         flags=ParseGeometry(image_info->density,&geometry_info);
1521         resolution.x=geometry_info.rho;
1522         resolution.y=geometry_info.sigma;
1523         if ((flags & SigmaValue) == 0)
1524           resolution.y=resolution.x;
1525       }
1526     if (image->units == PixelsPerCentimeterResolution)
1527       {
1528         resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1529         resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1530       }
1531     SetGeometry(image,&geometry);
1532     (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
1533       (double) image->columns,(double) image->rows);
1534     if (image_info->page != (char *) NULL)
1535       (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
1536     else
1537       if ((image->page.width != 0) && (image->page.height != 0))
1538         (void) FormatLocaleString(page_geometry,MagickPathExtent,
1539           "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1540           image->page.height,(double) image->page.x,(double) image->page.y);
1541       else
1542         if ((image->gravity != UndefinedGravity) &&
1543             (LocaleCompare(image_info->magick,"PDF") == 0))
1544           (void) CopyMagickString(page_geometry,PSPageGeometry,
1545             MagickPathExtent);
1546     (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
1547     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1548       &geometry.width,&geometry.height);
1549     scale.x=(double) (geometry.width*delta.x)/resolution.x;
1550     geometry.width=(size_t) floor(scale.x+0.5);
1551     scale.y=(double) (geometry.height*delta.y)/resolution.y;
1552     geometry.height=(size_t) floor(scale.y+0.5);
1553     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1554     (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1555     if (image->gravity != UndefinedGravity)
1556       {
1557         geometry.x=(-page_info.x);
1558         geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1559       }
1560     pointsize=12.0;
1561     if (image_info->pointsize != 0.0)
1562       pointsize=image_info->pointsize;
1563     text_size=0;
1564     value=GetImageProperty(image,"label",exception);
1565     if (value != (const char *) NULL)
1566       text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1567     (void) text_size;
1568     /*
1569       Write Page object.
1570     */
1571     xref[object++]=TellBlob(image);
1572     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1573       object);
1574     (void) WriteBlobString(image,buffer);
1575     (void) WriteBlobString(image,"<<\n");
1576     (void) WriteBlobString(image,"/Type /Page\n");
1577     (void) FormatLocaleString(buffer,MagickPathExtent,"/Parent %.20g 0 R\n",
1578       (double) pages_id);
1579     (void) WriteBlobString(image,buffer);
1580     (void) WriteBlobString(image,"/Resources <<\n");
1581     labels=(char **) NULL;
1582     value=GetImageProperty(image,"label",exception);
1583     if (value != (const char *) NULL)
1584       labels=StringToList(value);
1585     if (labels != (char **) NULL)
1586       {
1587         (void) FormatLocaleString(buffer,MagickPathExtent,
1588           "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1589           object+4);
1590         (void) WriteBlobString(image,buffer);
1591       }
1592     (void) FormatLocaleString(buffer,MagickPathExtent,
1593       "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1594       object+5);
1595     (void) WriteBlobString(image,buffer);
1596     (void) FormatLocaleString(buffer,MagickPathExtent,"/ProcSet %.20g 0 R >>\n",
1597       (double) object+3);
1598     (void) WriteBlobString(image,buffer);
1599     (void) FormatLocaleString(buffer,MagickPathExtent,
1600       "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1601       72.0*media_info.height/resolution.y);
1602     (void) WriteBlobString(image,buffer);
1603     (void) FormatLocaleString(buffer,MagickPathExtent,
1604       "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1605       72.0*media_info.height/resolution.y);
1606     (void) WriteBlobString(image,buffer);
1607     (void) FormatLocaleString(buffer,MagickPathExtent,"/Contents %.20g 0 R\n",
1608       (double) object+1);
1609     (void) WriteBlobString(image,buffer);
1610     (void) FormatLocaleString(buffer,MagickPathExtent,"/Thumb %.20g 0 R\n",(double)
1611       object+8);
1612     (void) WriteBlobString(image,buffer);
1613     (void) WriteBlobString(image,">>\n");
1614     (void) WriteBlobString(image,"endobj\n");
1615     /*
1616       Write Contents object.
1617     */
1618     xref[object++]=TellBlob(image);
1619     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1620       object);
1621     (void) WriteBlobString(image,buffer);
1622     (void) WriteBlobString(image,"<<\n");
1623     (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
1624       (double) object+1);
1625     (void) WriteBlobString(image,buffer);
1626     (void) WriteBlobString(image,">>\n");
1627     (void) WriteBlobString(image,"stream\n");
1628     offset=TellBlob(image);
1629     (void) WriteBlobString(image,"q\n");
1630     if (labels != (char **) NULL)
1631       for (i=0; labels[i] != (char *) NULL; i++)
1632       {
1633         (void) WriteBlobString(image,"BT\n");
1634         (void) FormatLocaleString(buffer,MagickPathExtent,"/F%.20g %g Tf\n",
1635           (double) image->scene,pointsize);
1636         (void) WriteBlobString(image,buffer);
1637         (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g Td\n",
1638           (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+
1639           12));
1640         (void) WriteBlobString(image,buffer);
1641         (void) FormatLocaleString(buffer,MagickPathExtent,"(%s) Tj\n",
1642            labels[i]);
1643         (void) WriteBlobString(image,buffer);
1644         (void) WriteBlobString(image,"ET\n");
1645         labels[i]=DestroyString(labels[i]);
1646       }
1647     (void) FormatLocaleString(buffer,MagickPathExtent,
1648       "%g 0 0 %g %.20g %.20g cm\n",scale.x,scale.y,(double) geometry.x,
1649       (double) geometry.y);
1650     (void) WriteBlobString(image,buffer);
1651     (void) FormatLocaleString(buffer,MagickPathExtent,"/Im%.20g Do\n",(double)
1652       image->scene);
1653     (void) WriteBlobString(image,buffer);
1654     (void) WriteBlobString(image,"Q\n");
1655     offset=TellBlob(image)-offset;
1656     (void) WriteBlobString(image,"\nendstream\n");
1657     (void) WriteBlobString(image,"endobj\n");
1658     /*
1659       Write Length object.
1660     */
1661     xref[object++]=TellBlob(image);
1662     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1663       object);
1664     (void) WriteBlobString(image,buffer);
1665     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",
1666       (double) offset);
1667     (void) WriteBlobString(image,buffer);
1668     (void) WriteBlobString(image,"endobj\n");
1669     /*
1670       Write Procset object.
1671     */
1672     xref[object++]=TellBlob(image);
1673     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1674       object);
1675     (void) WriteBlobString(image,buffer);
1676     if ((image->storage_class == DirectClass) || (image->colors > 256))
1677       (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MagickPathExtent);
1678     else
1679       if ((compression == FaxCompression) || (compression == Group4Compression))
1680         (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MagickPathExtent);
1681       else
1682         (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MagickPathExtent);
1683     (void) WriteBlobString(image,buffer);
1684     (void) WriteBlobString(image," ]\n");
1685     (void) WriteBlobString(image,"endobj\n");
1686     /*
1687       Write Font object.
1688     */
1689     xref[object++]=TellBlob(image);
1690     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1691       object);
1692     (void) WriteBlobString(image,buffer);
1693     (void) WriteBlobString(image,"<<\n");
1694     if (labels != (char **) NULL)
1695       {
1696         (void) WriteBlobString(image,"/Type /Font\n");
1697         (void) WriteBlobString(image,"/Subtype /Type1\n");
1698         (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /F%.20g\n",
1699           (double) image->scene);
1700         (void) WriteBlobString(image,buffer);
1701         (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1702         (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1703         labels=(char **) RelinquishMagickMemory(labels);
1704       }
1705     (void) WriteBlobString(image,">>\n");
1706     (void) WriteBlobString(image,"endobj\n");
1707     /*
1708       Write XObject object.
1709     */
1710     xref[object++]=TellBlob(image);
1711     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1712       object);
1713     (void) WriteBlobString(image,buffer);
1714     (void) WriteBlobString(image,"<<\n");
1715     (void) WriteBlobString(image,"/Type /XObject\n");
1716     (void) WriteBlobString(image,"/Subtype /Image\n");
1717     (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Im%.20g\n",(double)
1718       image->scene);
1719     (void) WriteBlobString(image,buffer);
1720     switch (compression)
1721     {
1722       case NoCompression:
1723       {
1724         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"ASCII85Decode");
1725         break;
1726       }
1727       case JPEGCompression:
1728       {
1729         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode");
1730         if (image->colorspace != CMYKColorspace)
1731           break;
1732         (void) WriteBlobString(image,buffer);
1733         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1734           MagickPathExtent);
1735         break;
1736       }
1737       case JPEG2000Compression:
1738       {
1739         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode");
1740         if (image->colorspace != CMYKColorspace)
1741           break;
1742         (void) WriteBlobString(image,buffer);
1743         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1744           MagickPathExtent);
1745         break;
1746       }
1747       case LZWCompression:
1748       {
1749         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode");
1750         break;
1751       }
1752       case ZipCompression:
1753       {
1754         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1755           "FlateDecode");
1756         break;
1757       }
1758       case FaxCompression:
1759       case Group4Compression:
1760       {
1761         (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1762           MagickPathExtent);
1763         (void) WriteBlobString(image,buffer);
1764         (void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << "
1765           "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1766           (double) image->columns,(double) image->rows);
1767         break;
1768       }
1769       default:
1770       {
1771         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1772           "RunLengthDecode");
1773         break;
1774       }
1775     }
1776     (void) WriteBlobString(image,buffer);
1777     (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double)
1778       image->columns);
1779     (void) WriteBlobString(image,buffer);
1780     (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double)
1781       image->rows);
1782     (void) WriteBlobString(image,buffer);
1783     (void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n",
1784       (double) object+2);
1785     (void) WriteBlobString(image,buffer);
1786     (void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n",
1787       (compression == FaxCompression) || (compression == Group4Compression) ?
1788       1 : 8);
1789     (void) WriteBlobString(image,buffer);
1790     if (image->alpha_trait != UndefinedPixelTrait)
1791       {
1792         (void) FormatLocaleString(buffer,MagickPathExtent,"/SMask %.20g 0 R\n",
1793           (double) object+7);
1794         (void) WriteBlobString(image,buffer);
1795       }
1796     (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
1797       (double) object+1);
1798     (void) WriteBlobString(image,buffer);
1799     (void) WriteBlobString(image,">>\n");
1800     (void) WriteBlobString(image,"stream\n");
1801     offset=TellBlob(image);
1802     number_pixels=(MagickSizeType) image->columns*image->rows;
1803     if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1804       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1805     if ((compression == FaxCompression) || (compression == Group4Compression) ||
1806         ((image_info->type != TrueColorType) &&
1807          (SetImageGray(image,exception) != MagickFalse)))
1808       {
1809         switch (compression)
1810         {
1811           case FaxCompression:
1812           case Group4Compression:
1813           {
1814             if (LocaleCompare(CCITTParam,"0") == 0)
1815               {
1816                 (void) HuffmanEncodeImage(image_info,image,image,exception);
1817                 break;
1818               }
1819             (void) Huffman2DEncodeImage(image_info,image,image,exception);
1820             break;
1821           }
1822           case JPEGCompression:
1823           {
1824             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1825             if (status == MagickFalse)
1826               {
1827                 (void) CloseBlob(image);
1828                 return(MagickFalse);
1829               }
1830             break;
1831           }
1832           case JPEG2000Compression:
1833           {
1834             status=InjectImageBlob(image_info,image,image,"jp2",exception);
1835             if (status == MagickFalse)
1836               {
1837                 (void) CloseBlob(image);
1838                 return(MagickFalse);
1839               }
1840             break;
1841           }
1842           case RLECompression:
1843           default:
1844           {
1845             MemoryInfo
1846               *pixel_info;
1847
1848             /*
1849               Allocate pixel array.
1850             */
1851             length=(size_t) number_pixels;
1852             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1853             if (pixel_info == (MemoryInfo *) NULL)
1854               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1855             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1856             /*
1857               Dump Runlength encoded pixels.
1858             */
1859             q=pixels;
1860             for (y=0; y < (ssize_t) image->rows; y++)
1861             {
1862               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1863               if (p == (const Quantum *) NULL)
1864                 break;
1865               for (x=0; x < (ssize_t) image->columns; x++)
1866               {
1867                 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
1868                 p+=GetPixelChannels(image);
1869               }
1870               if (image->previous == (Image *) NULL)
1871                 {
1872                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1873                     y,image->rows);
1874                   if (status == MagickFalse)
1875                     break;
1876                 }
1877             }
1878 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1879             if (compression == ZipCompression)
1880               status=ZLIBEncodeImage(image,length,pixels,exception);
1881             else
1882 #endif
1883               if (compression == LZWCompression)
1884                 status=LZWEncodeImage(image,length,pixels,exception);
1885               else
1886                 status=PackbitsEncodeImage(image,length,pixels,exception);
1887             pixel_info=RelinquishVirtualMemory(pixel_info);
1888             if (status == MagickFalse)
1889               {
1890                 (void) CloseBlob(image);
1891                 return(MagickFalse);
1892               }
1893             break;
1894           }
1895           case NoCompression:
1896           {
1897             /*
1898               Dump uncompressed PseudoColor packets.
1899             */
1900             Ascii85Initialize(image);
1901             for (y=0; y < (ssize_t) image->rows; y++)
1902             {
1903               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1904               if (p == (const Quantum *) NULL)
1905                 break;
1906               for (x=0; x < (ssize_t) image->columns; x++)
1907               {
1908                 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
1909                   GetPixelLuma(image,p))));
1910                 p+=GetPixelChannels(image);
1911               }
1912               if (image->previous == (Image *) NULL)
1913                 {
1914                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1915                     y,image->rows);
1916                   if (status == MagickFalse)
1917                     break;
1918                 }
1919             }
1920             Ascii85Flush(image);
1921             break;
1922           }
1923         }
1924       }
1925     else
1926       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1927           (compression == JPEGCompression) ||
1928           (compression == JPEG2000Compression))
1929         switch (compression)
1930         {
1931           case JPEGCompression:
1932           {
1933             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1934             if (status == MagickFalse)
1935               {
1936                 (void) CloseBlob(image);
1937                 return(MagickFalse);
1938               }
1939             break;
1940           }
1941           case JPEG2000Compression:
1942           {
1943             status=InjectImageBlob(image_info,image,image,"jp2",exception);
1944             if (status == MagickFalse)
1945               {
1946                 (void) CloseBlob(image);
1947                 return(MagickFalse);
1948               }
1949             break;
1950           }
1951           case RLECompression:
1952           default:
1953           {
1954             MemoryInfo
1955               *pixel_info;
1956
1957             /*
1958               Allocate pixel array.
1959             */
1960             length=(size_t) number_pixels;
1961             length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1962             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1963             if (pixel_info == (MemoryInfo *) NULL)
1964               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1965             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1966             /*
1967               Dump runoffset encoded pixels.
1968             */
1969             q=pixels;
1970             for (y=0; y < (ssize_t) image->rows; y++)
1971             {
1972               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1973               if (p == (const Quantum *) NULL)
1974                 break;
1975               for (x=0; x < (ssize_t) image->columns; x++)
1976               {
1977                 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1978                 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1979                 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1980                 if (image->colorspace == CMYKColorspace)
1981                   *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
1982                 p+=GetPixelChannels(image);
1983               }
1984               if (image->previous == (Image *) NULL)
1985                 {
1986                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1987                     y,image->rows);
1988                   if (status == MagickFalse)
1989                     break;
1990                 }
1991             }
1992 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1993             if (compression == ZipCompression)
1994               status=ZLIBEncodeImage(image,length,pixels,exception);
1995             else
1996 #endif
1997               if (compression == LZWCompression)
1998                 status=LZWEncodeImage(image,length,pixels,exception);
1999               else
2000                 status=PackbitsEncodeImage(image,length,pixels,exception);
2001             pixel_info=RelinquishVirtualMemory(pixel_info);
2002             if (status == MagickFalse)
2003               {
2004                 (void) CloseBlob(image);
2005                 return(MagickFalse);
2006               }
2007             break;
2008           }
2009           case NoCompression:
2010           {
2011             /*
2012               Dump uncompressed DirectColor packets.
2013             */
2014             Ascii85Initialize(image);
2015             for (y=0; y < (ssize_t) image->rows; y++)
2016             {
2017               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2018               if (p == (const Quantum *) NULL)
2019                 break;
2020               for (x=0; x < (ssize_t) image->columns; x++)
2021               {
2022                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelRed(image,p)));
2023                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
2024                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
2025                 if (image->colorspace == CMYKColorspace)
2026                   Ascii85Encode(image,ScaleQuantumToChar(
2027                     GetPixelBlack(image,p)));
2028                 p+=GetPixelChannels(image);
2029               }
2030               if (image->previous == (Image *) NULL)
2031                 {
2032                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
2033                     y,image->rows);
2034                   if (status == MagickFalse)
2035                     break;
2036                 }
2037             }
2038             Ascii85Flush(image);
2039             break;
2040           }
2041         }
2042       else
2043         {
2044           /*
2045             Dump number of colors and colormap.
2046           */
2047           switch (compression)
2048           {
2049             case RLECompression:
2050             default:
2051             {
2052               MemoryInfo
2053                 *pixel_info;
2054
2055               /*
2056                 Allocate pixel array.
2057               */
2058               length=(size_t) number_pixels;
2059               pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2060               if (pixel_info == (MemoryInfo *) NULL)
2061                 ThrowWriterException(ResourceLimitError,
2062                   "MemoryAllocationFailed");
2063               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2064               /*
2065                 Dump Runlength encoded pixels.
2066               */
2067               q=pixels;
2068               for (y=0; y < (ssize_t) image->rows; y++)
2069               {
2070                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2071                 if (p == (const Quantum *) NULL)
2072                   break;
2073                 for (x=0; x < (ssize_t) image->columns; x++)
2074                 {
2075                   *q++=(unsigned char) GetPixelIndex(image,p);
2076                   p+=GetPixelChannels(image);
2077                 }
2078                 if (image->previous == (Image *) NULL)
2079                   {
2080                     status=SetImageProgress(image,SaveImageTag,
2081                       (MagickOffsetType) y,image->rows);
2082                     if (status == MagickFalse)
2083                       break;
2084                   }
2085               }
2086 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2087               if (compression == ZipCompression)
2088                 status=ZLIBEncodeImage(image,length,pixels,exception);
2089               else
2090 #endif
2091                 if (compression == LZWCompression)
2092                   status=LZWEncodeImage(image,length,pixels,exception);
2093                 else
2094                   status=PackbitsEncodeImage(image,length,pixels,exception);
2095               pixel_info=RelinquishVirtualMemory(pixel_info);
2096               if (status == MagickFalse)
2097                 {
2098                   (void) CloseBlob(image);
2099                   return(MagickFalse);
2100                 }
2101               break;
2102             }
2103             case NoCompression:
2104             {
2105               /*
2106                 Dump uncompressed PseudoColor packets.
2107               */
2108               Ascii85Initialize(image);
2109               for (y=0; y < (ssize_t) image->rows; y++)
2110               {
2111                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2112                 if (p == (const Quantum *) NULL)
2113                   break;
2114                 for (x=0; x < (ssize_t) image->columns; x++)
2115                 {
2116                   Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
2117                   p+=GetPixelChannels(image);
2118                 }
2119                 if (image->previous == (Image *) NULL)
2120                   {
2121                     status=SetImageProgress(image,SaveImageTag,
2122                       (MagickOffsetType) y,image->rows);
2123                     if (status == MagickFalse)
2124                       break;
2125                   }
2126               }
2127               Ascii85Flush(image);
2128               break;
2129             }
2130           }
2131         }
2132     offset=TellBlob(image)-offset;
2133     (void) WriteBlobString(image,"\nendstream\n");
2134     (void) WriteBlobString(image,"endobj\n");
2135     /*
2136       Write Length object.
2137     */
2138     xref[object++]=TellBlob(image);
2139     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2140       object);
2141     (void) WriteBlobString(image,buffer);
2142     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2143       offset);
2144     (void) WriteBlobString(image,buffer);
2145     (void) WriteBlobString(image,"endobj\n");
2146     /*
2147       Write Colorspace object.
2148     */
2149     xref[object++]=TellBlob(image);
2150     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2151       object);
2152     (void) WriteBlobString(image,buffer);
2153     if (image->colorspace == CMYKColorspace)
2154       (void) CopyMagickString(buffer,"/DeviceCMYK\n",MagickPathExtent);
2155     else
2156       if ((compression == FaxCompression) ||
2157           (compression == Group4Compression) ||
2158           ((image_info->type != TrueColorType) &&
2159            (SetImageGray(image,exception) != MagickFalse)))
2160           (void) CopyMagickString(buffer,"/DeviceGray\n",MagickPathExtent);
2161       else
2162         if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2163             (compression == JPEGCompression) ||
2164             (compression == JPEG2000Compression))
2165           (void) CopyMagickString(buffer,"/DeviceRGB\n",MagickPathExtent);
2166         else
2167           (void) FormatLocaleString(buffer,MagickPathExtent,
2168             "[ /Indexed /DeviceRGB %.20g %.20g 0 R ]\n",(double) image->colors-
2169             1,(double) object+3);
2170     (void) WriteBlobString(image,buffer);
2171     (void) WriteBlobString(image,"endobj\n");
2172     /*
2173       Write Thumb object.
2174     */
2175     SetGeometry(image,&geometry);
2176     (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
2177       &geometry.width,&geometry.height);
2178     tile_image=ThumbnailImage(image,geometry.width,geometry.height,exception);
2179     if (tile_image == (Image *) NULL)
2180       return(MagickFalse);
2181     xref[object++]=TellBlob(image);
2182     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2183       object);
2184     (void) WriteBlobString(image,buffer);
2185     (void) WriteBlobString(image,"<<\n");
2186     switch (compression)
2187     {
2188       case NoCompression:
2189       {
2190         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2191           "ASCII85Decode");
2192         break;
2193       }
2194       case JPEGCompression:
2195       {
2196         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode");
2197         if (image->colorspace != CMYKColorspace)
2198           break;
2199         (void) WriteBlobString(image,buffer);
2200         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2201           MagickPathExtent);
2202         break;
2203       }
2204       case JPEG2000Compression:
2205       {
2206         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode");
2207         if (image->colorspace != CMYKColorspace)
2208           break;
2209         (void) WriteBlobString(image,buffer);
2210         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2211           MagickPathExtent);
2212         break;
2213       }
2214       case LZWCompression:
2215       {
2216         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode");
2217         break;
2218       }
2219       case ZipCompression:
2220       {
2221         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2222           "FlateDecode");
2223         break;
2224       }
2225       case FaxCompression:
2226       case Group4Compression:
2227       {
2228         (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
2229           MagickPathExtent);
2230         (void) WriteBlobString(image,buffer);
2231         (void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << "
2232           "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
2233           (double) tile_image->columns,(double) tile_image->rows);
2234         break;
2235       }
2236       default:
2237       {
2238         (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2239           "RunLengthDecode");
2240         break;
2241       }
2242     }
2243     (void) WriteBlobString(image,buffer);
2244     (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double)
2245       tile_image->columns);
2246     (void) WriteBlobString(image,buffer);
2247     (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double)
2248       tile_image->rows);
2249     (void) WriteBlobString(image,buffer);
2250     (void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n",
2251       (double) object-1);
2252     (void) WriteBlobString(image,buffer);
2253     (void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n",
2254       (compression == FaxCompression) || (compression == Group4Compression) ?
2255       1 : 8);
2256     (void) WriteBlobString(image,buffer);
2257     (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2258       (double) object+1);
2259     (void) WriteBlobString(image,buffer);
2260     (void) WriteBlobString(image,">>\n");
2261     (void) WriteBlobString(image,"stream\n");
2262     offset=TellBlob(image);
2263     number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
2264     if ((compression == FaxCompression) ||
2265         (compression == Group4Compression) ||
2266         ((image_info->type != TrueColorType) &&
2267          (SetImageGray(tile_image,exception) != MagickFalse)))
2268       {
2269         switch (compression)
2270         {
2271           case FaxCompression:
2272           case Group4Compression:
2273           {
2274             if (LocaleCompare(CCITTParam,"0") == 0)
2275               {
2276                 (void) HuffmanEncodeImage(image_info,image,tile_image,
2277                   exception);
2278                 break;
2279               }
2280             (void) Huffman2DEncodeImage(image_info,image,tile_image,exception);
2281             break;
2282           }
2283           case JPEGCompression:
2284           {
2285             status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2286               exception);
2287             if (status == MagickFalse)
2288               {
2289                 (void) CloseBlob(image);
2290                 return(MagickFalse);
2291               }
2292             break;
2293           }
2294           case JPEG2000Compression:
2295           {
2296             status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
2297             if (status == MagickFalse)
2298               {
2299                 (void) CloseBlob(image);
2300                 return(MagickFalse);
2301               }
2302             break;
2303           }
2304           case RLECompression:
2305           default:
2306           {
2307             MemoryInfo
2308               *pixel_info;
2309
2310             /*
2311               Allocate pixel array.
2312             */
2313             length=(size_t) number_pixels;
2314             pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2315             if (pixel_info == (MemoryInfo *) NULL)
2316               {
2317                 tile_image=DestroyImage(tile_image);
2318                 ThrowWriterException(ResourceLimitError,
2319                   "MemoryAllocationFailed");
2320               }
2321             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2322             /*
2323               Dump runlength encoded pixels.
2324             */
2325             q=pixels;
2326             for (y=0; y < (ssize_t) tile_image->rows; y++)
2327             {
2328               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2329                 exception);
2330               if (p == (const Quantum *) NULL)
2331                 break;
2332               for (x=0; x < (ssize_t) tile_image->columns; x++)
2333               {
2334                 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2335                   tile_image,p)));
2336                 p+=GetPixelChannels(tile_image);
2337               }
2338             }
2339 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2340             if (compression == ZipCompression)
2341               status=ZLIBEncodeImage(image,length,pixels,exception);
2342             else
2343 #endif
2344               if (compression == LZWCompression)
2345                 status=LZWEncodeImage(image,length,pixels,exception);
2346               else
2347                 status=PackbitsEncodeImage(image,length,pixels,exception);
2348             pixel_info=RelinquishVirtualMemory(pixel_info);
2349             if (status == MagickFalse)
2350               {
2351                 (void) CloseBlob(image);
2352                 return(MagickFalse);
2353               }
2354             break;
2355           }
2356           case NoCompression:
2357           {
2358             /*
2359               Dump uncompressed PseudoColor packets.
2360             */
2361             Ascii85Initialize(image);
2362             for (y=0; y < (ssize_t) tile_image->rows; y++)
2363             {
2364               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2365                 exception);
2366               if (p == (const Quantum *) NULL)
2367                 break;
2368               for (x=0; x < (ssize_t) tile_image->columns; x++)
2369               {
2370                 Ascii85Encode(tile_image,ScaleQuantumToChar(ClampToQuantum(
2371                   GetPixelLuma(tile_image,p))));
2372                 p+=GetPixelChannels(tile_image);
2373               }
2374             }
2375             Ascii85Flush(image);
2376             break;
2377           }
2378         }
2379       }
2380     else
2381       if ((tile_image->storage_class == DirectClass) ||
2382           (tile_image->colors > 256) || (compression == JPEGCompression) ||
2383           (compression == JPEG2000Compression))
2384         switch (compression)
2385         {
2386           case JPEGCompression:
2387           {
2388             status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2389               exception);
2390             if (status == MagickFalse)
2391               {
2392                 (void) CloseBlob(image);
2393                 return(MagickFalse);
2394               }
2395             break;
2396           }
2397           case JPEG2000Compression:
2398           {
2399             status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
2400             if (status == MagickFalse)
2401               {
2402                 (void) CloseBlob(image);
2403                 return(MagickFalse);
2404               }
2405             break;
2406           }
2407           case RLECompression:
2408           default:
2409           {
2410             MemoryInfo
2411               *pixel_info;
2412
2413             /*
2414               Allocate pixel array.
2415             */
2416             length=(size_t) number_pixels;
2417             length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2418             pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2419             if (pixel_info == (MemoryInfo *) NULL)
2420               {
2421                 tile_image=DestroyImage(tile_image);
2422                 ThrowWriterException(ResourceLimitError,
2423                   "MemoryAllocationFailed");
2424               }
2425             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2426             /*
2427               Dump runlength encoded pixels.
2428             */
2429             q=pixels;
2430             for (y=0; y < (ssize_t) tile_image->rows; y++)
2431             {
2432               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2433                 exception);
2434               if (p == (const Quantum *) NULL)
2435                 break;
2436               for (x=0; x < (ssize_t) tile_image->columns; x++)
2437               {
2438                 *q++=ScaleQuantumToChar(GetPixelRed(tile_image,p));
2439                 *q++=ScaleQuantumToChar(GetPixelGreen(tile_image,p));
2440                 *q++=ScaleQuantumToChar(GetPixelBlue(tile_image,p));
2441                 if (tile_image->colorspace == CMYKColorspace)
2442                   *q++=ScaleQuantumToChar(GetPixelBlack(tile_image,p));
2443                 p+=GetPixelChannels(tile_image);
2444               }
2445             }
2446 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2447             if (compression == ZipCompression)
2448               status=ZLIBEncodeImage(image,length,pixels,exception);
2449             else
2450 #endif
2451               if (compression == LZWCompression)
2452                 status=LZWEncodeImage(image,length,pixels,exception);
2453               else
2454                 status=PackbitsEncodeImage(image,length,pixels,exception);
2455             pixel_info=RelinquishVirtualMemory(pixel_info);
2456             if (status == MagickFalse)
2457               {
2458                 (void) CloseBlob(image);
2459                 return(MagickFalse);
2460               }
2461             break;
2462           }
2463           case NoCompression:
2464           {
2465             /*
2466               Dump uncompressed DirectColor packets.
2467             */
2468             Ascii85Initialize(image);
2469             for (y=0; y < (ssize_t) tile_image->rows; y++)
2470             {
2471               p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2472                 exception);
2473               if (p == (const Quantum *) NULL)
2474                 break;
2475               for (x=0; x < (ssize_t) tile_image->columns; x++)
2476               {
2477                 Ascii85Encode(image,ScaleQuantumToChar(
2478                   GetPixelRed(tile_image,p)));
2479                 Ascii85Encode(image,ScaleQuantumToChar(
2480                   GetPixelGreen(tile_image,p)));
2481                 Ascii85Encode(image,ScaleQuantumToChar(
2482                   GetPixelBlue(tile_image,p)));
2483                 if (image->colorspace == CMYKColorspace)
2484                   Ascii85Encode(image,ScaleQuantumToChar(
2485                     GetPixelBlack(tile_image,p)));
2486                 p+=GetPixelChannels(tile_image);
2487               }
2488             }
2489             Ascii85Flush(image);
2490             break;
2491           }
2492         }
2493       else
2494         {
2495           /*
2496             Dump number of colors and colormap.
2497           */
2498           switch (compression)
2499           {
2500             case RLECompression:
2501             default:
2502             {
2503               MemoryInfo
2504                 *pixel_info;
2505
2506               /*
2507                 Allocate pixel array.
2508               */
2509               length=(size_t) number_pixels;
2510               pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2511               if (pixel_info == (MemoryInfo *) NULL)
2512                 {
2513                   tile_image=DestroyImage(tile_image);
2514                   ThrowWriterException(ResourceLimitError,
2515                     "MemoryAllocationFailed");
2516                 }
2517               pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2518               /*
2519                 Dump runlength encoded pixels.
2520               */
2521               q=pixels;
2522               for (y=0; y < (ssize_t) tile_image->rows; y++)
2523               {
2524                 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2525                   exception);
2526                 if (p == (const Quantum *) NULL)
2527                   break;
2528                 for (x=0; x < (ssize_t) tile_image->columns; x++)
2529                 {
2530                   *q++=(unsigned char) GetPixelIndex(tile_image,p);
2531                   p+=GetPixelChannels(tile_image);
2532                 }
2533               }
2534 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2535               if (compression == ZipCompression)
2536                 status=ZLIBEncodeImage(image,length,pixels,exception);
2537               else
2538 #endif
2539                 if (compression == LZWCompression)
2540                   status=LZWEncodeImage(image,length,pixels,exception);
2541                 else
2542                   status=PackbitsEncodeImage(image,length,pixels,exception);
2543               pixel_info=RelinquishVirtualMemory(pixel_info);
2544               if (status == MagickFalse)
2545                 {
2546                   (void) CloseBlob(image);
2547                   return(MagickFalse);
2548                 }
2549               break;
2550             }
2551             case NoCompression:
2552             {
2553               /*
2554                 Dump uncompressed PseudoColor packets.
2555               */
2556               Ascii85Initialize(image);
2557               for (y=0; y < (ssize_t) tile_image->rows; y++)
2558               {
2559                 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2560                   exception);
2561                 if (p == (const Quantum *) NULL)
2562                   break;
2563                 for (x=0; x < (ssize_t) tile_image->columns; x++)
2564                 {
2565                   Ascii85Encode(image,(unsigned char)
2566                     GetPixelIndex(tile_image,p));
2567                   p+=GetPixelChannels(image);
2568                 }
2569               }
2570               Ascii85Flush(image);
2571               break;
2572             }
2573           }
2574         }
2575     tile_image=DestroyImage(tile_image);
2576     offset=TellBlob(image)-offset;
2577     (void) WriteBlobString(image,"\nendstream\n");
2578     (void) WriteBlobString(image,"endobj\n");
2579     /*
2580       Write Length object.
2581     */
2582     xref[object++]=TellBlob(image);
2583     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2584       object);
2585     (void) WriteBlobString(image,buffer);
2586     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2587       offset);
2588     (void) WriteBlobString(image,buffer);
2589     (void) WriteBlobString(image,"endobj\n");
2590     xref[object++]=TellBlob(image);
2591     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2592       object);
2593     (void) WriteBlobString(image,buffer);
2594     (void) WriteBlobString(image,"<<\n");
2595     if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2596         (compression == FaxCompression) || (compression == Group4Compression))
2597       (void) WriteBlobString(image,">>\n");
2598     else
2599       {
2600         /*
2601           Write Colormap object.
2602         */
2603         if (compression == NoCompression)
2604           (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
2605         (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2606           (double) object+1);
2607         (void) WriteBlobString(image,buffer);
2608         (void) WriteBlobString(image,">>\n");
2609         (void) WriteBlobString(image,"stream\n");
2610         offset=TellBlob(image);
2611         if (compression == NoCompression)
2612           Ascii85Initialize(image);
2613         for (i=0; i < (ssize_t) image->colors; i++)
2614         {
2615           if (compression == NoCompression)
2616             {
2617               Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2618                 image->colormap[i].red)));
2619               Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2620                 image->colormap[i].green)));
2621               Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2622                 image->colormap[i].blue)));
2623               continue;
2624             }
2625           (void) WriteBlobByte(image,ScaleQuantumToChar(
2626              ClampToQuantum(image->colormap[i].red)));
2627           (void) WriteBlobByte(image,ScaleQuantumToChar(
2628              ClampToQuantum(image->colormap[i].green)));
2629           (void) WriteBlobByte(image,ScaleQuantumToChar(
2630              ClampToQuantum(image->colormap[i].blue)));
2631         }
2632         if (compression == NoCompression)
2633           Ascii85Flush(image);
2634        offset=TellBlob(image)-offset;
2635        (void) WriteBlobString(image,"\nendstream\n");
2636       }
2637     (void) WriteBlobString(image,"endobj\n");
2638     /*
2639       Write Length object.
2640     */
2641     xref[object++]=TellBlob(image);
2642     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2643       object);
2644     (void) WriteBlobString(image,buffer);
2645     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2646       offset);
2647     (void) WriteBlobString(image,buffer);
2648     (void) WriteBlobString(image,"endobj\n");
2649     /*
2650       Write softmask object.
2651     */
2652     xref[object++]=TellBlob(image);
2653     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2654       object);
2655     (void) WriteBlobString(image,buffer);
2656     (void) WriteBlobString(image,"<<\n");
2657     if (image->alpha_trait == UndefinedPixelTrait)
2658       (void) WriteBlobString(image,">>\n");
2659     else
2660       {
2661         (void) WriteBlobString(image,"/Type /XObject\n");
2662         (void) WriteBlobString(image,"/Subtype /Image\n");
2663         (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Ma%.20g\n",
2664           (double) image->scene);
2665         (void) WriteBlobString(image,buffer);
2666         switch (compression)
2667         {
2668           case NoCompression:
2669           {
2670             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2671               "ASCII85Decode");
2672             break;
2673           }
2674           case LZWCompression:
2675           {
2676             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2677               "LZWDecode");
2678             break;
2679           }
2680           case ZipCompression:
2681           {
2682             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2683               "FlateDecode");
2684             break;
2685           }
2686           default:
2687           {
2688             (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2689               "RunLengthDecode");
2690             break;
2691           }
2692         }
2693         (void) WriteBlobString(image,buffer);
2694         (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",
2695           (double) image->columns);
2696         (void) WriteBlobString(image,buffer);
2697         (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",
2698           (double) image->rows);
2699         (void) WriteBlobString(image,buffer);
2700         (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2701         (void) FormatLocaleString(buffer,MagickPathExtent,
2702           "/BitsPerComponent %d\n",(compression == FaxCompression) ||
2703           (compression == Group4Compression) ? 1 : 8);
2704         (void) WriteBlobString(image,buffer);
2705         (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2706           (double) object+1);
2707         (void) WriteBlobString(image,buffer);
2708         (void) WriteBlobString(image,">>\n");
2709         (void) WriteBlobString(image,"stream\n");
2710         offset=TellBlob(image);
2711         number_pixels=(MagickSizeType) image->columns*image->rows;
2712         switch (compression)
2713         {
2714           case RLECompression:
2715           default:
2716           {
2717             MemoryInfo
2718               *pixel_info;
2719
2720             /*
2721               Allocate pixel array.
2722             */
2723             length=(size_t) number_pixels;
2724             pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2725             if (pixel_info == (MemoryInfo *) NULL)
2726               {
2727                 image=DestroyImage(image);
2728                 ThrowWriterException(ResourceLimitError,
2729                   "MemoryAllocationFailed");
2730               }
2731             pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2732             /*
2733               Dump Runlength encoded pixels.
2734             */
2735             q=pixels;
2736             for (y=0; y < (ssize_t) image->rows; y++)
2737             {
2738               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2739               if (p == (const Quantum *) NULL)
2740                 break;
2741               for (x=0; x < (ssize_t) image->columns; x++)
2742               {
2743                 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
2744                 p+=GetPixelChannels(image);
2745               }
2746             }
2747 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2748             if (compression == ZipCompression)
2749               status=ZLIBEncodeImage(image,length,pixels,exception);
2750             else
2751 #endif
2752               if (compression == LZWCompression)
2753                 status=LZWEncodeImage(image,length,pixels,exception);
2754               else
2755                 status=PackbitsEncodeImage(image,length,pixels,exception);
2756             pixel_info=RelinquishVirtualMemory(pixel_info);
2757             if (status == MagickFalse)
2758               {
2759                 (void) CloseBlob(image);
2760                 return(MagickFalse);
2761               }
2762             break;
2763           }
2764           case NoCompression:
2765           {
2766             /*
2767               Dump uncompressed PseudoColor packets.
2768             */
2769             Ascii85Initialize(image);
2770             for (y=0; y < (ssize_t) image->rows; y++)
2771             {
2772               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2773               if (p == (const Quantum *) NULL)
2774                 break;
2775               for (x=0; x < (ssize_t) image->columns; x++)
2776               {
2777                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
2778                 p+=GetPixelChannels(image);
2779               }
2780             }
2781             Ascii85Flush(image);
2782             break;
2783           }
2784         }
2785         offset=TellBlob(image)-offset;
2786         (void) WriteBlobString(image,"\nendstream\n");
2787       }
2788     (void) WriteBlobString(image,"endobj\n");
2789     /*
2790       Write Length object.
2791     */
2792     xref[object++]=TellBlob(image);
2793     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2794       object);
2795     (void) WriteBlobString(image,buffer);
2796     (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2797       offset);
2798     (void) WriteBlobString(image,buffer);
2799     (void) WriteBlobString(image,"endobj\n");
2800     if (GetNextImageInList(image) == (Image *) NULL)
2801       break;
2802     image=SyncNextImageInList(image);
2803     status=SetImageProgress(image,SaveImagesTag,scene++,
2804       GetImageListLength(image));
2805     if (status == MagickFalse)
2806       break;
2807   } while (image_info->adjoin != MagickFalse);
2808   /*
2809     Write Metadata object.
2810   */
2811   xref[object++]=TellBlob(image);
2812   info_id=object;
2813   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2814     object);
2815   (void) WriteBlobString(image,buffer);
2816   (void) WriteBlobString(image,"<<\n");
2817   utf16=ConvertUTF8ToUTF16((unsigned char *) basename,&length);
2818   if (utf16 != (wchar_t *) NULL)
2819     {
2820       (void) FormatLocaleString(buffer,MagickPathExtent,"/Title (\xfe\xff");
2821       (void) WriteBlobString(image,buffer);
2822       for (i=0; i < (ssize_t) length; i++)
2823         WriteBlobMSBShort(image,(unsigned short) utf16[i]);
2824       (void) FormatLocaleString(buffer,MagickPathExtent,")\n");
2825       (void) WriteBlobString(image,buffer);
2826       utf16=(wchar_t *) RelinquishMagickMemory(utf16);
2827     }
2828   seconds=time((time_t *) NULL);
2829 #if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2830   (void) localtime_r(&seconds,&local_time);
2831 #else
2832   (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2833 #endif
2834   (void) FormatLocaleString(date,MagickPathExtent,"D:%04d%02d%02d%02d%02d%02d",
2835     local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2836     local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2837   (void) FormatLocaleString(buffer,MagickPathExtent,"/CreationDate (%s)\n",
2838     date);
2839   (void) WriteBlobString(image,buffer);
2840   (void) FormatLocaleString(buffer,MagickPathExtent,"/ModDate (%s)\n",date);
2841   (void) WriteBlobString(image,buffer);
2842   url=GetMagickHomeURL();
2843   (void) FormatLocaleString(buffer,MagickPathExtent,"/Producer (%s)\n",
2844     EscapeParenthesis(url));
2845   url=DestroyString(url);
2846   (void) WriteBlobString(image,buffer);
2847   (void) WriteBlobString(image,">>\n");
2848   (void) WriteBlobString(image,"endobj\n");
2849   /*
2850     Write Xref object.
2851   */
2852   offset=TellBlob(image)-xref[0]+
2853    (LocaleCompare(image_info->magick,"PDFA") == 0 ? 6 : 0)+10;
2854   (void) WriteBlobString(image,"xref\n");
2855   (void) FormatLocaleString(buffer,MagickPathExtent,"0 %.20g\n",(double)
2856     object+1);
2857   (void) WriteBlobString(image,buffer);
2858   (void) WriteBlobString(image,"0000000000 65535 f \n");
2859   for (i=0; i < (ssize_t) object; i++)
2860   {
2861     (void) FormatLocaleString(buffer,MagickPathExtent,"%010lu 00000 n \n",
2862       (unsigned long) xref[i]);
2863     (void) WriteBlobString(image,buffer);
2864   }
2865   (void) WriteBlobString(image,"trailer\n");
2866   (void) WriteBlobString(image,"<<\n");
2867   (void) FormatLocaleString(buffer,MagickPathExtent,"/Size %.20g\n",(double)
2868     object+1);
2869   (void) WriteBlobString(image,buffer);
2870   (void) FormatLocaleString(buffer,MagickPathExtent,"/Info %.20g 0 R\n",(double)
2871     info_id);
2872   (void) WriteBlobString(image,buffer);
2873   (void) FormatLocaleString(buffer,MagickPathExtent,"/Root %.20g 0 R\n",(double)
2874     root_id);
2875   (void) WriteBlobString(image,buffer);
2876   (void) SignatureImage(image,exception);
2877   (void) FormatLocaleString(buffer,MagickPathExtent,"/ID [<%s> <%s>]\n",
2878     GetImageProperty(image,"signature",exception),
2879     GetImageProperty(image,"signature",exception));
2880   (void) WriteBlobString(image,buffer);
2881   (void) WriteBlobString(image,">>\n");
2882   (void) WriteBlobString(image,"startxref\n");
2883   (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) offset);
2884   (void) WriteBlobString(image,buffer);
2885   (void) WriteBlobString(image,"%%EOF\n");
2886   xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2887   (void) CloseBlob(image);
2888   return(MagickTrue);
2889 }