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