Coverage Report

Created: 2025-07-23 08:18

/src/graphicsmagick/coders/pdf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
% Copyright (C) 2003-2025 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            PPPP   DDDD   FFFFF                              %
15
%                            P   P  D   D  F                                  %
16
%                            PPPP   D   D  FFF                                %
17
%                            P      D   D  F                                  %
18
%                            P      DDDD   F                                  %
19
%                                                                             %
20
%                                                                             %
21
%                  Read/Write Portable Document Format.                       %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
%
33
*/
34

35
/*
36
  Include declarations.
37
*/
38
#include "magick/studio.h"
39
#include "magick/analyze.h"
40
#include "magick/attribute.h"
41
#include "magick/blob.h"
42
#include "magick/compress.h"
43
#include "magick/constitute.h"
44
#include "magick/delegate.h"
45
#include "magick/enum_strings.h"
46
#include "magick/log.h"
47
#include "magick/magick.h"
48
#include "magick/monitor.h"
49
#include "magick/pixel_cache.h"
50
#include "magick/resize.h"
51
#include "magick/shear.h"
52
#include "magick/tempfile.h"
53
#include "magick/utility.h"
54
#include "magick/version.h"
55

56
/*
57
  Forward declarations.
58
*/
59
static unsigned int WritePDFImage(const ImageInfo *,Image *);
60
#if defined(HasZLIB)
61
static unsigned int ZLIBEncodeImage(Image *,const size_t,const unsigned long,unsigned char *);
62
#endif
63

64

65
/*
66
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67
%                                                                             %
68
%                                                                             %
69
%                                                                             %
70
%   I s P D F                                                                 %
71
%                                                                             %
72
%                                                                             %
73
%                                                                             %
74
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75
%
76
%  Method IsPDF returns True if the image format type, identified by the
77
%  magick string, is PDF.
78
%
79
%  The format of the IsPDF method is:
80
%
81
%      unsigned int IsPDF(const unsigned char *magick,const size_t offset)
82
%
83
%  A description of each parameter follows:
84
%
85
%    o status:  Method IsPDF returns True if the image format type is PDF.
86
%
87
%    o magick: This string is generally the first few bytes of an image file
88
%      or blob.
89
%
90
%    o offset: Specifies the offset of the magick string.
91
%
92
%
93
*/
94
static unsigned int IsPDF(const unsigned char *magick,const size_t offset)
95
0
{
96
0
  if (offset < 5)
97
0
    return(False);
98
0
  if (LocaleNCompare((char *) magick,"%PDF-",5) == 0)
99
0
    return(True);
100
0
  return(False);
101
0
}
102

103
/*
104
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105
%                                                                             %
106
%                                                                             %
107
%                                                                             %
108
%   R e a d P D F I m a g e                                                   %
109
%                                                                             %
110
%                                                                             %
111
%                                                                             %
112
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113
%
114
%  Method ReadPDFImage reads a Portable Document Format image file and
115
%  returns it.  It allocates the memory necessary for the new Image structure
116
%  and returns a pointer to the new image.
117
%
118
%  The format of the ReadPDFImage method is:
119
%
120
%      Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
121
%
122
%  A description of each parameter follows:
123
%
124
%    o image:  Method ReadPDFImage returns a pointer to the image after
125
%      reading.  A null image is returned if there is a memory shortage or
126
%      if the image cannot be read.
127
%
128
%    o image_info: Specifies a pointer to a ImageInfo structure.
129
%
130
%    o exception: return any errors or warnings in this structure.
131
%
132
%
133
*/
134
#if defined(HasGS)
135
static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
136
176
{
137
176
#define MediaBox  "/MediaBox"
138
176
#define RenderPostscriptText  "[%s] Rendering postscript..."
139
140
176
  char
141
176
    density[MaxTextExtent],
142
176
    command[MaxTextExtent],
143
176
    filename[MaxTextExtent],
144
176
    postscript_filename[MaxTextExtent];
145
146
176
  const char
147
176
    *value;
148
149
176
  const DelegateInfo
150
176
    *delegate_info;
151
152
176
  double
153
176
    dx_resolution,
154
176
    dy_resolution;
155
156
176
  FILE
157
176
    *file;
158
159
176
  Image
160
176
    *image,
161
176
    *next_image;
162
163
176
  ImageInfo
164
176
    *clone_info;
165
166
176
  int
167
176
    count,
168
176
    status;
169
170
176
  unsigned int
171
176
    antialias=4;
172
173
176
  MagickBool
174
176
    use_crop_box = MagickFalse;
175
176
176
  MagickBool
177
176
    pdf_stop_on_error = MagickFalse;
178
179
180
176
  assert(image_info != (const ImageInfo *) NULL);
181
176
  assert(image_info->signature == MagickSignature);
182
176
  assert(exception != (ExceptionInfo *) NULL);
183
176
  assert(exception->signature == MagickSignature);
184
185
176
  if ((value=AccessDefinition(image_info,"pdf","use-cropbox")))
186
0
    {
187
0
      if (strcmp(value,"true") == 0)
188
0
        use_crop_box = True;
189
0
    }
190
191
176
   if ((value=AccessDefinition(image_info,"pdf","stop-on-error")))
192
0
     {
193
0
       if (strcmp(value,"true") == 0)
194
0
         pdf_stop_on_error = True;
195
0
     }
196
197
  /*
198
    Select Postscript delegate driver
199
  */
200
176
  delegate_info=GetPostscriptDelegateInfo(image_info,&antialias,exception);
201
176
  if (delegate_info == (const DelegateInfo *) NULL)
202
176
    return((Image *) NULL);
203
  /*
204
    Open image file.
205
  */
206
0
  image=AllocateImage(image_info);
207
0
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
208
0
  if (status == False)
209
0
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
210
  /*
211
    Open temporary output file.
212
  */
213
0
  file=AcquireTemporaryFileStream(postscript_filename,BinaryFileIOMode);
214
0
  if (file == (FILE *) NULL)
215
0
    ThrowReaderTemporaryFileException(postscript_filename);
216
  /*
217
    Set the page density.
218
  */
219
0
  dx_resolution=72.0;
220
0
  dy_resolution=72.0;
221
0
  if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
222
0
    {
223
0
      (void) strlcpy(density,PSDensityGeometry,sizeof(density));
224
0
      count=GetMagickDimension(density,&image->x_resolution,&image->y_resolution,NULL,NULL);
225
0
      if (count != 2)
226
0
        image->y_resolution=image->x_resolution;
227
0
    }
228
0
  FormatString(density,"%gx%g",image->x_resolution,image->y_resolution);
229
0
  {
230
    /*
231
      Determine page geometry from the PDF media box.
232
233
      Note that we can use Ghostscript to obtain the bounding box info like
234
235
      gs -q -dBATCH -dNOPAUSE -sDEVICE=bbox ENV.003.01.pdf
236
      %%BoundingBox: 70 61 2089 2954
237
      %%HiResBoundingBox: 70.737537 61.199998 2088.587889 2953.601629
238
    */
239
240
0
    char
241
0
      geometry[MaxTextExtent];
242
243
0
    RectangleInfo
244
0
      box,
245
0
      page;
246
247
0
    SegmentInfo
248
0
      bounds;
249
250
0
    unsigned long
251
0
      height,
252
0
      width;
253
254
0
    int
255
0
      rotate;
256
257
0
    register char
258
0
      *p,
259
0
      *q;
260
261
0
    register long
262
0
      c;
263
264
0
    rotate=0;
265
0
    (void) memset(&page,0,sizeof(RectangleInfo));
266
0
    (void) memset(&box,0,sizeof(RectangleInfo));
267
0
    for (p=command; ; )
268
0
      {
269
0
        c=ReadBlobByte(image);
270
0
        if (c == EOF)
271
0
          break;
272
0
        (void) fputc(c,file);
273
0
        *p++=(char) c;
274
0
        if ((c != '\n') && (c != '\r') && ((p-command) < (MaxTextExtent-1)))
275
0
          continue;
276
0
        *p='\0';
277
0
        p=command;
278
        /*
279
          Continue unless this is a MediaBox statement.
280
        */
281
0
        if (LocaleNCompare(command,"/Rotate ",8) == 0)
282
0
          {
283
0
            count=sscanf(command,"/Rotate %d",&rotate);
284
0
            if (count > 0)
285
0
              {
286
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
287
0
                                      "Rotate by %d degrees",rotate);
288
0
              }
289
0
          }
290
0
        q=strstr(command,MediaBox);
291
0
        if (q == (char *) NULL)
292
0
          continue;
293
0
        count=sscanf(q,"/MediaBox [%lf %lf %lf %lf",&bounds.x1,&bounds.y1,
294
0
                     &bounds.x2,&bounds.y2);
295
0
        if (count != 4)
296
0
          count=sscanf(q,"/MediaBox[%lf %lf %lf %lf",&bounds.x1,&bounds.y1,
297
0
                       &bounds.x2,&bounds.y2);
298
0
        if (count == 4)
299
0
          {
300
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
301
0
                                  "Parsed: MediaBox %lf %lf %lf %lf",
302
0
                                  bounds.x1,bounds.y1,
303
0
                                  bounds.x2,bounds.y2);
304
0
          }
305
0
        if (count != 4)
306
0
          continue;
307
0
        if ((bounds.x1 > bounds.x2) || (bounds.y1 > bounds.y2))
308
0
          continue;
309
        /*
310
          Set Postscript render geometry.
311
        */
312
0
        width=(unsigned long) (bounds.x2-bounds.x1+0.5);
313
0
        height=(unsigned long) (bounds.y2-bounds.y1+0.5);
314
0
        if ((width <= box.width) && (height <= box.height))
315
0
          continue;
316
0
        page.width=width;
317
0
        page.height=height;
318
0
        box=page;
319
0
      }
