Coverage Report

Created: 2026-05-16 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/ps3.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            PPPP   SSSSS  33333                              %
7
%                            P   P  SS        33                              %
8
%                            PPPP    SSS    333                               %
9
%                            P         SS     33                              %
10
%                            P      SSSSS  33333                              %
11
%                                                                             %
12
%                                                                             %
13
%                     Write Postscript Level III Format                       %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                              Lars Ruben Skyum                               %
18
%                                 July 1992                                   %
19
%                                                                             %
20
%                                                                             %
21
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
22
%  dedicated to making software imaging solutions freely available.           %
23
%                                                                             %
24
%  You may not use this file except in compliance with the License.  You may  %
25
%  obtain a copy of the License at                                            %
26
%                                                                             %
27
%    https://imagemagick.org/license/                                         %
28
%                                                                             %
29
%  Unless required by applicable law or agreed to in writing, software        %
30
%  distributed under the License is distributed on an "AS IS" BASIS,          %
31
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32
%  See the License for the specific language governing permissions and        %
33
%  limitations under the License.                                             %
34
%                                                                             %
35
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36
%
37
%
38
*/
39

40
/*
41
  Include declarations.
42
*/
43
#include "MagickCore/studio.h"
44
#include "MagickCore/artifact.h"
45
#include "MagickCore/attribute.h"
46
#include "MagickCore/blob.h"
47
#include "MagickCore/blob-private.h"
48
#include "MagickCore/cache.h"
49
#include "MagickCore/channel.h"
50
#include "MagickCore/color.h"
51
#include "MagickCore/color-private.h"
52
#include "MagickCore/colorspace-private.h"
53
#include "MagickCore/compress.h"
54
#include "MagickCore/constitute.h"
55
#include "MagickCore/draw.h"
56
#include "MagickCore/exception.h"
57
#include "MagickCore/exception-private.h"
58
#include "MagickCore/geometry.h"
59
#include "MagickCore/image.h"
60
#include "MagickCore/image-private.h"
61
#include "MagickCore/list.h"
62
#include "MagickCore/magick.h"
63
#include "MagickCore/memory_.h"
64
#include "MagickCore/module.h"
65
#include "MagickCore/monitor.h"
66
#include "MagickCore/monitor-private.h"
67
#include "MagickCore/option.h"
68
#include "MagickCore/pixel-accessor.h"
69
#include "MagickCore/property.h"
70
#include "MagickCore/quantum-private.h"
71
#include "MagickCore/resource_.h"
72
#include "MagickCore/static.h"
73
#include "MagickCore/string_.h"
74
#include "MagickCore/module.h"
75
#include "MagickCore/timer-private.h"
76
#include "MagickCore/token.h"
77
#include "MagickCore/utility.h"
78
#include "coders/coders-private.h"
79

80
/*
81
  Define declarations.
82
*/
83
0
#define PS3_NoCompression "0"
84
0
#define PS3_FaxCompression "1"
85
0
#define PS3_JPEGCompression "2"
86
0
#define PS3_LZWCompression "3"
87
0
#define PS3_RLECompression "4"
88
0
#define PS3_ZipCompression "5"
89
90
0
#define PS3_RGBColorspace "0"
91
0
#define PS3_CMYKColorspace "1"
92
93
0
#define PS3_DirectClass "0"
94
0
#define PS3_PseudoClass "1"
95
96
#if defined(MAGICKCORE_TIFF_DELEGATE)
97
0
#define CCITTParam  "-1"
98
#else
99
#define CCITTParam  "0"
100
#endif
101

102
/*
103
  Forward declarations.
104
*/
105
static MagickBooleanType
106
  WritePS3Image(const ImageInfo *,Image *,ExceptionInfo *);
107

108
/*
109
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110
%                                                                             %
111
%                                                                             %
112
%                                                                             %
113
%   R e g i s t e r P S 3 I m a g e                                           %
114
%                                                                             %
115
%                                                                             %
116
%                                                                             %
117
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118
%
119
%  RegisterPS3Image() adds properties for the PS3 image format to the list of
120
%  supported formats.  The properties include the image format tag, a method to
121
%  read and/or write the format, whether the format supports the saving of more
122
%  than one frame to the same file or blob, whether the format supports native
123
%  in-memory I/O, and a brief description of the format.
124
%
125
%  The format of the RegisterPS3Image method is:
126
%
127
%      size_t RegisterPS3Image(void)
128
%
129
*/
130
ModuleExport size_t RegisterPS3Image(void)
131
7
{
132
7
  MagickInfo
133
7
    *entry;
134
135
7
  entry=AcquireMagickInfo("PS3","EPS3","Level III Encapsulated PostScript");
136
7
  entry->encoder=(EncodeImageHandler *) WritePS3Image;
137
7
  entry->mime_type=ConstantString("application/postscript");
138
7
  entry->flags|=CoderEncoderSeekableStreamFlag;
139
7
  entry->flags^=CoderBlobSupportFlag;
140
7
  (void) RegisterMagickInfo(entry);
141
7
  entry=AcquireMagickInfo("PS3","PS3","Level III PostScript");
142
7
  entry->encoder=(EncodeImageHandler *) WritePS3Image;
143
7
  entry->mime_type=ConstantString("application/postscript");
144
7
  entry->flags|=CoderEncoderSeekableStreamFlag;
145
7
  entry->flags^=CoderBlobSupportFlag;
146
7
  (void) RegisterMagickInfo(entry);
147
7
  return(MagickImageCoderSignature);
148
7
}
149

150
/*
151
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152
%                                                                             %
153
%                                                                             %
154
%                                                                             %
155
%   U n r e g i s t e r P S 3 I m a g e                                       %
156
%                                                                             %
157
%                                                                             %
158
%                                                                             %
159
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160
%
161
%  UnregisterPS3Image() removes format registrations made by the PS3 module
162
%  from the list of supported formats.
163
%
164
%  The format of the UnregisterPS3Image method is:
165
%
166
%      UnregisterPS3Image(void)
167
%
168
*/
169
ModuleExport void UnregisterPS3Image(void)
170
0
{
171
0
  (void) UnregisterMagickInfo("EPS3");
172
0
  (void) UnregisterMagickInfo("PS3");
173
0
}
174

175
/*
176
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177
%                                                                             %
178
%                                                                             %
179
%                                                                             %
180
%   W r i t e P S 3 I m a g e                                                 %
181
%                                                                             %
182
%                                                                             %
183
%                                                                             %
184
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185
%
186
%  WritePS3Image() translates an image to encapsulated Postscript Level III
187
%  for printing.  If the supplied geometry is null, the image is centered on
188
%  the Postscript page.  Otherwise, the image is positioned as specified by the
189
%  geometry.
190
%
191
%  The format of the WritePS3Image method is:
192
%
193
%      MagickBooleanType WritePS3Image(const ImageInfo *image_info,
194
%        Image *image,ExceptionInfo *exception)
195
%
196
%  A description of each parameter follows:
197
%
198
%    o image_info: Specifies a pointer to a ImageInfo structure.
199
%
200
%    o image: the image.
201
%
202
%    o exception: return any errors or warnings in this structure.
203
%
204
*/
205
206
static inline void FilenameToTitle(const char *filename,char *title,
207
  const size_t extent)
