Coverage Report

Created: 2025-07-23 08:18

/src/graphicsmagick/coders/ps.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
% Copyright (C) 2003 - 2020 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   SSSSS                                  %
15
%                               P   P  SS                                     %
16
%                               PPPP    SSS                                   %
17
%                               P         SS                                  %
18
%                               P      SSSSS                                  %
19
%                                                                             %
20
%                                                                             %
21
%                        Read/Write Postscript 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/pixel_cache.h"
43
#include "magick/color.h"
44
#include "magick/constitute.h"
45
#include "magick/delegate.h"
46
#include "magick/enum_strings.h"
47
#include "magick/magick.h"
48
#include "magick/monitor.h"
49
#include "magick/tempfile.h"
50
#include "magick/utility.h"
51
52
/*
53
  Forward declarations.
54
*/
55
static unsigned int
56
  WritePSImage(const ImageInfo *,Image *);
57

58
/*
59
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60
%                                                                             %
61
%                                                                             %
62
%                                                                             %
63
%   I s P S                                                                   %
64
%                                                                             %
65
%                                                                             %
66
%                                                                             %
67
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68
%
69
%  Method IsPS returns True if the image format type, identified by the
70
%  magick string, is PS.
71
%
72
%  The format of the IsPS method is:
73
%
74
%      unsigned int IsPS(const unsigned char *magick,const size_t length)
75
%
76
%  A description of each parameter follows:
77
%
78
%    o status:  Method IsPS returns True if the image format type is PS.
79
%
80
%    o magick: This string is generally the first few bytes of an image file
81
%      or blob.
82
%
83
%    o length: Specifies the length of the magick string.
84
%
85
%
86
*/
87
static unsigned int IsPS(const unsigned char *magick,const size_t length)
88
0
{
89
0
  if (length < 4)
90
0
    return(False);
91
0
  if (LocaleNCompare((char *) magick,"%!",2) == 0)
92
0
    return(True);
93
0
  if (memcmp(magick,"\004%!",3) == 0)
94
0
    return(True);
95
0
  return(False);
96
0
}
97

98
/*
99
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100
%                                                                             %
101
%                                                                             %
102
%                                                                             %
103
%   R e a d P S I m a g e                                                     %
104
%                                                                             %
105
%                                                                             %
106
%                                                                             %
107
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108
%
109
%  Method ReadPSImage reads a Adobe Postscript image file and returns it.  It
110
%  allocates the memory necessary for the new Image structure and returns a
111
%  pointer to the new image.
112
%
113
%  The format of the ReadPSImage method is:
114
%
115
%      Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
116
%
117
%  A description of each parameter follows:
118
%
119
%    o image:  Method ReadPSImage returns a pointer to the image after
120
%      reading.  A null image is returned if there is a memory shortage or
121
%      if the image cannot be read.
122
%
123
%    o image_info: Specifies a pointer to a ImageInfo structure.
124
%
125
%    o exception: return any errors or warnings in this structure.
126
%
127
%
128
*/
129
#if defined(HasGS)
130
static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
131
12.5k
{
132
12.5k
#define BoundingBox  "%%BoundingBox:"
133
12.5k
#define DocumentMedia  "%%DocumentMedia:"
134
12.5k
#define PageBoundingBox  "%%PageBoundingBox:"
135
12.5k
#define PostscriptLevel  "%!PS-"
136
12.5k
#define RenderPostscriptText  "[%s] Rendering postscript..."
137
138
12.5k
  char
139
12.5k
    command[MaxTextExtent],
140
12.5k
    density[MaxTextExtent],
141
12.5k
    filename[MaxTextExtent],
142
12.5k
    geometry[MaxTextExtent],
143
12.5k
    postscript_filename[MaxTextExtent],
144
12.5k
    translate_geometry[MaxTextExtent];
145
146
12.5k
  const DelegateInfo
147
12.5k
    *delegate_info;
148
149
12.5k
  double
150
12.5k
    dx_resolution,
151
12.5k
    dy_resolution;
152
153
12.5k
  ExtendedSignedIntegralType
154
12.5k
    filesize;
155
156
12.5k
  FILE
157
12.5k
    *file;
158
159
12.5k
  Image
160
12.5k
    *image,
161
12.5k
    *next_image;
162
163
12.5k
  int
164
12.5k
    c,
165
12.5k
    status;
166
167
12.5k
  unsigned int
168
12.5k
    antialias=4;
169
170
12.5k
  RectangleInfo
171
12.5k
    page;
172
173
12.5k
  register char
174
12.5k
    *p;
175
176
12.5k
  register long
177
12.5k
    i;
178
179
12.5k
  SegmentInfo
180
12.5k
    bounds;
181
182
12.5k
  size_t
183
12.5k
    count;
184
185
12.5k
  unsigned long
186
12.5k
    height,
187
12.5k
    width;
188
189
12.5k
  assert(image_info != (const ImageInfo *) NULL);
190
12.5k
  assert(image_info->signature == MagickSignature);
191
12.5k
  assert(exception != (ExceptionInfo *) NULL);
192
12.5k
  assert(exception->signature == MagickSignature);
193
194
  /*
195
    Select Postscript delegate driver
196
  */
197
12.5k
  delegate_info=GetPostscriptDelegateInfo(image_info,&antialias,exception);
198
12.5k
  if (delegate_info == (const DelegateInfo *) NULL)
199
12.5k
    return((Image *) NULL);
200
  /*
201
    Open image file.
202
  */
203
0
  image=AllocateImage(image_info);
204
0
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
205
0
  if (status == False)
206
0
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
207
  /*
208
    Open temporary output file.
209
  */
210
0
  file=AcquireTemporaryFileStream(postscript_filename,BinaryFileIOMode);
211
0
  if (file == (FILE *) NULL)
212
0
    ThrowReaderTemporaryFileException(postscript_filename);
213
0
  FormatString(translate_geometry,"%g %g translate\n              ",0.0,0.0);
214
0
  (void) fputs(translate_geometry,file);
215
  /*
216
    Set the page density.
217
  */
218
0
  dx_resolution=72.0;
219
0
  dy_resolution=72.0;
220
0
  if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
221
0
    {
222
0
      (void) strlcpy(density,PSDensityGeometry,sizeof(density));
223
0
      count=GetMagickDimension(density,&image->x_resolution,&image->y_resolution,NULL,NULL);
224
0
      if (count != 2)
225
0
        image->y_resolution=image->x_resolution;
226
0
    }
227
0
  FormatString(density,"%gx%g",image->x_resolution,image->y_resolution);
228
  /*
229
    Determine page geometry from the Postscript bounding box.
230
  */
231
0
  (void) memset(&page,0,sizeof(RectangleInfo));
232
0
  filesize=0;
233
0
  if (LocaleCompare(image_info->magick,"EPT") == 0)
234
0
    {
235
      /*
236
        Dos binary file header.
237
      */
238
0
      (void) ReadBlobLSBLong(image);
239
0
      count=ReadBlobLSBLong(image);
240
0
      filesize=(ExtendedSignedIntegralType) ReadBlobLSBLong(image);
241
0
      for (i=0; i < (long) (count-12); i++)
242
0
        (void) ReadBlobByte(image);
243
0
    }
244
0
  bounds.x1=0.0;
245
0
  bounds.y1=0.0;
246
0
  bounds.x2=0.0;
247
0
  bounds.y2=0.0;
248
0
  p=command;
249
0
  for (i=0; (LocaleCompare(image_info->magick,"EPT") != 0) ||
250
0
    (i < (long) filesize); i++)
251
0
  {
252
0
    c=ReadBlobByte(image);
253
0
    if (c == EOF)
254
0
      break;
255
0
    (void) fputc(c,file);
256
0
    *p++=c;
257
0
    if ((c != '\n') && (c != '\r') && ((p-command) < (MaxTextExtent-1)))
258
0
      continue;
259
0
    *p='\0';
260
0
    p=command;
261
    /*
262
      Parse a bounding box statement.
263
    */
264
0
    count=0;
265
0
    if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0)
266
0
      count=sscanf(command,"%%%%BoundingBox: %lf %lf %lf %lf",&bounds.x1,
267
0
        &bounds.y1,&bounds.x2,&bounds.y2);
268
0
    if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0)
269
0
      count=(size_t) sscanf(command,"%%%%DocumentMedia: %*s %lf %lf",&bounds.x2,
270
0
        &bounds.y2)+2;
271
0
    if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0)