320
    /*
321
      If page is rotated right or left, then swap width and height values.
322
    */
323
0
    if ((90 == AbsoluteValue(rotate)) || (270 == AbsoluteValue(rotate)))
324
0
      {
325
0
        double
326
0
          value;
327
328
0
        value=page.width;
329
0
        page.width=page.height;
330
0
        page.height=value;
331
0
      }
332
0
    if ((page.width == 0) || (page.height == 0))
333
0
      {
334
0
        SetGeometry(image,&page);
335
0
        (void) GetGeometry(PSPageGeometry,&page.x,&page.y,&page.width,
336
0
                           &page.height);
337
0
      }
338
0
    if (image_info->page != (char *) NULL)
339
0
      (void) GetGeometry(image_info->page,&page.x,&page.y,&page.width,
340
0
                         &page.height);
341
0
    geometry[0]='\0';
342
0
    FormatString(geometry,"%lux%lu",
343
0
                 (unsigned long) ceil(page.width*image->x_resolution/dx_resolution-0.5),
344
0
                 (unsigned long) ceil(page.height*image->y_resolution/dy_resolution-0.5));
345
0
    if (ferror(file))
346
0
      {
347
0
        (void) fclose(file);
348
0
        ThrowReaderException(CorruptImageError,AnErrorHasOccurredWritingToFile,
349
0
                             image);
350
0
      }
351
0
  }
352
353
0
  (void) fclose(file);
354
0
  CloseBlob(image);
355
  /*
356
    Use Ghostscript to convert Postscript image.
357
  */
358
0
  {
359
0
    char
360
0
      options[MaxTextExtent],
361
0
      arg[MaxTextExtent];
362
363
0
    options[0]='\0';
364
365
0
    if (use_crop_box)
366
0
      (void) strlcat(options,"-dUseCropBox",sizeof(options));
367
368
0
    if (pdf_stop_on_error)
369
0
      {
370
0
        if (options[0] != '\0')
371
0
          (void) strlcat(options," ",sizeof(options));
372
0
        (void) strlcat(options,"-dPDFSTOPONERROR",sizeof(options));
373
0
      }
374
375
    /*
376
      Append subrange.
377
    */
378
0
    if (image_info->subrange != 0)
379
0
      {
380
0
        FormatString(arg,"-dFirstPage=%lu -dLastPage=%lu",
381
0
                     image_info->subimage+1,
382
0
                     image_info->subimage+image_info->subrange);
383
0
        if (options[0] != '\0')
384
0
          (void) strlcat(options," ",sizeof(options));
385
0
        (void) strlcat(options,arg,sizeof(options));
386
0
      }
387
388
    /*
389
      Append authentication string.
390
    */
391
0
    if (image_info->authenticate != (char *) NULL)
392
0
      {
393
0
        FormatString(arg,"-sPDFPassword=%.1024s", image_info->authenticate);
394
0
        if (options[0] != '\0')
395
0
          (void) strlcat(options," ",sizeof(options));
396
0
        (void) strlcat(options,arg,sizeof(options));
397
0
      }
398
0
    (void) strlcpy(filename,image_info->filename,MaxTextExtent);
399
0
    clone_info=CloneImageInfo(image_info);
400
0
    if (!AcquireTemporaryFileName(clone_info->filename))
401
0
      {
402
0
        DestroyImageInfo(clone_info);
403
0
        ThrowReaderTemporaryFileException(clone_info->filename);
404
0
      }
405
0
    FormatString(command,delegate_info->commands,antialias,
406
0
                 antialias,density,options,clone_info->filename,
407
0
                 postscript_filename);
408
0
  }
409
0
  (void) MagickMonitorFormatted(0,8,&image->exception,RenderPostscriptText,
410
0
                                image->filename);
411
0
  status=InvokePostscriptDelegate(clone_info->verbose,command,exception);
412
0
  (void) MagickMonitorFormatted(7,8,&image->exception,RenderPostscriptText,
413
0
                                image->filename);
414
0
  DestroyImage(image);
415
0
  image=(Image *) NULL;
416
0
  if (IsAccessibleAndNotEmpty(clone_info->filename))
417
0
    {
418
      /*
419
        Read Ghostscript output.
420
      */
421
0
      clone_info->blob=(void *) NULL;
422
0
      clone_info->length=0;
423
0
      clone_info->magick[0]='\0';
424
0
      clone_info->subimage=0;
425
0
      clone_info->subrange=0;
426
0
      MagickFreeMemory(clone_info->tile);
427
0
      image=ReadImage(clone_info,exception);
428
0
    }
429
0
  (void) LiberateTemporaryFile(postscript_filename);
430
0
  (void) LiberateTemporaryFile(clone_info->filename);
431
0
  DestroyImageInfo(clone_info);
432
0
  if (image == (Image *) NULL)
433
0
    {
434
0
      if (UndefinedException == exception->severity)
435
0
        ThrowException(exception,DelegateError,PostscriptDelegateFailed,filename);
436
0
    }
437
0
  else
438
0
    {
439
0
      do
440
0
        {
441
0
          (void) strlcpy(image->magick,"PDF",sizeof(image->magick));
442
0
          (void) strlcpy(image->filename,filename,sizeof(image->filename));
443
0
          next_image=SyncNextImageInList(image);
444
0
          if (next_image != (Image *) NULL)
445
0
            image=next_image;
446
0
        } while (next_image != (Image *) NULL);
447
0
      while (image->previous != (Image *) NULL)
448
0
        image=image->previous;
449
0
      if (image_info->subimage != 0)
450
0
        {
451
0
          unsigned long
452
0
            scene = image_info->subimage;
453
454
0
          for (next_image=image;
455
0
               next_image != (Image *) NULL;
456
0
               next_image=next_image->next)
457
0
            next_image->scene = scene++;
458
0
        }
459
0
    }
460
0
  return(image);
461
0
}
462
#endif /* if defined(HasGS) */
463

464
/*
465
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466
%                                                                             %
467
%                                                                             %
468
%                                                                             %
469
%   R e g i s t e r P D F I m a g e                                           %
470
%                                                                             %
471
%                                                                             %
472
%                                                                             %
473
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474
%
475
%  Method RegisterPDFImage adds attributes for the PDF image format to
476
%  the list of supported formats.  The attributes include the image format
477
%  tag, a method to read and/or write the format, whether the format
478
%  supports the saving of more than one frame to the same file or blob,
479
%  whether the format supports native in-memory I/O, and a brief
480
%  description of the format.
481
%
482
%  The format of the RegisterPDFImage method is:
483
%
484
%      RegisterPDFImage(void)
485
%
486
*/
487
ModuleExport void RegisterPDFImage(void)
488
4
{
489
4
  MagickInfo
490
4
    *entry;
491
492
4
  entry=SetMagickInfo("EPDF");
493
4
#if defined(HasGS)
494
4
  entry->decoder=(DecoderHandler) ReadPDFImage;
495
4
#endif /* if defined(HasGS) */
496
4
  entry->encoder=(EncoderHandler) WritePDFImage;
497
4
  entry->adjoin=False;
498
4
  entry->blob_support=False;
499
4
  entry->seekable_stream=True;
500
4
  entry->description="Encapsulated Portable Document Format";
501
4
  entry->module="PDF";
502
4
  entry->coder_class=PrimaryCoderClass;
503
4
  (void) RegisterMagickInfo(entry);
504
505
4
  entry=SetMagickInfo("PDF");
506
4
#if defined(HasGS)
507
4
  entry->decoder=(DecoderHandler) ReadPDFImage;
508
4
#endif /* if defined(HasGS) */
509
4
  entry->encoder=(EncoderHandler) WritePDFImage;
510
4
  entry->magick=(MagickHandler) IsPDF;
511
4
  entry->blob_support=False;
512
4
  entry->seekable_stream=True;
513
4
  entry->description="Portable Document Format";
514
4
  entry->module="PDF";
515
4
  entry->coder_class=PrimaryCoderClass;
516
4
  (void) RegisterMagickInfo(entry);
517
4
}
518