208
0
{
209
0
  int
210
0
    depth = 0;
211
212
0
  ssize_t
213
0
    i,
214
0
    offset = 0;
215
216
0
  if (extent == 0)
217
0
    return;
218
0
  for (i=0; (filename[i] != '\0') && ((offset+1) < (ssize_t) extent); i++)
219
0
  {
220
0
    unsigned char
221
0
      c = filename[i];
222
223
    /*
224
      Only allow printable ASCII.
225
    */
226
0
    if ((c < 32) || (c > 126))
227
0
      {
228
0
        title[offset++]='_';
229
0
        continue;
230
0
      }
231
    /*
232
      Percent signs break DSC parsing.
233
    */
234
0
    if (c == '%')
235
0
      {
236
0
        title[offset++]='_';
237
0
        continue;
238
0
      }
239
    /*
240
      Parentheses must remain balanced.
241
    */
242
0
    if (c == '(')
243
0
      {
244
0
        depth++;
245
0
        title[offset++] = '(';
246
0
        continue;
247
0
      }
248
0
    if (c == ')')
249
0
      {
250
0
        if (depth <= 0)
251
0
          title[offset++]='_';
252
0
        else
253
0
          {
254
0
            depth--;
255
0
            title[offset++]=')';
256
0
          }
257
0
         continue;
258
0
     }
259
    /*
260
      Everything else is allowed.
261
    */
262
0
    title[offset++]=c;
263
0
  }
264
  /*
265
    If parentheses remain unbalanced, close them.
266
  */
267
0
  while ((depth > 0) && ((offset+1) < (ssize_t) extent)) {
268
0
    title[offset++]=')';
269
0
    depth--;
270
0
  }
271
0
  title[offset]='\0';
272
  /*
273
    Ensure non-empty result.
274
  */
275
0
  if (offset == 0)
276
0
    {
277
0
      (void) CopyMagickString(title,"Untitled",extent-1);
278
0
      title[extent-1]='\0';
279
0
    }
280
0
}
281
282
static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
283
  Image *image,Image *inject_image,ExceptionInfo *exception)
284
0
{
285
0
  Image
286
0
    *group4_image;
287
288
0
  ImageInfo
289
0
    *write_info;
290
291
0
  MagickBooleanType
292
0
    status;
293
294
0
  size_t
295
0
    length;
296
297
0
  unsigned char
298
0
    *group4;
299
300
0
  group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
301
0
  if (group4_image == (Image *) NULL)
302
0
    return(MagickFalse);
303
0
  status=MagickTrue;
304
0
  write_info=CloneImageInfo(image_info);
305
0
  (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
306
0
  (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
307
0
  group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
308
0
    exception);
309
0
  group4_image=DestroyImage(group4_image);
310
0
  write_info=DestroyImageInfo(write_info);
311
0
  if (group4 == (unsigned char *) NULL)
312
0
    return(MagickFalse);
313
0
  if (WriteBlob(image,length,group4) != (ssize_t) length)
314
0
    status=MagickFalse;
315
0
  group4=(unsigned char *) RelinquishMagickMemory(group4);
316
0
  return(status);
317
0
}
318
319
static MagickBooleanType SerializeImage(const ImageInfo *image_info,
320
  Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
321
0
{
322
0
  MagickBooleanType
323
0
    status;
324
325
0
  const Quantum
326
0
    *p;
327
328
0
  size_t
329
0
    channels,
330
0
    extent;
331
332
0
  ssize_t
333
0
    x,
334
0
    y;
335
336
0
  unsigned char
337
0
    *q;
338
339
0
  assert(image != (Image *) NULL);
340
0
  assert(image->signature == MagickCoreSignature);
341
0
  if (IsEventLogging() != MagickFalse)
342
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
343
0
  status=MagickTrue;
344
0
  channels=(image->colorspace == CMYKColorspace ? 4 : 3);
345
0
  if (HeapOverflowSanityCheckGetSize(channels,(size_t) image->columns,&extent) != MagickFalse)
346
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
347
0
  if (HeapOverflowSanityCheckGetSize(extent,image->rows,length) != MagickFalse)
348
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
349
0
  *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
350
0
  if (*pixel_info == (MemoryInfo *) NULL)
351
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
352
0
  q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
353
0
  (void) memset(q,0,*length*sizeof(*q));
354
0
  for (y=0; y < (ssize_t) image->rows; y++)
355
0
  {
356
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
357
0
    if (p == (const Quantum *) NULL)
358
0
      break;
359
0
    if (image->colorspace != CMYKColorspace)
360
0
      for (x=0; x < (ssize_t) image->columns; x++)
361
0
      {
362
0
        *q++=ScaleQuantumToChar(GetPixelRed(image,p));
363
0
        *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
364
0
        *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
365
0
        p+=(ptrdiff_t) GetPixelChannels(image);
366
0
      }
367
0
    else
368
0
      for (x=0; x < (ssize_t) image->columns; x++)
369
0
      {
370
0
        *q++=ScaleQuantumToChar(GetPixelRed(image,p));
371
0
        *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
372
0
        *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
373
0
        *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
374
0
        p+=(ptrdiff_t) GetPixelChannels(image);
375
0
      }
376
0
    if (image->previous == (Image *) NULL)
377
0
      {
378
0
        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
379
0
          image->rows);
380
0
        if (status == MagickFalse)
381
0
          break;
382
0
      }
383
0
  }
384
0
  if (status == MagickFalse)
385
0
    *pixel_info=RelinquishVirtualMemory(*pixel_info);
386
0
  return(status);
387
0
}
388
389
static MagickBooleanType SerializeImageChannel(const ImageInfo *image_info,
390
  Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
391
0
{
392
0
  MagickBooleanType
393
0
    status;
394
395
0
  const Quantum
396
0
    *p;
397
398
0
  ssize_t
399
0
    x;
400
401
0
  unsigned char
402
0
    *q;
403
404
0
  size_t
405
0
    pack,
406
0
    padded_columns;
407
408
0
  ssize_t
409
0
    y;
410
411
0
  unsigned char
412
0
    code,
413
0
    bit;
414
415
0
  assert(image != (Image *) NULL);
416
0
  assert(image->signature == MagickCoreSignature);
417
0
  if (IsEventLogging() != MagickFalse)
418
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
419
0
  status=MagickTrue;
420
0
  pack=SetImageMonochrome(image,exception) == MagickFalse ? 1UL : 8UL;
421
0
  padded_columns=((image->columns+pack-1)/pack)*pack;
422
0
  *length=(size_t) padded_columns*image->rows/pack;
423
0
  *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
424
0
  if (*pixel_info == (MemoryInfo *) NULL)
425
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
426
0
  q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
427
0
  for (y=0; y < (ssize_t) image->rows; y++)
428
0
  {
429
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
430
0
    if (p == (const Quantum *) NULL)
431
0
      break;
432
0
    if (pack == 1)
433
0
      for (x=0; x < (ssize_t) image->columns; x++)
434
0
      {
435
0
        *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
436
0
        p+=(ptrdiff_t) GetPixelChannels(image);
437
0
      }
438
0
    else
439
0
      {
440
0
        code='\0';
441
0
        for (x=0; x < (ssize_t) padded_columns; x++)
442
0
        {
443
0
          bit=(unsigned char) 0x00;
444
0
          if (x < (ssize_t) image->columns)
445
0
            bit=(unsigned char) (GetPixelLuma(image,p) == (double)
446
0
              TransparentAlpha ? 0x01 : 0x00);
447
0
          code=(code << 1)+bit;
448
0
          if (((x+1) % (ssize_t) pack) == 0)
449
0
            {
450
0
              *q++=code;
451
0
              code='\0';
452
0
            }
453
0
          p+=(ptrdiff_t) GetPixelChannels(image);
454
0
        }
455
0
      }
456
0
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
457
0
      image->rows);
458
0
    if (status == MagickFalse)
459
0
      break;
460
0
  }
461
0
  if (status == MagickFalse)
462
0
    *pixel_info=RelinquishVirtualMemory(*pixel_info);
463
0
  return(status);
464
0
}
465
466
static MagickBooleanType SerializeImageIndexes(const ImageInfo *image_info,
467
  Image *image,MemoryInfo **pixel_info,size_t *length,ExceptionInfo *exception)
468
0
{
469
0
  MagickBooleanType
470
0
    status;
471
472
0
  const Quantum
473
0
    *p;
474
475
0
  ssize_t
476
0
    x;
477
478
0
  unsigned char
479
0
    *q;
480
481
0
  ssize_t
482
0
    y;
483
484
0
  assert(image != (Image *) NULL);
485
0
  assert(image->signature == MagickCoreSignature);
486
0
  if (IsEventLogging() != MagickFalse)
487
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
488
0
  status=MagickTrue;
489
0
  *length=(size_t) image->columns*image->rows;
490
0
  *pixel_info=AcquireVirtualMemory(*length,sizeof(*q));
491
0
  if (*pixel_info == (MemoryInfo *) NULL)
492
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
493
0
  q=(unsigned char *) GetVirtualMemoryBlob(*pixel_info);
494
0
  for (y=0; y < (ssize_t) image->rows; y++)
495
0
  {
496
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
497
0
    if (p == (const Quantum *) NULL)
498
0
      break;
499
0
    for (x=0; x < (ssize_t) image->columns; x++)
500
0
    {
501
0
      *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
502
0
      p+=(ptrdiff_t) GetPixelChannels(image);
503
0
    }
504
0
    if (image->previous == (Image *) NULL)
505
0
      {
506
0
        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
507
0
          image->rows);
508
0
        if (status == MagickFalse)
509
0
          break;
510
0
      }
511
0
  }
512
0
  if (status == MagickFalse)
513
0
    *pixel_info=RelinquishVirtualMemory(*pixel_info);
514
0
  return(status);
515
0
}
516
517
static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info,
518
  Image *image,const CompressionType compression,ExceptionInfo *exception)
