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