519
/*
520
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
521
%                                                                             %
522
%                                                                             %
523
%                                                                             %
524
%   U n r e g i s t e r P D F I m a g e                                       %
525
%                                                                             %
526
%                                                                             %
527
%                                                                             %
528
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529
%
530
%  Method UnregisterPDFImage removes format registrations made by the
531
%  PDF module from the list of supported formats.
532
%
533
%  The format of the UnregisterPDFImage method is:
534
%
535
%      UnregisterPDFImage(void)
536
%
537
*/
538
ModuleExport void UnregisterPDFImage(void)
539
0
{
540
0
  (void) UnregisterMagickInfo("EPDF");
541
0
  (void) UnregisterMagickInfo("PDF");
542
0
}
543

544
/*
545
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546
%                                                                             %
547
%                                                                             %
548
%                                                                             %
549
%   W r i t e P D F I m a g e                                                 %
550
%                                                                             %
551
%                                                                             %
552
%                                                                             %
553
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554
%
555
%  Method WritePDFImage writes an image in the Portable Document image
556
%  format.
557
%
558
%  The format of the WritePDFImage method is:
559
%
560
%      unsigned int WritePDFImage(const ImageInfo *image_info,Image *image)
561
%
562
%  A description of each parameter follows.
563
%
564
%    o status: Method WritePDFImage return True if the image is written.
565
%      False is returned is there is a memory shortage or if the image file
566
%      fails to write.
567
%
568
%    o image_info: Specifies a pointer to a ImageInfo structure.
569
%
570
%    o image:  A pointer to an Image structure.
571
%
572
%
573
*/
574
575
static char *EscapeParenthesis(const char *text, char *paren_buffer)
576
0
{
577
0
  register char
578
0
    *p;
579
580
0
  register long
581
0
    i;
582
583
0
  unsigned long
584
0
    escapes;
585
586
0
  escapes=0;
587
0
  p=paren_buffer;
588
0
  for (i=0; i < (long) Min(strlen(text),(MaxTextExtent-escapes-1)); i++)
589
0
  {
590
0
    if ((text[i] == '(') || (text[i] == ')'))
591
0
      {
592
0
        *p++='\\';
593
0
        escapes++;
594
0
      }
595
0
    *p++=text[i];
596
0
  }
597
0
  *p='\0';
598
0
  return(paren_buffer);
599
0
}
600
601
#define ThrowPDFWriterException(code_,reason_,image_)                \
602
0
  {                                                                  \
603
0
    MagickFreeMemory(fax_blob);                                      \
604
0
    MagickFreeResourceLimitedMemory(xref);                           \
605
0
    ThrowWriterException(code_,reason_,image_);                      \
606
0
  }
607
#define ThrowPDFWriterException2(code_,reason_,image_)                 \
608
0
  {                                                                    \
609
0
    MagickFreeMemory(fax_blob);                                        \
610
0
    MagickFreeResourceLimitedMemory(xref);                             \
611
0
    ThrowWriterException2(code_,reason_,image_);                       \
612
0
  }
613
static unsigned int WritePDFImage(const ImageInfo *image_info,Image *image)
614
0
{
615
0
#define CFormat  "/Filter [ /%.1024s ]\n"
616
0
#define ObjectsPerImage  9
617
618
0
  char
619
0
    basename[MaxTextExtent],
620
0
    buffer[MaxTextExtent],
621
0
    date[MaxTextExtent],
622
0
    density[MaxTextExtent],
623
0
    **labels,
624
0
    page_geometry[MaxTextExtent],
625
0
    paren_buffer[MaxTextExtent];
626
627
0
  unsigned char
628
0
    *fax_blob=(unsigned char *) NULL;
629
630
0
  const ImageAttribute
631
0
    *attribute;
632
633
0
  double
634
0
    dx_resolution,
635
0
    dy_resolution,
636
0
    x_resolution,
637
0
    x_scale,
638
0
    y_resolution,
639
0
    y_scale;
640
641
0
  ExtendedSignedIntegralType
642
0
    offset;
643
644
0
  long
645
0
    count,
646
0
    y;
647
648
0
  RectangleInfo
649
0
    geometry,
650
0
    media_info;
651
652
0
  register const PixelPacket
653
0
    *p;
654
655
0
  register const IndexPacket
656
0
    *indexes;
657
658
0
  register unsigned char
659
0
    *q;
660
661
0
  register long
662
0
    i,
663
0
    x;
664
665
0
  size_t
666
0
    fax_blob_length,
667
0
    length;
668
669
0
#if defined(HAVE_LOCALTIME_R)
670
0
  struct tm
671
0
    tm_buf;
672
0
#endif /* if defined(HAVE_LOCALTIME_R) */
673
674
0
  struct tm
675
0
    *time_meridian;
676
677
0
  time_t
678
0
    seconds;
679
680
0
  unsigned char
681
0
    *pixels;
682
683
0
  MagickPassFail
684
0
    status;
685
686
0
  unsigned long
687
0
    info_id,
688
0
    number_pixels,
689
0
    object,
690
0
    pages_id,
691
0
    root_id,
692
0
    scene,
693
0
    text_size;
694
695
0
  ExtendedSignedIntegralType
696
0
    *xref = (ExtendedSignedIntegralType *) NULL;
697
698
0
  size_t
699
0
    image_list_length;
700
701
  /*
702
    Open output image file.
703
  */
704
0
  assert(image_info != (const ImageInfo *) NULL);
705
0
  assert(image_info->signature == MagickSignature);
706
0
  assert(image != (Image *) NULL);
707
0
  assert(image->signature == MagickSignature);
708
0
  image_list_length=GetImageListLength(image);
709
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
710
0
  if (status == False)
711
0
    ThrowPDFWriterException(FileOpenError,UnableToOpenFile,image);
712
713
  /*
714
    Allocate X ref memory.
715
  */
716
0
  xref=MagickAllocateResourceLimitedMemory(ExtendedSignedIntegralType *,
717
0
                            2048*sizeof(ExtendedSignedIntegralType));
718
0
  if (xref == (ExtendedSignedIntegralType *) NULL)
719
0
    ThrowPDFWriterException(ResourceLimitError,MemoryAllocationFailed,image);
720
0
  (void) memset(xref,0,2048*sizeof(ExtendedSignedIntegralType));
721
  /*
722
    Write Documentation Information Dictionary
723
  */
724
0
  object=0;
725
0
  (void) WriteBlobString(image,"%PDF-1.2 \n");
726
0
  xref[object++]=TellBlob(image);
727
0
  info_id=object;
728
0
  FormatString(buffer,"%lu 0 obj\n",object);
729
0
  (void) WriteBlobString(image,buffer);
730
0
  (void) WriteBlobString(image,"<<\n");
731
0
  seconds=time((time_t *) NULL);
732
0
#if defined(HAVE_LOCALTIME_R)
733
0
  time_meridian=localtime_r(&seconds,&tm_buf);
734
#else
735
  time_meridian=localtime(&seconds); /* Thread-unsafe version */
736
#endif  /* if defined(HAVE_LOCALTIME_R) */
737
738
0
  FormatString(date,"D:%04d%02d%02d%02d%02d%02d",time_meridian->tm_year+1900,
739
0
               time_meridian->tm_mon+1,time_meridian->tm_mday,time_meridian->tm_hour,
740
0
               time_meridian->tm_min,time_meridian->tm_sec);
741
0
  GetPathComponent(image->filename,BasePath,basename);
742
743
0
  FormatString(buffer,"/Title (%.1024s)\n",
744
0
               EscapeParenthesis(basename,paren_buffer));
745
0
  (void) WriteBlobString(image,buffer);
746
0
  FormatString(buffer,"/CreationDate (%.1024s)\n",date);
747
0
  (void) WriteBlobString(image,buffer);
748
0
  FormatString(buffer,"/ModDate (%.1024s)\n",date);
749
0
  (void) WriteBlobString(image,buffer);
750
0
  FormatString(buffer,"/Producer (%.1024s)\n",
751
0
               EscapeParenthesis(GetMagickVersion((unsigned long *) NULL),
752
0
                                 paren_buffer));
753
0
  (void) WriteBlobString(image,buffer);
754
0
  (void) WriteBlobString(image,">>\n");
755
0
  (void) WriteBlobString(image,"endobj\n");
756
  /*
757
    Write Catalog object.
758
  */
759
0
  xref[object++]=TellBlob(image);
760
0
  root_id=object;
761
0
  FormatString(buffer,"%lu 0 obj\n",object);
762
0
  (void) WriteBlobString(image,buffer);
763
0
  (void) WriteBlobString(image,"<<\n");
764
0
  (void) WriteBlobString(image,"/Type /Catalog\n");
765
0
  FormatString(buffer,"/Pages %lu 0 R\n",object+1);
766
0
  (void) WriteBlobString(image,buffer);
767
0
  (void) WriteBlobString(image,">>\n");
768
0
  (void) WriteBlobString(image,"endobj\n");
769
  /*
770
    Write Pages object.
771
  */
772
0
  xref[object++]=TellBlob(image);
773
0
  pages_id=object;
774
0
  FormatString(buffer,"%lu 0 obj\n",object);
775
0
  (void) WriteBlobString(image,buffer);
776
0
  (void) WriteBlobString(image,"<<\n");
777
0
  (void) WriteBlobString(image,"/Type /Pages\n");
778
0
  FormatString(buffer,"/Kids [ %lu 0 R ",object+1);
779
0
  (void) WriteBlobString(image,buffer);
780
0
  count=(long) (pages_id+ObjectsPerImage+1);
781
0
  if (image_info->adjoin)
782
0
    {
783
0
      Image
784
0
        *kid_image;
785
786
0
      ExtendedSignedIntegralType
787
0
        *new_xref;
788
789
      /*
790
        Predict page object id's.
791
      */
792
0
      kid_image=image;
793
0
      for ( ; kid_image->next != (Image *) NULL; count+=ObjectsPerImage)
794
0
        {
795
0
          FormatString(buffer,"%ld 0 R ",count);
796
0
          (void) WriteBlobString(image,buffer);
797
0
          kid_image=kid_image->next;
798
0
        }
799
0
      new_xref=MagickReallocateResourceLimitedArray(ExtendedSignedIntegralType *,xref,
800
0
                                                    (size_t) count+2048,sizeof(ExtendedSignedIntegralType));
801
0
      if (new_xref == (ExtendedSignedIntegralType *) NULL)
802
0
        {
803
0
          MagickFreeResourceLimitedMemory(xref);
804
0
          ThrowPDFWriterException(ResourceLimitError,MemoryAllocationFailed,image);
805
0
        }
806
0
      xref=new_xref;
807
0
    }
808
0
  (void) WriteBlobString(image,"]\n");
809
0
  FormatString(buffer,"/Count %lu\n",(count-pages_id)/ObjectsPerImage);
810
0
  (void) WriteBlobString(image,buffer);
811
0
  (void) WriteBlobString(image,">>\n");
812
0
  (void) WriteBlobString(image,"endobj\n");
813
0
  scene=0;
814
0
  do
815
0
    {
816
0
      ImageCharacteristics
817
0
        characteristics;
818
819
0
      CompressionType
820
0
        compression;
821
822
      /*
823
        Analyze image properties.
824
      */
825
0
      (void) GetImageCharacteristics(image,&characteristics,
826
0
                                     (OptimizeType == image_info->type),
827
0
                                     &image->exception);
828
829
0
      compression=image->compression;
830
0
      if (image_info->compression != UndefinedCompression)
831
0
        {
832
          /*
833
            ImageInfo compression always prevails if it is set.
834
          */
835
0
          compression=image_info->compression;
836
0
        }
837
0
      else
838
0
        {
839
          /*
840
            Default to Zip compression unless the image was JPEG
841
            compressed and is not now monochrome or colormapped.
842
          */
843
0
          if ((JPEGCompression != compression) ||
844
0
              (characteristics.monochrome) ||
845
0
              (characteristics.palette))
846
0
            {
847
0
#if defined(HasZLIB)
848
0
              compression=ZipCompression;
849
#else
850
              compression=LZWCompression;
851
#endif
852
0
            }
853
0
        }
854
855
0
      switch (compression)
856
0
        {
857
#if !defined(HasJPEG)
858
        case JPEGCompression:
859
          {
860
            /*
861
              If JPEG compression is not supported, then use RLE compression
862
              and report a warning to user.
863
            */
864
            compression=RLECompression;
865
            ThrowException(&image->exception,MissingDelegateError,JPEGLibraryIsNotAvailable,image->filename);
866
            break;
867
          }
868
#endif
869
#if !defined(HasZLIB)
870
        case ZipCompression:
871
          {
872
            /*
873
              If ZIP compression is not supported, then use RLE compression
874
              and report a warning to user.
875
            */
876
            compression=RLECompression;
877
            ThrowException(&image->exception,MissingDelegateError,ZipLibraryIsNotAvailable,image->filename);
878
            break;
879
          }
880
#endif
881
0
        default:
882
0
          break;
883
0
        }
884
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
885
0
                            "%s compression.",
886
0
                            CompressionTypeToString(compression));
887
888
      /*
889
        Scale image to size of Portable Document page.
890
      */
891
0
      text_size=0;
892
0
      attribute=GetImageAttribute(image,"label");
893
0
      if (attribute != (const ImageAttribute *) NULL)
894
0
        text_size=(unsigned int)
895
0
          (MultilineCensus(attribute->value)*image_info->pointsize+12);
896
0
      SetGeometry(image,&geometry);
897
0
      geometry.y=(long) text_size;
898
0
      FormatString(page_geometry,"%lux%lu",image->columns,image->rows);
899
0
      if (image_info->page != (char *) NULL)
900
0
        {
901
0
          (void) strlcpy(page_geometry,image_info->page,MaxTextExtent);
902
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
903
0
                                "Page: %s (from ImageInfo) ", page_geometry);
904
905
0
        }