272
0
      count=(size_t) sscanf(command,"%%%%PageBoundingBox: %lf %lf %lf %lf",
273
0
        &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
274
0
    if (count != 4)
275
0
      continue;
276
0
    if ((bounds.x1 > bounds.x2) || (bounds.y1 > bounds.y2))
277
0
      continue;
278
    /*
279
      Set Postscript render geometry.
280
    */
281
0
    FormatString(translate_geometry,"%g %g translate\n",-bounds.x1,-bounds.y1);
282
0
    width=(unsigned long) (bounds.x2-bounds.x1+0.5);
283
0
    height=(unsigned long) (bounds.y2-bounds.y1+0.5);
284
0
    if (width > page.width)
285
0
      page.width=width;
286
0
    if (height > page.height)
287
0
      page.height=height;
288
0
  }
289
0
  if ((page.width == 0) || (page.height == 0))
290
0
    {
291
0
      SetGeometry(image,&page);
292
0
      (void) GetGeometry(PSPageGeometry,&page.x,&page.y,&page.width,
293
0
        &page.height);
294
0
    }
295
0
  if (image_info->page != (char *) NULL)
296
0
    (void) GetGeometry(image_info->page,&page.x,&page.y,&page.width,
297
0
      &page.height);
298
0
  FormatString(geometry,"%lux%lu",
299
0
    (unsigned long) ceil(page.width*image->x_resolution/dx_resolution-0.5),
300
0
    (unsigned long) ceil(page.height*image->y_resolution/dy_resolution-0.5));
301
0
  if (ferror(file))
302
0
    {
303
0
      (void) fclose(file);
304
0
      (void) LiberateTemporaryFile(postscript_filename);
305
0
      ThrowReaderException(CorruptImageError,AnErrorHasOccurredWritingToFile,
306
0
        image)
307
0
    }
308
0
  (void) rewind(file);
309
0
  (void) fputs(translate_geometry,file);
310
0
  (void) fclose(file);
311
0
  CloseBlob(image);
312
0
  filesize=GetBlobSize(image);
313
0
  DestroyImage(image);
314
0
  image=(Image *) NULL;
315
  /*
316
    Use Ghostscript to convert Postscript image.
317
  */
318
0
  {
319
0
    char
320
0
      options[MaxTextExtent],
321
0
      arg[MaxTextExtent];
322
323
0
    options[0]='\0';
324
    /*
325
      Append subrange.
326
    */
327
0
    if (image_info->subrange != 0)
328
0
      FormatString(options,"-dFirstPage=%lu -dLastPage=%lu",
329
0
                   image_info->subimage+1,image_info->subimage+image_info->subrange);
330
    /*
331
      Append bounding box.
332
    */
333
0
    FormatString(arg,"-g%s",geometry);
334
0
    if (options[0] != '\0')
335
0
      (void) strlcat(options," ",sizeof(options));
336
0
    (void) strlcat(options,arg,sizeof(options));
337
338
0
    (void) strlcpy(filename,image_info->filename,MaxTextExtent);
339
0
    if (image_info->temporary)
340
0
      (void) LiberateTemporaryFile((char *) image_info->filename);
341
0
    if(!AcquireTemporaryFileName((char *) image_info->filename))
342
0
      {
343
0
        (void) LiberateTemporaryFile(postscript_filename);
344
0
        ThrowReaderTemporaryFileException(image_info->filename);
345
0
      }
346
0
    FormatString(command,delegate_info->commands,antialias,
347
0
                 antialias,density,options,image_info->filename,
348
0
                 postscript_filename);
349
0
  }
350
0
  (void) MagickMonitorFormatted(0,8,exception,RenderPostscriptText,
351
0
                                image_info->filename);
352
0
  status=InvokePostscriptDelegate(image_info->verbose,command,exception);
353
0
  if (!IsAccessibleAndNotEmpty(image_info->filename))
354
0
    {
355
      /*
356
        Ghostscript requires a showpage operator.
357
      */
358
0
      file=fopen(postscript_filename,"ab");
359
0
      if (file == (FILE *) NULL)
360
0
        {
361
0
          (void) LiberateTemporaryFile((char *) image_info->filename);
362
0
          ThrowReaderException(FileOpenError,UnableToWriteFile,image);
363
0
        }
364
0
      (void) fputs("showpage\n",file);
365
0
      (void) fclose(file);
366
0
      status=InvokePostscriptDelegate(image_info->verbose,command,exception);
367
0
    }
368
0
  (void) LiberateTemporaryFile(postscript_filename);
369
0
  (void) MagickMonitorFormatted(7,8,exception,RenderPostscriptText,
370
0
                                image_info->filename);
371
0
  if (IsAccessibleAndNotEmpty(image_info->filename))
372
0
    {
373
      /*
374
        Read Ghostscript output.
375
      */
376
0
      ImageInfo
377
0
        *clone_info;
378
379
0
      clone_info=CloneImageInfo(image_info);
380
0
      clone_info->blob=(void *) NULL;
381
0
      clone_info->length=0;
382
0
      clone_info->magick[0]='\0';
383
0
      clone_info->subimage=0;
384
0
      clone_info->subrange=0;
385
0
      MagickFreeMemory(clone_info->tile);
386
0
      image=ReadImage(clone_info,exception);
387
0
      DestroyImageInfo(clone_info);
388
0
    }
389
0
  (void) LiberateTemporaryFile((char *) image_info->filename);
390
0
  if (image == (Image *) NULL)
391
0
    {
392
0
      if (UndefinedException == exception->severity)
393
0
        ThrowException(exception,DelegateError,PostscriptDelegateFailed,filename);
394
0
    }
395
0
  else
396
0
    {
397
0
      do
398
0
        {
399
0
          (void) strlcpy(image->magick,"PS",sizeof(image->magick));
400
0
          (void) strlcpy(image->filename,filename,sizeof(image->filename));
401
0
          next_image=SyncNextImageInList(image);
402
0
          if (next_image != (Image *) NULL)
403
0
            image=next_image;
404
0
        } while (next_image != (Image *) NULL);
405
0
      while (image->previous != (Image *) NULL)
406
0
        image=image->previous;
407
0
      if (image_info->subimage != 0)
408
0
        {
409
0
          unsigned long
410
0
            scene = image_info->subimage;
411
412
0
          for (next_image=image;
413
0
               next_image != (Image *) NULL;
414
0
               next_image=next_image->next)
415
0
            next_image->scene = scene++;
416
0
        }
417
0
    }
418
0
  return(image);
419
0
}
420
#endif /* if defined(HasGS) */
421

422
/*
423
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424
%                                                                             %
425
%                                                                             %
426
%                                                                             %
427
%   R e g i s t e r P S I m a g e                                             %
428
%                                                                             %
429
%                                                                             %
430
%                                                                             %
431
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432
%
433
%  Method RegisterPSImage adds attributes for the PS image format to
434
%  the list of supported formats.  The attributes include the image format
435
%  tag, a method to read and/or write the format, whether the format
436
%  supports the saving of more than one frame to the same file or blob,
437
%  whether the format supports native in-memory I/O, and a brief
438
%  description of the format.
439
%
440
%  The format of the RegisterPSImage method is:
441
%
442
%      RegisterPSImage(void)
443
%
444
*/
445
ModuleExport void RegisterPSImage(void)
446
8
{
447
8
  MagickInfo
448
8
    *entry;
449
450
8
  entry=SetMagickInfo("EPI");
451
8
#if defined(HasGS)
452
8
  entry->decoder=(DecoderHandler) ReadPSImage;
453
8
#endif /* if defined(HasGS) */
454
8
  entry->encoder=(EncoderHandler) WritePSImage;
455
8
  entry->magick=(MagickHandler) IsPS;
456
8
  entry->adjoin=False;
457
8
  entry->description="Adobe Encapsulated PostScript Interchange format";
458
8
  entry->module="PS";
459
8
  entry->coder_class=PrimaryCoderClass;
460
8
  (void) RegisterMagickInfo(entry);
461
462
8
  entry=SetMagickInfo("EPS");
463
8
#if defined(HasGS)
464
8
  entry->decoder=(DecoderHandler) ReadPSImage;
465
8
#endif /* if defined(HasGS) */
466
8
  entry->encoder=(EncoderHandler) WritePSImage;
467
8
  entry->magick=(MagickHandler) IsPS;
468
8
  entry->adjoin=False;
469
8
  entry->description="Adobe Encapsulated PostScript";
470
8
  entry->module="PS";
471
8
  entry->coder_class=PrimaryCoderClass;
472
8
  (void) RegisterMagickInfo(entry);
473
474
8
  entry=SetMagickInfo("EPSF");
475
8
#if defined(HasGS)
476
8
  entry->decoder=(DecoderHandler) ReadPSImage;
477
8
#endif /* if defined(HasGS) */
478
8
  entry->encoder=(EncoderHandler) WritePSImage;
479
8
  entry->magick=(MagickHandler) IsPS;
480
8
  entry->adjoin=False;
481
8
  entry->description="Adobe Encapsulated PostScript";
482
8
  entry->module="PS";
483
8
  entry->coder_class=PrimaryCoderClass;
484
8
  (void) RegisterMagickInfo(entry);
485
486
8
  entry=SetMagickInfo("EPSI");
487
8
#if defined(HasGS)
488
8
  entry->decoder=(DecoderHandler) ReadPSImage;
489
8
#endif /* if defined(HasGS) */
490
8
  entry->encoder=(EncoderHandler) WritePSImage;
491
8
  entry->magick=(MagickHandler) IsPS;
492
8
  entry->adjoin=False;
493
8
  entry->description="Adobe Encapsulated PostScript Interchange format";
494
8
  entry->module="PS";
495
8
  entry->coder_class=PrimaryCoderClass;
496
8
  (void) RegisterMagickInfo(entry);
497
498
8
  entry=SetMagickInfo("PS");
499
8
#if defined(HasGS)
500
8
  entry->decoder=(DecoderHandler) ReadPSImage;
501
8
#endif /* if defined(HasGS) */
502
8
  entry->encoder=(EncoderHandler) WritePSImage;
503
8
  entry->magick=(MagickHandler) IsPS;
504
8
  entry->description="Adobe PostScript";
505
8
  entry->module="PS";
506
8
  entry->coder_class=PrimaryCoderClass;
507
8
  (void) RegisterMagickInfo(entry);
508
8
}
509

