]> 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 CropBox  "CropBox"
297 #define DeviceCMYK  "DeviceCMYK"
298 #define MediaBox  "MediaBox"
299 #define RenderPostscriptText  "Rendering Postscript...  "
300 #define PDFRotate  "Rotate"
301 #define SpotColor  "Separation"
302 #define TrimBox  "TrimBox"
303 #define PDFVersion  "PDF-"
304
305   char
306     command[MaxTextExtent],
307     density[MaxTextExtent],
308     filename[MaxTextExtent],
309     geometry[MaxTextExtent],
310     options[MaxTextExtent],
311     input_filename[MaxTextExtent],
312     postscript_filename[MaxTextExtent];
313
314   const char
315     *option;
316
317   const DelegateInfo
318     *delegate_info;
319
320   double
321     angle;
322
323   GeometryInfo
324     geometry_info;
325
326   Image
327     *image,
328     *next,
329     *pdf_image;
330
331   ImageInfo
332     *read_info;
333
334   int
335     c,
336     file;
337
338   MagickBooleanType
339     cmyk,
340     cropbox,
341     trimbox,
342     status;
343
344   MagickStatusType
345     flags;
346
347   PointInfo
348     delta;
349
350   RectangleInfo
351     bounding_box,
352     page;
353
354   register char
355     *p;
356
357   register ssize_t
358     i;
359
360   SegmentInfo
361     bounds,
362     hires_bounds;
363
364   size_t
365     scene,
366     spotcolor;
367
368   ssize_t
369     count;
370
371   assert(image_info != (const ImageInfo *) NULL);
372   assert(image_info->signature == MagickSignature);
373   if (image_info->debug != MagickFalse)
374     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
375       image_info->filename);
376   assert(exception != (ExceptionInfo *) NULL);
377   assert(exception->signature == MagickSignature);
378   /*
379     Open image file.
380   */
381   image=AcquireImage(image_info,exception);
382   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
383   if (status == MagickFalse)
384     {
385       image=DestroyImageList(image);
386       return((Image *) NULL);
387     }
388   status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
389   if (status == MagickFalse)
390     {
391       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
392         image_info->filename);
393       image=DestroyImageList(image);
394       return((Image *) NULL);
395     }
396   /*
397     Set the page density.
398   */
399   delta.x=DefaultResolution;
400   delta.y=DefaultResolution;
401   if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
402     {
403       flags=ParseGeometry(PSDensityGeometry,&geometry_info);
404       image->resolution.x=geometry_info.rho;
405       image->resolution.y=geometry_info.sigma;
406       if ((flags & SigmaValue) == 0)
407         image->resolution.y=image->resolution.x;
408     }
409   if (image_info->density != (char *) NULL)
410     {
411       flags=ParseGeometry(image_info->density,&geometry_info);
412       image->resolution.x=geometry_info.rho;
413       image->resolution.y=geometry_info.sigma;
414       if ((flags & SigmaValue) == 0)
415         image->resolution.y=image->resolution.x;
416     }
417   (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
418   if (image_info->page != (char *) NULL)
419     (void) ParseAbsoluteGeometry(image_info->page,&page);
420   page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)-
421     0.5);
422   page.height=(size_t) ceil((double) (page.height*image->resolution.y/delta.y)-
423     0.5);
424   /*
425     Determine page geometry from the PDF media box.
426   */
427   cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
428   cropbox=MagickFalse;
429   option=GetImageOption(image_info,"pdf:use-cropbox");
430   if (option != (const char *) NULL)
431     cropbox=IsMagickTrue(option);
432   trimbox=MagickFalse;
433   option=GetImageOption(image_info,"pdf:use-trimbox");
434   if (option != (const char *) NULL)
435     trimbox=IsMagickTrue(option);
436   count=0;
437   spotcolor=0;
438   (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
439   (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
440   (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
441   (void) ResetMagickMemory(command,0,sizeof(command));
442   angle=0.0;
443   p=command;
444   for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
445   {
446     /*
447       Note PDF elements.
448     */
449     if (c == '\n')
450       c=' ';
451     *p++=(char) c;
452     if ((c != (int) '/') && (c != (int) '%') &&
453         ((size_t) (p-command) < (MaxTextExtent-1)))
454       continue;
455     *(--p)='\0';
456     p=command;
457     if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
458       count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
459     /*
460       Is this a CMYK document?
461     */
462     if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 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 (IsRGBColorspace(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       next=ReadImage(read_info,exception);
663       (void) RelinquishUniqueFileResource(read_info->filename);
664       if (next == (Image *) NULL)
665         break;
666       AppendImageToList(&pdf_image,next);
667     }
668   read_info=DestroyImageInfo(read_info);
669   if (pdf_image == (Image *) NULL)
670     {
671       ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
672         image_info->filename);
673       image=DestroyImage(image);
674       return((Image *) NULL);
675     }
676   if (LocaleCompare(pdf_image->magick,"BMP") == 0)
677     {
678       Image
679         *cmyk_image;
680
681       cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
682       if (cmyk_image != (Image *) NULL)
683         {
684           pdf_image=DestroyImageList(pdf_image);
685           pdf_image=cmyk_image;
686         }
687     }
688   if (image_info->number_scenes != 0)
689     {
690       Image
691         *clone_image;
692
693       register ssize_t
694         i;
695
696       /*
697         Add place holder images to meet the subimage specification requirement.
698       */
699       for (i=0; i < (ssize_t) image_info->scene; i++)
700       {
701         clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
702         if (clone_image != (Image *) NULL)
703           PrependImageToList(&pdf_image,clone_image);
704       }
705     }
706   do
707   {
708     (void) CopyMagickString(pdf_image->filename,filename,MaxTextExtent);
709     pdf_image->page=page;
710     (void) CloneImageProfiles(pdf_image,image);
711     (void) CloneImageProperties(pdf_image,image);
712     next=SyncNextImageInList(pdf_image);
713     if (next != (Image *) NULL)
714       pdf_image=next;
715   } while (next != (Image *) NULL);
716   image=DestroyImage(image);
717   scene=0;
718   for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
719   {
720     next->scene=scene++;
721     next=GetNextImageInList(next);
722   }
723   return(GetFirstImageInList(pdf_image));
724 }
725 \f
726 /*
727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 %                                                                             %
729 %                                                                             %
730 %                                                                             %
731 %   R e g i s t e r P D F I m a g e                                           %
732 %                                                                             %
733 %                                                                             %
734 %                                                                             %
735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
736 %
737 %  RegisterPDFImage() adds properties for the PDF image format to
738 %  the list of supported formats.  The properties include the image format
739 %  tag, a method to read and/or write the format, whether the format
740 %  supports the saving of more than one frame to the same file or blob,
741 %  whether the format supports native in-memory I/O, and a brief
742 %  description of the format.
743 %
744 %  The format of the RegisterPDFImage method is:
745 %
746 %      size_t RegisterPDFImage(void)
747 %
748 */
749 ModuleExport size_t RegisterPDFImage(void)
750 {
751   MagickInfo
752     *entry;
753
754   entry=SetMagickInfo("AI");
755   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
756   entry->encoder=(EncodeImageHandler *) WritePDFImage;
757   entry->adjoin=MagickFalse;
758   entry->blob_support=MagickFalse;
759   entry->seekable_stream=MagickTrue;
760   entry->thread_support=EncoderThreadSupport;
761   entry->description=ConstantString("Adobe Illustrator CS2");
762   entry->module=ConstantString("PDF");
763   (void) RegisterMagickInfo(entry);
764   entry=SetMagickInfo("EPDF");
765   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
766   entry->encoder=(EncodeImageHandler *) WritePDFImage;
767   entry->adjoin=MagickFalse;
768   entry->blob_support=MagickFalse;
769   entry->seekable_stream=MagickTrue;
770   entry->thread_support=EncoderThreadSupport;
771   entry->description=ConstantString("Encapsulated Portable Document Format");
772   entry->module=ConstantString("PDF");
773   (void) RegisterMagickInfo(entry);
774   entry=SetMagickInfo("PDF");
775   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
776   entry->encoder=(EncodeImageHandler *) WritePDFImage;
777   entry->magick=(IsImageFormatHandler *) IsPDF;
778   entry->blob_support=MagickFalse;
779   entry->seekable_stream=MagickTrue;
780   entry->thread_support=EncoderThreadSupport;
781   entry->description=ConstantString("Portable Document Format");
782   entry->module=ConstantString("PDF");
783   (void) RegisterMagickInfo(entry);
784   entry=SetMagickInfo("PDFA");
785   entry->decoder=(DecodeImageHandler *) ReadPDFImage;
786   entry->encoder=(EncodeImageHandler *) WritePDFImage;
787   entry->magick=(IsImageFormatHandler *) IsPDF;
788   entry->blob_support=MagickFalse;
789   entry->seekable_stream=MagickTrue;
790   entry->thread_support=EncoderThreadSupport;
791   entry->description=ConstantString("Portable Document Archive Format");
792   entry->module=ConstantString("PDF");
793   (void) RegisterMagickInfo(entry);
794   return(MagickImageCoderSignature);
795 }
796 \f
797 /*
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799 %                                                                             %
800 %                                                                             %
801 %                                                                             %
802 %   U n r e g i s t e r P D F I m a g e                                       %
803 %                                                                             %
804 %                                                                             %
805 %                                                                             %
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807 %
808 %  UnregisterPDFImage() removes format registrations made by the
809 %  PDF module from the list of supported formats.
810 %
811 %  The format of the UnregisterPDFImage method is:
812 %
813 %      UnregisterPDFImage(void)
814 %
815 */
816 ModuleExport void UnregisterPDFImage(void)
817 {
818   (void) UnregisterMagickInfo("AI");
819   (void) UnregisterMagickInfo("EPDF");
820   (void) UnregisterMagickInfo("PDF");
821   (void) UnregisterMagickInfo("PDFA");
822 }
823 \f
824 /*
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 %                                                                             %
827 %                                                                             %
828 %                                                                             %
829 %   W r i t e P D F I m a g e                                                 %
830 %                                                                             %
831 %                                                                             %
832 %                                                                             %
833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
834 %
835 %  WritePDFImage() writes an image in the Portable Document image
836 %  format.
837 %
838 %  The format of the WritePDFImage method is:
839 %
840 %      MagickBooleanType WritePDFImage(const ImageInfo *image_info,
841 %        Image *image,ExceptionInfo *exception)
842 %
843 %  A description of each parameter follows.
844 %
845 %    o image_info: the image info.
846 %
847 %    o image:  The image.
848 %
849 %    o exception: return any errors or warnings in this structure.
850 %
851 */
852
853 static inline size_t MagickMax(const size_t x,const size_t y)
854 {
855   if (x > y)
856     return(x);
857   return(y);
858 }
859
860 static inline size_t MagickMin(const size_t x,const size_t y)
861 {
862   if (x < y)
863     return(x);
864   return(y);
865 }
866
867 static char *EscapeParenthesis(const char *text)
868 {
869   register char
870     *p;
871
872   register ssize_t
873     i;
874
875   size_t
876     escapes;
877
878   static char
879     buffer[MaxTextExtent];
880
881   escapes=0;
882   p=buffer;
883   for (i=0; i < (ssize_t) MagickMin(strlen(text),(MaxTextExtent-escapes-1)); i++)
884   {
885     if ((text[i] == '(') || (text[i] == ')'))
886       {
887         *p++='\\';
888         escapes++;
889       }
890     *p++=text[i];
891   }
892   *p='\0';
893   return(buffer);
894 }
895
896 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
897   Image *image,Image *inject_image,ExceptionInfo *exception)
898 {
899   Image
900     *group4_image;
901
902   ImageInfo
903     *write_info;
904
905   MagickBooleanType
906     status;
907
908   size_t
909     length;
910
911   unsigned char
912     *group4;
913
914   status=MagickTrue;
915   write_info=CloneImageInfo(image_info);
916   (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
917   (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
918   group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
919   if (group4_image == (Image *) NULL)
920     return(MagickFalse);
921   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
922     exception);
923   group4_image=DestroyImage(group4_image);
924   if (group4 == (unsigned char *) NULL)
925     return(MagickFalse);
926   write_info=DestroyImageInfo(write_info);
927   if (WriteBlob(image,length,group4) != (ssize_t) length)
928     status=MagickFalse;
929   group4=(unsigned char *) RelinquishMagickMemory(group4);
930   return(status);
931 }
932
933 static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image,
934   ExceptionInfo *exception)
935 {
936 #define CFormat  "/Filter [ /%s ]\n"
937 #define ObjectsPerImage  14
938
939   static const char
940     XMPProfile[]=
941     {
942       "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
943       "<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"
944       "   <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
945       "      <rdf:Description rdf:about=\"\"\n"
946       "            xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
947       "         <xap:ModifyDate>%s</xap:ModifyDate>\n"
948       "         <xap:CreateDate>%s</xap:CreateDate>\n"
949       "         <xap:MetadataDate>%s</xap:MetadataDate>\n"
950       "         <xap:CreatorTool>%s</xap:CreatorTool>\n"
951       "      </rdf:Description>\n"
952       "      <rdf:Description rdf:about=\"\"\n"
953       "            xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
954       "         <dc:format>application/pdf</dc:format>\n"
955       "      </rdf:Description>\n"
956       "      <rdf:Description rdf:about=\"\"\n"
957       "            xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
958       "         <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
959       "         <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
960       "      </rdf:Description>\n"
961       "      <rdf:Description rdf:about=\"\"\n"
962       "            xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
963       "         <pdf:Producer>%s</pdf:Producer>\n"
964       "      </rdf:Description>\n"
965       "      <rdf:Description rdf:about=\"\"\n"
966       "            xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
967       "         <pdfaid:part>1</pdfaid:part>\n"
968       "         <pdfaid:conformance>B</pdfaid:conformance>\n"
969       "      </rdf:Description>\n"
970       "   </rdf:RDF>\n"
971       "</x:xmpmeta>\n"
972       "<?xpacket end=\"w\"?>\n"
973     },
974     XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
975
976   char
977     basename[MaxTextExtent],
978     buffer[MaxTextExtent],
979     date[MaxTextExtent],
980     **labels,
981     page_geometry[MaxTextExtent];
982
983   CompressionType
984     compression;
985
986   const char
987     *value;
988
989   double
990     pointsize;
991
992   GeometryInfo
993     geometry_info;
994
995   Image
996     *next,
997     *tile_image;
998
999   MagickBooleanType
1000     status;
1001
1002   MagickOffsetType
1003     offset,
1004     scene,
1005     *xref;
1006
1007   MagickSizeType
1008     number_pixels;
1009
1010   MagickStatusType
1011     flags;
1012
1013   PointInfo
1014     delta,
1015     resolution,
1016     scale;
1017
1018   RectangleInfo
1019     geometry,
1020     media_info,
1021     page_info;
1022
1023   register const Quantum
1024     *p;
1025
1026   register unsigned char
1027     *q;
1028
1029   register ssize_t
1030     i,
1031     x;
1032
1033   size_t
1034     info_id,
1035     length,
1036     object,
1037     pages_id,
1038     root_id,
1039     text_size,
1040     version;
1041
1042   ssize_t
1043     count,
1044     y;
1045
1046   struct tm
1047     local_time;
1048
1049   time_t
1050     seconds;
1051
1052   unsigned char
1053     *pixels;
1054
1055   /*
1056     Open output image file.
1057   */
1058   assert(image_info != (const ImageInfo *) NULL);
1059   assert(image_info->signature == MagickSignature);
1060   assert(image != (Image *) NULL);
1061   assert(image->signature == MagickSignature);
1062   if (image->debug != MagickFalse)
1063     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1064   assert(exception != (ExceptionInfo *) NULL);
1065   assert(exception->signature == MagickSignature);
1066   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1067   if (status == MagickFalse)
1068     return(status);
1069   /*
1070     Allocate X ref memory.
1071   */
1072   xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1073   if (xref == (MagickOffsetType *) NULL)
1074     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1075   (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1076   /*
1077     Write Info object.
1078   */
1079   object=0;
1080   version=3;
1081   if (image_info->compression == JPEG2000Compression)
1082     version=(size_t) MagickMax(version,5);
1083   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1084     if (next->matte != MagickFalse)
1085       version=(size_t) MagickMax(version,4);
1086   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1087     version=(size_t) MagickMax(version,6);
1088   (void) FormatLocaleString(buffer,MaxTextExtent,"%%PDF-1.%.20g \n",
1089     (double) version);
1090   (void) WriteBlobString(image,buffer);
1091   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1092     (void) WriteBlobString(image,"%âãÏÓ\n");
1093   /*
1094     Write Catalog object.
1095   */
1096   xref[object++]=TellBlob(image);
1097   root_id=object;
1098   (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1099     object);
1100   (void) WriteBlobString(image,buffer);
1101   (void) WriteBlobString(image,"<<\n");
1102   if (LocaleCompare(image_info->magick,"PDFA") != 0)
1103     (void) FormatLocaleString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n",
1104       (double) object+1);
1105   else
1106     {
1107       (void) FormatLocaleString(buffer,MaxTextExtent,"/Metadata %.20g 0 R\n",
1108         (double) object+1);
1109       (void) WriteBlobString(image,buffer);
1110       (void) FormatLocaleString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n",
1111         (double) object+2);
1112     }
1113   (void) WriteBlobString(image,buffer);
1114   (void) WriteBlobString(image,"/Type /Catalog\n");
1115   (void) WriteBlobString(image,">>\n");
1116   (void) WriteBlobString(image,"endobj\n");
1117   if (LocaleCompare(image_info->magick,"PDFA") == 0)
1118     {
1119       char
1120         create_date[MaxTextExtent],
1121         modify_date[MaxTextExtent],
1122         timestamp[MaxTextExtent],
1123         xmp_profile[MaxTextExtent];
1124
1125       size_t
1126         version;
1127
1128       /*
1129         Write XMP object.
1130       */
1131       xref[object++]=TellBlob(image);
1132       (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",
1133         (double) object);
1134       (void) WriteBlobString(image,buffer);
1135       (void) WriteBlobString(image,"<<\n");
1136       (void) WriteBlobString(image,"/Subtype /XML\n");
1137       *modify_date='\0';
1138       value=GetImageProperty(image,"date:modify",exception);
1139       if (value != (const char *) NULL)
1140         (void) CopyMagickString(modify_date,value,MaxTextExtent);
1141       *create_date='\0';
1142       value=GetImageProperty(image,"date:create",exception);
1143       if (value != (const char *) NULL)
1144         (void) CopyMagickString(create_date,value,MaxTextExtent);
1145       (void) FormatMagickTime(time((time_t *) NULL),MaxTextExtent,timestamp);
1146       i=FormatLocaleString(xmp_profile,MaxTextExtent,XMPProfile,
1147         XMPProfileMagick,modify_date,create_date,timestamp,
1148         GetMagickVersion(&version),GetMagickVersion(&version));
1149       (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g\n",
1150         (double) i);
1151       (void) WriteBlobString(image,buffer);
1152       (void) WriteBlobString(image,"/Type /Metadata\n");
1153       (void) WriteBlobString(image,">>\nstream\n");
1154       (void) WriteBlobString(image,xmp_profile);
1155       (void) WriteBlobString(image,"endstream\n");
1156       (void) WriteBlobString(image,"endobj\n");
1157     }
1158   /*
1159     Write Pages object.
1160   */
1161   xref[object++]=TellBlob(image);
1162   pages_id=object;
1163   (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1164     object);
1165   (void) WriteBlobString(image,buffer);
1166   (void) WriteBlobString(image,"<<\n");
1167   (void) WriteBlobString(image,"/Type /Pages\n");
1168   (void) FormatLocaleString(buffer,MaxTextExtent,"/Kids [ %.20g 0 R ",
1169     (double) object+1);
1170   (void) WriteBlobString(image,buffer);
1171   count=(ssize_t) (pages_id+ObjectsPerImage+1);
1172   if (image_info->adjoin != MagickFalse)
1173     {
1174       Image
1175         *kid_image;
1176
1177       /*
1178         Predict page object id's.
1179       */
1180       kid_image=image;
1181       for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1182       {
1183         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 R ",(double)
1184           count);
1185         (void) WriteBlobString(image,buffer);
1186         kid_image=GetNextImageInList(kid_image);
1187       }
1188       xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1189         sizeof(*xref));
1190       if (xref == (MagickOffsetType *) NULL)
1191         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1192     }
1193   (void) WriteBlobString(image,"]\n");
1194   (void) FormatLocaleString(buffer,MaxTextExtent,"/Count %.20g\n",
1195     (double) ((count-pages_id)/ObjectsPerImage));
1196   (void) WriteBlobString(image,buffer);
1197   (void) WriteBlobString(image,">>\n");
1198   (void) WriteBlobString(image,"endobj\n");
1199   scene=0;
1200   do
1201   {
1202     compression=image->compression;
1203     if (image_info->compression != UndefinedCompression)
1204       compression=image_info->compression;
1205     switch (compression)
1206     {
1207       case FaxCompression:
1208       case Group4Compression:
1209       {
1210         if ((IsImageMonochrome(image,exception) == MagickFalse) ||
1211             (image->matte != MagickFalse))
1212           compression=RLECompression;
1213         break;
1214       }
1215 #if !defined(MAGICKCORE_JPEG_DELEGATE)
1216       case JPEGCompression:
1217       {
1218         compression=RLECompression;
1219         (void) ThrowMagickException(exception,GetMagickModule(),
1220           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1221           image->filename);
1222         break;
1223       }
1224 #endif
1225 #if !defined(MAGICKCORE_JP2_DELEGATE)
1226       case JPEG2000Compression:
1227       {
1228         compression=RLECompression;
1229         (void) ThrowMagickException(exception,GetMagickModule(),
1230           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1231           image->filename);
1232         break;
1233       }
1234 #endif
1235 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1236       case ZipCompression:
1237       {
1238         compression=RLECompression;
1239         (void) ThrowMagickException(exception,GetMagickModule(),
1240           MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1241           image->filename);
1242         break;
1243       }
1244 #endif
1245       case LZWCompression:
1246       {
1247         if (LocaleCompare(image_info->magick,"PDFA") == 0)
1248           compression=RLECompression;  /* LZW compression is forbidden */
1249         break;
1250       }
1251       case NoCompression:
1252       {
1253         if (LocaleCompare(image_info->magick,"PDFA") == 0)
1254           compression=RLECompression; /* ASCII 85 compression is forbidden */
1255         break;
1256       }
1257       default:
1258         break;
1259     }
1260     if (compression == JPEG2000Compression)
1261       {
1262         if (IsRGBColorspace(image->colorspace) == MagickFalse)
1263           (void) TransformImageColorspace(image,sRGBColorspace,exception);
1264       }
1265     /*
1266       Scale relative to dots-per-inch.
1267     */
1268     delta.x=DefaultResolution;
1269     delta.y=DefaultResolution;
1270     resolution.x=image->resolution.x;
1271     resolution.y=image->resolution.y;
1272     if ((resolution.x == 0.0) || (resolution.y == 0.0))
1273       {
1274         flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1275         resolution.x=geometry_info.rho;
1276         resolution.y=geometry_info.sigma;
1277         if ((flags & SigmaValue) == 0)
1278           resolution.y=resolution.x;
1279       }
1280     if (image_info->density != (char *) NULL)
1281       {
1282         flags=ParseGeometry(image_info->density,&geometry_info);
1283         resolution.x=geometry_info.rho;
1284         resolution.y=geometry_info.sigma;
1285         if ((flags & SigmaValue) == 0)
1286           resolution.y=resolution.x;
1287       }
1288     if (image->units == PixelsPerCentimeterResolution)
1289       {
1290         resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1291         resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1292       }
1293     SetGeometry(image,&geometry);
1294     (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1295       (double) image->columns,(double) image->rows);
1296     if (image_info->page != (char *) NULL)
1297       (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1298     else
1299       if ((image->page.width != 0) && (image->page.height != 0))
1300         (void) FormatLocaleString(page_geometry,MaxTextExtent,
1301           "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,
1302           (double) image->page.height,(double) image->page.x,(double)
1303           image->page.y);
1304       else
1305         if ((image->gravity != UndefinedGravity) &&
1306             (LocaleCompare(image_info->magick,"PDF") == 0))
1307           (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1308     (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1309     (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1310       &geometry.width,&geometry.height);
1311     scale.x=(double) (geometry.width*delta.x)/resolution.x;
1312     geometry.width=(size_t) floor(scale.x+0.5);
1313     scale.y=(double) (geometry.height*delta.y)/resolution.y;
1314     geometry.height=(size_t) floor(scale.y+0.5);
1315     (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1316     (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1317     if (image->gravity != UndefinedGravity)
1318       {
1319         geometry.x=(-page_info.x);
1320         geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1321       }
1322     pointsize=12.0;
1323     if (image_info->pointsize != 0.0)
1324       pointsize=image_info->pointsize;
1325     text_size=0;
1326     value=GetImageProperty(image,"label",exception);
1327     if (value != (const char *) NULL)
1328       text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1329     (void) text_size;
1330     /*
1331       Write Page object.
1332     */
1333     xref[object++]=TellBlob(image);
1334     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1335       object);
1336     (void) WriteBlobString(image,buffer);
1337     (void) WriteBlobString(image,"<<\n");
1338     (void) WriteBlobString(image,"/Type /Page\n");
1339     (void) FormatLocaleString(buffer,MaxTextExtent,"/Parent %.20g 0 R\n",
1340       (double) pages_id);
1341     (void) WriteBlobString(image,buffer);
1342     (void) WriteBlobString(image,"/Resources <<\n");
1343     labels=(char **) NULL;
1344     value=GetImageProperty(image,"label",exception);
1345     if (value != (const char *) NULL)
1346       labels=StringToList(value);
1347     if (labels != (char **) NULL)
1348       {
1349         (void) FormatLocaleString(buffer,MaxTextExtent,
1350           "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1351           object+4);
1352         (void) WriteBlobString(image,buffer);
1353       }
1354     (void) FormatLocaleString(buffer,MaxTextExtent,
1355       "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1356       object+5);
1357     (void) WriteBlobString(image,buffer);
1358     (void) FormatLocaleString(buffer,MaxTextExtent,"/ProcSet %.20g 0 R >>\n",
1359       (double) object+3);
1360     (void) WriteBlobString(image,buffer);
1361     (void) FormatLocaleString(buffer,MaxTextExtent,
1362       "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1363       72.0*media_info.height/resolution.y);
1364     (void) WriteBlobString(image,buffer);
1365     (void) FormatLocaleString(buffer,MaxTextExtent,
1366       "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1367       72.0*media_info.height/resolution.y);
1368     (void) WriteBlobString(image,buffer);
1369     (void) FormatLocaleString(buffer,MaxTextExtent,"/Contents %.20g 0 R\n",
1370       (double) object+1);
1371     (void) WriteBlobString(image,buffer);
1372     (void) FormatLocaleString(buffer,MaxTextExtent,"/Thumb %.20g 0 R\n",
1373       (double) object+8);
1374     (void) WriteBlobString(image,buffer);
1375     (void) WriteBlobString(image,">>\n");
1376     (void) WriteBlobString(image,"endobj\n");
1377     /*
1378       Write Contents object.
1379     */
1380     xref[object++]=TellBlob(image);
1381     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1382       object);
1383     (void) WriteBlobString(image,buffer);
1384     (void) WriteBlobString(image,"<<\n");
1385     (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
1386       (double) object+1);
1387     (void) WriteBlobString(image,buffer);
1388     (void) WriteBlobString(image,">>\n");
1389     (void) WriteBlobString(image,"stream\n");
1390     offset=TellBlob(image);
1391     (void) WriteBlobString(image,"q\n");
1392     if (labels != (char **) NULL)
1393       for (i=0; labels[i] != (char *) NULL; i++)
1394       {
1395         (void) WriteBlobString(image,"BT\n");
1396         (void) FormatLocaleString(buffer,MaxTextExtent,"/F%.20g %g Tf\n",
1397           (double) image->scene,pointsize);
1398         (void) WriteBlobString(image,buffer);
1399         (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g Td\n",
1400           (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+
1401           12));
1402         (void) WriteBlobString(image,buffer);
1403         (void) FormatLocaleString(buffer,MaxTextExtent,"(%s) Tj\n",labels[i]);
1404         (void) WriteBlobString(image,buffer);
1405         (void) WriteBlobString(image,"ET\n");
1406         labels[i]=DestroyString(labels[i]);
1407       }
1408     (void) FormatLocaleString(buffer,MaxTextExtent,"%g 0 0 %g %.20g %.20g cm\n",
1409       scale.x,scale.y,(double) geometry.x,(double) geometry.y);
1410     (void) WriteBlobString(image,buffer);
1411     (void) FormatLocaleString(buffer,MaxTextExtent,"/Im%.20g Do\n",
1412       (double) image->scene);
1413     (void) WriteBlobString(image,buffer);
1414     (void) WriteBlobString(image,"Q\n");
1415     offset=TellBlob(image)-offset;
1416     (void) WriteBlobString(image,"endstream\n");
1417     (void) WriteBlobString(image,"endobj\n");
1418     /*
1419       Write Length object.
1420     */
1421     xref[object++]=TellBlob(image);
1422     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1423       object);
1424     (void) WriteBlobString(image,buffer);
1425     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
1426     (void) WriteBlobString(image,buffer);
1427     (void) WriteBlobString(image,"endobj\n");
1428     /*
1429       Write Procset object.
1430     */
1431     xref[object++]=TellBlob(image);
1432     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",
1433       (double) object);
1434     (void) WriteBlobString(image,buffer);
1435     if ((image->storage_class == DirectClass) || (image->colors > 256))
1436       (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MaxTextExtent);
1437     else
1438       if ((compression == FaxCompression) || (compression == Group4Compression))
1439         (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MaxTextExtent);
1440       else
1441         (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MaxTextExtent);
1442     (void) WriteBlobString(image,buffer);
1443     (void) WriteBlobString(image," ]\n");
1444     (void) WriteBlobString(image,"endobj\n");
1445     /*
1446       Write Font object.
1447     */
1448     xref[object++]=TellBlob(image);
1449     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",
1450       (double) object);
1451     (void) WriteBlobString(image,buffer);
1452     (void) WriteBlobString(image,"<<\n");
1453     if (labels != (char **) NULL)
1454       {
1455         (void) WriteBlobString(image,"/Type /Font\n");
1456         (void) WriteBlobString(image,"/Subtype /Type1\n");
1457         (void) FormatLocaleString(buffer,MaxTextExtent,"/Name /F%.20g\n",
1458           (double) image->scene);
1459         (void) WriteBlobString(image,buffer);
1460         (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1461         (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1462         labels=(char **) RelinquishMagickMemory(labels);
1463       }
1464     (void) WriteBlobString(image,">>\n");
1465     (void) WriteBlobString(image,"endobj\n");
1466     /*
1467       Write XObject object.
1468     */
1469     xref[object++]=TellBlob(image);
1470     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1471       object);
1472     (void) WriteBlobString(image,buffer);
1473     (void) WriteBlobString(image,"<<\n");
1474     (void) WriteBlobString(image,"/Type /XObject\n");
1475     (void) WriteBlobString(image,"/Subtype /Image\n");
1476     (void) FormatLocaleString(buffer,MaxTextExtent,"/Name /Im%.20g\n",
1477       (double) image->scene);
1478     (void) WriteBlobString(image,buffer);
1479     switch (compression)
1480     {
1481       case NoCompression:
1482       {
1483         (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1484         break;
1485       }
1486       case JPEGCompression:
1487       {
1488         (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1489         if (image->colorspace != CMYKColorspace)
1490           break;
1491         (void) WriteBlobString(image,buffer);
1492         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1493           MaxTextExtent);
1494         break;
1495       }
1496       case JPEG2000Compression:
1497       {
1498         (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1499         if (image->colorspace != CMYKColorspace)
1500           break;
1501         (void) WriteBlobString(image,buffer);
1502         (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1503           MaxTextExtent);
1504         break;
1505       }
1506       case LZWCompression:
1507       {
1508         (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1509         break;
1510       }
1511       case ZipCompression:
1512       {
1513         (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1514         break;
1515       }
1516       case FaxCompression:
1517       case Group4Compression:
1518       {
1519         (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1520           MaxTextExtent);
1521         (void) WriteBlobString(image,buffer);
1522         (void) FormatLocaleString(buffer,MaxTextExtent,"/DecodeParms [ << "
1523           "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1524           (double) image->columns,(double) image->rows);
1525         break;
1526       }
1527       default:
1528       {
1529         (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,
1530           "RunLengthDecode");
1531         break;
1532       }
1533     }
1534     (void) WriteBlobString(image,buffer);
1535     (void) FormatLocaleString(buffer,MaxTextExtent,"/Width %.20g\n",(double)
1536       image->columns);
1537     (void) WriteBlobString(image,buffer);
1538     (void) FormatLocaleString(buffer,MaxTextExtent,"/Height %.20g\n",(double)
1539       image->rows);
1540     (void) WriteBlobString(image,buffer);
1541     (void) FormatLocaleString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n",
1542       (double) object+2);
1543     (void) WriteBlobString(image,buffer);
1544     (void) FormatLocaleString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1545       (compression == FaxCompression) || (compression == Group4Compression) ?
1546       1 : 8);
1547     (void) WriteBlobString(image,buffer);
1548     if (image->matte != MagickFalse)
1549       {
1550         (void) FormatLocaleString(buffer,MaxTextExtent,"/SMask %.20g 0 R\n",
1551           (double) object+7);
1552         (void) WriteBlobString(image,buffer);
1553       }
1554     (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
1555       (double) object+1);
1556     (void) WriteBlobString(image,buffer);
1557     (void) WriteBlobString(image,">>\n");
1558     (void) WriteBlobString(image,"stream\n");
1559     offset=TellBlob(image);
1560     number_pixels=(MagickSizeType) image->columns*image->rows;
1561     if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1562       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1563     if ((compression == FaxCompression) || (compression == Group4Compression) ||
1564         ((image_info->type != TrueColorType) &&
1565          (IsImageGray(image,exception) != MagickFalse)))
1566       {
1567         switch (compression)
1568         {
1569           case FaxCompression:
1570           case Group4Compression:
1571           {
1572             if (LocaleCompare(CCITTParam,"0") == 0)
1573               {
1574                 (void) HuffmanEncodeImage(image_info,image,image,exception);
1575                 break;
1576               }
1577             (void) Huffman2DEncodeImage(image_info,image,image,exception);
1578             break;
1579           }
1580           case JPEGCompression:
1581           {
1582             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1583             if (status == MagickFalse)
1584               {
1585                 (void) CloseBlob(image);
1586                 return(MagickFalse);
1587               }
1588             break;
1589           }
1590           case JPEG2000Compression:
1591           {
1592             status=InjectImageBlob(image_info,image,image,"jp2",exception);
1593             if (status == MagickFalse)
1594               {
1595                 (void) CloseBlob(image);
1596                 return(MagickFalse);
1597               }
1598             break;
1599           }
1600           case RLECompression:
1601           default:
1602           {
1603             /*
1604               Allocate pixel array.
1605             */
1606             length=(size_t) number_pixels;
1607             pixels=(unsigned char *) AcquireQuantumMemory(length,
1608               sizeof(*pixels));
1609             if (pixels == (unsigned char *) NULL)
1610               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1611             /*
1612               Dump Runlength encoded pixels.
1613             */
1614             q=pixels;
1615             for (y=0; y < (ssize_t) image->rows; y++)
1616             {
1617               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1618               if (p == (const Quantum *) NULL)
1619                 break;
1620               for (x=0; x < (ssize_t) image->columns; x++)
1621               {
1622                 *q++=ScaleQuantumToChar(GetPixelIntensity(image,p));
1623                 p+=GetPixelChannels(image);
1624               }
1625               if (image->previous == (Image *) NULL)
1626                 {
1627                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1628                     y,image->rows);
1629                   if (status == MagickFalse)
1630                     break;
1631                 }
1632             }
1633 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1634             if (compression == ZipCompression)
1635               status=ZLIBEncodeImage(image,length,pixels,exception);
1636             else
1637 #endif
1638               if (compression == LZWCompression)
1639                 status=LZWEncodeImage(image,length,pixels,exception);
1640               else
1641                 status=PackbitsEncodeImage(image,length,pixels,exception);
1642             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1643             if (status == MagickFalse)
1644               {
1645                 (void) CloseBlob(image);
1646                 return(MagickFalse);
1647               }
1648             break;
1649           }
1650           case NoCompression:
1651           {
1652             /*
1653               Dump uncompressed PseudoColor packets.
1654             */
1655             Ascii85Initialize(image);
1656             for (y=0; y < (ssize_t) image->rows; y++)
1657             {
1658               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1659               if (p == (const Quantum *) NULL)
1660                 break;
1661               for (x=0; x < (ssize_t) image->columns; x++)
1662               {
1663                 Ascii85Encode(image,ScaleQuantumToChar(
1664                   GetPixelIntensity(image,p)));
1665                 p+=GetPixelChannels(image);
1666               }
1667               if (image->previous == (Image *) NULL)
1668                 {
1669                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1670                     y,image->rows);
1671                   if (status == MagickFalse)
1672                     break;
1673                 }
1674             }
1675             Ascii85Flush(image);
1676             break;
1677           }
1678         }
1679       }
1680     else
1681       if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1682           (compression == JPEGCompression) ||
1683           (compression == JPEG2000Compression))
1684         switch (compression)
1685         {
1686           case JPEGCompression:
1687           {
1688             status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1689             if (status == MagickFalse)
1690               {
1691                 (void) CloseBlob(image);
1692                 return(MagickFalse);
1693               }
1694             break;
1695           }
1696           case JPEG2000Compression:
1697           {
1698             status=InjectImageBlob(image_info,image,image,"jp2",exception);
1699             if (status == MagickFalse)
1700               {
1701                 (void) CloseBlob(image);
1702                 return(MagickFalse);
1703               }
1704             break;
1705           }
1706           case RLECompression:
1707           default:
1708           {
1709             /*
1710               Allocate pixel array.
1711             */
1712             length=(size_t) number_pixels;
1713             pixels=(unsigned char *) AcquireQuantumMemory(length,
1714               4*sizeof(*pixels));
1715             length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1716             if (pixels == (unsigned char *) NULL)
1717               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1718             /*
1719               Dump runoffset encoded pixels.
1720             */
1721             q=pixels;
1722             for (y=0; y < (ssize_t) image->rows; y++)
1723             {
1724               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1725               if (p == (const Quantum *) NULL)
1726                 break;
1727               for (x=0; x < (ssize_t) image->columns; x++)
1728               {
1729                 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1730                 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1731                 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1732                 if (image->colorspace == CMYKColorspace)
1733                   *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
1734                 p+=GetPixelChannels(image);
1735               }
1736               if (image->previous == (Image *) NULL)
1737                 {
1738                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1739                     y,image->rows);
1740                   if (status == MagickFalse)
1741                     break;
1742                 }
1743             }
1744 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1745             if (compression == ZipCompression)
1746               status=ZLIBEncodeImage(image,length,pixels,exception);
1747             else
1748 #endif
1749               if (compression == LZWCompression)
1750                 status=LZWEncodeImage(image,length,pixels,exception);
1751               else
1752                 status=PackbitsEncodeImage(image,length,pixels,exception);
1753             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1754             if (status == MagickFalse)
1755               {
1756                 (void) CloseBlob(image);
1757                 return(MagickFalse);
1758               }
1759             break;
1760           }
1761           case NoCompression:
1762           {
1763             /*
1764               Dump uncompressed DirectColor packets.
1765             */
1766             Ascii85Initialize(image);
1767             for (y=0; y < (ssize_t) image->rows; y++)
1768             {
1769               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1770               if (p == (const Quantum *) NULL)
1771                 break;
1772               for (x=0; x < (ssize_t) image->columns; x++)
1773               {
1774                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelRed(image,p)));
1775                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
1776                 Ascii85Encode(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
1777                 if (image->colorspace == CMYKColorspace)
1778                   Ascii85Encode(image,ScaleQuantumToChar(
1779                     GetPixelBlack(image,p)));
1780                 p+=GetPixelChannels(image);
1781               }
1782               if (image->previous == (Image *) NULL)
1783                 {
1784                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1785                     y,image->rows);
1786                   if (status == MagickFalse)
1787                     break;
1788                 }
1789             }
1790             Ascii85Flush(image);
1791             break;
1792           }
1793         }
1794       else
1795         {
1796           /*
1797             Dump number of colors and colormap.
1798           */
1799           switch (compression)
1800           {
1801             case RLECompression:
1802             default:
1803             {
1804               /*
1805                 Allocate pixel array.
1806               */
1807               length=(size_t) number_pixels;
1808               pixels=(unsigned char *) AcquireQuantumMemory(length,
1809                 sizeof(*pixels));
1810               if (pixels == (unsigned char *) NULL)
1811                 ThrowWriterException(ResourceLimitError,
1812                   "MemoryAllocationFailed");
1813               /*
1814                 Dump Runlength encoded pixels.
1815               */
1816               q=pixels;
1817               for (y=0; y < (ssize_t) image->rows; y++)
1818               {
1819                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1820                 if (p == (const Quantum *) NULL)
1821                   break;
1822                 for (x=0; x < (ssize_t) image->columns; x++)
1823                 {
1824                   *q++=(unsigned char) GetPixelIndex(image,p);
1825                   p+=GetPixelChannels(image);
1826                 }
1827                 if (image->previous == (Image *) NULL)
1828                   {
1829                     status=SetImageProgress(image,SaveImageTag,
1830                       (MagickOffsetType) y,image->rows);
1831                     if (status == MagickFalse)
1832                       break;
1833                   }
1834               }
1835 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1836               if (compression == ZipCompression)
1837                 status=ZLIBEncodeImage(image,length,pixels,exception);
1838               else
1839 #endif
1840                 if (compression == LZWCompression)
1841                   status=LZWEncodeImage(image,length,pixels,exception);
1842                 else
1843                   status=PackbitsEncodeImage(image,length,pixels,exception);
1844               pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1845               if (status == MagickFalse)
1846                 {
1847                   (void) CloseBlob(image);
1848                   return(MagickFalse);
1849                 }
1850               break;
1851             }
1852             case NoCompression:
1853             {
1854               /*
1855                 Dump uncompressed PseudoColor packets.
1856               */
1857               Ascii85Initialize(image);
1858               for (y=0; y < (ssize_t) image->rows; y++)
1859               {
1860                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1861                 if (p == (const Quantum *) NULL)
1862                   break;
1863                 for (x=0; x < (ssize_t) image->columns; x++)
1864                 {
1865                   Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
1866                   p+=GetPixelChannels(image);
1867                 }
1868                 if (image->previous == (Image *) NULL)
1869                   {
1870                     status=SetImageProgress(image,SaveImageTag,
1871                       (MagickOffsetType) y,image->rows);
1872                     if (status == MagickFalse)
1873                       break;
1874                   }
1875               }
1876               Ascii85Flush(image);
1877               break;
1878             }
1879           }
1880         }
1881     offset=TellBlob(image)-offset;
1882     (void) WriteBlobString(image,"\nendstream\n");
1883     (void) WriteBlobString(image,"endobj\n");
1884     /*
1885       Write Length object.
1886     */
1887     xref[object++]=TellBlob(image);
1888     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1889       object);
1890     (void) WriteBlobString(image,buffer);
1891     (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",
1892       (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                   q+=GetPixelChannels(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",
2425           (double) 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]+10;
2569   (void) WriteBlobString(image,"xref\n");
2570   (void) FormatLocaleString(buffer,MaxTextExtent,"0 %.20g\n",(double)
2571     object+1);
2572   (void) WriteBlobString(image,buffer);
2573   (void) WriteBlobString(image,"0000000000 65535 f \n");
2574   for (i=0; i < (ssize_t) object; i++)
2575   {
2576     (void) FormatLocaleString(buffer,MaxTextExtent,"%010lu 00000 n \n",
2577       (unsigned long) xref[i]);
2578     (void) WriteBlobString(image,buffer);
2579   }
2580   (void) WriteBlobString(image,"trailer\n");
2581   (void) WriteBlobString(image,"<<\n");
2582   (void) FormatLocaleString(buffer,MaxTextExtent,"/Size %.20g\n",(double)
2583     object+1);
2584   (void) WriteBlobString(image,buffer);
2585   (void) FormatLocaleString(buffer,MaxTextExtent,"/Info %.20g 0 R\n",(double)
2586     info_id);
2587   (void) WriteBlobString(image,buffer);
2588   (void) FormatLocaleString(buffer,MaxTextExtent,"/Root %.20g 0 R\n",(double)
2589     root_id);
2590   (void) WriteBlobString(image,buffer);
2591   (void) WriteBlobString(image,">>\n");
2592   (void) WriteBlobString(image,"startxref\n");
2593   (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
2594   (void) WriteBlobString(image,buffer);
2595   (void) WriteBlobString(image,"%%EOF\n");
2596   xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2597   (void) CloseBlob(image);
2598   return(MagickTrue);
2599 }