906
0
      else
907
0
        {
908
0
          if ((image->page.width != 0) && (image->page.height != 0))
909
0
            {
910
0
              (void) FormatString(page_geometry,"%lux%lu%+ld%+ld",image->page.width,
911
0
                                  image->page.height,image->page.x,image->page.y);
912
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
913
0
                                    "Page: %s (from Image)", page_geometry);
914
0
            }
915
0
          else
916
0
            {
917
0
              if (LocaleCompare(image_info->magick,"PDF") == 0)
918
0
                {
919
0
                  (void) strlcpy(page_geometry,PSPageGeometry,sizeof(page_geometry));
920
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
921
0
                                        "Page: %s (defaulted)", page_geometry);
922
0
                }
923
0
              else
924
0
                {
925
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
926
0
                                        "Page: %s (from Image columns/rows)",
927
0
                                        page_geometry);
928
929
0
                }
930
0
            }
931
0
        }
932
0
      (void) GetMagickGeometry(page_geometry,&geometry.x,&geometry.y,
933
0
                               &geometry.width,&geometry.height);
934
0
      (void) GetGeometry(page_geometry,&media_info.x,&media_info.y,
935
0
                         &media_info.width,&media_info.height);
936
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
937
0
                            "Image Resolution: %gx%g %s",
938
0
                            image->x_resolution,
939
0
                            image->y_resolution,
940
0
                            ResolutionTypeToString(image->units));
941
      /*
942
        Scale relative to dots-per-inch.
943
      */
944
0
      dx_resolution=72.0;
945
0
      dy_resolution=72.0;
946
0
      x_resolution=72.0;
947
0
      (void) strlcpy(density,PSDensityGeometry,sizeof(density));
948
0
      count=GetMagickDimension(density,&x_resolution,&y_resolution,NULL,NULL);
949
0
      if (count != 2)
950
0
        y_resolution=x_resolution;
951
      /*
952
        Use override resolution information if it appears to be valid.
953
      */
954
0
      if ((image_info->density != (char *) NULL) &&
955
0
          ((image_info->units == PixelsPerInchResolution) ||
956
0
           (image_info->units == PixelsPerCentimeterResolution)))
957
0
        {
958
0
          count=GetMagickDimension(image_info->density,&x_resolution,
959
0
                                   &y_resolution,NULL,NULL);
960
0
          if (count != 2)
961
0
            y_resolution=x_resolution;
962
0
          if (image_info->units == PixelsPerCentimeterResolution)
963
0
            {
964
0
              x_resolution *= 2.54;
965
0
              y_resolution *= 2.54;
966
0
            }
967
0
        }
968
      /*
969
        Use image resolution information if it appears to be valid.
970
      */
971
0
      else if ((image->x_resolution > 0.0) && (image->y_resolution > 0.0) &&
972
0
               ((image->units == PixelsPerInchResolution) ||
973
0
                (image->units == PixelsPerCentimeterResolution)))
974
0
        {
975
0
          x_resolution = image->x_resolution;
976
0
          y_resolution = image->y_resolution;
977
0
          if (image->units == PixelsPerCentimeterResolution)
978
0
            {
979
0
              x_resolution *= 2.54;
980
0
              y_resolution *= 2.54;
981
0
            }
982
0
        }
983
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
984
0
                            "PDF Resolution: %gx%g DPI",
985
0
                            x_resolution,y_resolution);
986
987
0
      x_scale=(geometry.width*dx_resolution)/x_resolution;
988
0
      geometry.width=(unsigned long) (x_scale+0.5);
989
0
      y_scale=(geometry.height*dy_resolution)/y_resolution;
990
0
      geometry.height=(unsigned long) (y_scale+0.5);
991
      /*
992
        Write Page object.
993
      */
994
0
      xref[object++]=TellBlob(image);
995
0
      FormatString(buffer,"%lu 0 obj\n",object);
996
0
      (void) WriteBlobString(image,buffer);
997
0
      (void) WriteBlobString(image,"<<\n");
998
0
      (void) WriteBlobString(image,"/Type /Page\n");
999
0
      FormatString(buffer,"/Parent %lu 0 R\n",pages_id);
1000
0
      (void) WriteBlobString(image,buffer);
1001
0
      (void) WriteBlobString(image,"/Resources <<\n");
1002
0
      FormatString(buffer,"/XObject << /Im%lu %lu 0 R >>\n",image->scene,
1003
0
                   object+4);
