blob: 9e014fe67b4005ad7d4a7e6d85eee3d74222358e [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% PPPP SSSSS 22222 %
7% P P SS 22 %
8% PPPP SSS 222 %
9% P SS 22 %
10% P SSSSS 22222 %
11% %
12% %
13% Write Postscript Level II Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/color.h"
47#include "magick/color-private.h"
48#include "magick/compress.h"
49#include "magick/constitute.h"
50#include "magick/draw.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/geometry.h"
54#include "magick/image.h"
55#include "magick/image-private.h"
56#include "magick/list.h"
57#include "magick/magick.h"
58#include "magick/memory_.h"
59#include "magick/monitor.h"
60#include "magick/monitor-private.h"
61#include "magick/monitor-private.h"
cristy47b838c2009-09-19 16:09:30 +000062#include "magick/option.h"
cristy3ed852e2009-09-05 21:47:34 +000063#include "magick/resource_.h"
64#include "magick/property.h"
65#include "magick/quantum-private.h"
66#include "magick/static.h"
67#include "magick/string_.h"
68#include "magick/module.h"
69#include "magick/utility.h"
cristy80975862009-09-25 14:34:31 +000070
71/*
72 Define declarations.
73*/
cristy3ed852e2009-09-05 21:47:34 +000074#if defined(MAGICKCORE_TIFF_DELEGATE)
75#define CCITTParam "-1"
76#else
77#define CCITTParam "0"
78#endif
79
80/*
81 Forward declarations.
82*/
83static MagickBooleanType
84 WritePS2Image(const ImageInfo *,Image *);
85
86/*
87%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88% %
89% %
90% %
91% R e g i s t e r P S 2 I m a g e %
92% %
93% %
94% %
95%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96%
97% RegisterPS2Image() adds properties for the PS2 image format to
98% the list of supported formats. The properties include the image format
99% tag, a method to read and/or write the format, whether the format
100% supports the saving of more than one frame to the same file or blob,
101% whether the format supports native in-memory I/O, and a brief
102% description of the format.
103%
104% The format of the RegisterPS2Image method is:
105%
cristybb503372010-05-27 20:51:26 +0000106% size_t RegisterPS2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000107%
108*/
cristybb503372010-05-27 20:51:26 +0000109ModuleExport size_t RegisterPS2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000110{
111 MagickInfo
112 *entry;
113
114 entry=SetMagickInfo("EPS2");
115 entry->encoder=(EncodeImageHandler *) WritePS2Image;
116 entry->adjoin=MagickFalse;
117 entry->seekable_stream=MagickTrue;
118 entry->description=ConstantString("Level II Encapsulated PostScript");
119 entry->module=ConstantString("PS2");
120 (void) RegisterMagickInfo(entry);
121 entry=SetMagickInfo("PS2");
122 entry->encoder=(EncodeImageHandler *) WritePS2Image;
123 entry->seekable_stream=MagickTrue;
124 entry->description=ConstantString("Level II PostScript");
125 entry->module=ConstantString("PS2");
126 (void) RegisterMagickInfo(entry);
127 return(MagickImageCoderSignature);
128}
129
130/*
131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132% %
133% %
134% %
135% U n r e g i s t e r P S 2 I m a g e %
136% %
137% %
138% %
139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140%
141% UnregisterPS2Image() removes format registrations made by the
142% PS2 module from the list of supported formats.
143%
144% The format of the UnregisterPS2Image method is:
145%
146% UnregisterPS2Image(void)
147%
148*/
149ModuleExport void UnregisterPS2Image(void)
150{
151 (void) UnregisterMagickInfo("EPS2");
152 (void) UnregisterMagickInfo("PS2");
153}
154
155/*
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157% %
158% %
159% %
160% W r i t e P S 2 I m a g e %
161% %
162% %
163% %
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165%
166% WritePS2Image translates an image to encapsulated Postscript
167% Level II for printing. If the supplied geometry is null, the image is
168% centered on the Postscript page. Otherwise, the image is positioned as
169% specified by the geometry.
170%
171% The format of the WritePS2Image method is:
172%
173% MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image)
174%
175% A description of each parameter follows:
176%
177% o image_info: the image info.
178%
179% o image: the image.
180%
181*/
cristy47b838c2009-09-19 16:09:30 +0000182
183static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
184 Image *image,Image *inject_image)
185{
cristy47b838c2009-09-19 16:09:30 +0000186 Image
cristy80975862009-09-25 14:34:31 +0000187 *group4_image;
cristy47b838c2009-09-19 16:09:30 +0000188
189 ImageInfo
190 *write_info;
191
cristy47b838c2009-09-19 16:09:30 +0000192 MagickBooleanType
193 status;
194
cristy80975862009-09-25 14:34:31 +0000195 size_t
196 length;
cristy47b838c2009-09-19 16:09:30 +0000197
198 unsigned char
cristy80975862009-09-25 14:34:31 +0000199 *group4;
cristy47b838c2009-09-19 16:09:30 +0000200
cristy42751fe2009-10-05 00:15:50 +0000201 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +0000202 write_info=CloneImageInfo(image_info);
cristy80975862009-09-25 14:34:31 +0000203 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
204 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
205 group4_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
206 if (group4_image == (Image *) NULL)
207 return(MagickFalse);
208 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
209 &image->exception);
210 group4_image=DestroyImage(group4_image);
211 if (group4 == (unsigned char *) NULL)
212 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +0000213 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +0000214 if (WriteBlob(image,length,group4) != (ssize_t) length)
215 status=MagickFalse;
216 group4=(unsigned char *) RelinquishMagickMemory(group4);
217 return(status);
cristy47b838c2009-09-19 16:09:30 +0000218}
219
cristy3ed852e2009-09-05 21:47:34 +0000220static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image)
221{
222 static const char
223 *PostscriptProlog[]=
224 {
225 "%%%%BeginProlog",
226 "%%",
227 "%% Display a color image. The image is displayed in color on",
228 "%% Postscript viewers or printers that support color, otherwise",
229 "%% it is displayed as grayscale.",
230 "%%",
231 "/DirectClassImage",
232 "{",
233 " %%",
234 " %% Display a DirectClass image.",
235 " %%",
236 " colorspace 0 eq",
237 " {",
238 " /DeviceRGB setcolorspace",
239 " <<",
240 " /ImageType 1",
241 " /Width columns",
242 " /Height rows",
243 " /BitsPerComponent 8",
244 " /Decode [0 1 0 1 0 1]",
245 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
246 " compression 0 gt",
cristy80975862009-09-25 14:34:31 +0000247 " { /DataSource pixel_stream %s }",
248 " { /DataSource pixel_stream %s } ifelse",
cristy3ed852e2009-09-05 21:47:34 +0000249 " >> image",
250 " }",
251 " {",
252 " /DeviceCMYK setcolorspace",
253 " <<",
254 " /ImageType 1",
255 " /Width columns",
256 " /Height rows",
257 " /BitsPerComponent 8",
258 " /Decode [1 0 1 0 1 0 1 0]",
259 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
260 " compression 0 gt",
cristy80975862009-09-25 14:34:31 +0000261 " { /DataSource pixel_stream %s }",
262 " { /DataSource pixel_stream %s } ifelse",
cristy3ed852e2009-09-05 21:47:34 +0000263 " >> image",
264 " } ifelse",
265 "} bind def",
266 "",
267 "/PseudoClassImage",
268 "{",
269 " %%",
270 " %% Display a PseudoClass image.",
271 " %%",
272 " %% Parameters:",
273 " %% colors: number of colors in the colormap.",
274 " %%",
275 " currentfile buffer readline pop",
276 " token pop /colors exch def pop",
277 " colors 0 eq",
278 " {",
279 " %%",
280 " %% Image is grayscale.",
281 " %%",
282 " currentfile buffer readline pop",
283 " token pop /bits exch def pop",
284 " /DeviceGray setcolorspace",
285 " <<",
286 " /ImageType 1",
287 " /Width columns",
288 " /Height rows",
289 " /BitsPerComponent bits",
290 " /Decode [0 1]",
291 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
292 " compression 0 gt",
cristy80975862009-09-25 14:34:31 +0000293 " { /DataSource pixel_stream %s }",
cristy3ed852e2009-09-05 21:47:34 +0000294 " {",
cristy80975862009-09-25 14:34:31 +0000295 " /DataSource pixel_stream %s",
cristy3ed852e2009-09-05 21:47:34 +0000296 " <<",
297 " /K "CCITTParam,
298 " /Columns columns",
299 " /Rows rows",
300 " >> /CCITTFaxDecode filter",
301 " } ifelse",
302 " >> image",
303 " }",
304 " {",
305 " %%",
306 " %% Parameters:",
307 " %% colormap: red, green, blue color packets.",
308 " %%",
309 " /colormap colors 3 mul string def",
310 " currentfile colormap readhexstring pop pop",
311 " currentfile buffer readline pop",
312 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace",
313 " <<",
314 " /ImageType 1",
315 " /Width columns",
316 " /Height rows",
317 " /BitsPerComponent 8",
318 " /Decode [0 255]",
319 " /ImageMatrix [columns 0 0 rows neg 0 rows]",
320 " compression 0 gt",
cristy80975862009-09-25 14:34:31 +0000321 " { /DataSource pixel_stream %s }",
322 " { /DataSource pixel_stream %s } ifelse",
cristy3ed852e2009-09-05 21:47:34 +0000323 " >> image",
324 " } ifelse",
325 "} bind def",
326 "",
327 "/DisplayImage",
328 "{",
329 " %%",
330 " %% Display a DirectClass or PseudoClass image.",
331 " %%",
332 " %% Parameters:",
333 " %% x & y translation.",
334 " %% x & y scale.",
335 " %% label pointsize.",
336 " %% image label.",
337 " %% image columns & rows.",
338 " %% class: 0-DirectClass or 1-PseudoClass.",
339 " %% colorspace: 0-RGB or 1-CMYK.",
340 " %% compression: 0-RLECompression or 1-NoCompression.",
341 " %% hex color packets.",
342 " %%",
343 " gsave",
344 " /buffer 512 string def",
345 " /pixel_stream currentfile def",
346 "",
347 " currentfile buffer readline pop",
348 " token pop /x exch def",
349 " token pop /y exch def pop",
350 " x y translate",
351 " currentfile buffer readline pop",
352 " token pop /x exch def",
353 " token pop /y exch def pop",
354 " currentfile buffer readline pop",
355 " token pop /pointsize exch def pop",
356 " /Helvetica findfont pointsize scalefont setfont",
357 (char *) NULL
358 },
359 *PostscriptEpilog[]=
360 {
361 " x y scale",
362 " currentfile buffer readline pop",
363 " token pop /columns exch def",
364 " token pop /rows exch def pop",
365 " currentfile buffer readline pop",
366 " token pop /class exch def pop",
367 " currentfile buffer readline pop",
368 " token pop /colorspace exch def pop",
369 " currentfile buffer readline pop",
370 " token pop /compression exch def pop",
371 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
372 (char *) NULL
373 };
374
375 char
376 buffer[MaxTextExtent],
377 date[MaxTextExtent],
378 page_geometry[MaxTextExtent],
379 **labels;
380
381 CompressionType
382 compression;
383
384 const char
385 **q,
386 *value;
387
388 double
389 pointsize;
390
391 GeometryInfo
392 geometry_info;
393
cristy3ed852e2009-09-05 21:47:34 +0000394 MagickOffsetType
395 scene,
396 start,
397 stop;
398
399 MagickBooleanType
400 progress,
401 status;
402
403 MagickOffsetType
404 offset;
405
406 MagickSizeType
407 number_pixels;
408
409 MagickStatusType
410 flags;
411
412 PointInfo
413 delta,
414 resolution,
415 scale;
416
417 RectangleInfo
418 geometry,
419 media_info,
420 page_info;
421
422 register const IndexPacket
423 *indexes;
424
425 register const PixelPacket
426 *p;
427
cristybb503372010-05-27 20:51:26 +0000428 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000429 x;
430
cristybb503372010-05-27 20:51:26 +0000431 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000432 i;
433
434 SegmentInfo
435 bounds;
436
437 size_t
cristy802d3642011-04-27 02:02:41 +0000438 length,
439 page,
440 text_size;
441
442 ssize_t
443 j,
444 y;
cristy3ed852e2009-09-05 21:47:34 +0000445
446 time_t
447 timer;
448
449 unsigned char
450 *pixels;
451
cristy3ed852e2009-09-05 21:47:34 +0000452 /*
453 Open output image file.
454 */
455 assert(image_info != (const ImageInfo *) NULL);
456 assert(image_info->signature == MagickSignature);
457 assert(image != (Image *) NULL);
458 assert(image->signature == MagickSignature);
459 if (image->debug != MagickFalse)
460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
461 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
462 if (status == MagickFalse)
463 return(status);
464 compression=image->compression;
465 if (image_info->compression != UndefinedCompression)
466 compression=image_info->compression;
467 switch (compression)
468 {
469#if !defined(MAGICKCORE_JPEG_DELEGATE)
470 case JPEGCompression:
471 {
472 compression=RLECompression;
473 (void) ThrowMagickException(&image->exception,GetMagickModule(),
474 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
475 image->filename);
476 break;
477 }
478#endif
479 default:
480 break;
481 }
482 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
483 page=1;
484 scene=0;
485 do
486 {
487 /*
488 Scale relative to dots-per-inch.
489 */
490 delta.x=DefaultResolution;
491 delta.y=DefaultResolution;
492 resolution.x=image->x_resolution;
493 resolution.y=image->y_resolution;
494 if ((resolution.x == 0.0) || (resolution.y == 0.0))
495 {
496 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
497 resolution.x=geometry_info.rho;
498 resolution.y=geometry_info.sigma;
499 if ((flags & SigmaValue) == 0)
500 resolution.y=resolution.x;
501 }
502 if (image_info->density != (char *) NULL)
503 {
504 flags=ParseGeometry(image_info->density,&geometry_info);
505 resolution.x=geometry_info.rho;
506 resolution.y=geometry_info.sigma;
507 if ((flags & SigmaValue) == 0)
508 resolution.y=resolution.x;
509 }
510 if (image->units == PixelsPerCentimeterResolution)
511 {
cristybb503372010-05-27 20:51:26 +0000512 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
513 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000514 }
515 SetGeometry(image,&geometry);
cristye8c25f92010-06-03 00:53:06 +0000516 (void) FormatMagickString(page_geometry,MaxTextExtent,"%.20gx%.20g",
517 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000518 if (image_info->page != (char *) NULL)
519 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
520 else
521 if ((image->page.width != 0) && (image->page.height != 0))
cristye8c25f92010-06-03 00:53:06 +0000522 (void) FormatMagickString(page_geometry,MaxTextExtent,
523 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
524 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +0000525 else
526 if ((image->gravity != UndefinedGravity) &&
527 (LocaleCompare(image_info->magick,"PS") == 0))
528 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
529 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
530 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
531 &geometry.width,&geometry.height);
532 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +0000533 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000534 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +0000535 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000536 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
537 (void) ParseGravityGeometry(image,page_geometry,&page_info,
538 &image->exception);
539 if (image->gravity != UndefinedGravity)
540 {
541 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +0000542 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000543 }
544 pointsize=12.0;
545 if (image_info->pointsize != 0.0)
546 pointsize=image_info->pointsize;
547 text_size=0;
548 value=GetImageProperty(image,"label");
549 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +0000550 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +0000551 if (page == 1)
552 {
553 /*
554 Output Postscript header.
555 */
556 if (LocaleCompare(image_info->magick,"PS2") == 0)
557 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MaxTextExtent);
558 else
559 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n",
560 MaxTextExtent);
561 (void) WriteBlobString(image,buffer);
562 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
563 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Title: (%s)\n",
564 image->filename);
565 (void) WriteBlobString(image,buffer);
566 timer=time((time_t *) NULL);
567 (void) FormatMagickTime(timer,MaxTextExtent,date);
568 (void) FormatMagickString(buffer,MaxTextExtent,
569 "%%%%CreationDate: (%s)\n",date);
570 (void) WriteBlobString(image,buffer);
571 bounds.x1=(double) geometry.x;
572 bounds.y1=(double) geometry.y;
573 bounds.x2=(double) geometry.x+geometry.width;
574 bounds.y2=(double) geometry.y+geometry.height+text_size;
575 if ((image_info->adjoin != MagickFalse) &&
576 (GetNextImageInList(image) != (Image *) NULL))
577 (void) CopyMagickString(buffer,"%%BoundingBox: (atend)\n",
578 MaxTextExtent);
579 else
580 {
581 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000582 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
583 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
cristy3ed852e2009-09-05 21:47:34 +0000584 (void) WriteBlobString(image,buffer);
585 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +0000586 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,
cristy8cd5b312010-01-07 01:10:24 +0000587 bounds.y1,bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +0000588 }
589 (void) WriteBlobString(image,buffer);
590 value=GetImageProperty(image,"label");
591 if (value != (const char *) NULL)
592 (void) WriteBlobString(image,
593 "%%DocumentNeededResources: font Helvetica\n");
594 (void) WriteBlobString(image,"%%LanguageLevel: 2\n");
595 if (LocaleCompare(image_info->magick,"PS2") != 0)
596 (void) WriteBlobString(image,"%%Pages: 1\n");
597 else
598 {
599 (void) WriteBlobString(image,"%%Orientation: Portrait\n");
600 (void) WriteBlobString(image,"%%PageOrder: Ascend\n");
601 if (image_info->adjoin == MagickFalse)
602 (void) CopyMagickString(buffer,"%%Pages: 1\n",MaxTextExtent);
603 else
cristye8c25f92010-06-03 00:53:06 +0000604 (void) FormatMagickString(buffer,MaxTextExtent,
605 "%%%%Pages: %.20g\n",(double) GetImageListLength(image));
cristy3ed852e2009-09-05 21:47:34 +0000606 (void) WriteBlobString(image,buffer);
607 }
608 (void) WriteBlobString(image,"%%EndComments\n");
609 (void) WriteBlobString(image,"\n%%BeginDefaults\n");
610 (void) WriteBlobString(image,"%%EndDefaults\n\n");
611 /*
612 Output Postscript commands.
613 */
614 for (q=PostscriptProlog; *q; q++)
615 {
616 switch (compression)
617 {
618 case NoCompression:
619 {
620 (void) FormatMagickString(buffer,MaxTextExtent,*q,
cristy80975862009-09-25 14:34:31 +0000621 "/ASCII85Decode filter");
cristy3ed852e2009-09-05 21:47:34 +0000622 break;
623 }
624 case JPEGCompression:
625 {
cristy80975862009-09-25 14:34:31 +0000626 (void) FormatMagickString(buffer,MaxTextExtent,*q,
627 "/DCTDecode filter");
cristy3ed852e2009-09-05 21:47:34 +0000628 break;
629 }
630 case LZWCompression:
631 {
cristy80975862009-09-25 14:34:31 +0000632 (void) FormatMagickString(buffer,MaxTextExtent,*q,
633 "/LZWDecode filter");
cristy3ed852e2009-09-05 21:47:34 +0000634 break;
635 }
636 case FaxCompression:
637 case Group4Compression:
638 {
cristy80975862009-09-25 14:34:31 +0000639 (void) FormatMagickString(buffer,MaxTextExtent,*q," ");
cristy3ed852e2009-09-05 21:47:34 +0000640 break;
641 }
642 default:
643 {
644 (void) FormatMagickString(buffer,MaxTextExtent,*q,
cristy80975862009-09-25 14:34:31 +0000645 "/RunLengthDecode filter");
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 }
649 (void) WriteBlobString(image,buffer);
650 (void) WriteBlobByte(image,'\n');
651 }
652 value=GetImageProperty(image,"label");
653 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +0000654 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--)
cristy3ed852e2009-09-05 21:47:34 +0000655 {
656 (void) WriteBlobString(image," /label 512 string def\n");
657 (void) WriteBlobString(image," currentfile label readline pop\n");
658 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +0000659 " 0 y %g add moveto label show pop\n",j*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +0000660 (void) WriteBlobString(image,buffer);
661 }
662 for (q=PostscriptEpilog; *q; q++)
663 {
664 (void) FormatMagickString(buffer,MaxTextExtent,"%s\n",*q);
665 (void) WriteBlobString(image,buffer);
666 }
667 if (LocaleCompare(image_info->magick,"PS2") == 0)
668 (void) WriteBlobString(image," showpage\n");
669 (void) WriteBlobString(image,"} bind def\n");
670 (void) WriteBlobString(image,"%%EndProlog\n");
671 }
cristye8c25f92010-06-03 00:53:06 +0000672 (void) FormatMagickString(buffer,MaxTextExtent,"%%%%Page: 1 %.20g\n",
673 (double) page++);
cristy3ed852e2009-09-05 21:47:34 +0000674 (void) WriteBlobString(image,buffer);
675 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000676 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x,
677 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double)
cristy3ed852e2009-09-05 21:47:34 +0000678 (geometry.height+text_size));
679 (void) WriteBlobString(image,buffer);
680 if ((double) geometry.x < bounds.x1)
681 bounds.x1=(double) geometry.x;
682 if ((double) geometry.y < bounds.y1)
683 bounds.y1=(double) geometry.y;
684 if ((double) (geometry.x+geometry.width-1) > bounds.x2)
685 bounds.x2=(double) geometry.x+geometry.width-1;
686 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2)
687 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1;
688 value=GetImageProperty(image,"label");
689 if (value != (const char *) NULL)
690 (void) WriteBlobString(image,"%%PageResources: font Times-Roman\n");
691 if (LocaleCompare(image_info->magick,"PS2") != 0)
692 (void) WriteBlobString(image,"userdict begin\n");
693 start=TellBlob(image);
694 (void) FormatMagickString(buffer,MaxTextExtent,
695 "%%%%BeginData:%13ld %s Bytes\n",0L,
696 compression == NoCompression ? "ASCII" : "Binary");
697 (void) WriteBlobString(image,buffer);
698 stop=TellBlob(image);
699 (void) WriteBlobString(image,"DisplayImage\n");
700 /*
701 Output image data.
702 */
cristye8c25f92010-06-03 00:53:06 +0000703 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n%g %g\n%g\n",
704 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize);
cristy3ed852e2009-09-05 21:47:34 +0000705 (void) WriteBlobString(image,buffer);
706 labels=(char **) NULL;
707 value=GetImageProperty(image,"label");
708 if (value != (const char *) NULL)
709 labels=StringToList(value);
710 if (labels != (char **) NULL)
711 {
712 for (i=0; labels[i] != (char *) NULL; i++)
713 {
714 (void) FormatMagickString(buffer,MaxTextExtent,"%s \n",
715 labels[i]);
716 (void) WriteBlobString(image,buffer);
717 labels[i]=DestroyString(labels[i]);
718 }
719 labels=(char **) RelinquishMagickMemory(labels);
720 }
721 number_pixels=(MagickSizeType) image->columns*image->rows;
722 if (number_pixels != (MagickSizeType) ((size_t) number_pixels))
723 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
724 if ((compression == FaxCompression) || (compression == Group4Compression) ||
725 ((image_info->type != TrueColorType) &&
726 (IsGrayImage(image,&image->exception) != MagickFalse)))
727 {
cristye8c25f92010-06-03 00:53:06 +0000728 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n1\n%d\n",
729 (double) image->columns,(double) image->rows,(int)
cristy3ed852e2009-09-05 21:47:34 +0000730 (image->colorspace == CMYKColorspace));
731 (void) WriteBlobString(image,buffer);
732 (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
733 (int) ((compression != FaxCompression) &&
734 (compression != Group4Compression)));
735 (void) WriteBlobString(image,buffer);
736 (void) WriteBlobString(image,"0\n");
737 (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
738 (compression == FaxCompression) ||
739 (compression == Group4Compression) ? 1 : 8);
740 (void) WriteBlobString(image,buffer);
741 switch (compression)
742 {
743 case FaxCompression:
744 case Group4Compression:
745 {
746 if (LocaleCompare(CCITTParam,"0") == 0)
747 {
748 (void) HuffmanEncodeImage(image_info,image,image);
749 break;
750 }
cristy3ed852e2009-09-05 21:47:34 +0000751 (void) Huffman2DEncodeImage(image_info,image,image);
cristy3ed852e2009-09-05 21:47:34 +0000752 break;
753 }
754 case JPEGCompression:
755 {
756 status=InjectImageBlob(image_info,image,image,"jpeg",
757 &image->exception);
758 if (status == MagickFalse)
759 ThrowWriterException(CoderError,image->exception.reason);
760 break;
761 }
762 case RLECompression:
763 default:
764 {
765 register unsigned char
766 *q;
767
768 /*
769 Allocate pixel array.
770 */
771 length=(size_t) number_pixels;
772 pixels=(unsigned char *) AcquireQuantumMemory(length,
773 sizeof(*pixels));
774 if (pixels == (unsigned char *) NULL)
775 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
776 /*
777 Dump Runlength encoded pixels.
778 */
779 q=pixels;
cristybb503372010-05-27 20:51:26 +0000780 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000781 {
782 p=GetVirtualPixels(image,0,y,image->columns,1,
783 &image->exception);
784 if (p == (const PixelPacket *) NULL)
785 break;
cristybb503372010-05-27 20:51:26 +0000786 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000787 {
788 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
789 p++;
790 }
cristy802d3642011-04-27 02:02:41 +0000791 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
792 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000793 if (progress == MagickFalse)
794 break;
795 }
796 length=(size_t) (q-pixels);
797 if (compression == LZWCompression)
798 status=LZWEncodeImage(image,length,pixels);
799 else
800 status=PackbitsEncodeImage(image,length,pixels);
801 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
802 if (status == MagickFalse)
803 {
804 (void) CloseBlob(image);
805 return(MagickFalse);
806 }
807 break;
808 }
809 case NoCompression:
810 {
811 /*
812 Dump uncompressed PseudoColor packets.
813 */
814 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +0000815 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000816 {
817 p=GetVirtualPixels(image,0,y,image->columns,1,
818 &image->exception);
819 if (p == (const PixelPacket *) NULL)
820 break;
cristybb503372010-05-27 20:51:26 +0000821 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000822 {
cristy802d3642011-04-27 02:02:41 +0000823 Ascii85Encode(image,ScaleQuantumToChar(
824 PixelIntensityToQuantum(p)));
cristy3ed852e2009-09-05 21:47:34 +0000825 p++;
826 }
cristye8c25f92010-06-03 00:53:06 +0000827 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
828 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000829 if (progress == MagickFalse)
830 break;
831 }
832 Ascii85Flush(image);
833 break;
834 }
835 }
836 }
837 else
838 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
839 (compression == JPEGCompression) || (image->matte != MagickFalse))
840 {
cristye8c25f92010-06-03 00:53:06 +0000841 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n0\n%d\n",
842 (double) image->columns,(double) image->rows,(int)
cristy3ed852e2009-09-05 21:47:34 +0000843 (image->colorspace == CMYKColorspace));
844 (void) WriteBlobString(image,buffer);
845 (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
846 (int) (compression == NoCompression));
847 (void) WriteBlobString(image,buffer);
848 switch (compression)
849 {
850 case JPEGCompression:
851 {
852 status=InjectImageBlob(image_info,image,image,"jpeg",
853 &image->exception);
854 if (status == MagickFalse)
855 ThrowWriterException(CoderError,image->exception.reason);
856 break;
857 }
858 case RLECompression:
859 default:
860 {
861 register unsigned char
862 *q;
863
864 /*
865 Allocate pixel array.
866 */
867 length=(size_t) number_pixels;
868 pixels=(unsigned char *) AcquireQuantumMemory(length,
869 4*sizeof(*pixels));
870 if (pixels == (unsigned char *) NULL)
871 ThrowWriterException(ResourceLimitError,
872 "MemoryAllocationFailed");
873 /*
874 Dump Packbit encoded pixels.
875 */
876 q=pixels;
cristybb503372010-05-27 20:51:26 +0000877 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000878 {
879 p=GetVirtualPixels(image,0,y,image->columns,1,
880 &image->exception);
881 if (p == (const PixelPacket *) NULL)
882 break;
883 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +0000884 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000885 {
886 if ((image->matte != MagickFalse) &&
cristyd05ecd12011-04-22 20:44:42 +0000887 (GetOpacityPixelComponent(p) == (Quantum) TransparentOpacity))
cristy3ed852e2009-09-05 21:47:34 +0000888 {
889 *q++=ScaleQuantumToChar((Quantum) QuantumRange);
890 *q++=ScaleQuantumToChar((Quantum) QuantumRange);
891 *q++=ScaleQuantumToChar((Quantum) QuantumRange);
892 }
893 else
894 if (image->colorspace != CMYKColorspace)
895 {
cristyce70c172010-01-07 17:15:30 +0000896 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
897 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
898 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000899 }
900 else
901 {
cristyce70c172010-01-07 17:15:30 +0000902 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
903 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
904 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy802d3642011-04-27 02:02:41 +0000905 *q++=ScaleQuantumToChar(GetIndexPixelComponent(
906 indexes+x));
cristy3ed852e2009-09-05 21:47:34 +0000907 }
908 p++;
909 }
cristy802d3642011-04-27 02:02:41 +0000910 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
911 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000912 if (progress == MagickFalse)
913 break;
914 }
915 length=(size_t) (q-pixels);
916 if (compression == LZWCompression)
917 status=LZWEncodeImage(image,length,pixels);
918 else
919 status=PackbitsEncodeImage(image,length,pixels);
920 if (status == MagickFalse)
921 {
922 (void) CloseBlob(image);
923 return(MagickFalse);
924 }
925 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
926 break;
927 }
928 case NoCompression:
929 {
930 /*
931 Dump uncompressed DirectColor packets.
932 */
933 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +0000934 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000935 {
936 p=GetVirtualPixels(image,0,y,image->columns,1,
937 &image->exception);
938 if (p == (const PixelPacket *) NULL)
939 break;
940 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +0000941 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000942 {
943 if ((image->matte != MagickFalse) &&
cristyd05ecd12011-04-22 20:44:42 +0000944 (GetOpacityPixelComponent(p) == (Quantum) TransparentOpacity))
cristy3ed852e2009-09-05 21:47:34 +0000945 {
946 Ascii85Encode(image,ScaleQuantumToChar((Quantum)
947 QuantumRange));
948 Ascii85Encode(image,ScaleQuantumToChar((Quantum)
949 QuantumRange));
950 Ascii85Encode(image,ScaleQuantumToChar((Quantum)
951 QuantumRange));
952 }
953 else
954 if (image->colorspace != CMYKColorspace)
955 {
cristy802d3642011-04-27 02:02:41 +0000956 Ascii85Encode(image,ScaleQuantumToChar(
957 GetRedPixelComponent(p)));
958 Ascii85Encode(image,ScaleQuantumToChar(
959 GetGreenPixelComponent(p)));
960 Ascii85Encode(image,ScaleQuantumToChar(
961 GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +0000962 }
963 else
964 {
cristy802d3642011-04-27 02:02:41 +0000965 Ascii85Encode(image,ScaleQuantumToChar(
966 GetRedPixelComponent(p)));
967 Ascii85Encode(image,ScaleQuantumToChar(
968 GetGreenPixelComponent(p)));
969 Ascii85Encode(image,ScaleQuantumToChar(
970 GetBluePixelComponent(p)));
cristy9fff7b42011-04-29 01:09:31 +0000971 Ascii85Encode(image,ScaleQuantumToChar(
972 GetIndexPixelComponent(indexes+x)));
cristy3ed852e2009-09-05 21:47:34 +0000973 }
974 p++;
975 }
cristy802d3642011-04-27 02:02:41 +0000976 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
977 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000978 if (progress == MagickFalse)
979 break;
980 }
981 Ascii85Flush(image);
982 break;
983 }
984 }
985 }
986 else
987 {
988 /*
989 Dump number of colors and colormap.
990 */
cristye8c25f92010-06-03 00:53:06 +0000991 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g\n1\n%d\n",
992 (double) image->columns,(double) image->rows,(int)
cristy3ed852e2009-09-05 21:47:34 +0000993 (image->colorspace == CMYKColorspace));
994 (void) WriteBlobString(image,buffer);
995 (void) FormatMagickString(buffer,MaxTextExtent,"%d\n",
996 (int) (compression == NoCompression));
997 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +0000998 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +0000999 image->colors);
cristy3ed852e2009-09-05 21:47:34 +00001000 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001001 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001002 {
1003 (void) FormatMagickString(buffer,MaxTextExtent,"%02X%02X%02X\n",
1004 ScaleQuantumToChar(image->colormap[i].red),
1005 ScaleQuantumToChar(image->colormap[i].green),
1006 ScaleQuantumToChar(image->colormap[i].blue));
1007 (void) WriteBlobString(image,buffer);
1008 }
1009 switch (compression)
1010 {
1011 case RLECompression:
1012 default:
1013 {
1014 register unsigned char
1015 *q;
1016
1017 /*
1018 Allocate pixel array.
1019 */
1020 length=(size_t) number_pixels;
1021 pixels=(unsigned char *) AcquireQuantumMemory(length,
1022 sizeof(*pixels));
1023 if (pixels == (unsigned char *) NULL)
1024 ThrowWriterException(ResourceLimitError,
1025 "MemoryAllocationFailed");
1026 /*
1027 Dump Runlength encoded pixels.
1028 */
1029 q=pixels;
cristybb503372010-05-27 20:51:26 +00001030 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001031 {
1032 p=GetVirtualPixels(image,0,y,image->columns,1,
1033 &image->exception);
1034 if (p == (const PixelPacket *) NULL)
1035 break;
1036 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001037 for (x=0; x < (ssize_t) image->columns; x++)
cristy4e82e512011-04-24 01:33:42 +00001038 *q++=(unsigned char) GetIndexPixelComponent(indexes+x);
cristy802d3642011-04-27 02:02:41 +00001039 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1040 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001041 if (progress == MagickFalse)
1042 break;
1043 }
1044 length=(size_t) (q-pixels);
1045 if (compression == LZWCompression)
1046 status=LZWEncodeImage(image,length,pixels);
1047 else
1048 status=PackbitsEncodeImage(image,length,pixels);
1049 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1050 if (status == MagickFalse)
1051 {
1052 (void) CloseBlob(image);
1053 return(MagickFalse);
1054 }
1055 break;
1056 }
1057 case NoCompression:
1058 {
1059 /*
1060 Dump uncompressed PseudoColor packets.
1061 */
1062 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001063 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001064 {
1065 p=GetVirtualPixels(image,0,y,image->columns,1,
1066 &image->exception);
1067 if (p == (const PixelPacket *) NULL)
1068 break;
1069 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001070 for (x=0; x < (ssize_t) image->columns; x++)
cristy802d3642011-04-27 02:02:41 +00001071 Ascii85Encode(image,(unsigned char) GetIndexPixelComponent(
1072 indexes+x));
1073 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1074 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001075 if (progress == MagickFalse)
1076 break;
1077 }
1078 Ascii85Flush(image);
1079 break;
1080 }
1081 }
1082 }
1083 (void) WriteBlobByte(image,'\n');
1084 length=(size_t) (TellBlob(image)-stop);
1085 stop=TellBlob(image);
1086 offset=SeekBlob(image,start,SEEK_SET);
1087 if (offset < 0)
1088 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1089 (void) FormatMagickString(buffer,MaxTextExtent,
cristyf2faecf2010-05-28 19:19:36 +00001090 "%%%%BeginData:%13ld %s Bytes\n",(long) length,
cristy3ed852e2009-09-05 21:47:34 +00001091 compression == NoCompression ? "ASCII" : "Binary");
1092 (void) WriteBlobString(image,buffer);
1093 offset=SeekBlob(image,stop,SEEK_SET);
1094 (void) WriteBlobString(image,"%%EndData\n");
1095 if (LocaleCompare(image_info->magick,"PS2") != 0)
1096 (void) WriteBlobString(image,"end\n");
1097 (void) WriteBlobString(image,"%%PageTrailer\n");
1098 if (GetNextImageInList(image) == (Image *) NULL)
1099 break;
1100 image=SyncNextImageInList(image);
1101 status=SetImageProgress(image,SaveImagesTag,scene++,
1102 GetImageListLength(image));
1103 if (status == MagickFalse)
1104 break;
1105 } while (image_info->adjoin != MagickFalse);
1106 (void) WriteBlobString(image,"%%Trailer\n");
1107 if (page > 1)
1108 {
1109 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001110 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5),
1111 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5));
cristy3ed852e2009-09-05 21:47:34 +00001112 (void) WriteBlobString(image,buffer);
1113 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001114 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +00001115 bounds.x2,bounds.y2);
cristy3ed852e2009-09-05 21:47:34 +00001116 (void) WriteBlobString(image,buffer);
1117 }
1118 (void) WriteBlobString(image,"%%EOF\n");
1119 (void) CloseBlob(image);
1120 return(MagickTrue);
1121}