510
/*
511
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512
%                                                                             %
513
%                                                                             %
514
%                                                                             %
515
%   U n r e g i s t e r P S I m a g e                                         %
516
%                                                                             %
517
%                                                                             %
518
%                                                                             %
519
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520
%
521
%  Method UnregisterPSImage removes format registrations made by the
522
%  PS module from the list of supported formats.
523
%
524
%  The format of the UnregisterPSImage method is:
525
%
526
%      UnregisterPSImage(void)
527
%
528
*/
529
ModuleExport void UnregisterPSImage(void)
530
0
{
531
0
  (void) UnregisterMagickInfo("EPI");
532
0
  (void) UnregisterMagickInfo("EPS");
533
0
  (void) UnregisterMagickInfo("EPSF");
534
0
  (void) UnregisterMagickInfo("EPSI");
535
0
  (void) UnregisterMagickInfo("PS");
536
0
}
537

538
/*
539
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540
%                                                                             %
541
%                                                                             %
542
%                                                                             %
543
%   W r i t e P S I m a g e                                                   %
544
%                                                                             %
545
%                                                                             %
546
%                                                                             %
547
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548
%
549
%  Method WritePSImage translates an image to encapsulated Postscript
550
%  Level I for printing.  If the supplied geometry is null, the image is
551
%  centered on the Postscript page.  Otherwise, the image is positioned as
552
%  specified by the geometry.
553
%
554
%  The format of the WritePSImage method is:
555
%
556
%      unsigned int WritePSImage(const ImageInfo *image_info,Image *image)
557
%
558
%  A description of each parameter follows:
559
%
560
%    o status: Method WritePSImage return True if the image is printed.
561
%      False is returned if the image file cannot be opened for printing.
562
%
563
%    o image_info: Specifies a pointer to a ImageInfo structure.
564
%
565
%    o image: The address of a structure of type Image;  returned from
566
%      ReadImage.
567
%
568
%
569
*/
570
0
#define WriteRunlengthPacket(image,bp,pixel,length,p) \
571
0
{ \
572
0
  if (image->matte && (p->opacity == TransparentOpacity)) \
573
0
    { \
574
0
      bp=AppendHexTriplet(bp,0xff,0xff,0xff); \
575
0
    } \
576
0
  else \
577
0
    { \
578
0
      bp=AppendHexTriplet(bp, \
579
0
                          ScaleQuantumToChar(pixel.red), \
580
0
                          ScaleQuantumToChar(pixel.green), \
581
0
                          ScaleQuantumToChar(pixel.blue)); \
582
0
    } \
583
0
  bp=AppendHexVal(bp,Min(length,0xff)); \
584
0
}
585
586
static char const hexvals[][3] =
587
  {
588
    "00","01","02","03","04","05","06","07","08","09","0A","0B",
589
    "0C","0D","0E","0F","10","11","12","13","14","15","16","17",
590
    "18","19","1A","1B","1C","1D","1E","1F","20","21","22","23",
591
    "24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
592
    "30","31","32","33","34","35","36","37","38","39","3A","3B",
593
    "3C","3D","3E","3F","40","41","42","43","44","45","46","47",
594
    "48","49","4A","4B","4C","4D","4E","4F","50","51","52","53",
595
    "54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
596
    "60","61","62","63","64","65","66","67","68","69","6A","6B",
597
    "6C","6D","6E","6F","70","71","72","73","74","75","76","77",
598
    "78","79","7A","7B","7C","7D","7E","7F","80","81","82","83",
599
    "84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
600
    "90","91","92","93","94","95","96","97","98","99","9A","9B",
601
    "9C","9D","9E","9F","A0","A1","A2","A3","A4","A5","A6","A7",
602
    "A8","A9","AA","AB","AC","AD","AE","AF","B0","B1","B2","B3",
603
    "B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
604
    "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB",
605
    "CC","CD","CE","CF","D0","D1","D2","D3","D4","D5","D6","D7",
606
    "D8","D9","DA","DB","DC","DD","DE","DF","E0","E1","E2","E3",
607
    "E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
608
    "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB",
609
    "FC","FD","FE","FF"
610
  };
611
static inline char *AppendHexVal(char *q,const unsigned char val)
612
0
{
613
0
  *q++=*(hexvals[0xff & val]);
614
0
  *q++=*(hexvals[0xff & val]+1);
615
0
  return q;
616
0
}
617
static inline char* AppendHexTriplet(char *q,
618
                                     unsigned char a,
619
                                     unsigned char b,
620
                                     unsigned char c)