1004
0
      (void) WriteBlobString(image,buffer);
1005
0
      FormatString(buffer,"/ProcSet %lu 0 R >>\n",object+3);
1006
0
      (void) WriteBlobString(image,buffer);
1007
0
      FormatString(buffer,"/MediaBox [0 0 %ld %ld]\n",
1008
0
                   (long int)(((media_info.width * dx_resolution) / x_resolution) + 0.5),
1009
0
                   (long int)(((media_info.height * dy_resolution) / y_resolution) + 0.5));
1010
0
      (void) WriteBlobString(image,buffer);
1011
0
      FormatString(buffer,"/CropBox [%ld %ld %ld %ld]\n",geometry.x,geometry.y,
1012
0
                   geometry.x+geometry.width,geometry.y+geometry.height);
1013
0
      (void) WriteBlobString(image,buffer);
1014
0
      FormatString(buffer,"/Contents %lu 0 R\n",object+1);
1015
0
      (void) WriteBlobString(image,buffer);
1016
0
      (void) WriteBlobString(image,">>\n");
1017
0
      (void) WriteBlobString(image,"endobj\n");
1018
      /*
1019
        Write Contents object.
1020
      */
1021
0
      xref[object++]=TellBlob(image);
1022
0
      FormatString(buffer,"%lu 0 obj\n",object);
1023
0
      (void) WriteBlobString(image,buffer);
1024
0
      (void) WriteBlobString(image,"<<\n");
1025
0
      FormatString(buffer,"/Length %lu 0 R\n",object+1);
1026
0
      (void) WriteBlobString(image,buffer);
1027
0
      (void) WriteBlobString(image,">>\n");
1028
0
      (void) WriteBlobString(image,"stream\n");
1029
0
      offset=TellBlob(image);
1030
0
      (void) WriteBlobString(image,"q\n");
1031
0
      labels=(char **) NULL;
1032
0
      attribute=GetImageAttribute(image,"label");
1033
0
      if (attribute != (const ImageAttribute *) NULL)
1034
0
        labels=StringToList(attribute->value);
1035
0
      if (labels != (char **) NULL)
1036
0
        {
1037
0
          for (i=0; labels[i] != (char *) NULL; i++)
1038
0
            {
1039
0
              (void) WriteBlobString(image,"BT\n");
1040
0
              FormatString(buffer,"/F%lu %g Tf\n",image->scene,
1041
0
                           image_info->pointsize);
1042
0
              (void) WriteBlobString(image,buffer);
1043
0
              FormatString(buffer,"%ld %g Td\n",geometry.x,(double) geometry.y+
1044
0
                           (double) geometry.height+i*(double) image_info->pointsize+12);
1045
0
              (void) WriteBlobString(image,buffer);
1046
0
              FormatString(buffer,"(%.1024s) Tj\n",labels[i]);
1047
0
              (void) WriteBlobString(image,buffer);
1048
0
              (void) WriteBlobString(image,"ET\n");
1049
0
              MagickFreeMemory(labels[i]);
1050
0
            }
1051
0
          MagickFreeMemory(labels);
1052
0
        }
1053
0
      FormatString(buffer,"%g 0 0 %g %ld %ld cm\n",x_scale,y_scale,geometry.x,
1054
0
                   geometry.y);
1055
0
      (void) WriteBlobString(image,buffer);
1056
0
      FormatString(buffer,"/Im%lu Do\n",image->scene);
1057
0
      (void) WriteBlobString(image,buffer);
1058
0
      (void) WriteBlobString(image,"Q\n");
1059
0
      offset=TellBlob(image)-offset;
1060
0
      (void) WriteBlobString(image,"endstream\n");
1061
0
      (void) WriteBlobString(image,"endobj\n");
1062
      /*
1063
        Write Length object.
1064
      */
1065
0
      xref[object++]=TellBlob(image);
1066
0
      FormatString(buffer,"%lu 0 obj\n",object);
1067
0
      (void) WriteBlobString(image,buffer);
1068
0
      FormatString(buffer,"%lu\n",(unsigned long) offset);
1069
0
      (void) WriteBlobString(image,buffer);
1070
0
      (void) WriteBlobString(image,"endobj\n");
1071
      /*
1072
        Write Procset object.
1073
      */
1074
0
      xref[object++]=TellBlob(image);
1075
0
      FormatString(buffer,"%lu 0 obj\n",object);
1076
0
      (void) WriteBlobString(image,buffer);
1077
0
      if ((image->storage_class == DirectClass) || (image->colors > 256))
1078
0
        (void) strlcpy(buffer,"[ /PDF /Text /ImageC",sizeof(buffer));
1079
0
      else
1080
0
        if (compression == FaxCompression)
1081
0
          (void) strlcpy(buffer,"[ /PDF /Text /ImageB",sizeof(buffer));
1082
0
        else
1083
0
          (void) strlcpy(buffer,"[ /PDF /Text /ImageI",sizeof(buffer));
1084
0
      (void) WriteBlobString(image,buffer);
1085
0
      (void) WriteBlobString(image," ]\n");
1086
0
      (void) WriteBlobString(image,"endobj\n");
1087
      /*
1088
        Write XObject object.
1089
      */
1090
0
      xref[object++]=TellBlob(image);
1091
0
      FormatString(buffer,"%lu 0 obj\n",object);
1092
0
      (void) WriteBlobString(image,buffer);
1093
0
      (void) WriteBlobString(image,"<<\n");
1094
0
      (void) WriteBlobString(image,"/Type /XObject\n");
1095
0
      (void) WriteBlobString(image,"/Subtype /Image\n");
1096
0
      FormatString(buffer,"/Name /Im%lu\n",image->scene);
1097
0
      (void) WriteBlobString(image,buffer);
1098
0
      switch (compression)
1099
0
        {
1100
0
        case NoCompression:
1101
0
          {
1102
0
            FormatString(buffer,CFormat,"ASCII85Decode");
1103
0
            break;
1104
0
          }
1105
0
        case JPEGCompression:
1106
0
          {
1107
0
            FormatString(buffer,CFormat,"DCTDecode");
1108
0
            if (image->colorspace != CMYKColorspace)
1109
0
              break;
1110
0
            (void) WriteBlobString(image,buffer);
1111
0
            (void) strlcpy(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",sizeof(buffer));
1112
0
            break;
1113
0
          }
1114
0
        case LZWCompression:
1115
0
          {
1116
0
            FormatString(buffer,CFormat,"LZWDecode");
1117
0
            break;
1118
0
          }
1119
0
        case ZipCompression:
1120
0
          {
1121
0
            FormatString(buffer,CFormat,"FlateDecode");
1122
0
            break;
1123
0
          }
1124
0
        case FaxCompression:
1125
0
          {
1126
0
            char
1127
0
              CCITTParam[4];
1128
1129
0
            ExceptionInfo
1130
0
              exception;
1131
1132
            /*
1133
              Try compressing page to Group4 to see if it is
1134
              supported, otherwise we will fall back to Group3.
1135
            */
1136
0
            (void) strlcpy(CCITTParam,"0",sizeof(CCITTParam));
1137
0
            GetExceptionInfo(&exception);
1138
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1139
0
                                  "Executing ImageToHuffman2DBlob for CCITT Fax4 ...");
1140
0
            fax_blob=ImageToHuffman2DBlob(image,image_info,&fax_blob_length,
1141
0
                                          &exception);
1142
0
            if (fax_blob != (unsigned char *) NULL)
1143
0
              {
1144
0
                (void) strlcpy(CCITTParam,"-1",sizeof(CCITTParam));
1145
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1146
0
                                      "ImageToHuffman2DBlob reports success!");
1147
0
              }
1148
0
            DestroyExceptionInfo(&exception);
1149
0
            (void) strlcpy(buffer,"/Filter [ /CCITTFaxDecode ]\n",sizeof(buffer));
1150
0
            (void) WriteBlobString(image,buffer);
1151
0
            (void) strlcpy(buffer,"/Interpolate false\n",sizeof(buffer));
1152
0
            (void) WriteBlobString(image,buffer);
1153
0
            FormatString(buffer,
1154
0
                         "/DecodeParms [ << /K %.1024s /BlackIs1 false /Columns %ld /Rows %ld >> ]\n",
1155
0
                         CCITTParam,image->columns,image->rows);
1156
0
            break;
1157
0
          }
1158
0
        default:
1159
0
          {
1160
0
            FormatString(buffer,CFormat,"RunLengthDecode");
1161
0
            break;
1162
0
          }
1163
0
        }
1164
0
      (void) WriteBlobString(image,buffer);
1165
0
      FormatString(buffer,"/Width %lu\n",image->columns);
1166
0
      (void) WriteBlobString(image,buffer);
1167
0
      FormatString(buffer,"/Height %lu\n",image->rows);
1168
0
      (void) WriteBlobString(image,buffer);
1169
0
      if (compression == FaxCompression)
1170
0
        strlcpy(buffer,"/ColorSpace /DeviceGray\n",MaxTextExtent);
