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