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