1171
0
      else
1172
0
        FormatString(buffer,"/ColorSpace %lu 0 R\n",object+2);
1173
0
      (void) WriteBlobString(image,buffer);
1174
0
      FormatString(buffer,"/BitsPerComponent %d\n",
1175
0
                   compression == FaxCompression ? 1 : 8);
1176
0
      (void) WriteBlobString(image,buffer);
1177
0
      FormatString(buffer,"/Length %lu 0 R\n",object+1);
1178
0
      (void) WriteBlobString(image,buffer);
1179
0
      (void) WriteBlobString(image,">>\n");
1180
0
      (void) WriteBlobString(image,"stream\n");
1181
0
      offset=TellBlob(image);
1182
0
      number_pixels=image->columns*image->rows;
1183
0
      if ((compression == FaxCompression) ||
1184
0
          ((image_info->type != TrueColorType) &&
1185
0
           characteristics.grayscale))
1186
0
        {
1187
          /*
1188
            Write grayscale output.
1189
          */
1190
0
          switch (compression)
1191
0
            {
1192
0
            case FaxCompression:
1193
0
              {
1194
                /*
1195
                  Try Group4 first and use Group3 as a fallback.
1196
                */
1197
0
                if (fax_blob != (unsigned char *) NULL)
1198
0
                  {
1199
0
                    (void) WriteBlob(image,fax_blob_length,fax_blob);
1200
0
                    MagickFreeMemory(fax_blob);
1201
0
                  }
1202
0
                else
1203
0
                  {
1204
0
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1205
0
                                          "Executing HuffmanEncodeImage for CCITT Fax3 ...");
1206
0
                    if (!HuffmanEncodeImage(image_info,image))
1207
0
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1208
0
                                            "HuffmanEncodeImage reports failure!");
1209
0
                  }
1210
0
                break;
1211
0
              }
1212
0
            case JPEGCompression:
1213
0
              {
1214
0
                unsigned char
1215
0
                  *jpeg_blob;
1216
1217
                /*
1218
                  Write image in JPEG format.
1219
                */
1220
0
                jpeg_blob=ImageToJPEGBlob(image,image_info,&length,&image->exception);
1221
0
                if (jpeg_blob == (unsigned char *) NULL)
1222
0
                  ThrowPDFWriterException2(CoderError,image->exception.reason,image);
1223
0
                (void) WriteBlob(image,length,jpeg_blob);
1224
0
                MagickFreeMemory(jpeg_blob);
1225
0
                break;
1226
0
              }
1227
0
            case RLECompression:
1228
0
            default:
1229
0
              {
1230
                /*
1231
                  Allocate pixel array.
1232
                */
1233
0
                length=number_pixels;
1234
0
                pixels=MagickAllocateResourceLimitedMemory(unsigned char *,length);
1235
0
                if (pixels == (unsigned char *) NULL)
1236
0
                  ThrowPDFWriterException(ResourceLimitError,MemoryAllocationFailed,
1237
0
                                          image);
1238
                /*
1239
                  Dump Runlength encoded pixels.
1240
                */
1241
0
                q=pixels;
1242
0
                for (y=0; y < (long) image->rows; y++)
1243
0
                  {
1244
0
                    p=AcquireImagePixels(image,0,y,image->columns,1,
1245
0
                                         &image->exception);
1246
0
                    if (p == (const PixelPacket *) NULL)
1247
0
                      break;
1248
0
                    for (x=0; x < (long) image->columns; x++)
1249
0
                      {
1250
0
                        *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1251
0
                        p++;
1252
0
                      }
1253
0
                    if (image->previous == (Image *) NULL)
1254
0
                      if (QuantumTick(y,image->rows))
1255
0
                        {
1256
0
                          status=MagickMonitorFormatted(y,image->rows,
1257
0
                                                        &image->exception,
1258
0
                                                        SaveImageText,
1259
0
                                                        image->filename,
1260
0
                                                        image->columns,image->rows);
1261
0
                          if (status == False)
1262
0
                            break;
1263
0
                        }
1264
0
                  }
1265
0
#if defined(HasZLIB)
1266
0
                if (compression == ZipCompression)
1267
0
                  status=ZLIBEncodeImage(image,length,image_info->quality,pixels);
1268
0
                else
1269
0
#endif /* defined(HasZLIB) */
1270
0
                  if (compression == LZWCompression)
1271
0
                    status=LZWEncodeImage(image,length,pixels);
1272
0
                  else
1273
0
                    status=PackbitsEncodeImage(image,length,pixels);
1274
0
                MagickFreeResourceLimitedMemory(pixels);
1275
0
                if (!status)
1276
0
                  {
1277
0
                    CloseBlob(image);
1278
0
                    MagickFreeResourceLimitedMemory(xref);
1279
0
                    return(MagickFail);
1280
0
                  }
1281
0
                break;
1282
0
              }
1283
0
            case NoCompression:
1284
0
              {
1285
                /*
1286
                  Dump uncompressed PseudoColor packets.
1287
                */
1288
0
                Ascii85Initialize(image);
1289
0
                for (y=0; y < (long) image->rows; y++)
1290
0
                  {
1291
0
                    p=AcquireImagePixels(image,0,y,image->columns,1,
1292
0
                                         &image->exception);
1293
0
                    if (p == (const PixelPacket *) NULL)
1294
0
                      break;
1295
0
                    for (x=0; x < (long) image->columns; x++)
1296
0
                      {
1297
0
                        Ascii85Encode(image,
1298
0
                                      ScaleQuantumToChar(PixelIntensityToQuantum(p)));
1299
0
                        p++;
1300
0
                      }
1301
0
                    if (image->previous == (Image *) NULL)
1302
0
                      if (QuantumTick(y,image->rows))
1303
0
                        {
1304
0
                          status=MagickMonitorFormatted(y,image->rows,
1305
0
                                                        &image->exception,
1306
0
                                                        SaveImageText,
1307
0
                                                        image->filename,
1308
0
                                                        image->columns,image->rows);
1309
0
                          if (status == False)
1310
0
                            break;
1311
0
                        }
1312
0
                  }
1313
0
                Ascii85Flush(image);
1314
0
                break;
1315
0
              }
1316
0
            }
1317
0
        }
1318
0
      else
1319
0
        if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1320
0
            (compression == JPEGCompression))
1321
0
          switch (compression)
