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