519
0
{
520
0
  char
521
0
    buffer[MagickPathExtent];
522
523
0
  Image
524
0
    *mask_image;
525
526
0
  MagickBooleanType
527
0
    status;
528
529
0
  MagickOffsetType
530
0
    offset,
531
0
    start,
532
0
    stop;
533
534
0
  MemoryInfo
535
0
    *pixel_info;
536
537
0
  ssize_t
538
0
    i;
539
540
0
  size_t
541
0
    length;
542
543
0
  unsigned char
544
0
    *pixels;
545
546
0
  assert(image_info != (ImageInfo *) NULL);
547
0
  assert(image_info->signature == MagickCoreSignature);
548
0
  assert(image != (Image *) NULL);
549
0
  assert(image->signature == MagickCoreSignature);
550
0
  assert(image->alpha_trait != UndefinedPixelTrait);
551
0
  if (IsEventLogging() != MagickFalse)
552
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
553
0
  status=MagickTrue;
554
  /*
555
    Note BeginData DSC comment for update later.
556
  */
557
0
  start=TellBlob(image);
558
0
  if (start < 0)
559
0
    ThrowWriterException(CorruptImageError,"ImproperImageHeader");
560
0
  (void) FormatLocaleString(buffer,MagickPathExtent,
561
0
    "%%%%BeginData:%13ld %s Bytes\n",0L,compression == NoCompression ?
562
0
    "ASCII" : "BINARY");
563
0
  (void) WriteBlobString(image,buffer);
564
0
  stop=TellBlob(image);
565
0
  if (stop < 0)
566
0
    ThrowWriterException(CorruptImageError,"ImproperImageHeader");
567
  /*
568
    Only lossless compressions for the mask.
569
  */
570
0
  switch (compression)
571
0
  {
572
0
    case NoCompression:
573
0
    default:
574
0
    {
575
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
576
0
        "currentfile %.20g %.20g " PS3_NoCompression
577
0
        " ByteStreamDecodeFilter\n",(double) image->columns,(double)
578
0
        image->rows);
579
0
      break;
580
0
    }
581
0
    case FaxCompression:
582
0
    case Group4Compression:
583
0
    {
584
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
585
0
        "currentfile %.20g %.20g " PS3_FaxCompression
586
0
        " ByteStreamDecodeFilter\n",(double) image->columns,(double)
587
0
        image->rows);
588
0
      break;
589
0
    }
590
0
    case LZWCompression:
591
0
    {
592
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
593
0
        "currentfile %.20g %.20g " PS3_LZWCompression
594
0
        " ByteStreamDecodeFilter\n",(double) image->columns,(double)
595
0
        image->rows);
596
0
      break;
597
0
    }
598
0
    case RLECompression:
599
0
    {
600
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
601
0
        "currentfile %.20g %.20g " PS3_RLECompression
602
0
        " ByteStreamDecodeFilter\n",(double) image->columns,(double)
603
0
        image->rows);
604
0
      break;
605
0
    }
606
0
    case ZipCompression:
607
0
    {
608
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
609
0
        "currentfile %.20g %.20g " PS3_ZipCompression
610
0
        " ByteStreamDecodeFilter\n",(double) image->columns,(double)
611
0
        image->rows);
612
0
      break;
613
0
    }
614
0
  }
615
0
  (void) WriteBlobString(image,buffer);
616
0
  (void) WriteBlobString(image,"/ReusableStreamDecode filter\n");
617
0
  mask_image=SeparateImage(image,AlphaChannel,exception);
618
0
  if (mask_image == (Image *) NULL)
619
0
    ThrowWriterException(CoderError,exception->reason);
620
0
  (void) SetImageType(mask_image,BilevelType,exception);
621
0
  (void) SetImageType(mask_image,PaletteType,exception);
622
0
  mask_image->alpha_trait=UndefinedPixelTrait;
623
0
  pixels=(unsigned char *) NULL;
624
0
  length=0;
625
0
  switch (compression)
626
0
  {
627
0
    case NoCompression:
628
0
    default:
629
0
    {
630
0
      status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
631
0
        exception);
632
0
      if (status == MagickFalse)
633
0
        break;
634
0
      Ascii85Initialize(image);
635
0
      pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
636
0
      for (i=0; i < (ssize_t) length; i++)
637
0
        Ascii85Encode(image,pixels[i]);
638
0
      Ascii85Flush(image);
639
0
      pixel_info=RelinquishVirtualMemory(pixel_info);
640
0
      break;
641
0
    }
642
0
    case FaxCompression:
643
0
    case Group4Compression:
644
0
    {
645
0
      if ((compression == FaxCompression) ||
646
0
          (LocaleCompare(CCITTParam,"0") == 0))
647
0
        status=HuffmanEncodeImage(image_info,image,mask_image,exception);
648
0
      else
649
0
        status=Huffman2DEncodeImage(image_info,image,mask_image,exception);
650
0
      break;
651
0
    }
652
0
    case LZWCompression:
653
0
    {
654
0
      status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
655
0
        exception);
656
0
      if (status == MagickFalse)
657
0
        break;
658
0
      pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
659
0
      status=LZWEncodeImage(image,length,pixels,exception);
660
0
      pixel_info=RelinquishVirtualMemory(pixel_info);
661
0
      break;
662
0
    }
663
0
    case RLECompression:
664
0
    {
665
0
      status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
666
0
        exception);
667
0
      if (status == MagickFalse)
668
0
        break;
669
0
      pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
670
0
      status=PackbitsEncodeImage(image,length,pixels,exception);
671
0
      pixel_info=RelinquishVirtualMemory(pixel_info);
672
0
      break;
673
0
    }
674
0
    case ZipCompression:
675
0
    {
676
0
      status=SerializeImageChannel(image_info,mask_image,&pixel_info,&length,
677
0
        exception);
678
0
      if (status == MagickFalse)
679
0
        break;
680
0
      pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
681
0
      status=ZLIBEncodeImage(image,length,pixels,exception);
682
0
      pixel_info=RelinquishVirtualMemory(pixel_info);
683
0
      break;
684
0
    }
685
0
  }
686
0
  mask_image=DestroyImage(mask_image);
687
0
  (void) WriteBlobByte(image,'\n');
688
0
  length=(size_t) (TellBlob(image)-stop);
689
0
  stop=TellBlob(image);
690
0
  if (stop < 0)
691
0
    ThrowWriterException(CorruptImageError,"ImproperImageHeader");
692
0
  offset=SeekBlob(image,start,SEEK_SET);
693
0
  if (offset < 0)
694
0
    ThrowWriterException(CorruptImageError,"ImproperImageHeader");
695
0
  (void) FormatLocaleString(buffer,MagickPathExtent,
696
0
    "%%%%BeginData:%13ld %s Bytes\n",(long) length,
697
0
    compression == NoCompression ? "ASCII" : "BINARY");
698
0
  (void) WriteBlobString(image,buffer);
699
0
  offset=SeekBlob(image,stop,SEEK_SET);
700
0
  if (offset < 0)
701
0
    ThrowWriterException(CorruptImageError,"ImproperImageHeader");
702
0
  (void) WriteBlobString(image,"%%EndData\n");
703
0
  (void) WriteBlobString(image, "/mask_stream exch def\n");
704
0
  return(status);
705
0
}
706
707
static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
708
  ExceptionInfo *exception)
