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