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