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