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