Coverage Report

Created: 2025-08-12 07:37

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