621
0
{
622
0
  q=AppendHexVal(q,a);
623
0
  q=AppendHexVal(q,b);
624
0
  q=AppendHexVal(q,c);
625
0
  return q;
626
0
}
627
static unsigned int WritePSImage(const ImageInfo *image_info,Image *image)
628
0
{
629
0
  char
630
0
    *bp,
631
0
    buffer[MaxTextExtent],
632
0
    date[MaxTextExtent],
633
0
    density[MaxTextExtent],
634
0
    **labels,
635
0
    page_geometry[MaxTextExtent];
636
637
0
  const ImageAttribute
638
0
    *attribute;
639
640
0
  double
641
0
    dx_resolution,
642
0
    dy_resolution,
643
0
    x_resolution,
644
0
    x_scale,
645
0
    y_resolution,
646
0
    y_scale;
647
648
0
  IndexPacket
649
0
    index;
650
651
0
  long
652
0
    length,
653
0
    y;
654
655
0
  long
656
0
    j;
657
658
0
  PixelPacket
659
0
    pixel;
660
661
0
  RectangleInfo
662
0
    geometry;
663
664
0
  register const PixelPacket
665
0
    *p;
666
667
0
  register const IndexPacket
668
0
    *indexes;
669
670
0
  register long
671
0
    i,
672
0
    x;
673
674
0
  SegmentInfo
675
0
    bounds={0.0,0.0,0.0,0.0};
676
677
0
  time_t
678
0
    timer;
679
680
0
  unsigned char
681
0
    bit,
682
0
    byte;
683
684
0
  unsigned int
685
0
    status;
686
687
0
  unsigned long
688
0
    count,
689
0
    page,
690
0
    polarity,
691
0
    scene,
692
0
    text_size;
693
694
0
  size_t
695
0
    image_list_length;
696
697
  /*
698
    Open output image file.
699
  */
700
0
  assert(image_info != (const ImageInfo *) NULL);
701
0
  assert(image_info->signature == MagickSignature);
702
0
  assert(image != (Image *) NULL);
703
0
  assert(image->signature == MagickSignature);
704
0
  image_list_length=GetImageListLength(image);
705
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
706
0
  if (status == False)
707
0
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
708
0
  page=1;
709
0
  scene=0;
710
0
  do
711
0
  {
712
0
    ImageCharacteristics
713
0
      characteristics;
714
715
    /*
716
      Scale image to size of Postscript page.
717
    */
718
0
    (void) TransformColorspace(image,RGBColorspace);
719
0
    text_size=0;
720
0
    attribute=GetImageAttribute(image,"label");
721
0
    if (attribute != (const ImageAttribute *) NULL)
722
0
      text_size=(unsigned int)
723
0
        (MultilineCensus(attribute->value)*image_info->pointsize+12);
724
0
    SetGeometry(image,&geometry);
725
0
    geometry.y=(long) text_size;
726
0
    FormatString(page_geometry,"%lux%lu",image->columns,image->rows);
727
0
    if (image_info->page != (char *) NULL)
728
0
      (void) strlcpy(page_geometry,image_info->page,MaxTextExtent);
729
0
    else
730
0
      if ((image->page.width != 0) && (image->page.height != 0))
731
0
        (void) FormatString(page_geometry,"%lux%lu%+ld%+ld",image->page.width,
732
0
          image->page.height,image->page.x,image->page.y);
733
0
      else
734
0
        if (LocaleCompare(image_info->magick,"PS") == 0)
735
0
          (void) strlcpy(page_geometry,PSPageGeometry,sizeof(page_geometry));
736
0
    (void) GetMagickGeometry(page_geometry,&geometry.x,&geometry.y,
737
0
      &geometry.width,&geometry.height);
738
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
739
0
                          "Image Resolution: %gx%g %s",
740
0
                          image->x_resolution,
741
0
                          image->y_resolution,
742
0
                          ResolutionTypeToString(image->units));
743
    /*
744
      Scale relative to dots-per-inch.
745
    */
746
0
    dx_resolution=72.0;
747
0
    dy_resolution=72.0;
748
0
    x_resolution=72.0;
749
0
    (void) strlcpy(density,PSDensityGeometry,sizeof(density));
750
0
    count=GetMagickDimension(density,&x_resolution,&y_resolution,NULL,NULL);
751
0
    if (count != 2)
752
0
      y_resolution=x_resolution;
753
    /*
754
      Use override resolution information if it appears to be valid.
755
    */
756
0
    if ((image_info->density != (char *) NULL) &&
757
0
        ((image_info->units == PixelsPerInchResolution) ||
758
0
         (image_info->units == PixelsPerCentimeterResolution)))
759
0
      {
760
0
        count=GetMagickDimension(image_info->density,&x_resolution,&y_resolution,NULL,NULL);
761
0
        if (count != 2)
762
0
          y_resolution=x_resolution;
763
0
        if (image_info->units == PixelsPerCentimeterResolution)
764
0
          {
765
0
            x_resolution *= 2.54;
766
0
            y_resolution *= 2.54;
767
0
          }
768
0
      }
769
    /*
770
      Use image resolution information if it appears to be valid.
771
    */
772
0
    else if ((image->x_resolution > 0.0) && (image->y_resolution > 0.0) &&
773
0
             ((image->units == PixelsPerInchResolution) ||
774
0
              (image->units == PixelsPerCentimeterResolution)))
775
0
      {
776
0
        x_resolution = image->x_resolution;
777
0
        y_resolution = image->y_resolution;
778
0
        if (image->units == PixelsPerCentimeterResolution)
779
0
          {
780
0
            x_resolution *= 2.54;
781
0
            y_resolution *= 2.54;
782
0
          }
783
0
      }
784
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
785
0
                          "Postscript Resolution: %gx%g DPI",
786
0
                          x_resolution,y_resolution);
787
0
    x_scale=(geometry.width*dx_resolution)/x_resolution;
788
0
    geometry.width=(unsigned long) (x_scale+0.5);
789
0
    y_scale=(geometry.height*dy_resolution)/y_resolution;
790
0
    geometry.height=(unsigned long) (y_scale+0.5);
791
0
    if (page == 1)