1322
0
            {
1323
0
            case JPEGCompression:
1324
0
              {
1325
0
                unsigned char
1326
0
                  *jpeg_blob;
1327
1328
                /*
1329
                  Write image in JPEG format.
1330
                */
1331
0
                jpeg_blob=ImageToJPEGBlob(image,image_info,&length,&image->exception);
1332
0
                if (jpeg_blob == (unsigned char *) NULL)
1333
0
                  ThrowPDFWriterException2(CoderError,image->exception.reason,image);
1334
0
                (void) WriteBlob(image,length,jpeg_blob);
1335
0
                MagickFreeMemory(jpeg_blob);
1336
0
                break;
1337
0
              }
1338
0
            case RLECompression:
1339
0
            default:
1340
0
              {
1341
                /*
1342
                  Allocate pixel array.
1343
                */
1344
0
                length=(size_t) (image->colorspace == CMYKColorspace ? 4 : 3)*number_pixels;
1345
0
                pixels=MagickAllocateResourceLimitedMemory(unsigned char *,length);
1346
0
                if (pixels == (unsigned char *) NULL)
1347
0
                  ThrowPDFWriterException(ResourceLimitError,MemoryAllocationFailed,
1348
0
                                          image);
1349
                /*
1350
                  Dump runoffset encoded pixels.
1351
                */
1352
0
                q=pixels;
1353
0
                for (y=0; y < (long) image->rows; y++)
1354
0
                  {
1355
0
                    p=AcquireImagePixels(image,0,y,image->columns,1,
1356
0
                                         &image->exception);
1357
0
                    if (p == (const PixelPacket *) NULL)
1358
0
                      break;
1359
0
                    for (x=0; x < (long) image->columns; x++)
1360
0
                      {
1361
0
                        if (image->matte && (p->opacity == TransparentOpacity))
1362
0
                          {
1363
0
                            *q++=ScaleQuantumToChar(MaxRGB);
1364
0
                            *q++=ScaleQuantumToChar(MaxRGB);
1365
0
                            *q++=ScaleQuantumToChar(MaxRGB);
1366
0
                            p++;
1367
0
                            continue;
1368
0
                          }
1369
0
                        *q++=ScaleQuantumToChar(p->red);
1370
0
                        *q++=ScaleQuantumToChar(p->green);
1371
0
                        *q++=ScaleQuantumToChar(p->blue);
1372
0
                        if (image->colorspace == CMYKColorspace)
1373
0
                          *q++=ScaleQuantumToChar(p->opacity);
1374
0
                        p++;
1375
0
                      }
1376
0
                    if (image->previous == (Image *) NULL)
1377
0
                      if (QuantumTick(y,image->rows))
1378
0
                        {
1379
0
                          status=MagickMonitorFormatted(y,image->rows,
1380
0
                                                        &image->exception,
1381
0
                                                        SaveImageText,
1382
0
                                                        image->filename,
1383
0
                                                        image->columns,image->rows);
1384
0
                          if (status == False)
1385
0
                            break;
1386
0
                        }
1387
0
                  }
1388
0
#if defined(HasZLIB)
1389
0
                if (compression == ZipCompression)
1390
0
                  status=ZLIBEncodeImage(image,length,image_info->quality,pixels);
1391
0
                else
1392
0
#endif /* defined(HasZLIB) */
1393
0
                  if (compression == LZWCompression)
1394
0
                    status=LZWEncodeImage(image,length,pixels);
1395
0
                  else
1396
0
                    status=PackbitsEncodeImage(image,length,pixels);
1397
0
                MagickFreeResourceLimitedMemory(pixels);
1398
0
                if (!status)
1399
0
                  {
1400
0
                    CloseBlob(image);
1401
0
                    MagickFreeResourceLimitedMemory(xref);
1402
0
                    return(False);
1403
0
                  }
1404
0
                break;
1405
0
              }
1406
0
            case NoCompression:
1407
0
              {
1408
                /*
1409
                  Dump uncompressed DirectColor packets.
1410
                */
1411
0
                Ascii85Initialize(image);
1412
0
                for (y=0; y < (long) image->rows; y++)
1413
0
                  {
1414
0
                    p=AcquireImagePixels(image,0,y,image->columns,1,
1415
0
                                         &image->exception);
1416
0
                    if (p == (const PixelPacket *) NULL)
1417
0
                      break;
1418
0
                    for (x=0; x < (long) image->columns; x++)
1419
0
                      {
1420
0
                        if (image->matte && (p->opacity == TransparentOpacity))
1421
0
                          {
1422
0
                            Ascii85Encode(image,ScaleQuantumToChar(MaxRGB));
1423
0
                            Ascii85Encode(image,ScaleQuantumToChar(MaxRGB));
1424
0
                            Ascii85Encode(image,ScaleQuantumToChar(MaxRGB));
1425
0
                            continue;
1426
0
                          }
1427
0
                        Ascii85Encode(image,ScaleQuantumToChar(p->red));
1428
0
                        Ascii85Encode(image,ScaleQuantumToChar(p->green));
1429
0
                        Ascii85Encode(image,ScaleQuantumToChar(p->blue));
1430
0
                        if (image->colorspace == CMYKColorspace)
1431
0
                          Ascii85Encode(image,ScaleQuantumToChar(p->opacity));
1432
0
                        p++;
1433
0
                      }
1434
0
                    if (image->previous == (Image *) NULL)
1435
0
                      if (QuantumTick(y,image->rows))
1436
0
                        {
1437
0
                          status=MagickMonitorFormatted(y,image->rows,
1438
0
                                                        &image->exception,
1439
0
                                                        SaveImageText,
1440
0
                                                        image->filename,
1441
0
                                                        image->columns,image->rows);
1442
0
                          if (status == False)
1443
0
                            break;
1444
0
                        }
1445
0
                  }
1446
0
                Ascii85Flush(image);
1447
0
                break;
1448
0
              }
1449
0
            }
1450
0
        else
1451
0
          {
1452
            /*
1453
              Dump number of colors and colormap.
1454
            */
1455
0
            switch (compression)
1456
0
              {
1457
0
              case RLECompression:
1458
0
              default:
1459
0
                {
1460
                  /*
1461
                    Allocate pixel array.
1462
                  */
1463
0
                  length=number_pixels;
1464
0
                  pixels=MagickAllocateResourceLimitedMemory(unsigned char *,length);
1465
0
                  if (pixels == (unsigned char *) NULL)
1466
0
                    ThrowPDFWriterException(ResourceLimitError,MemoryAllocationFailed,image);
1467
                  /*
1468
                    Dump Runlength encoded pixels.
1469
                  */
1470
0
                  q=pixels;
1471
0
                  for (y=0; y < (long) image->rows; y++)
1472
0
                    {
1473
0
                      p=AcquireImagePixels(image,0,y,image->columns,1,
1474
0
                                           &image->exception);
1475
0
                      if (p == (const PixelPacket *) NULL)
1476
0
                        break;
1477
0
                      indexes=AccessImmutableIndexes(image);
1478
0
                      for (x=0; x < (long) image->columns; x++)
1479
0
                        *q++=indexes[x];
1480
0
                      if (image->previous == (Image *) NULL)
1481
0
                        if (QuantumTick(y,image->rows))
1482
0
                          {
1483
0
                            status=MagickMonitorFormatted(y,image->rows,
1484
0
                                                          &image->exception,
1485
0
                                                          SaveImageText,
1486
0
                                                          image->filename,
1487
0
                                                          image->columns,image->rows);
1488
0
                            if (status == False)
1489
0
                              break;
1490
0
                          }
1491
0
                    }
1492
0
#if defined(HasZLIB)
1493
0
                  if (compression == ZipCompression)
1494
0
                    status=ZLIBEncodeImage(image,length,image_info->quality,pixels);
1495
0
                  else
1496
0
#endif /* defined(HasZLIB) */
1497
0
                    if (compression == LZWCompression)
1498
0
                      status=LZWEncodeImage(image,length,pixels);
1499
0
                    else
1500
0
                      status=PackbitsEncodeImage(image,length,pixels);
1501
0
                  MagickFreeResourceLimitedMemory(pixels);
1502
0
                  if (!status)
1503
0
                    {
1504
0
                      CloseBlob(image);
1505
0
                      MagickFreeResourceLimitedMemory(xref);
1506
0
                      return(False);
1507
0
                    }
1508
0
                  break;
1509
0
                }
1510
0
              case NoCompression:
1511
0
                {
1512
                  /*
1513
                    Dump uncompressed PseudoColor packets.
1514
                  */
1515
0
                  Ascii85Initialize(image);
1516
0
                  for (y=0; y < (long) image->rows; y++)
1517
0
                    {
1518
0
                      p=AcquireImagePixels(image,0,y,image->columns,1,
1519
0
                                           &image->exception);
1520
0
                      if (p == (const PixelPacket *) NULL)
1521
0
                        break;
1522
0
                      indexes=AccessImmutableIndexes(image);
1523
0
                      for (x=0; x < (long) image->columns; x++)
1524
0
                        Ascii85Encode(image,indexes[x]);
1525
0
                      if (image->previous == (Image *) NULL)
1526
0
                        if (QuantumTick(y,image->rows))
1527
0
                          {
1528
0
                            status=MagickMonitorFormatted(y,image->rows,
1529
0
                                                          &image->exception,
1530
0
                                                          SaveImageText,
1531
0
                                                          image->filename,
1532
0
                                                          image->columns,image->rows);
1533
0
                            if (status == False)
1534
0
                              break;
1535
0
                          }
1536
0
                    }
1537
0
                  Ascii85Flush(image);
1538
0
                  break;
1539
0
                }
1540
0
              }
1541
0
          }
1542
0
      offset=TellBlob(image)-offset;
1543
0
      (void) WriteBlobString(image,"\nendstream\n");
1544
0
      (void) WriteBlobString(image,"endobj\n");
1545
      /*
1546
        Write Length object.
1547
      */
1548
0
      xref[object++]=TellBlob(image);
1549
0
      FormatString(buffer,"%lu 0 obj\n",object);
1550
0
      (void) WriteBlobString(image,buffer);
1551
0
      FormatString(buffer,"%lu\n",(unsigned long) offset);
1552
0
      (void) WriteBlobString(image,buffer);
1553
0
      (void) WriteBlobString(image,"endobj\n");
1554
      /*
1555
        Write Colorspace object.
1556
      */
1557
0
      xref[object++]=TellBlob(image);
1558
0
      FormatString(buffer,"%lu 0 obj\n",object);
1559
0
      (void) WriteBlobString(image,buffer);
1560
0
      if (image->colorspace == CMYKColorspace)
1561
0
        {
1562
0
          (void) strlcpy(buffer,"/DeviceCMYK\n",sizeof(buffer));
1563
0
        }
1564
0
      else
1565
0
        {
1566
0
          if ((compression == FaxCompression) ||
1567
0
              (compression == Group4Compression) ||
1568
0
              ((image_info->type != TrueColorType) &&
1569
0
               (characteristics.grayscale)))
1570
0
            {
1571
0
              (void) strlcpy(buffer,"/DeviceGray\n",sizeof(buffer));
1572
0
            }
1573
0
          else
1574
0
            {
1575
0
              if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1576
0
                  (compression == JPEGCompression))
1577
0
                (void) strlcpy(buffer,"/DeviceRGB\n",sizeof(buffer));
1578
0
              else
1579
0
                FormatString(buffer,"[ /Indexed /DeviceRGB %u %lu 0 R ]\n",
1580
0
                             (unsigned int) image->colors-1,object+1);
1581
0
            }
1582
0
        }
1583
0
      (void) WriteBlobString(image,buffer);
1584
0
      (void) WriteBlobString(image,"endobj\n");