709
0
{
710
0
  static const char
711
0
    PostscriptProlog[] =
712
0
      "/ByteStreamDecodeFilter\n"
713
0
      "{\n"
714
0
      "  /z exch def\n"
715
0
      "  /r exch def\n"
716
0
      "  /c exch def\n"
717
0
      "  z " PS3_NoCompression " eq { /ASCII85Decode filter } if\n"
718
0
      "  z " PS3_FaxCompression " eq\n"
719
0
      "  {\n"
720
0
      "    <<\n"
721
0
      "      /K " CCITTParam "\n"
722
0
      "      /Columns c\n"
723
0
      "      /Rows r\n"
724
0
      "    >>\n"
725
0
      "    /CCITTFaxDecode filter\n"
726
0
      "  } if\n"
727
0
      "  z " PS3_JPEGCompression " eq { /DCTDecode filter } if\n"
728
0
      "  z " PS3_LZWCompression " eq { /LZWDecode filter } if\n"
729
0
      "  z " PS3_RLECompression " eq { /RunLengthDecode filter } if\n"
730
0
      "  z " PS3_ZipCompression " eq { /FlateDecode filter } if\n"
731
0
      "} bind def\n"
732
0
      "\n"
733
0
      "/DirectClassImageDict\n"
734
0
      "{\n"
735
0
      "  colorspace " PS3_RGBColorspace " eq\n"
736
0
      "  {\n"
737
0
      "    /DeviceRGB setcolorspace\n"
738
0
      "    <<\n"
739
0
      "      /ImageType 1\n"
740
0
      "      /Width columns\n"
741
0
      "      /Height rows\n"
742
0
      "      /BitsPerComponent 8\n"
743
0
      "      /DataSource pixel_stream\n"
744
0
      "      /MultipleDataSources false\n"
745
0
      "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
746
0
      "      /Decode [0 1 0 1 0 1]\n"
747
0
      "    >>\n"
748
0
      "  }\n"
749
0
      "  {\n"
750
0
      "    /DeviceCMYK setcolorspace\n"
751
0
      "    <<\n"
752
0
      "      /ImageType 1\n"
753
0
      "      /Width columns\n"
754
0
      "      /Height rows\n"
755
0
      "      /BitsPerComponent 8\n"
756
0
      "      /DataSource pixel_stream\n"
757
0
      "      /MultipleDataSources false\n"
758
0
      "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
759
0
      "      /Decode\n"
760
0
      "        compression " PS3_JPEGCompression " eq\n"
761
0
      "        { [1 0 1 0 1 0 1 0] }\n"
762
0
      "        { [0 1 0 1 0 1 0 1] }\n"
763
0
      "        ifelse\n"
764
0
      "    >>\n"
765
0
      "  }\n"
766
0
      "  ifelse\n"
767
0
      "} bind def\n"
768
0
      "\n"
769
0
      "/PseudoClassImageDict\n"
770
0
      "{\n"
771
0
      "  % Colors in colormap image.\n"
772
0
      "  currentfile buffer readline pop\n"
773
0
      "  token pop /colors exch def pop\n"
774
0
      "  colors 0 eq\n"
775
0
      "  {\n"
776
0
      "    % Depth of grayscale image.\n"
777
0
      "    currentfile buffer readline pop\n"
778
0
      "    token pop /bits exch def pop\n"
779
0
      "    /DeviceGray setcolorspace\n"
780
0
      "    <<\n"
781
0
      "      /ImageType 1\n"
782
0
      "      /Width columns\n"
783
0
      "      /Height rows\n"
784
0
      "      /BitsPerComponent bits\n"
785
0
      "      /Decode [0 1]\n"
786
0
      "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
787
0
      "      /DataSource pixel_stream\n"
788
0
      "    >>\n"
789
0
      "  }\n"
790
0
      "  {\n"
791
0
      "    % RGB colormap.\n"
792
0
      "    /colormap colors 3 mul string def\n"
793
0
      "    compression " PS3_NoCompression " eq\n"
794
0
      "    { currentfile /ASCII85Decode filter colormap readstring pop pop }\n"
795
0
      "    { currentfile colormap readstring pop pop }\n"
796
0
      "    ifelse\n"
797
0
      "    [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace\n"
798
0
      "    <<\n"
799
0
      "      /ImageType 1\n"
800
0
      "      /Width columns\n"
801
0
      "      /Height rows\n"
802
0
      "      /BitsPerComponent 8\n"
803
0
      "      /Decode [0 255]\n"
804
0
      "      /ImageMatrix [columns 0 0 rows neg 0 rows]\n"
805
0
      "      /DataSource pixel_stream\n"
806
0
      "    >>\n"
807
0
      "  }\n"
808
0
      "  ifelse\n"
809
0
      "} bind def\n"
810
0
      "\n"
811
0
      "/NonMaskedImageDict\n"
812
0
      "{\n"
813
0
      "  class " PS3_PseudoClass " eq\n"
814
0
      "  { PseudoClassImageDict }\n"
815
0
      "  { DirectClassImageDict }\n"
816
0
      "  ifelse\n"
817
0
      "} bind def\n"
818
0
      "\n"
819
0
      "/MaskedImageDict\n"
820
0
      "{\n"
821
0
      "  <<\n"
822
0
      "    /ImageType 3\n"
823
0
      "    /InterleaveType 3\n"
824
0
      "    /DataDict NonMaskedImageDict\n"
825
0
      "    /MaskDict\n"
826
0
      "    <<\n"
827
0
      "      /ImageType 1\n"
828
0
      "      /Width columns\n"
829
0
      "      /Height rows\n"
830
0
      "      /BitsPerComponent 1\n"
831
0
      "      /DataSource mask_stream\n"
832
0
      "      /MultipleDataSources false\n"
833
0
      "      /ImageMatrix [ columns 0 0 rows neg 0 rows]\n"
834
0
      "      /Decode [ 0 1 ]\n"
835
0
      "    >>\n"
836
0
      "  >>\n"
837
0
      "} bind def\n"
838
0
      "\n"
839
0
      "/ClipImage\n"
840
0
      "{} def\n"
841
0
      "\n"
842
0
      "/DisplayImage\n"
843
0
      "{\n"
844
0
      "  gsave\n"
845
0
      "  /buffer 512 string def\n"
846
0
      "  % Translation.\n"
847
0
      "  currentfile buffer readline pop\n"
848
0
      "  token pop /x exch def\n"
849
0
      "  token pop /y exch def pop\n"
850
0
      "  x y translate\n"
851
0
      "  % Image size and font size.\n"
852
0
      "  currentfile buffer readline pop\n"
853
0
      "  token pop /x exch def\n"
854
0
      "  token pop /y exch def pop\n"
855
0
      "  currentfile buffer readline pop\n"
856
0
      "  token pop /pointsize exch def pop\n";
857
0
  static const char
858
0
    PostscriptEpilog[] =
859
0
      "  x y scale\n"
860
0
      "  % Clipping path.\n"
861
0
      "  currentfile buffer readline pop\n"
862
0
      "  token pop /clipped exch def pop\n"
863
0
      "  % Showpage.\n"
864
0
      "  currentfile buffer readline pop\n"
865
0
      "  token pop /sp exch def pop\n"
866
0
      "  % Image pixel size.\n"
867
0
      "  currentfile buffer readline pop\n"
868
0
      "  token pop /columns exch def\n"
869
0
      "  token pop /rows exch def pop\n"
870
0
      "  % Colorspace (RGB/CMYK).\n"
871
0
      "  currentfile buffer readline pop\n"
872
0
      "  token pop /colorspace exch def pop\n"
873
0
      "  % Transparency.\n"
874
0
      "  currentfile buffer readline pop\n"
875
0
      "  token pop /alpha exch def pop\n"
876
0
      "  % Stencil mask?\n"
877
0
      "  currentfile buffer readline pop\n"
878
0
      "  token pop /stencil exch def pop\n"
879
0
      "  % Image class (direct/pseudo).\n"
880
0
      "  currentfile buffer readline pop\n"
881
0
      "  token pop /class exch def pop\n"
882
0
      "  % Compression type.\n"
883
0
      "  currentfile buffer readline pop\n"
884
0
      "  token pop /compression exch def pop\n"
885
0
      "  % Clip and render.\n"
886
0
      "  /pixel_stream currentfile columns rows compression ByteStreamDecodeFilter def\n"
887
0
      "  clipped { ClipImage } if\n"
888
0
      "  alpha stencil not and\n"
889
0
      "  { MaskedImageDict mask_stream resetfile }\n"
890
0
      "  { NonMaskedImageDict }\n"
891
0
      "  ifelse\n"
892
0
      "  stencil { 0 setgray imagemask } { image } ifelse\n"
893
0
      "  grestore\n"
894
0
      "  sp { showpage } if\n"
895
0
      "} bind def\n";
896
897
0
  char
898
0
    buffer[MagickPathExtent],
899
0
    date[MagickTimeExtent],
900
0
    **labels,
901
0
    page_geometry[MagickPathExtent];
902
903
0
  CompressionType
904
0
    compression;
905
906
0
  const char
907
0
    *option,
908
0
    *value;
909
910
0
  double
911
0
    pointsize;
912
913
0
  GeometryInfo
914
0
    geometry_info;
915
916
0
  MagickBooleanType
917
0
    status;
918
919
0
  MagickOffsetType
920
0
    offset,
921
0
    scene,
922
0
    start,
923
0
    stop;
924
925
0
  MagickStatusType
926
0
    flags;
927
928
0
  MemoryInfo
929
0
    *pixel_info;
930
931
0
  PointInfo
932
0
    delta,
933
0
    resolution,
934
0
    scale;
935
936
0
  RectangleInfo
937
0
    geometry,
938
0
    media_info,
939
0
    page_info;
940
941
0
  SegmentInfo
942
0
    bounds;
943
944
0
  size_t
945
0
    length,
946
0
    number_scenes,
947
0
    page,
948
0
    pixel,
949
0
    text_size;
950
951
0
  ssize_t
952
0
    i,
953
0
    j;
954
955
0
  time_t
956
0
    timer;
957
958
0
  unsigned char
959
0
    *pixels;
960
961
  /*
962
    Open output image file.
963
  */
964
0
  assert(image_info != (const ImageInfo *) NULL);
965
0
  assert(image_info->signature == MagickCoreSignature);
966
0
  assert(image != (Image *) NULL);
967
0
  assert(image->signature == MagickCoreSignature);
968
0
  assert(exception != (ExceptionInfo *) NULL);
969
0
  assert(exception->signature == MagickCoreSignature);
970
0
  if (IsEventLogging() != MagickFalse)
971
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
972
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
973
0
  if (status == MagickFalse)
974
0
    return(MagickFalse);
975
0
  compression=image->compression;
976
0
  if (image_info->compression != UndefinedCompression)
977
0
    compression=image_info->compression;
978
0
  switch (compression)
979
0
  {
980
0
    case FaxCompression:
981
0
    case Group4Compression:
982
0
    { 
983
0
      if ((SetImageMonochrome(image,exception) == MagickFalse) ||
984
0
          (image->alpha_trait != UndefinedPixelTrait))
985
0
        compression=RLECompression;
986
0
      break;
987
0
    }
988
#if !defined(MAGICKCORE_JPEG_DELEGATE)
989
    case JPEGCompression:
990
    {
991
      compression=RLECompression;
992
      (void) ThrowMagickException(exception,GetMagickModule(),
993
        MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
994
        image->filename);
995
      break;
996
    }
997
#endif
998
#if !defined(MAGICKCORE_ZLIB_DELEGATE)
999
    case ZipCompression:
1000
    {
1001
      compression=RLECompression;
1002
      (void) ThrowMagickException(exception,GetMagickModule(),
1003
        MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1004
        image->filename);
1005
      break;
1006
    }
1007
#endif
1008
0
    default:
1009
0
      break;
1010
0
  }
1011
0
  (void) memset(&bounds,0,sizeof(bounds));
1012
0
  page=0;
1013
0
  scene=0;
1014
0
  number_scenes=GetImageListLength(image);
1015
0
  do
1016
0
  {
1017
0
    MagickBooleanType
1018
0
      is_gray;
1019
1020
    /*
1021
      Scale relative to dots-per-inch.
1022
    */
1023
0
    delta.x=DefaultResolution;
1024
0
    delta.y=DefaultResolution;
1025
0
    resolution.x=image->resolution.x;
1026
0
    resolution.y=image->resolution.y;
1027
0
    if ((resolution.x == 0.0) || (resolution.y == 0.0))
1028
0
      {
1029
0
        flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1030
0
        if ((flags & RhoValue) != 0)
1031
0
          resolution.x=geometry_info.rho;
1032
0
        resolution.y=resolution.x;
1033
0
        if ((flags & SigmaValue) != 0)
1034
0
          resolution.y=geometry_info.sigma;
1035
0
      }
1036
0
    if (image_info->density != (char *) NULL)
1037
0
      {
1038
0
        flags=ParseGeometry(image_info->density,&geometry_info);
1039
0
        if ((flags & RhoValue) != 0)
1040
0
          resolution.x=geometry_info.rho;
1041
0
        resolution.y=resolution.x;
1042
0
        if ((flags & SigmaValue) != 0)
1043
0
          resolution.y=geometry_info.sigma;
1044
0
      }
1045
0
    if (image->units == PixelsPerCentimeterResolution)
1046
0
      {
1047
0
        resolution.x=(100.0*2.54*resolution.x+0.5)/100.0;
1048
0
        resolution.y=(100.0*2.54*resolution.y+0.5)/100.0;
1049
0
      }
1050
0
    SetGeometry(image,&geometry);
1051
0
    (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
1052
0
      (double) image->columns,(double) image->rows);
1053
0
    if (image_info->page != (char *) NULL)
1054
0
      (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
1055
0
    else
1056
0
      if ((image->page.width != 0) && (image->page.height != 0))
1057
0
        (void) FormatLocaleString(page_geometry,MagickPathExtent,
1058
0
          "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1059
0
          image->page.height,(double) image->page.x,(double) image->page.y);
1060
0
      else
1061
0
        if ((image->gravity != UndefinedGravity) &&
1062
0
            (LocaleCompare(image_info->magick,"PS") == 0))
1063
0
          (void) CopyMagickString(page_geometry,PSPageGeometry,
1064
0
            MagickPathExtent);
1065
0
    (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
1066
0
    (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1067
0
      &geometry.width,&geometry.height);
1068
0
    scale.x=MagickSafeReciprocal(resolution.x)*geometry.width*delta.x;
1069
0
    geometry.width=CastDoubleToSizeT(scale.x+0.5);
1070
0
    scale.y=MagickSafeReciprocal(resolution.y)*geometry.height*delta.y;
1071
0
    geometry.height=CastDoubleToSizeT(scale.y+0.5);
1072
0
    (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1073
0
    (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1074
0
    if (image->gravity != UndefinedGravity)
1075
0
      {
1076
0
        geometry.x=(-page_info.x);
1077
0
        geometry.y=(ssize_t) media_info.height+page_info.y-(ssize_t)
1078
0
          image->rows;
1079
0
      }
1080
0
    pointsize=12.0;
1081
0
    if (image_info->pointsize != 0.0)
1082
0
      pointsize=image_info->pointsize;
1083
0
    text_size=0;
1084
0
    value=GetImageProperty(image,"label",exception);
1085
0
    if (value != (const char *) NULL)
1086
0
      text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1087
0
    page++;
1088
0
    is_gray=IdentifyImageCoderGray(image,exception);
1089
0
    if (page == 1)
1090
0
      {
1091
0
        char
1092
0
          title[MagickPathExtent];
1093
1094
        /*
1095
          Postscript header on the first page.
1096
        */
1097
0
        if (LocaleCompare(image_info->magick,"PS3") == 0)
1098
0
          (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent);
1099
0
        else
1100
0
          (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
1101
0
            MagickPathExtent);
1102
0
        (void) WriteBlobString(image,buffer);
1103
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1104
0
          "%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
1105
0
        (void) WriteBlobString(image,buffer);
1106
0
        FilenameToTitle(image->filename,title,MagickPathExtent);
1107
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: %s\n",
1108
0
          title);
1109
0
        (void) WriteBlobString(image,buffer);
1110
0
        timer=GetMagickTime();
1111
0
        (void) FormatMagickTime(timer,sizeof(date),date);
1112
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1113
0
          "%%%%CreationDate: %s\n",date);
1114
0
        (void) WriteBlobString(image,buffer);
1115
0
        bounds.x1=(double) geometry.x;
1116
0
        bounds.y1=(double) geometry.y;
1117
0
        bounds.x2=(double) geometry.x+scale.x;
1118
0
        bounds.y2=(double) geometry.y+scale.y+text_size;
1119
0
        if ((image_info->adjoin != MagickFalse) &&
1120
0
            (GetNextImageInList(image) != (Image *) NULL))
1121
0
          {
1122
0
            (void) WriteBlobString(image,"%%BoundingBox: (atend)\n");
1123
0
            (void) WriteBlobString(image,"%%HiResBoundingBox: (atend)\n");
1124
0
          }
1125
0
        else
1126
0
          {
1127
0
            (void) FormatLocaleString(buffer,MagickPathExtent,
1128
0
              "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1129
0
              ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1130
0
            (void) WriteBlobString(image,buffer);
1131
0
            (void) FormatLocaleString(buffer,MagickPathExtent,
1132
0
              "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
1133
0
              bounds.y1,bounds.x2,bounds.y2);
1134
0
            (void) WriteBlobString(image,buffer);
1135
0
            if (image->colorspace == CMYKColorspace)
1136
0
              (void) WriteBlobString(image,
1137
0
                "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1138
0
            else
1139
0
              if (is_gray != MagickFalse)
1140
0
                (void) WriteBlobString(image,
1141
0
                  "%%DocumentProcessColors: Black\n");
1142
0
          }
1143
        /*
1144
          Font resources
1145
        */
1146
0
        value=GetImageProperty(image,"label",exception);
1147
0
        if (value != (const char *) NULL)
1148
0
          (void) WriteBlobString(image,
1149
0
            "%%DocumentNeededResources: font Helvetica\n");
1150
0
        (void) WriteBlobString(image,"%%LanguageLevel: 3\n");
1151
        /*
1152
          Pages, orientation and order.
1153
        */
1154
0
        if (LocaleCompare(image_info->magick,"PS3") != 0)
1155
0
          (void) WriteBlobString(image,"%%Pages: 1\n");
1156
0
        else
1157
0
          {
1158
0
            (void) WriteBlobString(image,"%%Orientation: Portrait\n");
1159
0
            (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
1160
0
            if (image_info->adjoin == MagickFalse)
1161
0
              (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent);
1162
0
            else
1163
0
              (void) FormatLocaleString(buffer,MagickPathExtent,
1164
0
                "%%%%Pages: %.20g\n",(double) number_scenes);
1165
0
            (void) WriteBlobString(image,buffer);
1166
0
          }
1167
0
        if (image->colorspace == CMYKColorspace)
1168
0
          (void) WriteBlobString(image,
1169
0
            "%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
1170
0
        (void) WriteBlobString(image,"%%EndComments\n");
1171
        /*
1172
          The static postscript procedures prolog.
1173
        */
1174
0
        (void) WriteBlobString(image,"%%BeginProlog\n");
1175
0
        (void) WriteBlob(image,sizeof(PostscriptProlog)-1,PostscriptProlog);
1176
        /*
1177
          One label line for each line in label string.
1178
        */
1179
0
        value=GetImageProperty(image,"label",exception);
1180
0
        if (value != (const char *) NULL)
1181
0
          {
1182
0
            (void) WriteBlobString(image,"\n  %% Labels.\n  /Helvetica "
1183
0
              " findfont pointsize scalefont setfont\n");
1184
0
            for (i=(ssize_t) MultilineCensus(value)-1; i >= 0; i--)
1185
0
            {
1186
0
              (void) WriteBlobString(image,
1187
0
                "  currentfile buffer readline pop token pop\n");
1188
0
              (void) FormatLocaleString(buffer,MagickPathExtent,
1189
0
                "  0 y %g add moveto show pop\n",i*pointsize+12);
1190
0
              (void) WriteBlobString(image,buffer);
1191
0
            }
1192
0
          }
1193
        /*
1194
          The static postscript procedures epilog.
1195
        */
1196
0
        (void) WriteBlob(image,sizeof(PostscriptEpilog)-1,PostscriptEpilog);
1197
0
        (void) WriteBlobString(image,"%%EndProlog\n");
1198
0
      }
1199
0
    (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n",
1200
0
      (double) page);
1201
0
    (void) WriteBlobString(image,buffer);
1202
    /*
1203
      Page bounding box.
1204
    */
1205
0
    (void) FormatLocaleString(buffer,MagickPathExtent,
1206
0
      "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
1207
0
       (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+
1208
0
       (double) (geometry.height+text_size));
1209
0
    (void) WriteBlobString(image,buffer);
1210
    /*
1211
      Page process colors if not RGB.
1212
    */
1213
0
    if (image->colorspace == CMYKColorspace)
1214
0
      (void) WriteBlobString(image,
1215
0
        "%%PageProcessColors: Cyan Magenta Yellow Black\n");
1216
0
    else
1217
0
      if (is_gray != MagickFalse)
1218
0
        (void) WriteBlobString(image,"%%PageProcessColors: Black\n");
1219
    /*
1220
      Adjust document bounding box to bound page bounding box.
1221
    */
1222
0
    if ((double) geometry.x < bounds.x1)
1223
0
      bounds.x1=(double) geometry.x;
1224
0
    if ((double) geometry.y < bounds.y1)
1225
0
      bounds.y1=(double) geometry.y;
1226
0
    if ((double) (geometry.x+scale.x) > bounds.x2)
1227
0
      bounds.x2=(double) geometry.x+scale.x;
1228
0
    if ((double) (geometry.y+scale.y+text_size) > bounds.y2)
1229
0
      bounds.y2=(double) geometry.y+scale.y+text_size;
1230
    /*
1231
      Page font resource if there's a label.
1232
    */
1233
0
    value=GetImageProperty(image,"label",exception);
1234
0
    if (value != (const char *) NULL)
1235
0
      (void) WriteBlobString(image,"%%PageResources: font Helvetica\n");
1236
    /*
1237
      PS clipping path from Photoshop clipping path.
1238
    */
1239
0
    if (((image->channels & WriteMaskChannel) != 0) ||
1240
0
        (LocaleNCompare("8BIM:",image->magick_filename,5) != 0))
1241
0
      (void) WriteBlobString(image,"/ClipImage {} def\n");
1242
0
    else
1243
0
      {
1244
0
        value=GetImageProperty(image,image->magick_filename,exception);
1245
0
        if (value == (const char *) NULL)
1246
0
          return(MagickFalse);
1247
0
        (void) WriteBlobString(image,value);
1248
0
        (void) WriteBlobByte(image,'\n');
1249
0
      }
1250
    /*
1251
      Push a dictionary for our own def's if this an EPS.
1252
    */
1253
0
    if (LocaleCompare(image_info->magick,"PS3") != 0)
1254
0
      (void) WriteBlobString(image,"userdict begin\n");
1255
    /*
1256
      Image mask.
1257
    */
1258
0
    if ((image->alpha_trait != UndefinedPixelTrait) &&
1259
0
        (WritePS3MaskImage(image_info,image,compression,exception) == MagickFalse))
1260
0
      {
1261
0
        (void) CloseBlob(image);
1262
0
        return(MagickFalse);
1263
0
      }
1264
    /*
1265
      Remember position of BeginData comment so we can update it.
1266
    */
1267
0
    start=TellBlob(image);
1268
0
    if (start < 0)
1269
0
      ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1270
0
    (void) FormatLocaleString(buffer,MagickPathExtent,
1271
0
      "%%%%BeginData:%13ld %s Bytes\n",0L,
1272
0
      compression == NoCompression ? "ASCII" : "BINARY");
1273
0
    (void) WriteBlobString(image,buffer);
1274
0
    stop=TellBlob(image);
1275
0
    if (stop < 0)
1276
0
      ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1277
0
    (void) WriteBlobString(image,"DisplayImage\n");
1278
    /*
1279
      Translate, scale, and font point size.
1280
    */
1281
0
    (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n",
1282
0
      (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
1283
0
    (void) WriteBlobString(image,buffer);
1284
    /*
1285
      Output labels.
1286
    */
1287
0
    labels=(char **) NULL;
1288
0
    value=GetImageProperty(image,"label",exception);
1289
0
    if (value != (const char *) NULL)
1290
0
      labels=StringToList(value);
1291
0
    if (labels != (char **) NULL)
1292
0
      {
1293
0
        for (i=0; labels[i] != (char *) NULL; i++)
1294
0
        {
1295
0
          if (compression != NoCompression)
1296
0
            {
1297
0
              for (j=0; labels[i][j] != '\0'; j++)
1298
0
                (void) WriteBlobByte(image,(unsigned char) labels[i][j]);
1299
0
              (void) WriteBlobByte(image,'\n');
1300
0
            }
1301
0
          else
1302
0
            {
1303
0
              (void) WriteBlobString(image,"<~");
1304
0
              Ascii85Initialize(image);
1305
0
              for (j=0; labels[i][j] != '\0'; j++)
1306
0
                Ascii85Encode(image,(unsigned char) labels[i][j]);
1307
0
              Ascii85Flush(image);
1308
0
            }
1309
0
          labels[i]=DestroyString(labels[i]);
1310
0
        }
1311
0
        labels=(char **) RelinquishMagickMemory(labels);
1312
0
      }
1313
    /*
1314
      Photoshop clipping path active?
1315
    */
1316
0
    if (((image->channels & WriteMaskChannel) != 0) &&
1317
0
        (LocaleNCompare("8BIM:",image->magick_filename,5) == 0))
1318
0
        (void) WriteBlobString(image,"true\n");
1319
0
      else
1320
0
        (void) WriteBlobString(image,"false\n");
1321
    /*
1322
      Showpage for non-EPS.
1323
    */
1324
0
    (void) WriteBlobString(image, LocaleCompare(image_info->magick,"PS3") == 0 ?
1325
0
      "true\n" : "false\n");
1326
    /*
1327
      Image columns, rows, and color space.
1328
    */
1329
0
    (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%s\n",
1330
0
      (double) image->columns,(double) image->rows,image->colorspace ==
1331
0
      CMYKColorspace ? PS3_CMYKColorspace : PS3_RGBColorspace);
1332
0
    (void) WriteBlobString(image,buffer);
1333
    /*
1334
      Masked image?
1335
    */
1336
0
    (void) WriteBlobString(image,image->alpha_trait != UndefinedPixelTrait ?
1337
0
      "true\n" : "false\n");
1338
    /*
1339
      Render with imagemask operator?
1340
    */
1341
0
    option=GetImageOption(image_info,"ps3:imagemask");
1342
0
    (void) WriteBlobString(image,((option != (const char *) NULL) &&
1343
0
      (SetImageMonochrome(image,exception) != MagickFalse)) ?
1344
0
      "true\n" : "false\n");
1345
    /*
1346
      Output pixel data.
1347
    */
1348
0
    pixels=(unsigned char *) NULL;
1349
0
    length=0;
1350
0
    if ((image_info->type != TrueColorType) &&
1351
0
        (image_info->type != TrueColorAlphaType) &&
1352
0
        (image_info->type != ColorSeparationType) &&
1353
0
        (image_info->type != ColorSeparationAlphaType) &&
1354
0
        (image->colorspace != CMYKColorspace) &&
1355
0
        (is_gray != MagickFalse))
1356
0
      {
1357
        /*
1358
          Gray images.
1359
        */
1360
0
        (void) WriteBlobString(image,PS3_PseudoClass"\n");
1361
0
        switch (compression)
1362
0
        {
1363
0
          case NoCompression:
1364
0
          default:
1365
0
          {
1366
0
            (void) WriteBlobString(image,PS3_NoCompression"\n");
1367
0
            break;
1368
0
          }
1369
0
          case FaxCompression:
1370
0
          case Group4Compression:
1371
0
          {
1372
0
            (void) WriteBlobString(image,PS3_FaxCompression"\n");
1373
0
            break;
1374
0
          }
1375
0
          case JPEGCompression:
1376
0
          {
1377
0
            (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1378
0
            break;
1379
0
          }
1380
0
          case LZWCompression:
1381
0
          {
1382
0
            (void) WriteBlobString(image,PS3_LZWCompression"\n");
1383
0
            break;
1384
0
          }
1385
0
          case RLECompression:
1386
0
          {
1387
0
            (void) WriteBlobString(image,PS3_RLECompression"\n");
1388
0
            break;
1389
0
          }
1390
0
          case ZipCompression:
1391
0
          {
1392
0
            (void) WriteBlobString(image,PS3_ZipCompression"\n");
1393
0
            break;
1394
0
          }
1395
0
        }
1396
        /*
1397
          Number of colors -- 0 for single component non-color mapped data.
1398
        */
1399
0
        (void) WriteBlobString(image,"0\n");
1400
        /*
1401
          1 bit or 8 bit components?
1402
        */
1403
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",
1404
0
          SetImageMonochrome(image,exception) != MagickFalse ? 1 : 8);
1405
0
        (void) WriteBlobString(image,buffer);
1406
        /*
1407
          Image data.
1408
        */
1409
0
        if (compression == JPEGCompression)
1410
0
          status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1411
0
        else
1412
0
          if ((compression == FaxCompression) ||
1413
0
              (compression == Group4Compression))
1414
0
            {
1415
0
              if (LocaleCompare(CCITTParam,"0") == 0)
1416
0
                status=HuffmanEncodeImage(image_info,image,image,exception);
1417
0
              else
1418
0
                status=Huffman2DEncodeImage(image_info,image,image,exception);
1419
0
            }
1420
0
          else
1421
0
            {
1422
0
              status=SerializeImageChannel(image_info,image,&pixel_info,&length,
1423
0
                exception);
1424
0
              if (status == MagickFalse)
1425
0
                {
1426
0
                  (void) CloseBlob(image);
1427
0
                  return(MagickFalse);
1428
0
                }
1429
0
              pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1430
0
              switch (compression)
1431
0
              {
1432
0
                case NoCompression:
1433
0
                default:
1434
0
                {
1435
0
                  Ascii85Initialize(image);
1436
0
                  for (i=0; i < (ssize_t) length; i++)
1437
0
                    Ascii85Encode(image,pixels[i]);
1438
0
                  Ascii85Flush(image);
1439
0
                  status=MagickTrue;
1440
0
                  break;
1441
0
                }
1442
0
                case LZWCompression:
1443
0
                {
1444
0
                  status=LZWEncodeImage(image,length,pixels,exception);
1445
0
                  break;
1446
0
                }
1447
0
                case RLECompression:
1448
0
                {
1449
0
                  status=PackbitsEncodeImage(image,length,pixels,exception);
1450
0
                  break;
1451
0
                }
1452
0
                case ZipCompression:
1453
0
                {
1454
0
                  status=ZLIBEncodeImage(image,length,pixels,exception);
1455
0
                  break;
1456
0
                }
1457
0
              }
1458
0
              pixel_info=RelinquishVirtualMemory(pixel_info);
1459
0
            }
1460
0
      }
1461
0
    else
1462
0
      if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1463
0
          (compression == JPEGCompression))
1464
0
        {
1465
          /*
1466
            Truecolor image.
1467
          */
1468
0
          (void) WriteBlobString(image,PS3_DirectClass"\n");
1469
0
          switch (compression)
1470
0
          {
1471
0
            case NoCompression:
1472
0
            default:
1473
0
            {
1474
0
              (void) WriteBlobString(image,PS3_NoCompression"\n");
1475
0
              break;
1476
0
            }
1477
0
            case RLECompression:
1478
0
            {
1479
0
              (void) WriteBlobString(image,PS3_RLECompression"\n");
1480
0
              break;
1481
0
            }
1482
0
            case JPEGCompression:
1483
0
            {
1484
0
              (void) WriteBlobString(image,PS3_JPEGCompression"\n");
1485
0
              break;
1486
0
            }
1487
0
            case LZWCompression:
1488
0
            {
1489
0
              (void) WriteBlobString(image,PS3_LZWCompression"\n");
1490
0
              break;
1491
0
            }
1492
0
            case ZipCompression:
1493
0
            {
1494
0
              (void) WriteBlobString(image,PS3_ZipCompression"\n");
1495
0
              break;
1496
0
            }
1497
0
          }
1498
          /*
1499
            Image data.
1500
          */
1501
0
          if (compression == JPEGCompression)
1502
0
            status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1503
0
          else
1504
0
            {
1505
              /*
1506
                Stream based compressions.
1507
              */
1508
0
              status=SerializeImage(image_info,image,&pixel_info,&length,
1509
0
                exception);
1510
0
              if (status == MagickFalse)
1511
0
                {
1512
0
                  (void) CloseBlob(image);
1513
0
                  return(MagickFalse);
1514
0
                }
1515
0
              pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1516
0
              switch (compression)
1517
0
              {
1518
0
                case NoCompression:
1519
0
                default:
1520
0
                {
1521
0
                  Ascii85Initialize(image);
1522
0
                  for (i=0; i < (ssize_t) length; i++)
1523
0
                    Ascii85Encode(image,pixels[i]);
1524
0
                  Ascii85Flush(image);
1525
0
                  status=MagickTrue;
1526
0
                  break;
1527
0
                }
1528
0
                case RLECompression:
1529
0
                {
1530
0
                  status=PackbitsEncodeImage(image,length,pixels,exception);
1531
0
                  break;
1532
0
                }
1533
0
                case LZWCompression:
1534
0
                {
1535
0
                  status=LZWEncodeImage(image,length,pixels,exception);
1536
0
                  break;
1537
0
                }
1538
0
                case ZipCompression:
1539
0
                {
1540
0
                  status=ZLIBEncodeImage(image,length,pixels,exception);
1541
0
                  break;
1542
0
                }
1543
0
              }
1544
0
              pixel_info=RelinquishVirtualMemory(pixel_info);
1545
0
            }
1546
0
          }
1547
0
        else
1548
0
          {
1549
            /*
1550
              Colormapped images.
1551
            */
1552
0
            (void) WriteBlobString(image,PS3_PseudoClass"\n");
1553
0
            switch (compression)
1554
0
            {
1555
0
              case NoCompression:
1556
0
              default:
1557
0
              {
1558
0
                (void) WriteBlobString(image,PS3_NoCompression"\n");
1559
0
                break;
1560
0
              }
1561
0
              case RLECompression:
1562
0
              {
1563
0
                (void) WriteBlobString(image,PS3_RLECompression"\n");
1564
0
                break;
1565
0
              }
1566
0
              case LZWCompression:
1567
0
              {
1568
0
                (void) WriteBlobString(image,PS3_LZWCompression"\n");
1569
0
                break;
1570
0
              }
1571
0
              case ZipCompression:
1572
0
              {
1573
0
                (void) WriteBlobString(image,PS3_ZipCompression"\n");
1574
0
                break;
1575
0
              }
1576
0
            }
1577
            /*
1578
              Number of colors in color map.
1579
            */
1580
0
            (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",
1581
0
              (double) image->colors);
1582
0
            (void) WriteBlobString(image,buffer);
1583
            /*
1584
              Color map - uncompressed.
1585
            */
1586
0
            if ((compression != NoCompression) &&
1587
0
                (compression != UndefinedCompression))
1588
0
              {
1589
0
                for (i=0; i < (ssize_t) image->colors; i++)
1590
0
                {
1591
0
                  pixel=ScaleQuantumToChar((Quantum) image->colormap[i].red);
1592
0
                  (void) WriteBlobByte(image,(unsigned char) pixel);
1593
0
                  pixel=ScaleQuantumToChar((Quantum) image->colormap[i].green);
1594
0
                  (void) WriteBlobByte(image,(unsigned char) pixel);
1595
0
                  pixel=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
1596
0
                  (void) WriteBlobByte(image,(unsigned char) pixel);
1597
0
                }
1598
0
              }
1599
0
            else
1600
0
              {
1601
0
                Ascii85Initialize(image);
1602
0
                for (i=0; i < (ssize_t) image->colors; i++)
1603
0
                {
1604
0
                  pixel=ScaleQuantumToChar((Quantum) image->colormap[i].red);
1605
0
                  Ascii85Encode(image,(unsigned char) pixel);
1606
0
                  pixel=ScaleQuantumToChar((Quantum) image->colormap[i].green);
1607
0
                  Ascii85Encode(image,(unsigned char) pixel);
1608
0
                  pixel=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
1609
0
                  Ascii85Encode(image,(unsigned char) pixel);
1610
0
                }
1611
0
                Ascii85Flush(image);
1612
0
              }
1613
0
            status=SerializeImageIndexes(image_info,image,&pixel_info,&length,
1614
0
              exception);
1615
0
            if (status == MagickFalse)
1616
0
              {
1617
0
                (void) CloseBlob(image);
1618
0
                return(MagickFalse);
1619
0
              }
1620
0
            pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1621
0
            switch (compression)
1622
0
            {
1623
0
              case NoCompression:
1624
0
              default:
1625
0
              {
1626
0
                Ascii85Initialize(image);
1627
0
                for (i=0; i < (ssize_t) length; i++)
1628
0
                  Ascii85Encode(image,pixels[i]);
1629
0
                Ascii85Flush(image);
1630
0
                status=MagickTrue;
1631
0
                break;
1632
0
              }
1633
0
              case RLECompression:
1634
0
              {
1635
0
                status=PackbitsEncodeImage(image,length,pixels,exception);
1636
0
                break;
1637
0
              }
1638
0
              case LZWCompression:
1639
0
              {
1640
0
                status=LZWEncodeImage(image,length,pixels,exception);
1641
0
                break;
1642
0
              }
1643
0
              case ZipCompression:
1644
0
              {
1645
0
                status=ZLIBEncodeImage(image,length,pixels,exception);
1646
0
                break;
1647
0
              }
1648
0
            }
1649
0
            pixel_info=RelinquishVirtualMemory(pixel_info);
1650
0
          }
1651
0
    (void) WriteBlobByte(image,'\n');
1652
0
    if (status == MagickFalse)
1653
0
      {
1654
0
        (void) CloseBlob(image);
1655
0
        return(MagickFalse);
1656
0
      }
1657
    /*
1658
      Update BeginData now that we know the data size.
1659
    */
1660
0
    length=(size_t) (TellBlob(image)-stop);
1661
0
    stop=TellBlob(image);
1662
0
    if (stop < 0)
1663
0
      ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1664
0
    offset=SeekBlob(image,start,SEEK_SET);
1665
0
    if (offset < 0)
1666
0
      ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1667
0
    (void) FormatLocaleString(buffer,MagickPathExtent,
1668
0
      "%%%%BeginData:%13ld %s Bytes\n",(long) length,
1669
0
      compression == NoCompression ? "ASCII" : "BINARY");
1670
0
    (void) WriteBlobString(image,buffer);
1671
0
    offset=SeekBlob(image,stop,SEEK_SET);
1672
0
    (void) WriteBlobString(image,"%%EndData\n");
1673
    /*
1674
      End private dictionary if this an EPS.
1675
    */
1676
0
    if (LocaleCompare(image_info->magick,"PS3") != 0)
1677
0
      (void) WriteBlobString(image,"end\n");
1678
0
    (void) WriteBlobString(image,"%%PageTrailer\n");
1679
0
    if (GetNextImageInList(image) == (Image *) NULL)
1680
0
      break;
1681
0
    image=SyncNextImageInList(image);
1682
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
1683
0
    if (status == MagickFalse)
1684
0
      break;
1685
0
  } while (image_info->adjoin != MagickFalse);
1686
0
  (void) WriteBlobString(image,"%%Trailer\n");
1687
0
  if (page > 1)
1688
0
    {
1689
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
1690
0
        "%%%%BoundingBox: %g %g %g %g\n",ceil(bounds.x1-0.5),
1691
0
        ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
1692
0
      (void) WriteBlobString(image,buffer);
1693
0
      (void) FormatLocaleString(buffer,MagickPathExtent,
1694
0
        "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2,
1695
0
        bounds.y2);
1696
0
      (void) WriteBlobString(image,buffer);
1697
0
    }
1698
0
  (void) WriteBlobString(image,"%%EOF\n");
1699
0
  if (CloseBlob(image) == MagickFalse)
1700
0
    status=MagickFalse;
1701
0
  return(status);
1702
0
}