792
0
      {
793
        /*
794
          Output Postscript header.
795
        */
796
0
#if defined(HAVE_CTIME_R)
797
0
        char time_buf[26];
798
0
#endif /* defined(HAVE_CTIME_R) */
799
0
        if (LocaleCompare(image_info->magick,"PS") == 0)
800
0
          (void) strlcpy(buffer,"%!PS-Adobe-3.0\n",sizeof(buffer));
801
0
        else
802
0
          (void) strlcpy(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",sizeof(buffer));
803
0
        (void) WriteBlobString(image,buffer);
804
0
        (void) WriteBlobString(image,"%%Creator: (GraphicsMagick)\n");
805
0
        FormatString(buffer,"%%%%Title: (%.1024s)\n",image->filename);
806
0
        (void) WriteBlobString(image,buffer);
807
0
        timer=time((time_t *) NULL);
808
0
#if defined(HAVE_CTIME_R)
809
0
        (void) strlcpy(date,ctime_r(&timer,time_buf),MaxTextExtent);
810
#else
811
        (void) strlcpy(date,ctime(&timer),MaxTextExtent); /* Thread-unsafe version */
812
#endif /* defined(HAVE_CTIME_R) */
813
0
        date[strlen(date)-1]='\0';
814
0
        FormatString(buffer,"%%%%CreationDate: (%.1024s)\n",date);
815
0
        (void) WriteBlobString(image,buffer);
816
0
        bounds.x1=geometry.x;
817
0
        bounds.y1=geometry.y;
818
0
        bounds.x2=geometry.x+x_scale;
819
0
        bounds.y2=geometry.y+((size_t) geometry.height+text_size);
820
0
        if (image_info->adjoin && (image->next != (Image *) NULL))
821
0
          (void) strlcpy(buffer,"%%%%BoundingBox: (atend)\n",sizeof(buffer));
822
0
        else
823
0
          FormatString(buffer,"%%%%BoundingBox: %g %g %g %g\n",
824
0
            floor(bounds.x1+0.5),floor(bounds.y1+0.5),ceil(bounds.x2-0.5),
825
0
            ceil(bounds.y2-0.5));
826
0
        (void) WriteBlobString(image,buffer);
827
0
        attribute=GetImageAttribute(image,"label");
828
0
        if (attribute != (const ImageAttribute *) NULL)
829
0
          (void) WriteBlobString(image,
830
0
            "%%DocumentNeededResources: font Times-Roman\n");
831
0
        (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n");
832
0
        (void) WriteBlobString(image,"%%LanguageLevel: 1\n");
833
0
        if (LocaleCompare(image_info->magick,"PS") != 0)
834
0
          (void) WriteBlobString(image,"%%Pages: 1\n");
835
0
        else
836
0
          {
837
            /*
838
              Compute the number of pages.
839
            */
840
0
            (void) WriteBlobString(image,"%%Orientation: Portrait\n");
841
0
            (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
842
0
            FormatString(buffer,"%%%%Pages: %lu\n", image_info->adjoin ?
843
0
              (unsigned long) image_list_length : 1L);
844
0
            (void) WriteBlobString(image,buffer);
845
0
          }
846
0
        (void) WriteBlobString(image,"%%EndComments\n");
847
0
        (void) WriteBlobString(image,"\n%%BeginDefaults\n");
848
0
        (void) WriteBlobString(image,"%%EndDefaults\n\n");
849
0
        if ((LocaleCompare(image_info->magick,"EPI") == 0) ||
850
0
            (LocaleCompare(image_info->magick,"EPT") == 0) ||
851
0
            (LocaleCompare(image_info->magick,"EPSI") == 0))
852
0
          {
853
0
            Image
854
0
              *preview_image;
855
856
            /*
857
              Create preview image.
858
            */
859
0
            preview_image=CloneImage(image,0,0,True,&image->exception);
860
0
            if (preview_image == (Image *) NULL)
861
0
              ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
862
0
                image);
863
            /*
864
              Dump image as bitmap.
865
            */
866
0
            (void) SetImageType(preview_image,BilevelType);
867
0
            polarity=
868
0
              PixelIntensityToQuantum(&preview_image->colormap[0]) < (MaxRGB/2);
869
0
            if (preview_image->colors == 2)
870
0
              polarity=PixelIntensityToQuantum(&preview_image->colormap[0]) >
871
0
                PixelIntensityToQuantum(&preview_image->colormap[1]);
872
0
            FormatString(buffer,"%%%%BeginPreview: %lu %lu %lu %lu\n%%  ",
873
0
              preview_image->columns,preview_image->rows,1L,
874
0
              (((preview_image->columns+7) >> 3)*preview_image->rows+35)/36);
875
0
            (void) WriteBlobString(image,buffer);
876
0
            count=0;
877
0
            bp=buffer;
878
0
            for (y=0; y < (long) image->rows; y++)
879
0
            {
880
0
              p=AcquireImagePixels(preview_image,0,y,preview_image->columns,1,
881
0
                &preview_image->exception);
882
0
              if (p == (const PixelPacket *) NULL)
883
0
                break;
884
0
              indexes=AccessImmutableIndexes(preview_image);
885
0
              bit=0;
886
0
              byte=0;
887
0
              for (x=0; x < (long) preview_image->columns; x++)
888
0
              {
889
0
                byte<<=1;
890
0
                if (indexes[x] == polarity)
891
0
                  byte|=0x01;
892
0
                bit++;
893
0
                if (bit == 8)
894
0
                  {
895
0
                    bp=AppendHexVal(bp,byte & 0xff);
896
0
                    count++;
897
0
                    if (count == 36)
898
0
                      {
899
0
                        count=0;
900
0
                        *bp++='\n';
901
0
                        *bp++='%';
902
0
                        *bp++=' ';
903
0
                        *bp++=' ';
904
0
                        (void) WriteBlob(image,bp-buffer,buffer);
905
0
                        bp=buffer;
906
0
                      };
907
0
                    bit=0;
908
0
                    byte=0;
909
0
                  }
910
0
              }
911
0
              if (bit != 0)
912
0
                {
913
0
                  byte<<=(8-bit);
914
0
                  bp=AppendHexVal(bp,byte & 0xff);
915
0
                  count++;
916
0
                  if (count == 36)
917
0
                    {
918
0
                      count=0;
919
0
                      *bp++='\n';
920
0
                      *bp++='%';
921
0
                      *bp++=' ';
922
0
                      *bp++=' ';
923
0
                      (void) WriteBlob(image,bp-buffer,buffer);
924
0
                      bp=buffer;
925
0
                    };
926
0
                };
927
0
            }
928
0
            if (bp != buffer)
929
0
              {
930
0
                (void) WriteBlob(image,bp-buffer,buffer);
931
0
                bp=buffer;
932
0
              }
933
0
            (void) WriteBlobString(image,"\n%%EndPreview\n");
934
0
            DestroyImage(preview_image);
935
0
          }
936
        /*
937
          Output Postscript commands.
938
        */
939
0
        (void) WriteBlobString(image,
940
0
                               "%%BeginProlog\n"
941
0
                               "%\n"
942
0
                               "% Display a color image.  The image is displayed in color on\n"
943
0
                               "% Postscript viewers or printers that support color, otherwise\n"
944
0
                               "% it is displayed as grayscale.\n"
945
0
                               "%\n"
946
0
                               "/DirectClassPacket\n"
947
0
                               "{\n"
948
0
                               "  %\n"
949
0
                               "  % Get a DirectClass packet.\n"
950
0
                               "  %\n"
951
0
                               "  % Parameters:\n"
952
0
                               "  %   red.\n"
953
0
                               "  %   green.\n"
954
0
                               "  %   blue.\n"
955
0
                               "  %   length: number of pixels minus one of this color (optional).\n"
956
0
                               "  %\n"
957
0
                               "  currentfile color_packet readhexstring pop pop\n"
958
0
                               "  compression 0 eq\n"
959
0
                               "  {\n"
960
0
                               "    /number_pixels 3 def\n"
961
0
                               "  }\n"
962
0
                               "  {\n"
963
0
                               "    currentfile byte readhexstring pop 0 get\n"
964
0
                               "    /number_pixels exch 1 add 3 mul def\n"
965
0
                               "  } ifelse\n"
966
0
                               "  0 3 number_pixels 1 sub\n"
967
0
                               "  {\n"
968
0
                               "    pixels exch color_packet putinterval\n"
969
0
                               "  } for\n"
970
0
                               "  pixels 0 number_pixels getinterval\n"
971
0
                               "} bind def\n"
972
0
                               "\n"
973
0
                               "/DirectClassImage\n"
974
0
                               "{\n"
975
0
                               "  %\n"
976
0
                               "  % Display a DirectClass image.\n"
977
0
                               "  %\n"
978
0
                               "  systemdict /colorimage known\n"
979
0
                               "  {\n"
980
0
                               "    columns rows 8\n"
981
0
                               "    [\n"
982
0
                               "      columns 0 0\n"
983
0
                               "      rows neg 0 rows\n"
984
0
                               "    ]\n"
985
0
                               "    { DirectClassPacket } false 3 colorimage\n"
986
0
                               "  }\n"
987
0
                               "  {\n"
988
0
                               "    %\n"
989
0
                               "    % No colorimage operator;  convert to grayscale.\n"
990
0
                               "    %\n"
991
0
                               "    columns rows 8\n"
992
0
                               "    [\n"
993
0
                               "      columns 0 0\n"
994
0
                               "      rows neg 0 rows\n"
995
0
                               "    ]\n"
996
0
                               "    { GrayDirectClassPacket } image\n"
997
0
                               "  } ifelse\n"
998
0
                               "} bind def\n"
999
0
                               "\n"
1000
0
                               "/GrayDirectClassPacket\n"
1001
0
                               "{\n"
1002
0
                               "  %\n"
1003
0
                               "  % Get a DirectClass packet;  convert to grayscale.\n"
1004
0
                               "  %\n"
1005
0
                               "  % Parameters:\n"
1006
0
                               "  %   red\n"
1007
0
                               "  %   green\n"
1008
0
                               "  %   blue\n"
1009
0
                               "  %   length: number of pixels minus one of this color (optional).\n"
1010
0
                               "  %\n"
1011
0
                               "  currentfile color_packet readhexstring pop pop\n"
1012
0
                               "  color_packet 0 get 0.299 mul\n"
1013
0
                               "  color_packet 1 get 0.587 mul add\n"
1014
0
                               "  color_packet 2 get 0.114 mul add\n"
1015
0
                               "  cvi\n"
1016
0
                               "  /gray_packet exch def\n"
1017
0
                               "  compression 0 eq\n"
1018
0
                               "  {\n"
1019
0
                               "    /number_pixels 1 def\n"
1020
0
                               "  }\n"
1021
0
                               "  {\n"
1022
0
                               "    currentfile byte readhexstring pop 0 get\n"
1023
0
                               "    /number_pixels exch 1 add def\n"
1024
0
                               "  } ifelse\n"
1025
0
                               "  0 1 number_pixels 1 sub\n"
1026
0
                               "  {\n"
1027
0
                               "    pixels exch gray_packet put\n"
1028
0
                               "  } for\n"
1029
0
                               "  pixels 0 number_pixels getinterval\n"
1030
0
                               "} bind def\n"
1031
0
                               "\n"
1032
0
                               "/GrayPseudoClassPacket\n"
1033
0
                               "{\n"
1034
0
                               "  %\n"
1035
0
                               "  % Get a PseudoClass packet;  convert to grayscale.\n"
1036
0
                               "  %\n"
1037
0
                               "  % Parameters:\n"
1038
0
                               "  %   index: index into the colormap.\n"
1039
0
                               "  %   length: number of pixels minus one of this color (optional).\n"
1040
0
                               "  %\n"
1041
0
                               "  currentfile byte readhexstring pop 0 get\n"
1042
0
                               "  /offset exch 3 mul def\n"
1043
0
                               "  /color_packet colormap offset 3 getinterval def\n"
1044
0
                               "  color_packet 0 get 0.299 mul\n"
1045
0
                               "  color_packet 1 get 0.587 mul add\n"
1046
0
                               "  color_packet 2 get 0.114 mul add\n"
1047
0
                               "  cvi\n"
1048
0
                               "  /gray_packet exch def\n"
1049
0
                               "  compression 0 eq\n"
1050
0
                               "  {\n"
1051
0
                               "    /number_pixels 1 def\n"
1052
0
                               "  }\n"
1053
0
                               "  {\n"
1054
0
                               "    currentfile byte readhexstring pop 0 get\n"
1055
0
                               "    /number_pixels exch 1 add def\n"
1056
0
                               "  } ifelse\n"
1057
0
                               "  0 1 number_pixels 1 sub\n"
1058
0
                               "  {\n"
1059
0
                               "    pixels exch gray_packet put\n"
1060
0
                               "  } for\n"
1061
0
                               "  pixels 0 number_pixels getinterval\n"
1062
0
                               "} bind def\n"
1063
0
                               "\n"
1064
0
                               "/PseudoClassPacket\n"
1065
0
                               "{\n"
1066
0
                               "  %\n"
1067
0
                               "  % Get a PseudoClass packet.\n"
1068
0
                               "  %\n"
1069
0
                               "  % Parameters:\n"
1070
0
                               "  %   index: index into the colormap.\n"
1071
0
                               "  %   length: number of pixels minus one of this color (optional).\n"
1072
0
                               "  %\n"
1073
0
                               "  currentfile byte readhexstring pop 0 get\n"
1074
0
                               "  /offset exch 3 mul def\n"
1075
0
                               "  /color_packet colormap offset 3 getinterval def\n"
1076
0
                               "  compression 0 eq\n"
1077
0
                               "  {\n"
1078
0
                               "    /number_pixels 3 def\n"
1079
0
                               "  }\n"
1080
0
                               "  {\n"
1081
0
                               "    currentfile byte readhexstring pop 0 get\n"
1082
0
                               "    /number_pixels exch 1 add 3 mul def\n"
1083
0
                               "  } ifelse\n"
1084
0
                               "  0 3 number_pixels 1 sub\n"
1085
0
                               "  {\n"
1086
0
                               "    pixels exch color_packet putinterval\n"
1087
0
                               "  } for\n"
1088
0
                               "  pixels 0 number_pixels getinterval\n"
1089
0
                               "} bind def\n"
1090
0
                               "\n"
1091
0
                               "/PseudoClassImage\n"
1092
0
                               "{\n"
1093
0
                               "  %\n"
1094
0
                               "  % Display a PseudoClass image.\n"
1095
0
                               "  %\n"
1096
0
                               "  % Parameters:\n"
1097
0
                               "  %   class: 0-PseudoClass or 1-Grayscale.\n"
1098
0
                               "  %\n"
1099
0
                               "  currentfile buffer readline pop\n"
1100
0
                               "  token pop /class exch def pop\n"
1101
0
                               "  class 0 gt\n"
1102
0
                               "  {\n"
1103
0
                               "    currentfile buffer readline pop\n"
1104
0
                               "    token pop /depth exch def pop\n"
1105
0
                               "    /grays columns 8 add depth sub depth mul 8 idiv string def\n"
1106
0
                               "    columns rows depth\n"
1107
0
                               "    [\n"
1108
0
                               "      columns 0 0\n"
1109
0
                               "      rows neg 0 rows\n"
1110
0
                               "    ]\n"
1111
0
                               "    { currentfile grays readhexstring pop } image\n"
1112
0
                               "  }\n"
1113
0
                               "  {\n"
1114
0
                               "    %\n"
1115
0
                               "    % Parameters:\n"
1116
0
                               "    %   colors: number of colors in the colormap.\n"
1117
0
                               "    %   colormap: red, green, blue color packets.\n"
1118
0
                               "    %\n"
1119
0
                               "    currentfile buffer readline pop\n"
1120
0
                               "    token pop /colors exch def pop\n"
1121
0
                               "    /colors colors 3 mul def\n"
1122
0
                               "    /colormap colors string def\n"
1123
0
                               "    currentfile colormap readhexstring pop pop\n"
1124
0
                               "    systemdict /colorimage known\n"
1125
0
                               "    {\n"
1126
0
                               "      columns rows 8\n"
1127
0
                               "      [\n"
1128
0
                               "        columns 0 0\n"
1129
0
                               "        rows neg 0 rows\n"
1130
0
                               "      ]\n"
1131
0
                               "      { PseudoClassPacket } false 3 colorimage\n"
1132
0
                               "    }\n"
1133
0
                               "    {\n"
1134
0
                               "      %\n"
1135
0
                               "      % No colorimage operator;  convert to grayscale.\n"
1136
0
                               "      %\n"
1137
0
                               "      columns rows 8\n"
1138
0
                               "      [\n"
1139
0
                               "        columns 0 0\n"
1140
0
                               "        rows neg 0 rows\n"
1141
0
                               "      ]\n"
1142
0
                               "      { GrayPseudoClassPacket } image\n"
1143
0
                               "    } ifelse\n"
1144
0
                               "  } ifelse\n"
1145
0
                               "} bind def\n"
1146
0
                               "\n"
1147
0
                               "/DisplayImage\n"
1148
0
                               "{\n"
1149
0
                               "  %\n"
1150
0
                               "  % Display a DirectClass or PseudoClass image.\n"
1151
0
                               "  %\n"
1152
0
                               "  % Parameters:\n"
1153
0
                               "  %   x & y translation.\n"
1154
0
                               "  %   x & y scale.\n"
1155
0
                               "  %   label pointsize.\n"
1156
0
                               "  %   image label.\n"
1157
0
                               "  %   image columns & rows.\n"
1158
0
                               "  %   class: 0-DirectClass or 1-PseudoClass.\n"
1159
0
                               "  %   compression: 0-none or 1-RunlengthEncoded.\n"
1160
0
                               "  %   hex color packets.\n"
1161
0
                               "  %\n"
1162
0
                               "  gsave\n"
1163
0
                               "  /buffer 512 string def\n"
1164
0
                               "  /byte 1 string def\n"
1165
0
                               "  /color_packet 3 string def\n"
1166
0
                               "  /pixels 768 string def\n"
1167
0
                               "\n"
1168
0
                               "  currentfile buffer readline pop\n"
1169
0
                               "  token pop /x exch def\n"
1170
0
                               "  token pop /y exch def pop\n"
1171
0
                               "  x y translate\n"
1172
0
                               "  currentfile buffer readline pop\n"
1173
0
                               "  token pop /x exch def\n"
1174
0
                               "  token pop /y exch def pop\n"
1175
0
                               "  currentfile buffer readline pop\n"
1176
0
                               "  token pop /pointsize exch def pop\n"
1177
0
                               "  /Times-Roman findfont pointsize scalefont setfont\n");
1178
1179
0
        attribute=GetImageAttribute(image,"label");
1180
0
        if (attribute != (const ImageAttribute *) NULL)
1181
0
          for (j=(long) MultilineCensus(attribute->value)-1; j >= 0; j--)
1182
0
          {
1183
0
            (void) WriteBlobString(image,"  /label 512 string def\n");
1184
0
            (void) WriteBlobString(image,"  currentfile label readline pop\n");
1185
0
            FormatString(buffer,"  0 y %g add moveto label show pop\n",
1186
0
              j*image_info->pointsize+12);
1187
0
            (void) WriteBlobString(image,buffer);
1188
0
          }
1189
0
        (void) WriteBlobString(image,
1190
0
                               "  x y scale\n"
1191
0
                               "  currentfile buffer readline pop\n"
1192
0
                               "  token pop /columns exch def\n"
1193
0
                               "  token pop /rows exch def pop\n"
1194
0
                               "  currentfile buffer readline pop\n"
1195
0
                               "  token pop /class exch def pop\n"
1196
0
                               "  currentfile buffer readline pop\n"
1197
0
                               "  token pop /compression exch def pop\n"
1198
0
                               "  class 0 gt { PseudoClassImage } { DirectClassImage } ifelse\n"
1199
0
                               "  grestore\n");
1200
0
        if (LocaleCompare(image_info->magick,"PS") == 0)
1201
0
          (void) WriteBlobString(image,"  showpage\n");
1202
0
        (void) WriteBlobString(image,"} bind def\n");
1203
0
        (void) WriteBlobString(image,"%%EndProlog\n");
1204
0
      }
1205
0
    FormatString(buffer,"%%%%Page:  1 %lu\n",page++);
1206
0
    (void) WriteBlobString(image,buffer);
1207
0
    FormatString(buffer,"%%%%PageBoundingBox: %ld %ld %ld %ld\n",geometry.x,
1208
0
      geometry.y,geometry.x+(long) geometry.width,geometry.y+(long)
1209
0
      (geometry.height+text_size));
1210
0
    (void) WriteBlobString(image,buffer);
1211
0
    if (geometry.x < bounds.x1)
1212
0
      bounds.x1=geometry.x;
1213
0
    if (geometry.y < bounds.y1)
1214
0
      bounds.y1=geometry.y;
1215
0
    if ((geometry.x+((size_t) geometry.width-1)) > bounds.x2)
1216
0
      bounds.x2=geometry.x+(size_t) geometry.width-1;
1217
0
    if ((geometry.y+((size_t) geometry.height+text_size)-1) > bounds.y2)
1218
0
      bounds.y2=geometry.y+((size_t) geometry.height+text_size)-1;
1219
0
    attribute=GetImageAttribute(image,"label");
1220
0
    if (attribute != (const ImageAttribute *) NULL)
1221
0
      (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n");
1222
0
    if (LocaleCompare(image_info->magick,"PS") != 0)
1223
0
      (void) WriteBlobString(image,"userdict begin\n");
1224
0
    (void) WriteBlobString(image,"DisplayImage\n");
1225
    /*
1226
      Output image data.
1227
    */
1228
0
    FormatString(buffer,"%ld %ld\n%g %g\n%f\n",geometry.x,geometry.y,
1229
0
      x_scale,y_scale,image_info->pointsize);
1230
0
    (void) WriteBlobString(image,buffer);
1231
0
    labels=(char **) NULL;
1232
0
    attribute=GetImageAttribute(image,"label");
1233
0
    if (attribute != (const ImageAttribute *) NULL)
1234
0
      labels=StringToList(attribute->value);
1235
0
    if (labels != (char **) NULL)
1236
0
      {
1237
0
        for (i=0; labels[i] != (char *) NULL; i++)
1238
0
        {
1239
0
          FormatString(buffer,"%.1024s \n",labels[i]);
1240
0
          (void) WriteBlobString(image,buffer);
1241
0
          MagickFreeMemory(labels[i]);
1242
0
        }
1243
0
        MagickFreeMemory(labels);
1244
0
      }
1245
0
    (void) memset(&pixel,0,sizeof(PixelPacket));
1246
0
    pixel.opacity=TransparentOpacity;
1247
0
    i=0;
1248
0
    index=0;
1249
0
    x=0;
1250
    /*
1251
      Analyze image to be written.
1252
    */
1253
0
    (void) GetImageCharacteristics(image,&characteristics,
1254
0
                                   (OptimizeType == image_info->type),
1255
0
                                   &image->exception);
1256
0
    if ((image_info->type != TrueColorType) &&
1257
0
        (characteristics.grayscale))
1258
0
      {
1259
0
        FormatString(buffer,"%lu %lu\n1\n1\n1\n%d\n",image->columns,
1260
0
          image->rows,((characteristics.monochrome) ? 1 : 8));
1261
0
        (void) WriteBlobString(image,buffer);
1262
0
        if (!characteristics.monochrome)
1263
0
          {
1264
            /*
1265
              Dump image as grayscale.
1266
            */
1267
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1268
0
                                  "Writing image as grayscale...");
1269
0
            i++;
1270
0
            bp=buffer;
1271
0
            for (y=0; y < (long) image->rows; y++)
1272
0
            {
1273
0
              p=AcquireImagePixels(image,0,y,image->columns,1,
1274
0
                &image->exception);
1275
0
              if (p == (const PixelPacket *) NULL)
1276
0
                break;
1277
0
              for (x=0; x < (long) image->columns; x++)
1278
0
              {
1279
0
                Quantum
1280
0
                  quantum;
1281
1282
0
                if (image->is_grayscale)
1283
0
                  quantum=GetGraySample(p);
1284
0
                else
1285
0
                  quantum=PixelIntensityToQuantum(p);
1286
1287
0
                bp=AppendHexVal(bp,ScaleQuantumToChar(quantum));
1288
0
                i++;
1289
0
                if (i == 36)
1290
0
                  {
1291
0
                    i=0;
1292
0
                    *bp++='\n';
1293
0
                    (void) WriteBlob(image,bp-buffer,buffer);
1294
0
                    bp=buffer;
1295
0
                  }
1296
0
                p++;
1297
0
              }
1298
0
              if (image->previous == (Image *) NULL)
1299
0
                if (QuantumTick(y,image->rows))
1300
0
                  if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1301
0
                                              SaveImageText,image->filename,
1302
0
                                              image->columns,image->rows))
1303
0
                    break;
1304
0
            }
1305
0
            if (bp != buffer)
1306
0
              {
1307
0
                *bp++='\n';
1308
0
                (void) WriteBlob(image,bp-buffer,buffer);
1309
0
                bp=buffer;
1310
0
              }
1311
0
          }
1312
0
        else
1313
0
          {
1314
            /*
1315
              Dump image as bitmap.
1316
            */
1317
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1318
0
                                  "Writing image as monochrome bitmap...");
1319
0
            (void) SetImageType(image,BilevelType);
1320
0
            count=0;
1321
0
            bp=buffer;
1322
0
            for (y=0; y < (long) image->rows; y++)
1323
0
            {
1324
0
              p=AcquireImagePixels(image,0,y,image->columns,1,
1325
0
                &image->exception);
1326
0
              if (p == (const PixelPacket *) NULL)
1327
0
                break;
1328
0
              indexes=AccessImmutableIndexes(image);
1329
0
              bit=0;
1330
0
              byte=0;
1331
0
              for (x=0; x < (long) image->columns; x++)
1332
0
              {
1333
0
                byte<<=1;
1334
0
                if (image->storage_class == PseudoClass)
1335
0
                  {
1336
0
                    if (GetGraySample(&image->colormap[indexes[x]]) >= MaxRGB/2)
1337
0
                      byte|=0x01;
1338
0
                  }
1339
0
                else
1340
0
                  {
1341
0
                    if (GetGraySample(p) >= MaxRGB/2)
1342
0
                      byte|=0x01;
1343
0
                  }
1344
0
                bit++;
1345
0
                if (bit == 8)
1346
0
                  {
1347
0
                    bp=AppendHexVal(bp,byte & 0xff);
1348
0
                    count++;
1349
0
                    if (count == 36)
1350
0
                      {
1351
0
                        count=0;
1352
0
                        *bp++='\n';
1353
0
                        (void) WriteBlob(image,bp-buffer,buffer);
1354
0
                        bp=buffer;
1355
0
                      }
1356
0
                    bit=0;
1357
0
                    byte=0;
1358
0
                  }
1359
0
                p++;
1360
0
              }
1361
0
              if (bit != 0)
1362
0
                {
1363
0
                  byte<<=(8-bit);
1364
0
                  bp=AppendHexVal(bp,byte & 0xff);
1365
0
                  count++;
1366
0
                  if (count == 36)
1367
0
                    {
1368
0
                      count=0;
1369
0
                      *bp++='\n';
1370
0
                      (void) WriteBlob(image,bp-buffer,buffer);
1371
0
                      bp=buffer;
1372
0
                    };
1373
0
                };
1374
0
              if (image->previous == (Image *) NULL)
1375
0
                if (QuantumTick(y,image->rows))
1376
0
                  if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1377
0
                                              SaveImageText,image->filename,
1378
0
                                              image->columns,image->rows))