1585
      /*
1586
        Write Colormap object.
1587
      */
1588
0
      xref[object++]=TellBlob(image);
1589
0
      FormatString(buffer,"%lu 0 obj\n",object);
1590
0
      (void) WriteBlobString(image,buffer);
1591
0
      (void) WriteBlobString(image,"<<\n");
1592
0
      if ((image->storage_class != DirectClass) && (image->colors <= 256) &&
1593
0
          (compression != FaxCompression))
1594
0
        {
1595
0
          if (compression == NoCompression)
1596
0
            (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
1597
0
          FormatString(buffer,"/Length %lu 0 R\n",object+1);
1598
0
          (void) WriteBlobString(image,buffer);
1599
0
          (void) WriteBlobString(image,">>\n");
1600
0
          (void) WriteBlobString(image,"stream\n");
1601
0
          offset=TellBlob(image);
1602
0
          if (compression == NoCompression)
1603
0
            Ascii85Initialize(image);
1604
0
          for (i=0; i < (long) image->colors; i++)
1605
0
            {
1606
0
              if (compression == NoCompression)
1607
0
                {
1608
0
                  Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].red));
1609
0
                  Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].green));
1610
0
                  Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].blue));
1611
0
                  continue;
1612
0
                }
1613
0
              (void) WriteBlobByte(image,
1614
0
                                   ScaleQuantumToChar(image->colormap[i].red));
1615
0
              (void) WriteBlobByte(image,
1616
0
                                   ScaleQuantumToChar(image->colormap[i].green));
1617
0
              (void) WriteBlobByte(image,
1618
0
                                   ScaleQuantumToChar(image->colormap[i].blue));
1619
0
            }
1620
0
          if (compression == NoCompression)
1621
0
            Ascii85Flush(image);
1622
0
        }
1623
0
      offset=TellBlob(image)-offset;
1624
0
      (void) WriteBlobString(image,"\nendstream\n");
1625
0
      (void) WriteBlobString(image,"endobj\n");
1626
      /*
1627
        Write Length object.
1628
      */
1629
0
      xref[object++]=TellBlob(image);
1630
0
      FormatString(buffer,"%lu 0 obj\n",object);
1631
0
      (void) WriteBlobString(image,buffer);
1632
0
      FormatString(buffer,"%lu\n",(unsigned long) offset);
1633
0
      (void) WriteBlobString(image,buffer);
1634
0
      (void) WriteBlobString(image,"endobj\n");
1635
0
      if (image->next == (Image *) NULL)
1636
0
        break;
1637
0
      image=SyncNextImageInList(image);
1638
0
      status=MagickMonitorFormatted(scene++,image_list_length,
1639
0
                                    &image->exception,SaveImagesText,
1640
0
                                    image->filename);
1641
0
      if (status == False)
1642
0
        break;
1643
0
    } while (image_info->adjoin);
1644
0
  if (image_info->adjoin)
1645
0
    while (image->previous != (Image *) NULL)
1646
0
      image=image->previous;
1647
  /*
1648
    Write Xref object.
1649
  */
1650
0
  offset=TellBlob(image)-xref[0]+10;
1651
0
  (void) WriteBlobString(image,"xref\n");
1652
0
  FormatString(buffer,"0 %lu\n",object+1);
1653
0
  (void) WriteBlobString(image,buffer);
1654
0
  (void) WriteBlobString(image,"0000000000 65535 f \n");
1655
0
  for (i=0; i < (long) object; i++)
1656
0
    {
1657
0
      FormatString(buffer,"%010lu 00000 n \n",(unsigned long) xref[i]);
1658
0
      (void) WriteBlobString(image,buffer);
1659
0
    }
1660
0
  (void) WriteBlobString(image,"trailer\n");
1661
0
  (void) WriteBlobString(image,"<<\n");
1662
0
  FormatString(buffer,"/Size %lu\n",object+1);
1663
0
  (void) WriteBlobString(image,buffer);
1664
0
  FormatString(buffer,"/Info %lu 0 R\n",info_id);
1665
0
  (void) WriteBlobString(image,buffer);
1666
0
  FormatString(buffer,"/Root %lu 0 R\n",root_id);
1667
0
  (void) WriteBlobString(image,buffer);
1668
0
  (void) WriteBlobString(image,">>\n");
1669
0
  (void) WriteBlobString(image,"startxref\n");
1670
0
  FormatString(buffer,"%lu\n",(unsigned long) offset);
1671
0
  (void) WriteBlobString(image,buffer);
1672
0
  (void) WriteBlobString(image,"%%EOF\n");
1673
0
  MagickFreeResourceLimitedMemory(xref);
1674
0
  status &= CloseBlob(image);
1675
0
  MagickFreeMemory(fax_blob);
1676
0
  return(status);
1677
0
}
1678

1679
#if defined(HasZLIB)
1680
#include "zlib.h"
1681
/*
1682
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683
%                                                                             %
1684
%                                                                             %
1685
%                                                                             %
1686
%   Z L I B E n c o d e I m a g e                                             %
1687
%                                                                             %
1688
%                                                                             %
1689
%                                                                             %
1690
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691
%
1692
%  Method ZLIBEncodeImage compresses an image via ZLIB-coding specific to
1693
%  Postscript Level II or Portable Document Format.  To ensure portability, the
1694
%  binary ZLIB bytes are encoded as ASCII base-85.
1695
%
1696
%  The format of the ZLIBEncodeImage method is:
1697
%
1698
%      unsigned int ZLIBEncodeImage(Image *image,const size_t length,
1699
%        const unsigned long quality,unsigned char *pixels)
1700
%
1701
%  A description of each parameter follows:
1702
%
1703
%    o status:  Method ZLIBEncodeImage returns True if all the pixels are
1704
%      compressed without error, otherwise False.
1705
%
1706
%    o file: The address of a structure of type FILE.  ZLIB encoded pixels
1707
%      are written to this file.
1708
%
1709
%    o length:  A value that specifies the number of pixels to compress.
1710
%
1711
%    o quality: the compression level (0-100).
1712
%
1713
%    o pixels: The address of an unsigned array of characters containing the
1714
%      pixels to compress.
1715
%
1716
%
1717
*/
1718
static voidpf ZLIBAllocFunc(voidpf opaque, uInt items, uInt size) MAGICK_FUNC_MALLOC;
1719
static voidpf ZLIBAllocFunc(voidpf opaque, uInt items, uInt size)
1720
0
{
1721
0
  ARG_NOT_USED(opaque);
1722
0
  return MagickMallocCleared(MagickArraySize(items,size));
1723
0
}
1724
static void ZLIBFreeFunc(voidpf opaque, voidpf address)
1725
0
{
1726
0
  ARG_NOT_USED(opaque);
1727
0
  MagickFree(address);
1728
0
}
1729
static unsigned int ZLIBEncodeImage(Image *image,const size_t length,
1730
  const unsigned long quality,unsigned char *pixels)
1731
0
{
1732
0
  int
1733
0
    status;
1734
1735
0
  register long
1736
0
    i;
1737
1738
0
  unsigned char
1739
0
    *compressed_pixels;
1740
1741
0
  unsigned long
1742
0
    compressed_packets;
1743
1744
0
  z_stream
1745
0
    stream;
1746
1747
0
  assert(image != (Image *) NULL);
1748
0
  assert(image->signature == MagickSignature);
1749
0
  compressed_packets=(unsigned long) (1.001*length+12);
1750
0
  compressed_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,compressed_packets);
1751
0
  if (compressed_pixels == (unsigned char *) NULL)
1752
0
    ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
1753
0
      (char *) NULL);
1754
0
  (void) memset(&stream,0,sizeof(stream));
1755
0
  stream.next_in=pixels;
1756
0
  stream.avail_in=(unsigned int) length;
1757
0
  stream.next_out=compressed_pixels;
1758
0
  stream.avail_out=(unsigned int) compressed_packets;
1759
0
  stream.zalloc=ZLIBAllocFunc;
1760
0
  stream.zfree=ZLIBFreeFunc;
1761
0
  stream.opaque=(voidpf) NULL;
1762
0
  status=deflateInit(&stream,(int) Min(quality/10,9));
1763
0
  if (status == Z_OK)
1764
0
    {
1765
0
      status=deflate(&stream,Z_FINISH);
1766
0
      if (status == Z_STREAM_END)
1767
0
        status=deflateEnd(&stream);
1768
0
      else
1769
0
        (void) deflateEnd(&stream);
1770
0
      compressed_packets=stream.total_out;
1771
0
    }
1772
0
  if (status)
1773
0
    {
1774
0
      (void) deflateEnd(&stream);
1775
0
      ThrowBinaryException(CoderError,UnableToZipCompressImage,(char *) NULL);
1776
0
    }
1777
0
  else
1778
0
    for (i=0; i < (long) compressed_packets; i++)
1779
0
      (void) WriteBlobByte(image,compressed_pixels[i]);
1780
0
  MagickFreeResourceLimitedMemory(compressed_pixels);
1781
0
  return(!status);
1782
0
}
1783
#endif