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