1379
0
                    break;
1380
0
            }
1381
0
            if (bp != buffer)
1382
0
              {
1383
0
                (void) WriteBlob(image,bp-buffer,buffer);
1384
0
                bp=buffer;
1385
0
              }
1386
0
          }
1387
0
        if (count != 0)
1388
0
          (void) WriteBlobByte(image,'\n');
1389
0
      }
1390
0
    else
1391
0
      if (image->storage_class == DirectClass)
1392
0
        {
1393
          /*
1394
            Dump DirectClass image.
1395
          */
1396
0
          FormatString(buffer,"%lu %lu\n0\n%d\n",image->columns,image->rows,
1397
0
            (int) (image_info->compression == RLECompression));
1398
0
          (void) WriteBlobString(image,buffer);
1399
0
          switch (image_info->compression)
1400
0
          {
1401
0
            case RLECompression:
1402
0
            {
1403
              /*
1404
                Dump runlength-encoded DirectColor packets.
1405
              */
1406
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1407
0
                                    "Writing image as DirectColor "
1408
0
                                    "(RLE compressed)...");
1409
0
              bp=buffer;
1410
0
              for (y=0; y < (long) image->rows; y++)
1411
0
              {
1412
0
                p=AcquireImagePixels(image,0,y,image->columns,1,
1413
0
                  &image->exception);
1414
0
                if (p == (const PixelPacket *) NULL)
1415
0
                  break;
1416
0
                pixel=(*p);
1417
0
                length=255;
1418
0
                for (x=0; x < (long) image->columns; x++)
1419
0
                {
1420
0
                  if ((p->red == pixel.red) && (p->green == pixel.green) &&
1421
0
                      (p->blue == pixel.blue) && (p->opacity == pixel.opacity) &&
1422
0
                      (length < 255) && (x < (long) (image->columns-1)))
1423
0
                    length++;
1424
0
                  else
1425
0
                    {
1426
0
                      if (x > 0)
1427
0
                        {
1428
0
                          WriteRunlengthPacket(image,bp,pixel,length,p);
1429
0
                          i++;
1430
0
                          if (i == 9)
1431
0
                            {
1432
0
                              *bp++='\n';
1433
0
                              (void) WriteBlob(image,bp-buffer,buffer);
1434
0
                              bp=buffer;
1435
0
                              i=0;
1436
0
                            }
1437
0
                        }
1438
0
                      length=0;
1439
0
                    }
1440
0
                  pixel=(*p);
1441
0
                  p++;
1442
0
                }
1443
0
                WriteRunlengthPacket(image,bp,pixel,length,p);
1444
0
                if (image->previous == (Image *) NULL)
1445
0
                  if (QuantumTick(y,image->rows))
1446
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1447
0
                                                SaveImageText,image->filename,
1448
0
                                                image->columns,image->rows))
1449
0
                      break;
1450
0
              }
