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