1451
0
              if (bp != buffer)
1452
0
                {
1453
0
                  (void) WriteBlob(image,bp-buffer,buffer);
1454
0
                  bp=buffer;
1455
0
                }
1456
0
              break;
1457
0
            }
1458
0
            case NoCompression:
1459
0
            default:
1460
0
            {
1461
              /*
1462
                Dump uncompressed DirectColor packets.
1463
              */
1464
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1465
0
                                    "Writing image as DirectColor "
1466
0
                                    "(uncompressed)...");
1467
0
              i=0;
1468
0
              bp=buffer;
1469
0
              for (y=0; y < (long) image->rows; y++)
1470
0
              {
1471
0
                p=AcquireImagePixels(image,0,y,image->columns,1,
1472
0
                  &image->exception);
1473
0
                if (p == (const PixelPacket *) NULL)
1474
0
                  break;
1475
0
                for (x=0; x < (long) image->columns; x++)
1476
0
                {
1477
0
                  if (image->matte && (p->opacity == TransparentOpacity))
1478
0
                    bp=AppendHexTriplet(bp,0xff,0xff,0xff);
1479
0
                  else
1480
0
                    bp=AppendHexTriplet(bp,
1481
0
                                        ScaleQuantumToChar(p->red),
1482
0
                                        ScaleQuantumToChar(p->green),
1483
0
                                        ScaleQuantumToChar(p->blue));
1484
0
                  i++;
1485
0
                  if (i == 12)
1486
0
                    {
1487
0
                      i=0;
1488
0
                      *bp++='\n';
1489
0
                      (void) WriteBlob(image,bp-buffer,buffer);
1490
0
                      bp=buffer;
1491
0
                    }
1492
0
                  p++;
1493
0
                }
1494
0
                if (image->previous == (Image *) NULL)
1495
0
                  if (QuantumTick(y,image->rows))
1496
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1497
0
                                                SaveImageText,image->filename,
1498
0
                                                image->columns,image->rows))
1499
0
                      break;
1500
0
              }
1501
0
              if (bp != buffer)
1502
0
                {
1503
0
                  *bp++='\n';
1504
0
                  (void) WriteBlob(image,bp-buffer,buffer);
1505
0
                  bp=buffer;
1506
0
                }
1507
0
              break;
1508
0
            }
1509
0
          }
1510
0
          (void) WriteBlobByte(image,'\n');
1511
0
        }
1512
0
      else
1513
0
        {
1514
          /*
1515
            Dump PseudoClass image.
1516
          */
1517
0
          FormatString(buffer,"%lu %lu\n%d\n%d\n0\n",image->columns,image->rows,
1518
0
            (int) (image->storage_class == PseudoClass),
1519
0
            (int) (image_info->compression == RLECompression));
1520
0
          (void) WriteBlobString(image,buffer);
1521
          /*
1522
            Dump number of colors and colormap.
1523
          */
1524
0
          FormatString(buffer,"%u\n",image->colors);
1525
0
          (void) WriteBlobString(image,buffer);
1526
0
          for (i=0; i < (long) image->colors; i++)
1527
0
          {
1528
0
            FormatString(buffer,"%02X%02X%02X\n",
1529
0
              ScaleQuantumToChar(image->colormap[i].red),
1530
0
              ScaleQuantumToChar(image->colormap[i].green),
1531
0
              ScaleQuantumToChar(image->colormap[i].blue));
1532
0
            (void) WriteBlobString(image,buffer);
1533
0
          }
1534
0
          switch (image_info->compression)
1535
0
          {
1536
0
            case RLECompression:
1537
0
            {
1538
              /*
1539
                Dump runlength-encoded PseudoColor packets.
1540
              */
1541
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1542
0
                                    "Writing image as PseudoColor "
1543
0
                                    "(%u colors, RLE compressed)...",
1544
0
                                    image->colors);
1545
0
              i=0;
1546
0
              bp=buffer;
1547
0
              for (y=0; y < (long) image->rows; y++)
1548
0
              {
1549
0
                p=AcquireImagePixels(image,0,y,image->columns,1,
1550
0
                  &image->exception);
1551
0
                if (p == (const PixelPacket *) NULL)
1552
0
                  break;
1553
0
                indexes=AccessImmutableIndexes(image);
1554
0
                index=(*indexes);
1555
0
                length=255;
1556
0
                for (x=0; x < (long) image->columns; x++)
1557
0
                {
1558
0
                  if ((index == indexes[x]) && (length < 255) &&
1559
0
                      (x < ((long) image->columns-1)))
1560
0
                    length++;
1561
0
                  else
1562
0
                    {
1563
0
                      if (x > 0)
1564
0
                        {
1565
0
                          bp=AppendHexVal(bp,index);
1566
0
                          bp=AppendHexVal(bp,Min(length,0xff));
1567
0
                          i++;
1568
0
                          if (i == 18)
1569
0
                            {
1570
0
                              *bp++='\n';
1571
0
                              (void) WriteBlob(image,bp-buffer,buffer);
1572
0
                              bp=buffer;
1573
0
                              i=0;
1574
0
                            }
1575
0
                        }
1576
0
                      length=0;
1577
0
                    }
1578
0
                  index=indexes[x];
1579
0
                  pixel=(*p);
1580
0
                  p++;
1581
0
                }
1582
0
                bp=AppendHexVal(bp,index);
1583
0
                bp=AppendHexVal(bp,Min(length,0xff));
1584
0
                if (image->previous == (Image *) NULL)
1585
0
                  if (QuantumTick(y,image->rows))
1586
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1587
0
                                                SaveImageText,image->filename,
1588
0
                                                image->columns,image->rows))
1589
0
                      break;
1590
0
              }
1591
0
              if (bp != buffer)
1592
0
              {
1593
0
                (void) WriteBlob(image,bp-buffer,buffer);
1594
0
                bp=buffer;
1595
0
              }
1596
0
              break;
1597
0
            }
1598
0
            case NoCompression:
1599
0
            default:
1600
0
            {
1601
              /*
1602
                Dump uncompressed PseudoColor packets.
1603
              */
1604
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1605
0
                                    "Writing image as PseudoColor "
1606
0
                                    "(%u colors, unompressed)...",
1607
0
                                    image->colors);
1608
0
              i=0;
1609
0
              bp=buffer;
1610
0
              for (y=0; y < (long) image->rows; y++)
1611
0
              {
1612
0
                p=AcquireImagePixels(image,0,y,image->columns,1,
1613
0
                  &image->exception);
1614
0
                if (p == (const PixelPacket *) NULL)
1615
0
                  break;
1616
0
                indexes=AccessImmutableIndexes(image);
1617
0
                for (x=0; x < (long) image->columns; x++)
1618
0
                {
1619
0
                  bp=AppendHexVal(bp,indexes[x]);
1620
0
                  i++;
1621
0
                  if (i == 36)
1622
0
                    {
1623
0
                      *bp++='\n';
1624
0
                      (void) WriteBlob(image,bp-buffer,buffer);
1625
0
                      bp=buffer;
1626
0
                      i=0;
1627
0
                    }
1628
0
                  p++;
1629
0
                }
1630
0
                if (image->previous == (Image *) NULL)
1631
0
                  if (QuantumTick(y,image->rows))
1632
0
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1633
0
                                                SaveImageText,image->filename,
1634
0
                                                image->columns,image->rows))
1635
0
                      break;
1636
0
              }
1637
0
              if (bp != buffer)
1638
0
                {
1639
0
                  (void) WriteBlob(image,bp-buffer,buffer);
1640
0
                  bp=buffer;
1641
0
                }
1642
0
              break;
1643
0
            }
1644
0
          }
1645
0
          (void) WriteBlobByte(image,'\n');
1646
0
        }
1647
0
    if (LocaleCompare(image_info->magick,"PS") != 0)
1648
0
      (void) WriteBlobString(image,"end\n");
1649
0
    (void) WriteBlobString(image,"%%PageTrailer\n");
1650
0
    if (image->next == (Image *) NULL)
1651
0
      break;
1652
0
    image=SyncNextImageInList(image);
1653
0
    if (!MagickMonitorFormatted(scene++,image_list_length,&image->exception,
1654
0
                                SaveImagesText,image->filename))
1655
0
      break;
1656
0
  } while (image_info->adjoin);
1657
0
  if (image_info->adjoin)
1658
0
    while (image->previous != (Image *) NULL)
1659
0
      image=image->previous;
1660
0
  (void) WriteBlobString(image,"%%Trailer\n");
1661
0
  if (page > 2)
1662
0
    {
1663
0
      FormatString(buffer,"%%%%BoundingBox: %g %g %g %g\n",floor(bounds.x1+0.5),
1664
0
        floor(bounds.y1+0.5),ceil(bounds.x2-0.5),ceil(bounds.y2-0.5));
1665
0
      (void) WriteBlobString(image,buffer);
1666
0
    }
1667
0
  (void) WriteBlobString(image,"%%EOF\n");
1668
0
  status &= CloseBlob(image);
1669
0
  return(status);
1670
0
}