blob: fcb993e3f12ef12030f5d4e67b19dc75d3677a8b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% PPPP DDDD FFFFF %
7% P P D D F %
8% PPPP D D FFF %
9% P D D F %
10% P DDDD F %
11% %
12% %
13% Read/Write Portable Document Format %
14% %
15% Software Design %
16% 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/colorspace.h"
49#include "magick/compress.h"
50#include "magick/constitute.h"
51#include "magick/delegate.h"
52#include "magick/delegate-private.h"
53#include "magick/draw.h"
54#include "magick/exception.h"
55#include "magick/exception-private.h"
56#include "magick/geometry.h"
57#include "magick/image.h"
58#include "magick/image-private.h"
59#include "magick/list.h"
60#include "magick/magick.h"
61#include "magick/memory_.h"
62#include "magick/monitor.h"
63#include "magick/monitor-private.h"
64#include "magick/option.h"
65#include "magick/profile.h"
66#include "magick/property.h"
67#include "magick/quantum-private.h"
68#include "magick/resource_.h"
69#include "magick/resize.h"
70#include "magick/static.h"
71#include "magick/string_.h"
72#include "magick/module.h"
73#include "magick/transform.h"
74#include "magick/utility.h"
75#include "magick/module.h"
cristy80975862009-09-25 14:34:31 +000076
77/*
78 Define declarations.
79*/
cristy3ed852e2009-09-05 21:47:34 +000080#if defined(MAGICKCORE_TIFF_DELEGATE)
81#define CCITTParam "-1"
82#else
83#define CCITTParam "0"
84#endif
85
86/*
87 Forward declarations.
88*/
89static MagickBooleanType
90 WritePDFImage(const ImageInfo *,Image *);
91
92/*
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94% %
95% %
96% %
cristydefb3f02009-09-10 02:18:35 +000097% I n v o k e P D F D e l e g a t e %
cristy3ed852e2009-09-05 21:47:34 +000098% %
99% %
100% %
101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102%
cristydefb3f02009-09-10 02:18:35 +0000103% InvokePDFDelegate() executes the PDF interpreter with the specified command.
cristy3ed852e2009-09-05 21:47:34 +0000104%
cristydefb3f02009-09-10 02:18:35 +0000105% The format of the InvokePDFDelegate method is:
cristy3ed852e2009-09-05 21:47:34 +0000106%
cristydefb3f02009-09-10 02:18:35 +0000107% MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
108% const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000109%
110% A description of each parameter follows:
111%
112% o verbose: A value other than zero displays the command prior to
113% executing it.
114%
115% o command: the address of a character string containing the command to
116% execute.
117%
cristyb32b90a2009-09-07 21:45:48 +0000118% o exception: return any errors or warnings in this structure.
119%
cristy3ed852e2009-09-05 21:47:34 +0000120*/
cristydefb3f02009-09-10 02:18:35 +0000121static MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
122 const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000123{
cristyb32b90a2009-09-07 21:45:48 +0000124 int
125 status;
126
cristy0157aea2010-04-24 21:12:18 +0000127#if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000128 char
129 **argv;
130
cristydefb3f02009-09-10 02:18:35 +0000131 const GhostInfo
132 *ghost_info;
cristy3ed852e2009-09-05 21:47:34 +0000133
134 gs_main_instance
135 *interpreter;
136
137 int
138 argc,
cristyb32b90a2009-09-07 21:45:48 +0000139 code;
cristy3ed852e2009-09-05 21:47:34 +0000140
cristybb503372010-05-27 20:51:26 +0000141 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000142 i;
143
cristy0157aea2010-04-24 21:12:18 +0000144#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristydefb3f02009-09-10 02:18:35 +0000145 ghost_info=NTGhostscriptDLLVectors();
cristy3ed852e2009-09-05 21:47:34 +0000146#else
cristydefb3f02009-09-10 02:18:35 +0000147 GhostInfo
148 ghost_info_struct;
cristy3ed852e2009-09-05 21:47:34 +0000149
cristydefb3f02009-09-10 02:18:35 +0000150 ghost_info=(&ghost_info_struct);
151 (void) ResetMagickMemory(&ghost_info,0,sizeof(ghost_info));
152 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
cristy3ed852e2009-09-05 21:47:34 +0000153 gsapi_new_instance;
cristydefb3f02009-09-10 02:18:35 +0000154 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
cristy3ed852e2009-09-05 21:47:34 +0000155 gsapi_init_with_args;
cristydefb3f02009-09-10 02:18:35 +0000156 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
157 int *)) gsapi_run_string;
158 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
cristy3ed852e2009-09-05 21:47:34 +0000159 gsapi_delete_instance;
cristydefb3f02009-09-10 02:18:35 +0000160 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
cristy3ed852e2009-09-05 21:47:34 +0000161#endif
cristydefb3f02009-09-10 02:18:35 +0000162 if (ghost_info == (GhostInfo *) NULL)
cristyb32b90a2009-09-07 21:45:48 +0000163 {
cristy6de4bc22010-01-12 17:10:35 +0000164 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000165 return(status == 0 ? MagickTrue : MagickFalse);
cristyb32b90a2009-09-07 21:45:48 +0000166 }
cristy3ed852e2009-09-05 21:47:34 +0000167 if (verbose != MagickFalse)
168 {
169 (void) fputs("[ghostscript library]",stdout);
170 (void) fputs(strchr(command,' '),stdout);
171 }
cristydefb3f02009-09-10 02:18:35 +0000172 status=(ghost_info->new_instance)(&interpreter,(void *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000173 if (status < 0)
cristyb32b90a2009-09-07 21:45:48 +0000174 {
cristy6de4bc22010-01-12 17:10:35 +0000175 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000176 return(status == 0 ? MagickTrue : MagickFalse);
cristyb32b90a2009-09-07 21:45:48 +0000177 }
cristya73c0f82010-12-20 15:57:05 +0000178 code=0;
cristy3ed852e2009-09-05 21:47:34 +0000179 argv=StringToArgv(command,&argc);
cristydefb3f02009-09-10 02:18:35 +0000180 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
cristy3ed852e2009-09-05 21:47:34 +0000181 if (status == 0)
cristydefb3f02009-09-10 02:18:35 +0000182 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
183 0,&code);
184 (ghost_info->exit)(interpreter);
185 (ghost_info->delete_instance)(interpreter);
cristy0157aea2010-04-24 21:12:18 +0000186#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000187 NTGhostscriptUnLoadDLL();
188#endif
cristybb503372010-05-27 20:51:26 +0000189 for (i=0; i < (ssize_t) argc; i++)
cristy3ed852e2009-09-05 21:47:34 +0000190 argv[i]=DestroyString(argv[i]);
191 argv=(char **) RelinquishMagickMemory(argv);
cristy41083a42009-09-07 23:47:59 +0000192 if ((status != 0) && (status != -101))
193 {
194 char
195 *message;
cristyb32b90a2009-09-07 21:45:48 +0000196
cristy41083a42009-09-07 23:47:59 +0000197 message=GetExceptionMessage(errno);
198 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
199 "`%s': %s",command,message);
200 message=DestroyString(message);
201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
202 "Ghostscript returns status %d, exit code %d",status,code);
203 return(MagickFalse);
204 }
cristy3ed852e2009-09-05 21:47:34 +0000205 return(MagickTrue);
206#else
cristy6de4bc22010-01-12 17:10:35 +0000207 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000208 return(status == 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000209#endif
210}
211
212/*
213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214% %
215% %
216% %
217% I s P D F %
218% %
219% %
220% %
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222%
223% IsPDF() returns MagickTrue if the image format type, identified by the
224% magick string, is PDF.
225%
226% The format of the IsPDF method is:
227%
228% MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
229%
230% A description of each parameter follows:
231%
232% o magick: compare image format pattern against these bytes.
233%
234% o offset: Specifies the offset of the magick string.
235%
236*/
237static MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
238{
239 if (offset < 5)
240 return(MagickFalse);
cristy41083a42009-09-07 23:47:59 +0000241 if (LocaleNCompare((const char *) magick,"%PDF-",5) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000242 return(MagickTrue);
243 return(MagickFalse);
244}
245
246/*
247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248% %
249% %
250% %
251% R e a d P D F I m a g e %
252% %
253% %
254% %
255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256%
257% ReadPDFImage() reads a Portable Document Format image file and
258% returns it. It allocates the memory necessary for the new Image structure
259% and returns a pointer to the new image.
260%
261% The format of the ReadPDFImage method is:
262%
263% Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
264%
265% A description of each parameter follows:
266%
267% o image_info: the image info.
268%
269% o exception: return any errors or warnings in this structure.
270%
271*/
272
273static MagickBooleanType IsPDFRendered(const char *path)
274{
275 MagickBooleanType
276 status;
277
278 struct stat
279 attributes;
280
281 if ((path == (const char *) NULL) || (*path == '\0'))
282 return(MagickFalse);
283 status=GetPathAttributes(path,&attributes);
284 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
285 (attributes.st_size > 0))
286 return(MagickTrue);
287 return(MagickFalse);
288}
289
290static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
291{
292#define CropBox "CropBox"
293#define DeviceCMYK "DeviceCMYK"
294#define MediaBox "MediaBox"
295#define RenderPostscriptText "Rendering Postscript... "
296#define PDFRotate "Rotate"
297#define SpotColor "Separation"
298#define TrimBox "TrimBox"
299#define PDFVersion "PDF-"
300
301 char
302 command[MaxTextExtent],
303 density[MaxTextExtent],
304 filename[MaxTextExtent],
305 geometry[MaxTextExtent],
306 options[MaxTextExtent],
307 input_filename[MaxTextExtent],
308 postscript_filename[MaxTextExtent];
309
310 const char
311 *option;
312
313 const DelegateInfo
314 *delegate_info;
315
316 double
317 angle;
318
cristydba40d42010-03-25 18:31:50 +0000319 GeometryInfo
320 geometry_info;
321
cristy3ed852e2009-09-05 21:47:34 +0000322 Image
323 *image,
324 *next,
325 *pdf_image;
326
327 ImageInfo
328 *read_info;
329
330 int
cristya97426c2011-02-04 01:41:27 +0000331 c,
cristy3ed852e2009-09-05 21:47:34 +0000332 file;
333
334 MagickBooleanType
335 cmyk,
336 cropbox,
337 trimbox,
338 status;
339
cristydba40d42010-03-25 18:31:50 +0000340 MagickStatusType
341 flags;
342
cristy3ed852e2009-09-05 21:47:34 +0000343 PointInfo
344 delta;
345
346 RectangleInfo
347 bounding_box,
348 page;
349
350 register char
351 *p;
352
cristya97426c2011-02-04 01:41:27 +0000353 register ssize_t
354 i;
cristy3ed852e2009-09-05 21:47:34 +0000355
356 SegmentInfo
357 bounds,
358 hires_bounds;
359
360 ssize_t
361 count;
362
cristybb503372010-05-27 20:51:26 +0000363 size_t
cristy3ed852e2009-09-05 21:47:34 +0000364 scene,
365 spotcolor;
366
367 assert(image_info != (const ImageInfo *) NULL);
368 assert(image_info->signature == MagickSignature);
369 if (image_info->debug != MagickFalse)
370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
371 image_info->filename);
372 assert(exception != (ExceptionInfo *) NULL);
373 assert(exception->signature == MagickSignature);
374 /*
375 Open image file.
376 */
377 image=AcquireImage(image_info);
378 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
379 if (status == MagickFalse)
380 {
381 image=DestroyImageList(image);
382 return((Image *) NULL);
383 }
384 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
385 if (status == MagickFalse)
386 {
387 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
388 image_info->filename);
389 image=DestroyImageList(image);
390 return((Image *) NULL);
391 }
392 /*
393 Set the page density.
394 */
395 delta.x=DefaultResolution;
396 delta.y=DefaultResolution;
397 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
398 {
cristy3ed852e2009-09-05 21:47:34 +0000399 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
400 image->x_resolution=geometry_info.rho;
401 image->y_resolution=geometry_info.sigma;
402 if ((flags & SigmaValue) == 0)
403 image->y_resolution=image->x_resolution;
404 }
405 /*
406 Determine page geometry from the PDF media box.
407 */
408 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
409 cropbox=MagickFalse;
410 option=GetImageOption(image_info,"pdf:use-cropbox");
411 if (option != (const char *) NULL)
412 cropbox=IsMagickTrue(option);
413 trimbox=MagickFalse;
414 option=GetImageOption(image_info,"pdf:use-trimbox");
415 if (option != (const char *) NULL)
416 trimbox=IsMagickTrue(option);
417 count=0;
418 spotcolor=0;
419 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
420 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
421 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
422 (void) ResetMagickMemory(&page,0,sizeof(page));
423 (void) ResetMagickMemory(command,0,sizeof(command));
424 hires_bounds.x2=0.0;
425 hires_bounds.y2=0.0;
426 angle=0.0;
427 p=command;
428 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
429 {
430 /*
431 Note PDF elements.
432 */
433 if (c == '\n')
434 c=' ';
435 *p++=(char) c;
cristyfd6e87b2011-02-03 18:48:17 +0000436 if ((c != (int) '/') && (c != (int) '%') &&
cristy3ed852e2009-09-05 21:47:34 +0000437 ((size_t) (p-command) < (MaxTextExtent-1)))
438 continue;
439 *(--p)='\0';
440 p=command;
441 if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
442 count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
443 /*
444 Is this a CMYK document?
445 */
446 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
447 cmyk=MagickTrue;
448 if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)
449 {
450 char
451 name[MaxTextExtent],
452 property[MaxTextExtent],
453 *value;
454
cristybb503372010-05-27 20:51:26 +0000455 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000456 i;
457
458 /*
459 Note spot names.
460 */
cristye8c25f92010-06-03 00:53:06 +0000461 (void) FormatMagickString(property,MaxTextExtent,"pdf:SpotColor-%.20g",
462 (double) spotcolor++);
cristy3ed852e2009-09-05 21:47:34 +0000463 i=0;
464 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
465 {
466 if ((isspace(c) != 0) || (c == '/') || ((i+1) == MaxTextExtent))
467 break;
468 name[i++]=(char) c;
469 }
470 name[i]='\0';
471 value=AcquireString(name);
472 (void) SubstituteString(&value,"#20"," ");
473 (void) SetImageProperty(image,property,value);
474 value=DestroyString(value);
475 continue;
476 }
477 if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0)
478 (void) SetImageProperty(image,"pdf:Version",command);
479 count=0;
480 if (cropbox != MagickFalse)
481 {
482 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
483 {
484 /*
485 Note region defined by crop box.
486 */
487 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
488 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
489 if (count != 4)
490 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
491 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
492 }
493 }
494 else
495 if (trimbox != MagickFalse)
496 {
497 if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0)
498 {
499 /*
500 Note region defined by trim box.
501 */
502 count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf",
503 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
504 if (count != 4)
505 count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf",
506 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
507 }
508 }
509 else
510 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
511 {
512 /*
513 Note region defined by media box.
514 */
515 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
516 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
517 if (count != 4)
518 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
519 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
520 }
521 if (count != 4)
522 continue;
523 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
524 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
525 {
526 /*
527 Set PDF render geometry.
528 */
cristy8cd5b312010-01-07 01:10:24 +0000529 (void) FormatMagickString(geometry,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +0000530 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +0000531 bounds.x1,bounds.y1);
cristy3ed852e2009-09-05 21:47:34 +0000532 (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry);
cristybb503372010-05-27 20:51:26 +0000533 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
534 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000535 hires_bounds=bounds;
536 }
537 }
538 (void) CloseBlob(image);
539 if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0))
540 {
cristybb503372010-05-27 20:51:26 +0000541 size_t
cristy3ed852e2009-09-05 21:47:34 +0000542 swap;
543
544 swap=page.width;
545 page.width=page.height;
546 page.height=swap;
547 }
548 if (image_info->colorspace == RGBColorspace)
549 cmyk=MagickFalse;
550 /*
551 Create Ghostscript control file.
552 */
553 file=AcquireUniqueFileResource(postscript_filename);
554 if (file == -1)
555 {
556 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
557 image_info->filename);
558 image=DestroyImage(image);
559 return((Image *) NULL);
560 }
561 count=write(file," ",1);
562 file=close(file)-1;
563 /*
564 Render Postscript with the Ghostscript delegate.
565 */
566 if ((image_info->ping != MagickFalse) ||
567 (image_info->monochrome != MagickFalse))
568 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
569 else
570 if (cmyk != MagickFalse)
571 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
572 else
cristya97426c2011-02-04 01:41:27 +0000573 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000574 if (delegate_info == (const DelegateInfo *) NULL)
575 {
576 (void) RelinquishUniqueFileResource(postscript_filename);
577 image=DestroyImage(image);
578 return((Image *) NULL);
579 }
580 *options='\0';
cristydba40d42010-03-25 18:31:50 +0000581 if (image_info->density != (char *) NULL)
582 {
583 flags=ParseGeometry(image_info->density,&geometry_info);
584 image->x_resolution=geometry_info.rho;
585 image->y_resolution=geometry_info.sigma;
586 if ((flags & SigmaValue) == 0)
587 image->y_resolution=image->x_resolution;
588 }
cristyd511bb52011-02-03 18:50:56 +0000589 (void) FormatMagickString(density,MaxTextExtent,"%gx%g",image->x_resolution,
590 image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000591 if (image_info->page != (char *) NULL)
592 {
593 (void) ParseAbsoluteGeometry(image_info->page,&page);
cristya97426c2011-02-04 01:41:27 +0000594 page.width=(size_t) floor((double) (page.width*image->x_resolution/
595 delta.x)+0.5);
596 page.height=(size_t) floor((double) (page.height*image->y_resolution/
597 delta.y)+0.5);
cristyd511bb52011-02-03 18:50:56 +0000598 (void) FormatMagickString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
599 page.width,(double) page.height);
cristy3ed852e2009-09-05 21:47:34 +0000600 }
601 if (cmyk != MagickFalse)
602 (void) ConcatenateMagickString(options,"-dUseCIEColor ",MaxTextExtent);
603 if (cropbox != MagickFalse)
604 (void) ConcatenateMagickString(options,"-dUseCropBox ",MaxTextExtent);
605 if (trimbox != MagickFalse)
606 (void) ConcatenateMagickString(options,"-dUseTrimBox ",MaxTextExtent);
607 read_info=CloneImageInfo(image_info);
608 *read_info->magick='\0';
609 if (read_info->number_scenes != 0)
610 {
611 char
612 pages[MaxTextExtent];
613
cristye8c25f92010-06-03 00:53:06 +0000614 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%.20g "
615 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
cristyf2faecf2010-05-28 19:19:36 +0000616 (read_info->scene+read_info->number_scenes));
cristy3ed852e2009-09-05 21:47:34 +0000617 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
618 read_info->number_scenes=0;
619 if (read_info->scenes != (char *) NULL)
620 *read_info->scenes='\0';
621 }
622 if (read_info->authenticate != (char *) NULL)
623 (void) FormatMagickString(options+strlen(options),MaxTextExtent,
624 " -sPDFPassword=%s",read_info->authenticate);
625 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
cristya97426c2011-02-04 01:41:27 +0000626 (void) AcquireUniqueFilename(filename);
627 (void) ConcatenateMagickString(filename,"-%08d",MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000628 (void) FormatMagickString(command,MaxTextExtent,
629 GetDelegateCommands(delegate_info),
630 read_info->antialias != MagickFalse ? 4 : 1,
cristya97426c2011-02-04 01:41:27 +0000631 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
632 postscript_filename,input_filename);
cristydefb3f02009-09-10 02:18:35 +0000633 status=InvokePDFDelegate(read_info->verbose,command,exception);
cristy3ed852e2009-09-05 21:47:34 +0000634 (void) RelinquishUniqueFileResource(postscript_filename);
cristy3ed852e2009-09-05 21:47:34 +0000635 (void) RelinquishUniqueFileResource(input_filename);
cristya97426c2011-02-04 01:41:27 +0000636 pdf_image=(Image *) NULL;
637 if (status == MagickFalse)
638 for (i=1; ; i++)
639 {
cristya97426c2011-02-04 01:41:27 +0000640 (void) InterpretImageFilename(image_info,image,filename,(int) i,
641 read_info->filename);
642 if (IsPDFRendered(read_info->filename) == MagickFalse)
643 break;
644 (void) RelinquishUniqueFileResource(read_info->filename);
645 }
646 else
647 for (i=1; ; i++)
648 {
cristya97426c2011-02-04 01:41:27 +0000649 (void) InterpretImageFilename(image_info,image,filename,(int) i,
650 read_info->filename);
651 if (IsPDFRendered(read_info->filename) == MagickFalse)
652 break;
653 next=ReadImage(read_info,exception);
654 (void) RelinquishUniqueFileResource(read_info->filename);
655 if (next == (Image *) NULL)
656 break;
657 AppendImageToList(&pdf_image,next);
658 }
cristy3ed852e2009-09-05 21:47:34 +0000659 read_info=DestroyImageInfo(read_info);
660 if (pdf_image == (Image *) NULL)
661 {
662 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
663 image_info->filename);
664 return((Image *) NULL);
665 }
666 if (LocaleCompare(pdf_image->magick,"BMP") == 0)
667 {
668 Image
669 *cmyk_image;
670
671 cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
672 if (cmyk_image != (Image *) NULL)
673 {
674 pdf_image=DestroyImageList(pdf_image);
675 pdf_image=cmyk_image;
676 }
677 }
678 if (image_info->number_scenes != 0)
679 {
680 Image
681 *clone_image;
682
cristybb503372010-05-27 20:51:26 +0000683 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000684 i;
685
686 /*
687 Add place holder images to meet the subimage specification requirement.
688 */
cristybb503372010-05-27 20:51:26 +0000689 for (i=0; i < (ssize_t) image_info->scene; i++)
cristy3ed852e2009-09-05 21:47:34 +0000690 {
691 clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
692 if (clone_image != (Image *) NULL)
693 PrependImageToList(&pdf_image,clone_image);
694 }
695 }
696 do
697 {
698 (void) CopyMagickString(pdf_image->filename,filename,MaxTextExtent);
699 pdf_image->page=page;
700 (void) CloneImageProfiles(pdf_image,image);
701 (void) CloneImageProperties(pdf_image,image);
702 next=SyncNextImageInList(pdf_image);
703 if (next != (Image *) NULL)
704 pdf_image=next;
705 } while (next != (Image *) NULL);
706 image=DestroyImage(image);
707 scene=0;
708 for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
709 {
710 next->scene=scene++;
711 next=GetNextImageInList(next);
712 }
713 return(GetFirstImageInList(pdf_image));
714}
715
716/*
717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718% %
719% %
720% %
721% R e g i s t e r P D F I m a g e %
722% %
723% %
724% %
725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726%
727% RegisterPDFImage() adds properties for the PDF image format to
728% the list of supported formats. The properties include the image format
729% tag, a method to read and/or write the format, whether the format
730% supports the saving of more than one frame to the same file or blob,
731% whether the format supports native in-memory I/O, and a brief
732% description of the format.
733%
734% The format of the RegisterPDFImage method is:
735%
cristybb503372010-05-27 20:51:26 +0000736% size_t RegisterPDFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000737%
738*/
cristybb503372010-05-27 20:51:26 +0000739ModuleExport size_t RegisterPDFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000740{
741 MagickInfo
742 *entry;
743
744 entry=SetMagickInfo("AI");
745 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
746 entry->encoder=(EncodeImageHandler *) WritePDFImage;
747 entry->adjoin=MagickFalse;
748 entry->blob_support=MagickFalse;
749 entry->seekable_stream=MagickTrue;
750 entry->thread_support=EncoderThreadSupport;
751 entry->description=ConstantString("Adobe Illustrator CS2");
752 entry->module=ConstantString("PDF");
753 (void) RegisterMagickInfo(entry);
754 entry=SetMagickInfo("EPDF");
755 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
756 entry->encoder=(EncodeImageHandler *) WritePDFImage;
757 entry->adjoin=MagickFalse;
758 entry->blob_support=MagickFalse;
759 entry->seekable_stream=MagickTrue;
760 entry->thread_support=EncoderThreadSupport;
761 entry->description=ConstantString("Encapsulated Portable Document Format");
762 entry->module=ConstantString("PDF");
763 (void) RegisterMagickInfo(entry);
764 entry=SetMagickInfo("PDF");
765 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
766 entry->encoder=(EncodeImageHandler *) WritePDFImage;
767 entry->magick=(IsImageFormatHandler *) IsPDF;
768 entry->blob_support=MagickFalse;
769 entry->seekable_stream=MagickTrue;
770 entry->thread_support=EncoderThreadSupport;
771 entry->description=ConstantString("Portable Document Format");
772 entry->module=ConstantString("PDF");
773 (void) RegisterMagickInfo(entry);
774 entry=SetMagickInfo("PDFA");
775 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
776 entry->encoder=(EncodeImageHandler *) WritePDFImage;
777 entry->magick=(IsImageFormatHandler *) IsPDF;
778 entry->blob_support=MagickFalse;
779 entry->seekable_stream=MagickTrue;
780 entry->thread_support=EncoderThreadSupport;
781 entry->description=ConstantString("Portable Document Archive Format");
782 entry->module=ConstantString("PDF");
783 (void) RegisterMagickInfo(entry);
784 return(MagickImageCoderSignature);
785}
786
787/*
788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789% %
790% %
791% %
792% U n r e g i s t e r P D F I m a g e %
793% %
794% %
795% %
796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797%
798% UnregisterPDFImage() removes format registrations made by the
799% PDF module from the list of supported formats.
800%
801% The format of the UnregisterPDFImage method is:
802%
803% UnregisterPDFImage(void)
804%
805*/
806ModuleExport void UnregisterPDFImage(void)
807{
808 (void) UnregisterMagickInfo("AI");
809 (void) UnregisterMagickInfo("EPDF");
810 (void) UnregisterMagickInfo("PDF");
811 (void) UnregisterMagickInfo("PDFA");
812}
813
814/*
815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816% %
817% %
818% %
819% W r i t e P D F I m a g e %
820% %
821% %
822% %
823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824%
825% WritePDFImage() writes an image in the Portable Document image
826% format.
827%
828% The format of the WritePDFImage method is:
829%
830% MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image)
831%
832% A description of each parameter follows.
833%
834% o image_info: the image info.
835%
836% o image: The image.
837%
838*/
839
840static inline size_t MagickMax(const size_t x,const size_t y)
841{
842 if (x > y)
843 return(x);
844 return(y);
845}
846
847static inline size_t MagickMin(const size_t x,const size_t y)
848{
849 if (x < y)
850 return(x);
851 return(y);
852}
853
854static char *EscapeParenthesis(const char *text)
855{
856 register char
857 *p;
858
cristybb503372010-05-27 20:51:26 +0000859 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000860 i;
861
862 static char
863 buffer[MaxTextExtent];
864
cristybb503372010-05-27 20:51:26 +0000865 size_t
cristy3ed852e2009-09-05 21:47:34 +0000866 escapes;
867
868 escapes=0;
869 p=buffer;
cristybb503372010-05-27 20:51:26 +0000870 for (i=0; i < (ssize_t) MagickMin(strlen(text),(MaxTextExtent-escapes-1)); i++)
cristy3ed852e2009-09-05 21:47:34 +0000871 {
872 if ((text[i] == '(') || (text[i] == ')'))
873 {
874 *p++='\\';
875 escapes++;
876 }
877 *p++=text[i];
878 }
879 *p='\0';
880 return(buffer);
881}
882
cristy47b838c2009-09-19 16:09:30 +0000883static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
884 Image *image,Image *inject_image)
885{
cristy47b838c2009-09-19 16:09:30 +0000886 Image
cristy80975862009-09-25 14:34:31 +0000887 *group4_image;
cristy47b838c2009-09-19 16:09:30 +0000888
889 ImageInfo
890 *write_info;
891
cristy47b838c2009-09-19 16:09:30 +0000892 MagickBooleanType
893 status;
894
cristy80975862009-09-25 14:34:31 +0000895 size_t
896 length;
cristy47b838c2009-09-19 16:09:30 +0000897
898 unsigned char
cristy80975862009-09-25 14:34:31 +0000899 *group4;
cristy47b838c2009-09-19 16:09:30 +0000900
cristy42751fe2009-10-05 00:15:50 +0000901 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +0000902 write_info=CloneImageInfo(image_info);
cristy80975862009-09-25 14:34:31 +0000903 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
904 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
905 group4_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
906 if (group4_image == (Image *) NULL)
907 return(MagickFalse);
908 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
909 &image->exception);
910 group4_image=DestroyImage(group4_image);
911 if (group4 == (unsigned char *) NULL)
912 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +0000913 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +0000914 if (WriteBlob(image,length,group4) != (ssize_t) length)
915 status=MagickFalse;
916 group4=(unsigned char *) RelinquishMagickMemory(group4);
917 return(status);
cristy47b838c2009-09-19 16:09:30 +0000918}
919
cristy3ed852e2009-09-05 21:47:34 +0000920static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image)
921{
922#define CFormat "/Filter [ /%s ]\n"
923#define ObjectsPerImage 14
924
925 static const char
926 XMPProfile[]=
927 {
928 "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
929 "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 4.0-c316 44.253921, Sun Oct 01 2006 17:08:23\">\n"
930 " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
931 " <rdf:Description rdf:about=\"\"\n"
932 " xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
933 " <xap:ModifyDate>%s</xap:ModifyDate>\n"
934 " <xap:CreateDate>%s</xap:CreateDate>\n"
935 " <xap:MetadataDate>%s</xap:MetadataDate>\n"
936 " <xap:CreatorTool>%s</xap:CreatorTool>\n"
937 " </rdf:Description>\n"
938 " <rdf:Description rdf:about=\"\"\n"
939 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
940 " <dc:format>application/pdf</dc:format>\n"
941 " </rdf:Description>\n"
942 " <rdf:Description rdf:about=\"\"\n"
943 " xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
944 " <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
945 " <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
946 " </rdf:Description>\n"
947 " <rdf:Description rdf:about=\"\"\n"
948 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
949 " <pdf:Producer>%s</pdf:Producer>\n"
950 " </rdf:Description>\n"
951 " <rdf:Description rdf:about=\"\"\n"
952 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
953 " <pdfaid:part>1</pdfaid:part>\n"
954 " <pdfaid:conformance>B</pdfaid:conformance>\n"
955 " </rdf:Description>\n"
956 " </rdf:RDF>\n"
957 "</x:xmpmeta>\n"
958 "<?xpacket end=\"w\"?>\n"
959 },
960 XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
961
962 char
cristy57015272010-12-30 01:16:38 +0000963 basename[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +0000964 buffer[MaxTextExtent],
965 date[MaxTextExtent],
966 **labels,
967 page_geometry[MaxTextExtent];
968
969 CompressionType
970 compression;
971
972 const char
973 *value;
974
975 double
976 pointsize;
977
978 GeometryInfo
979 geometry_info;
980
cristybb503372010-05-27 20:51:26 +0000981 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000982 count,
983 y;
984
985 Image
986 *next,
987 *tile_image;
988
989 MagickBooleanType
990 status;
991
992 MagickOffsetType
993 offset,
994 scene,
995 *xref;
996
997 MagickSizeType
998 number_pixels;
999
1000 MagickStatusType
1001 flags;
1002
1003 PointInfo
1004 delta,
1005 resolution,
1006 scale;
1007
1008 RectangleInfo
1009 geometry,
1010 media_info,
1011 page_info;
1012
1013 register const IndexPacket
1014 *indexes;
1015
1016 register const PixelPacket
1017 *p;
1018
1019 register unsigned char
1020 *q;
1021
cristybb503372010-05-27 20:51:26 +00001022 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001023 i,
1024 x;
1025
1026 size_t
1027 length;
1028
1029 struct tm
1030 local_time;
1031
1032 time_t
1033 seconds;
1034
1035 unsigned char
1036 *pixels;
1037
cristybb503372010-05-27 20:51:26 +00001038 size_t
cristy3ed852e2009-09-05 21:47:34 +00001039 info_id,
1040 object,
1041 pages_id,
1042 root_id,
1043 text_size,
1044 version;
1045
1046 /*
1047 Open output image file.
1048 */
1049 assert(image_info != (const ImageInfo *) NULL);
1050 assert(image_info->signature == MagickSignature);
1051 assert(image != (Image *) NULL);
1052 assert(image->signature == MagickSignature);
1053 if (image->debug != MagickFalse)
1054 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1055 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1056 if (status == MagickFalse)
1057 return(status);
1058 /*
1059 Allocate X ref memory.
1060 */
1061 xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1062 if (xref == (MagickOffsetType *) NULL)
1063 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1064 (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1065 /*
1066 Write Info object.
1067 */
1068 object=0;
1069 version=3;
1070 if (image_info->compression == JPEG2000Compression)
cristybb503372010-05-27 20:51:26 +00001071 version=(size_t) MagickMax(version,5);
cristy3ed852e2009-09-05 21:47:34 +00001072 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1073 if (next->matte != MagickFalse)
cristybb503372010-05-27 20:51:26 +00001074 version=(size_t) MagickMax(version,4);
cristy3ed852e2009-09-05 21:47:34 +00001075 if (LocaleCompare(image_info->magick,"PDFA") == 0)
cristybb503372010-05-27 20:51:26 +00001076 version=(size_t) MagickMax(version,6);
cristye8c25f92010-06-03 00:53:06 +00001077 (void) FormatMagickString(buffer,MaxTextExtent,"%%PDF-1.%.20g \n",
1078 (double) version);
cristy3ed852e2009-09-05 21:47:34 +00001079 (void) WriteBlobString(image,buffer);
1080 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1081 (void) WriteBlobString(image,"%âãÏÓ\n");
1082 /*
1083 Write Catalog object.
1084 */
1085 xref[object++]=TellBlob(image);
1086 root_id=object;
cristye8c25f92010-06-03 00:53:06 +00001087 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1088 object);
cristy3ed852e2009-09-05 21:47:34 +00001089 (void) WriteBlobString(image,buffer);
1090 (void) WriteBlobString(image,"<<\n");
1091 if (LocaleCompare(image_info->magick,"PDFA") != 0)
cristye8c25f92010-06-03 00:53:06 +00001092 (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n",
1093 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001094 else
1095 {
cristye8c25f92010-06-03 00:53:06 +00001096 (void) FormatMagickString(buffer,MaxTextExtent,"/Metadata %.20g 0 R\n",
1097 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001098 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001099 (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n",
1100 (double) object+2);
cristy3ed852e2009-09-05 21:47:34 +00001101 }
1102 (void) WriteBlobString(image,buffer);
1103 (void) WriteBlobString(image,"/Type /Catalog\n");
1104 (void) WriteBlobString(image,">>\n");
1105 (void) WriteBlobString(image,"endobj\n");
1106 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1107 {
1108 char
1109 create_date[MaxTextExtent],
1110 modify_date[MaxTextExtent],
1111 timestamp[MaxTextExtent],
1112 xmp_profile[MaxTextExtent];
1113
cristybb503372010-05-27 20:51:26 +00001114 size_t
cristy3ed852e2009-09-05 21:47:34 +00001115 version;
1116
1117 /*
1118 Write XMP object.
1119 */
1120 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001121 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",
1122 (double) object);
cristy3ed852e2009-09-05 21:47:34 +00001123 (void) WriteBlobString(image,buffer);
1124 (void) WriteBlobString(image,"<<\n");
1125 (void) WriteBlobString(image,"/Subtype /XML\n");
1126 *modify_date='\0';
1127 value=GetImageProperty(image,"date:modify");
1128 if (value != (const char *) NULL)
1129 (void) CopyMagickString(modify_date,value,MaxTextExtent);
1130 *create_date='\0';
1131 value=GetImageProperty(image,"date:create");
1132 if (value != (const char *) NULL)
1133 (void) CopyMagickString(create_date,value,MaxTextExtent);
1134 (void) FormatMagickTime(time((time_t *) NULL),MaxTextExtent,timestamp);
1135 i=FormatMagickString(xmp_profile,MaxTextExtent,XMPProfile,
1136 XMPProfileMagick,modify_date,create_date,timestamp,
1137 GetMagickVersion(&version),GetMagickVersion(&version));
cristye8c25f92010-06-03 00:53:06 +00001138 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g\n",
1139 (double) i);
cristy3ed852e2009-09-05 21:47:34 +00001140 (void) WriteBlobString(image,buffer);
1141 (void) WriteBlobString(image,"/Type /Metadata\n");
1142 (void) WriteBlobString(image,">>\nstream\n");
1143 (void) WriteBlobString(image,xmp_profile);
1144 (void) WriteBlobString(image,"endstream\n");
1145 (void) WriteBlobString(image,"endobj\n");
1146 }
1147 /*
1148 Write Pages object.
1149 */
1150 xref[object++]=TellBlob(image);
1151 pages_id=object;
cristye8c25f92010-06-03 00:53:06 +00001152 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001153 object);
cristy3ed852e2009-09-05 21:47:34 +00001154 (void) WriteBlobString(image,buffer);
1155 (void) WriteBlobString(image,"<<\n");
1156 (void) WriteBlobString(image,"/Type /Pages\n");
cristye8c25f92010-06-03 00:53:06 +00001157 (void) FormatMagickString(buffer,MaxTextExtent,"/Kids [ %.20g 0 R ",
1158 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001159 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001160 count=(ssize_t) (pages_id+ObjectsPerImage+1);
cristy3ed852e2009-09-05 21:47:34 +00001161 if (image_info->adjoin != MagickFalse)
1162 {
1163 Image
1164 *kid_image;
1165
1166 /*
1167 Predict page object id's.
1168 */
1169 kid_image=image;
1170 for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1171 {
cristye8c25f92010-06-03 00:53:06 +00001172 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 R ",(double)
1173 count);
cristy3ed852e2009-09-05 21:47:34 +00001174 (void) WriteBlobString(image,buffer);
1175 kid_image=GetNextImageInList(kid_image);
1176 }
1177 xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1178 sizeof(*xref));
1179 if (xref == (MagickOffsetType *) NULL)
1180 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1181 }
1182 (void) WriteBlobString(image,"]\n");
cristye8c25f92010-06-03 00:53:06 +00001183 (void) FormatMagickString(buffer,MaxTextExtent,"/Count %.20g\n",
1184 (double) ((count-pages_id)/ObjectsPerImage));
cristy3ed852e2009-09-05 21:47:34 +00001185 (void) WriteBlobString(image,buffer);
1186 (void) WriteBlobString(image,">>\n");
1187 (void) WriteBlobString(image,"endobj\n");
1188 scene=0;
1189 do
1190 {
1191 compression=image->compression;
1192 if (image_info->compression != UndefinedCompression)
1193 compression=image_info->compression;
1194 switch (compression)
1195 {
1196 case FaxCompression:
1197 case Group4Compression:
1198 {
1199 if ((IsMonochromeImage(image,&image->exception) == MagickFalse) ||
1200 (image->matte != MagickFalse))
1201 compression=RLECompression;
1202 break;
1203 }
1204#if !defined(MAGICKCORE_JPEG_DELEGATE)
1205 case JPEGCompression:
1206 {
1207 compression=RLECompression;
1208 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1209 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1210 image->filename);
1211 break;
1212 }
1213#endif
1214#if !defined(MAGICKCORE_JP2_DELEGATE)
1215 case JPEG2000Compression:
1216 {
1217 compression=RLECompression;
1218 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1219 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1220 image->filename);
1221 break;
1222 }
1223#endif
1224#if !defined(MAGICKCORE_ZLIB_DELEGATE)
1225 case ZipCompression:
1226 {
1227 compression=RLECompression;
1228 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1229 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1230 image->filename);
1231 break;
1232 }
1233#endif
1234 case LZWCompression:
1235 {
1236 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1237 compression=RLECompression; /* LZW compression is forbidden */
1238 break;
1239 }
1240 case NoCompression:
1241 {
1242 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1243 compression=RLECompression; /* ASCII 85 compression is forbidden */
1244 break;
1245 }
1246 default:
1247 break;
1248 }
1249 if (compression == JPEG2000Compression)
1250 {
1251 if (image->colorspace != RGBColorspace)
1252 (void) TransformImageColorspace(image,RGBColorspace);
1253 }
1254 /*
1255 Scale relative to dots-per-inch.
1256 */
1257 delta.x=DefaultResolution;
1258 delta.y=DefaultResolution;
1259 resolution.x=image->x_resolution;
1260 resolution.y=image->y_resolution;
1261 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1262 {
1263 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1264 resolution.x=geometry_info.rho;
1265 resolution.y=geometry_info.sigma;
1266 if ((flags & SigmaValue) == 0)
1267 resolution.y=resolution.x;
1268 }
1269 if (image_info->density != (char *) NULL)
1270 {
1271 flags=ParseGeometry(image_info->density,&geometry_info);
1272 resolution.x=geometry_info.rho;
1273 resolution.y=geometry_info.sigma;
1274 if ((flags & SigmaValue) == 0)
1275 resolution.y=resolution.x;
1276 }
1277 if (image->units == PixelsPerCentimeterResolution)
1278 {
cristya97426c2011-02-04 01:41:27 +00001279 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1280 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
cristy3ed852e2009-09-05 21:47:34 +00001281 }
1282 SetGeometry(image,&geometry);
cristye8c25f92010-06-03 00:53:06 +00001283 (void) FormatMagickString(page_geometry,MaxTextExtent,"%.20gx%.20g",
1284 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001285 if (image_info->page != (char *) NULL)
1286 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1287 else
1288 if ((image->page.width != 0) && (image->page.height != 0))
cristye8c25f92010-06-03 00:53:06 +00001289 (void) FormatMagickString(page_geometry,MaxTextExtent,
1290 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,
1291 (double) image->page.height,(double) image->page.x,(double)
1292 image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001293 else
1294 if ((image->gravity != UndefinedGravity) &&
1295 (LocaleCompare(image_info->magick,"PDF") == 0))
1296 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1297 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1298 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1299 &geometry.width,&geometry.height);
1300 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +00001301 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001302 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +00001303 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001304 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1305 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1306 &image->exception);
1307 if (image->gravity != UndefinedGravity)
1308 {
1309 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +00001310 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001311 }
1312 pointsize=12.0;
1313 if (image_info->pointsize != 0.0)
1314 pointsize=image_info->pointsize;
1315 text_size=0;
cristybedb2ab2011-02-27 03:15:58 +00001316 value=GetImageProperty(image,"label");
cristy3ed852e2009-09-05 21:47:34 +00001317 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +00001318 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristyda16f162011-02-19 23:52:17 +00001319 (void) text_size;
cristy3ed852e2009-09-05 21:47:34 +00001320 /*
1321 Write Page object.
1322 */
1323 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001324 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001325 object);
cristy3ed852e2009-09-05 21:47:34 +00001326 (void) WriteBlobString(image,buffer);
1327 (void) WriteBlobString(image,"<<\n");
1328 (void) WriteBlobString(image,"/Type /Page\n");
cristye8c25f92010-06-03 00:53:06 +00001329 (void) FormatMagickString(buffer,MaxTextExtent,"/Parent %.20g 0 R\n",
1330 (double) pages_id);
cristy3ed852e2009-09-05 21:47:34 +00001331 (void) WriteBlobString(image,buffer);
1332 (void) WriteBlobString(image,"/Resources <<\n");
1333 labels=(char **) NULL;
cristybedb2ab2011-02-27 03:15:58 +00001334 value=GetImageProperty(image,"label");
cristy3ed852e2009-09-05 21:47:34 +00001335 if (value != (const char *) NULL)
1336 labels=StringToList(value);
1337 if (labels != (char **) NULL)
1338 {
1339 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001340 "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1341 object+4);
cristy3ed852e2009-09-05 21:47:34 +00001342 (void) WriteBlobString(image,buffer);
1343 }
1344 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001345 "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1346 object+5);
cristy3ed852e2009-09-05 21:47:34 +00001347 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001348 (void) FormatMagickString(buffer,MaxTextExtent,"/ProcSet %.20g 0 R >>\n",
1349 (double) object+3);
cristy3ed852e2009-09-05 21:47:34 +00001350 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001351 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001352 "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001353 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001354 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001355 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001356 "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001357 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001358 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001359 (void) FormatMagickString(buffer,MaxTextExtent,"/Contents %.20g 0 R\n",
1360 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001361 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001362 (void) FormatMagickString(buffer,MaxTextExtent,"/Thumb %.20g 0 R\n",
1363 (double) object+8);
cristy3ed852e2009-09-05 21:47:34 +00001364 (void) WriteBlobString(image,buffer);
1365 (void) WriteBlobString(image,">>\n");
1366 (void) WriteBlobString(image,"endobj\n");
1367 /*
1368 Write Contents object.
1369 */
1370 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001371 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001372 object);
cristy3ed852e2009-09-05 21:47:34 +00001373 (void) WriteBlobString(image,buffer);
1374 (void) WriteBlobString(image,"<<\n");
cristye8c25f92010-06-03 00:53:06 +00001375 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
1376 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001377 (void) WriteBlobString(image,buffer);
1378 (void) WriteBlobString(image,">>\n");
1379 (void) WriteBlobString(image,"stream\n");
1380 offset=TellBlob(image);
1381 (void) WriteBlobString(image,"q\n");
1382 if (labels != (char **) NULL)
1383 for (i=0; labels[i] != (char *) NULL; i++)
1384 {
1385 (void) WriteBlobString(image,"BT\n");
cristye8c25f92010-06-03 00:53:06 +00001386 (void) FormatMagickString(buffer,MaxTextExtent,"/F%.20g %g Tf\n",
1387 (double) image->scene,pointsize);
cristy3ed852e2009-09-05 21:47:34 +00001388 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001389 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g %.20g Td\n",
1390 (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+
1391 12));
cristy3ed852e2009-09-05 21:47:34 +00001392 (void) WriteBlobString(image,buffer);
1393 (void) FormatMagickString(buffer,MaxTextExtent,"(%s) Tj\n",labels[i]);
1394 (void) WriteBlobString(image,buffer);
1395 (void) WriteBlobString(image,"ET\n");
1396 labels[i]=DestroyString(labels[i]);
1397 }
cristye8c25f92010-06-03 00:53:06 +00001398 (void) FormatMagickString(buffer,MaxTextExtent,"%g 0 0 %g %.20g %.20g cm\n",
1399 scale.x,scale.y,(double) geometry.x,(double) geometry.y);
cristy3ed852e2009-09-05 21:47:34 +00001400 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001401 (void) FormatMagickString(buffer,MaxTextExtent,"/Im%.20g Do\n",
1402 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001403 (void) WriteBlobString(image,buffer);
1404 (void) WriteBlobString(image,"Q\n");
1405 offset=TellBlob(image)-offset;
1406 (void) WriteBlobString(image,"endstream\n");
1407 (void) WriteBlobString(image,"endobj\n");
1408 /*
1409 Write Length object.
1410 */
1411 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001412 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001413 object);
cristy3ed852e2009-09-05 21:47:34 +00001414 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001415 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00001416 (void) WriteBlobString(image,buffer);
1417 (void) WriteBlobString(image,"endobj\n");
1418 /*
1419 Write Procset object.
1420 */
1421 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001422 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",
1423 (double) object);
cristy3ed852e2009-09-05 21:47:34 +00001424 (void) WriteBlobString(image,buffer);
1425 if ((image->storage_class == DirectClass) || (image->colors > 256))
1426 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MaxTextExtent);
1427 else
1428 if ((compression == FaxCompression) || (compression == Group4Compression))
1429 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MaxTextExtent);
1430 else
1431 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MaxTextExtent);
1432 (void) WriteBlobString(image,buffer);
1433 (void) WriteBlobString(image," ]\n");
1434 (void) WriteBlobString(image,"endobj\n");
1435 /*
1436 Write Font object.
1437 */
1438 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001439 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",
1440 (double) object);
cristy3ed852e2009-09-05 21:47:34 +00001441 (void) WriteBlobString(image,buffer);
1442 (void) WriteBlobString(image,"<<\n");
1443 if (labels != (char **) NULL)
1444 {
1445 (void) WriteBlobString(image,"/Type /Font\n");
1446 (void) WriteBlobString(image,"/Subtype /Type1\n");
cristye8c25f92010-06-03 00:53:06 +00001447 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /F%.20g\n",
1448 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001449 (void) WriteBlobString(image,buffer);
1450 (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1451 (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1452 labels=(char **) RelinquishMagickMemory(labels);
1453 }
1454 (void) WriteBlobString(image,">>\n");
1455 (void) WriteBlobString(image,"endobj\n");
1456 /*
1457 Write XObject object.
1458 */
1459 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001460 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001461 object);
cristy3ed852e2009-09-05 21:47:34 +00001462 (void) WriteBlobString(image,buffer);
1463 (void) WriteBlobString(image,"<<\n");
1464 (void) WriteBlobString(image,"/Type /XObject\n");
1465 (void) WriteBlobString(image,"/Subtype /Image\n");
cristye8c25f92010-06-03 00:53:06 +00001466 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Im%.20g\n",
1467 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001468 (void) WriteBlobString(image,buffer);
1469 switch (compression)
1470 {
1471 case NoCompression:
1472 {
1473 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1474 break;
1475 }
1476 case JPEGCompression:
1477 {
1478 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1479 if (image->colorspace != CMYKColorspace)
1480 break;
1481 (void) WriteBlobString(image,buffer);
1482 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1483 MaxTextExtent);
1484 break;
1485 }
1486 case JPEG2000Compression:
1487 {
1488 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1489 if (image->colorspace != CMYKColorspace)
1490 break;
1491 (void) WriteBlobString(image,buffer);
1492 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1493 MaxTextExtent);
1494 break;
1495 }
1496 case LZWCompression:
1497 {
cristyfa7becb2009-09-13 02:44:40 +00001498 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1499 break;
cristy3ed852e2009-09-05 21:47:34 +00001500 }
1501 case ZipCompression:
1502 {
cristyfa7becb2009-09-13 02:44:40 +00001503 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1504 break;
cristy3ed852e2009-09-05 21:47:34 +00001505 }
1506 case FaxCompression:
1507 case Group4Compression:
1508 {
1509 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1510 MaxTextExtent);
1511 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001512 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristye8c25f92010-06-03 00:53:06 +00001513 "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1514 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001515 break;
1516 }
1517 default:
1518 {
1519 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1520 "RunLengthDecode");
1521 break;
1522 }
1523 }
1524 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001525 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %.20g\n",(double)
1526 image->columns);
cristy3ed852e2009-09-05 21:47:34 +00001527 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001528 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %.20g\n",(double)
1529 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001530 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001531 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n",
1532 (double) object+2);
cristy3ed852e2009-09-05 21:47:34 +00001533 (void) WriteBlobString(image,buffer);
1534 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1535 (compression == FaxCompression) || (compression == Group4Compression) ?
1536 1 : 8);
1537 (void) WriteBlobString(image,buffer);
1538 if (image->matte != MagickFalse)
1539 {
cristye8c25f92010-06-03 00:53:06 +00001540 (void) FormatMagickString(buffer,MaxTextExtent,"/SMask %.20g 0 R\n",
1541 (double) object+7);
cristy3ed852e2009-09-05 21:47:34 +00001542 (void) WriteBlobString(image,buffer);
1543 }
cristye8c25f92010-06-03 00:53:06 +00001544 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
1545 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001546 (void) WriteBlobString(image,buffer);
1547 (void) WriteBlobString(image,">>\n");
1548 (void) WriteBlobString(image,"stream\n");
1549 offset=TellBlob(image);
1550 number_pixels=(MagickSizeType) image->columns*image->rows;
1551 if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1552 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1553 if ((compression == FaxCompression) || (compression == Group4Compression) ||
1554 ((image_info->type != TrueColorType) &&
1555 (IsGrayImage(image,&image->exception) != MagickFalse)))
1556 {
1557 switch (compression)
1558 {
1559 case FaxCompression:
1560 case Group4Compression:
1561 {
1562 if (LocaleCompare(CCITTParam,"0") == 0)
1563 {
1564 (void) HuffmanEncodeImage(image_info,image,image);
1565 break;
1566 }
1567 (void) Huffman2DEncodeImage(image_info,image,image);
1568 break;
1569 }
1570 case JPEGCompression:
1571 {
1572 status=InjectImageBlob(image_info,image,image,"jpeg",
1573 &image->exception);
1574 if (status == MagickFalse)
1575 ThrowWriterException(CoderError,image->exception.reason);
1576 break;
1577 }
1578 case JPEG2000Compression:
1579 {
1580 status=InjectImageBlob(image_info,image,image,"jp2",
1581 &image->exception);
1582 if (status == MagickFalse)
1583 ThrowWriterException(CoderError,image->exception.reason);
1584 break;
1585 }
1586 case RLECompression:
1587 default:
1588 {
1589 /*
1590 Allocate pixel array.
1591 */
1592 length=(size_t) number_pixels;
1593 pixels=(unsigned char *) AcquireQuantumMemory(length,
1594 sizeof(*pixels));
1595 if (pixels == (unsigned char *) NULL)
1596 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1597 /*
1598 Dump Runlength encoded pixels.
1599 */
1600 q=pixels;
cristybb503372010-05-27 20:51:26 +00001601 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001602 {
cristyf5c61ba2010-12-17 00:58:04 +00001603 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00001604 if (p == (const PixelPacket *) NULL)
1605 break;
cristybb503372010-05-27 20:51:26 +00001606 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001607 {
1608 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1609 p++;
1610 }
1611 if (image->previous == (Image *) NULL)
1612 {
cristyf5c61ba2010-12-17 00:58:04 +00001613 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1614 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001615 if (status == MagickFalse)
1616 break;
1617 }
1618 }
1619#if defined(MAGICKCORE_ZLIB_DELEGATE)
1620 if (compression == ZipCompression)
1621 status=ZLIBEncodeImage(image,length,pixels);
1622 else
1623#endif
1624 if (compression == LZWCompression)
1625 status=LZWEncodeImage(image,length,pixels);
1626 else
1627 status=PackbitsEncodeImage(image,length,pixels);
1628 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1629 if (status == MagickFalse)
1630 {
1631 (void) CloseBlob(image);
1632 return(MagickFalse);
1633 }
1634 break;
1635 }
1636 case NoCompression:
1637 {
1638 /*
1639 Dump uncompressed PseudoColor packets.
1640 */
1641 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001642 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001643 {
cristyf5c61ba2010-12-17 00:58:04 +00001644 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00001645 if (p == (const PixelPacket *) NULL)
1646 break;
cristybb503372010-05-27 20:51:26 +00001647 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001648 {
1649 Ascii85Encode(image,
1650 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
1651 p++;
1652 }
1653 if (image->previous == (Image *) NULL)
1654 {
cristyf5c61ba2010-12-17 00:58:04 +00001655 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1656 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001657 if (status == MagickFalse)
1658 break;
1659 }
1660 }
1661 Ascii85Flush(image);
1662 break;
1663 }
1664 }
1665 }
1666 else
1667 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1668 (compression == JPEGCompression) ||
1669 (compression == JPEG2000Compression))
1670 switch (compression)
1671 {
1672 case JPEGCompression:
1673 {
1674 status=InjectImageBlob(image_info,image,image,"jpeg",
1675 &image->exception);
1676 if (status == MagickFalse)
1677 ThrowWriterException(CoderError,image->exception.reason);
1678 break;
1679 }
1680 case JPEG2000Compression:
1681 {
1682 status=InjectImageBlob(image_info,image,image,"jp2",
1683 &image->exception);
1684 if (status == MagickFalse)
1685 ThrowWriterException(CoderError,image->exception.reason);
1686 break;
1687 }
1688 case RLECompression:
1689 default:
1690 {
1691 /*
1692 Allocate pixel array.
1693 */
1694 length=(size_t) number_pixels;
1695 pixels=(unsigned char *) AcquireQuantumMemory(length,
1696 4*sizeof(*pixels));
1697 length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1698 if (pixels == (unsigned char *) NULL)
1699 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1700 /*
1701 Dump runoffset encoded pixels.
1702 */
1703 q=pixels;
cristybb503372010-05-27 20:51:26 +00001704 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001705 {
cristyf5c61ba2010-12-17 00:58:04 +00001706 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00001707 if (p == (const PixelPacket *) NULL)
1708 break;
1709 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001710 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001711 {
cristyce70c172010-01-07 17:15:30 +00001712 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
1713 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
1714 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001715 if (image->colorspace == CMYKColorspace)
1716 *q++=ScaleQuantumToChar(indexes[x]);
1717 p++;
1718 }
1719 if (image->previous == (Image *) NULL)
1720 {
cristyf5c61ba2010-12-17 00:58:04 +00001721 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1722 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001723 if (status == MagickFalse)
1724 break;
1725 }
1726 }
1727#if defined(MAGICKCORE_ZLIB_DELEGATE)
1728 if (compression == ZipCompression)
1729 status=ZLIBEncodeImage(image,length,pixels);
1730 else
1731#endif
1732 if (compression == LZWCompression)
1733 status=LZWEncodeImage(image,length,pixels);
1734 else
1735 status=PackbitsEncodeImage(image,length,pixels);
1736 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1737 if (status == MagickFalse)
1738 {
1739 (void) CloseBlob(image);
1740 return(MagickFalse);
1741 }
1742 break;
1743 }
1744 case NoCompression:
1745 {
1746 /*
1747 Dump uncompressed DirectColor packets.
1748 */
1749 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001750 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001751 {
cristyf5c61ba2010-12-17 00:58:04 +00001752 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00001753 if (p == (const PixelPacket *) NULL)
1754 break;
1755 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001756 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001757 {
cristyf5c61ba2010-12-17 00:58:04 +00001758 Ascii85Encode(image,ScaleQuantumToChar(
1759 GetRedPixelComponent(p)));
1760 Ascii85Encode(image,ScaleQuantumToChar(
1761 GetGreenPixelComponent(p)));
1762 Ascii85Encode(image,ScaleQuantumToChar(
1763 GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00001764 if (image->colorspace == CMYKColorspace)
1765 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
1766 p++;
1767 }
1768 if (image->previous == (Image *) NULL)
1769 {
cristyf5c61ba2010-12-17 00:58:04 +00001770 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1771 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001772 if (status == MagickFalse)
1773 break;
1774 }
1775 }
1776 Ascii85Flush(image);
1777 break;
1778 }
1779 }
1780 else
1781 {
1782 /*
1783 Dump number of colors and colormap.
1784 */
1785 switch (compression)
1786 {
1787 case RLECompression:
1788 default:
1789 {
1790 /*
1791 Allocate pixel array.
1792 */
1793 length=(size_t) number_pixels;
1794 pixels=(unsigned char *) AcquireQuantumMemory(length,
1795 sizeof(*pixels));
1796 if (pixels == (unsigned char *) NULL)
1797 ThrowWriterException(ResourceLimitError,
1798 "MemoryAllocationFailed");
1799 /*
1800 Dump Runlength encoded pixels.
1801 */
1802 q=pixels;
cristybb503372010-05-27 20:51:26 +00001803 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001804 {
1805 p=GetVirtualPixels(image,0,y,image->columns,1,
1806 &image->exception);
1807 if (p == (const PixelPacket *) NULL)
1808 break;
1809 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001810 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001811 *q++=(unsigned char) indexes[x];
1812 if (image->previous == (Image *) NULL)
1813 {
cristyf5c61ba2010-12-17 00:58:04 +00001814 status=SetImageProgress(image,SaveImageTag,
1815 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001816 if (status == MagickFalse)
1817 break;
1818 }
1819 }
1820#if defined(MAGICKCORE_ZLIB_DELEGATE)
1821 if (compression == ZipCompression)
1822 status=ZLIBEncodeImage(image,length,pixels);
1823 else
1824#endif
1825 if (compression == LZWCompression)
1826 status=LZWEncodeImage(image,length,pixels);
1827 else
1828 status=PackbitsEncodeImage(image,length,pixels);
1829 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1830 if (status == MagickFalse)
1831 {
1832 (void) CloseBlob(image);
1833 return(MagickFalse);
1834 }
1835 break;
1836 }
1837 case NoCompression:
1838 {
1839 /*
1840 Dump uncompressed PseudoColor packets.
1841 */
1842 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001843 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001844 {
1845 p=GetVirtualPixels(image,0,y,image->columns,1,
1846 &image->exception);
1847 if (p == (const PixelPacket *) NULL)
1848 break;
1849 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001850 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001851 Ascii85Encode(image,(unsigned char) indexes[x]);
1852 if (image->previous == (Image *) NULL)
1853 {
cristyf5c61ba2010-12-17 00:58:04 +00001854 status=SetImageProgress(image,SaveImageTag,
1855 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001856 if (status == MagickFalse)
1857 break;
1858 }
1859 }
1860 Ascii85Flush(image);
1861 break;
1862 }
1863 }
1864 }
1865 offset=TellBlob(image)-offset;
1866 (void) WriteBlobString(image,"\nendstream\n");
1867 (void) WriteBlobString(image,"endobj\n");
1868 /*
1869 Write Length object.
1870 */
1871 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001872 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001873 object);
cristy3ed852e2009-09-05 21:47:34 +00001874 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001875 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",
1876 (double) offset);
cristy3ed852e2009-09-05 21:47:34 +00001877 (void) WriteBlobString(image,buffer);
1878 (void) WriteBlobString(image,"endobj\n");
1879 /*
1880 Write Colorspace object.
1881 */
1882 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001883 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001884 object);
cristy3ed852e2009-09-05 21:47:34 +00001885 (void) WriteBlobString(image,buffer);
1886 if (image->colorspace == CMYKColorspace)
1887 (void) CopyMagickString(buffer,"/DeviceCMYK\n",MaxTextExtent);
1888 else
1889 if ((compression == FaxCompression) ||
1890 (compression == Group4Compression) ||
1891 ((image_info->type != TrueColorType) &&
1892 (IsGrayImage(image,&image->exception) != MagickFalse)))
1893 (void) CopyMagickString(buffer,"/DeviceGray\n",MaxTextExtent);
1894 else
1895 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1896 (compression == JPEGCompression) ||
1897 (compression == JPEG2000Compression))
1898 (void) CopyMagickString(buffer,"/DeviceRGB\n",MaxTextExtent);
1899 else
1900 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001901 "[ /Indexed /DeviceRGB %.20g %.20g 0 R ]\n",(double) image->colors-
1902 1,(double) object+3);
cristy3ed852e2009-09-05 21:47:34 +00001903 (void) WriteBlobString(image,buffer);
1904 (void) WriteBlobString(image,"endobj\n");
1905 /*
1906 Write Thumb object.
1907 */
1908 SetGeometry(image,&geometry);
1909 (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
1910 &geometry.width,&geometry.height);
1911 tile_image=ThumbnailImage(image,geometry.width,geometry.height,
1912 &image->exception);
1913 if (tile_image == (Image *) NULL)
1914 ThrowWriterException(ResourceLimitError,image->exception.reason);
1915 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00001916 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001917 object);
cristy3ed852e2009-09-05 21:47:34 +00001918 (void) WriteBlobString(image,buffer);
1919 (void) WriteBlobString(image,"<<\n");
1920 switch (compression)
1921 {
1922 case NoCompression:
1923 {
1924 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1925 break;
1926 }
1927 case JPEGCompression:
1928 {
1929 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1930 if (image->colorspace != CMYKColorspace)
1931 break;
1932 (void) WriteBlobString(image,buffer);
1933 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1934 MaxTextExtent);
1935 break;
1936 }
1937 case JPEG2000Compression:
1938 {
1939 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1940 if (image->colorspace != CMYKColorspace)
1941 break;
1942 (void) WriteBlobString(image,buffer);
1943 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1944 MaxTextExtent);
1945 break;
1946 }
1947 case LZWCompression:
1948 {
1949 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1950 break;
1951 }
1952 case ZipCompression:
1953 {
1954 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1955 break;
1956 }
1957 case FaxCompression:
1958 case Group4Compression:
1959 {
1960 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1961 MaxTextExtent);
1962 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001963 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristye8c25f92010-06-03 00:53:06 +00001964 "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1965 (double) tile_image->columns,(double) tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001966 break;
1967 }
1968 default:
1969 {
1970 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1971 "RunLengthDecode");
1972 break;
1973 }
1974 }
1975 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001976 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %.20g\n",(double)
1977 tile_image->columns);
cristy3ed852e2009-09-05 21:47:34 +00001978 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001979 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %.20g\n",(double)
1980 tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001981 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001982 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n",
1983 (double) object-1);
cristy3ed852e2009-09-05 21:47:34 +00001984 (void) WriteBlobString(image,buffer);
1985 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1986 (compression == FaxCompression) || (compression == Group4Compression) ?
1987 1 : 8);
1988 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00001989 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
1990 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001991 (void) WriteBlobString(image,buffer);
1992 (void) WriteBlobString(image,">>\n");
1993 (void) WriteBlobString(image,"stream\n");
1994 offset=TellBlob(image);
1995 number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
1996 if ((compression == FaxCompression) ||
1997 (compression == Group4Compression) ||
1998 ((image_info->type != TrueColorType) &&
1999 (IsGrayImage(tile_image,&image->exception) != MagickFalse)))
2000 {
2001 switch (compression)
2002 {
2003 case FaxCompression:
2004 case Group4Compression:
2005 {
2006 if (LocaleCompare(CCITTParam,"0") == 0)
2007 {
2008 (void) HuffmanEncodeImage(image_info,image,tile_image);
2009 break;
2010 }
2011 (void) Huffman2DEncodeImage(image_info,image,tile_image);
2012 break;
2013 }
2014 case JPEGCompression:
2015 {
2016 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2017 &image->exception);
2018 if (status == MagickFalse)
2019 ThrowWriterException(CoderError,tile_image->exception.reason);
2020 break;
2021 }
2022 case JPEG2000Compression:
2023 {
2024 status=InjectImageBlob(image_info,image,tile_image,"jp2",
2025 &image->exception);
2026 if (status == MagickFalse)
2027 ThrowWriterException(CoderError,tile_image->exception.reason);
2028 break;
2029 }
2030 case RLECompression:
2031 default:
2032 {
2033 /*
2034 Allocate pixel array.
2035 */
2036 length=(size_t) number_pixels;
2037 pixels=(unsigned char *) AcquireQuantumMemory(length,
2038 sizeof(*pixels));
2039 if (pixels == (unsigned char *) NULL)
2040 {
2041 tile_image=DestroyImage(tile_image);
2042 ThrowWriterException(ResourceLimitError,
2043 "MemoryAllocationFailed");
2044 }
2045 /*
2046 Dump Runlength encoded pixels.
2047 */
2048 q=pixels;
cristybb503372010-05-27 20:51:26 +00002049 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002050 {
2051 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2052 &tile_image->exception);
2053 if (p == (const PixelPacket *) NULL)
2054 break;
cristybb503372010-05-27 20:51:26 +00002055 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002056 {
2057 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
2058 p++;
2059 }
2060 }
2061#if defined(MAGICKCORE_ZLIB_DELEGATE)
2062 if (compression == ZipCompression)
2063 status=ZLIBEncodeImage(image,length,pixels);
2064 else
2065#endif
2066 if (compression == LZWCompression)
2067 status=LZWEncodeImage(image,length,pixels);
2068 else
2069 status=PackbitsEncodeImage(image,length,pixels);
2070 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2071 if (status == MagickFalse)
2072 {
2073 (void) CloseBlob(image);
2074 return(MagickFalse);
2075 }
2076 break;
2077 }
2078 case NoCompression:
2079 {
2080 /*
2081 Dump uncompressed PseudoColor packets.
2082 */
2083 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002084 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002085 {
2086 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2087 &tile_image->exception);
2088 if (p == (const PixelPacket *) NULL)
2089 break;
cristybb503372010-05-27 20:51:26 +00002090 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002091 {
2092 Ascii85Encode(image,
2093 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
2094 p++;
2095 }
2096 }
2097 Ascii85Flush(image);
2098 break;
2099 }
2100 }
2101 }
2102 else
2103 if ((tile_image->storage_class == DirectClass) ||
2104 (tile_image->colors > 256) || (compression == JPEGCompression) ||
2105 (compression == JPEG2000Compression))
2106 switch (compression)
2107 {
2108 case JPEGCompression:
2109 {
2110 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2111 &image->exception);
2112 if (status == MagickFalse)
2113 ThrowWriterException(CoderError,tile_image->exception.reason);
2114 break;
2115 }
2116 case JPEG2000Compression:
2117 {
2118 status=InjectImageBlob(image_info,image,tile_image,"jp2",
2119 &image->exception);
2120 if (status == MagickFalse)
2121 ThrowWriterException(CoderError,tile_image->exception.reason);
2122 break;
2123 }
2124 case RLECompression:
2125 default:
2126 {
2127 /*
2128 Allocate pixel array.
2129 */
2130 length=(size_t) number_pixels;
2131 pixels=(unsigned char *) AcquireQuantumMemory(length,4*
2132 sizeof(*pixels));
2133 length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2134 if (pixels == (unsigned char *) NULL)
2135 {
2136 tile_image=DestroyImage(tile_image);
2137 ThrowWriterException(ResourceLimitError,
2138 "MemoryAllocationFailed");
2139 }
2140 /*
2141 Dump runoffset encoded pixels.
2142 */
2143 q=pixels;
cristybb503372010-05-27 20:51:26 +00002144 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002145 {
2146 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2147 &tile_image->exception);
2148 if (p == (const PixelPacket *) NULL)
2149 break;
2150 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002151 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002152 {
cristyce70c172010-01-07 17:15:30 +00002153 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
2154 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
2155 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00002156 if (image->colorspace == CMYKColorspace)
2157 *q++=ScaleQuantumToChar(indexes[x]);
2158 p++;
2159 }
2160 }
2161#if defined(MAGICKCORE_ZLIB_DELEGATE)
2162 if (compression == ZipCompression)
2163 status=ZLIBEncodeImage(image,length,pixels);
2164 else
2165#endif
2166 if (compression == LZWCompression)
2167 status=LZWEncodeImage(image,length,pixels);
2168 else
2169 status=PackbitsEncodeImage(image,length,pixels);
2170 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2171 if (status == MagickFalse)
2172 {
2173 (void) CloseBlob(image);
2174 return(MagickFalse);
2175 }
2176 break;
2177 }
2178 case NoCompression:
2179 {
2180 /*
2181 Dump uncompressed DirectColor packets.
2182 */
2183 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002184 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002185 {
2186 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2187 &tile_image->exception);
2188 if (p == (const PixelPacket *) NULL)
2189 break;
2190 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002191 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002192 {
cristyf5c61ba2010-12-17 00:58:04 +00002193 Ascii85Encode(image,ScaleQuantumToChar(
2194 GetRedPixelComponent(p)));
2195 Ascii85Encode(image,ScaleQuantumToChar(
2196 GetGreenPixelComponent(p)));
2197 Ascii85Encode(image,ScaleQuantumToChar(
2198 GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002199 if (image->colorspace == CMYKColorspace)
2200 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
2201 p++;
2202 }
2203 }
2204 Ascii85Flush(image);
2205 break;
2206 }
2207 }
2208 else
2209 {
2210 /*
2211 Dump number of colors and colormap.
2212 */
2213 switch (compression)
2214 {
2215 case RLECompression:
2216 default:
2217 {
2218 /*
2219 Allocate pixel array.
2220 */
2221 length=(size_t) number_pixels;
2222 pixels=(unsigned char *) AcquireQuantumMemory(length,
2223 sizeof(*pixels));
2224 if (pixels == (unsigned char *) NULL)
2225 {
2226 tile_image=DestroyImage(tile_image);
2227 ThrowWriterException(ResourceLimitError,
2228 "MemoryAllocationFailed");
2229 }
2230 /*
2231 Dump Runlength encoded pixels.
2232 */
2233 q=pixels;
cristybb503372010-05-27 20:51:26 +00002234 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002235 {
2236 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2237 &tile_image->exception);
2238 if (p == (const PixelPacket *) NULL)
2239 break;
2240 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002241 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002242 *q++=(unsigned char) indexes[x];
2243 }
2244#if defined(MAGICKCORE_ZLIB_DELEGATE)
2245 if (compression == ZipCompression)
2246 status=ZLIBEncodeImage(image,length,pixels);
2247 else
2248#endif
2249 if (compression == LZWCompression)
2250 status=LZWEncodeImage(image,length,pixels);
2251 else
2252 status=PackbitsEncodeImage(image,length,pixels);
2253 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2254 if (status == MagickFalse)
2255 {
2256 (void) CloseBlob(image);
2257 return(MagickFalse);
2258 }
2259 break;
2260 }
2261 case NoCompression:
2262 {
2263 /*
2264 Dump uncompressed PseudoColor packets.
2265 */
2266 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002267 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002268 {
2269 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2270 &tile_image->exception);
2271 if (p == (const PixelPacket *) NULL)
2272 break;
2273 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002274 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002275 Ascii85Encode(image,(unsigned char) indexes[x]);
2276 }
2277 Ascii85Flush(image);
2278 break;
2279 }
2280 }
2281 }
2282 tile_image=DestroyImage(tile_image);
2283 offset=TellBlob(image)-offset;
2284 (void) WriteBlobString(image,"\nendstream\n");
2285 (void) WriteBlobString(image,"endobj\n");
2286 /*
2287 Write Length object.
2288 */
2289 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00002290 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002291 object);
cristy3ed852e2009-09-05 21:47:34 +00002292 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002293 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002294 (void) WriteBlobString(image,buffer);
2295 (void) WriteBlobString(image,"endobj\n");
2296 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00002297 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002298 object);
cristy3ed852e2009-09-05 21:47:34 +00002299 (void) WriteBlobString(image,buffer);
2300 if ((image->storage_class != DirectClass) && (image->colors <= 256) &&
2301 (compression != FaxCompression) && (compression != Group4Compression))
2302 {
2303 /*
2304 Write Colormap object.
2305 */
2306 (void) WriteBlobString(image,"<<\n");
2307 if (compression == NoCompression)
2308 (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
cristye8c25f92010-06-03 00:53:06 +00002309 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
2310 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00002311 (void) WriteBlobString(image,buffer);
2312 (void) WriteBlobString(image,">>\n");
2313 (void) WriteBlobString(image,"stream\n");
2314 offset=TellBlob(image);
2315 if (compression == NoCompression)
2316 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002317 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002318 {
2319 if (compression == NoCompression)
2320 {
2321 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].red));
2322 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].green));
2323 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].blue));
2324 continue;
2325 }
2326 (void) WriteBlobByte(image,
2327 ScaleQuantumToChar(image->colormap[i].red));
2328 (void) WriteBlobByte(image,
2329 ScaleQuantumToChar(image->colormap[i].green));
2330 (void) WriteBlobByte(image,
2331 ScaleQuantumToChar(image->colormap[i].blue));
2332 }
2333 if (compression == NoCompression)
2334 Ascii85Flush(image);
2335 offset=TellBlob(image)-offset;
2336 (void) WriteBlobString(image,"\nendstream\n");
2337 }
2338 (void) WriteBlobString(image,"endobj\n");
2339 /*
2340 Write Length object.
2341 */
2342 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00002343 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002344 object);
cristy3ed852e2009-09-05 21:47:34 +00002345 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002346 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002347 offset);
cristy3ed852e2009-09-05 21:47:34 +00002348 (void) WriteBlobString(image,buffer);
2349 (void) WriteBlobString(image,"endobj\n");
2350 /*
2351 Write softmask object.
2352 */
2353 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00002354 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002355 object);
cristy3ed852e2009-09-05 21:47:34 +00002356 (void) WriteBlobString(image,buffer);
2357 (void) WriteBlobString(image,"<<\n");
2358 if (image->matte == MagickFalse)
2359 (void) WriteBlobString(image,">>\n");
2360 else
2361 {
2362 (void) WriteBlobString(image,"/Type /XObject\n");
2363 (void) WriteBlobString(image,"/Subtype /Image\n");
cristye8c25f92010-06-03 00:53:06 +00002364 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Ma%.20g\n",
2365 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00002366 (void) WriteBlobString(image,buffer);
2367 switch (compression)
2368 {
2369 case NoCompression:
2370 {
2371 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2372 "ASCII85Decode");
2373 break;
2374 }
2375 case LZWCompression:
2376 {
2377 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
2378 break;
2379 }
2380 case ZipCompression:
2381 {
2382 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2383 "FlateDecode");
2384 break;
2385 }
2386 default:
2387 {
2388 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2389 "RunLengthDecode");
2390 break;
2391 }
2392 }
2393 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002394 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %.20g\n",
2395 (double) image->columns);
cristy3ed852e2009-09-05 21:47:34 +00002396 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002397 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %.20g\n",
2398 (double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002399 (void) WriteBlobString(image,buffer);
2400 (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2401 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
2402 (compression == FaxCompression) || (compression == Group4Compression)
2403 ? 1 : 8);
2404 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002405 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
2406 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00002407 (void) WriteBlobString(image,buffer);
2408 (void) WriteBlobString(image,">>\n");
2409 (void) WriteBlobString(image,"stream\n");
2410 offset=TellBlob(image);
2411 number_pixels=(MagickSizeType) image->columns*image->rows;
2412 switch (compression)
2413 {
2414 case RLECompression:
2415 default:
2416 {
2417 /*
2418 Allocate pixel array.
2419 */
2420 length=(size_t) number_pixels;
2421 pixels=(unsigned char *) AcquireQuantumMemory(length,
2422 sizeof(*pixels));
2423 if (pixels == (unsigned char *) NULL)
2424 {
2425 image=DestroyImage(image);
2426 ThrowWriterException(ResourceLimitError,
2427 "MemoryAllocationFailed");
2428 }
2429 /*
2430 Dump Runlength encoded pixels.
2431 */
2432 q=pixels;
cristybb503372010-05-27 20:51:26 +00002433 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002434 {
cristyf5c61ba2010-12-17 00:58:04 +00002435 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00002436 if (p == (const PixelPacket *) NULL)
2437 break;
cristybb503372010-05-27 20:51:26 +00002438 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002439 {
cristy46f08202010-01-10 04:04:21 +00002440 *q++=ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002441 p++;
2442 }
2443 }
2444#if defined(MAGICKCORE_ZLIB_DELEGATE)
2445 if (compression == ZipCompression)
2446 status=ZLIBEncodeImage(image,length,pixels);
2447 else
2448#endif
2449 if (compression == LZWCompression)
2450 status=LZWEncodeImage(image,length,pixels);
2451 else
2452 status=PackbitsEncodeImage(image,length,pixels);
2453 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2454 if (status == MagickFalse)
2455 {
2456 (void) CloseBlob(image);
2457 return(MagickFalse);
2458 }
2459 break;
2460 }
2461 case NoCompression:
2462 {
2463 /*
2464 Dump uncompressed PseudoColor packets.
2465 */
2466 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002467 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002468 {
cristyf5c61ba2010-12-17 00:58:04 +00002469 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00002470 if (p == (const PixelPacket *) NULL)
2471 break;
cristybb503372010-05-27 20:51:26 +00002472 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002473 {
2474 Ascii85Encode(image,ScaleQuantumToChar((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002475 GetOpacityPixelComponent(p))));
cristy3ed852e2009-09-05 21:47:34 +00002476 p++;
2477 }
2478 }
2479 Ascii85Flush(image);
2480 break;
2481 }
2482 }
2483 offset=TellBlob(image)-offset;
2484 (void) WriteBlobString(image,"\nendstream\n");
2485 }
2486 (void) WriteBlobString(image,"endobj\n");
2487 /*
2488 Write Length object.
2489 */
2490 xref[object++]=TellBlob(image);
cristye8c25f92010-06-03 00:53:06 +00002491 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002492 object);
cristy3ed852e2009-09-05 21:47:34 +00002493 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002494 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002495 (void) WriteBlobString(image,buffer);
2496 (void) WriteBlobString(image,"endobj\n");
2497 if (GetNextImageInList(image) == (Image *) NULL)
2498 break;
2499 image=SyncNextImageInList(image);
2500 status=SetImageProgress(image,SaveImagesTag,scene++,
2501 GetImageListLength(image));
2502 if (status == MagickFalse)
2503 break;
2504 } while (image_info->adjoin != MagickFalse);
2505 /*
2506 Write Metadata object.
2507 */
2508 xref[object++]=TellBlob(image);
2509 info_id=object;
cristye8c25f92010-06-03 00:53:06 +00002510 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002511 object);
cristy3ed852e2009-09-05 21:47:34 +00002512 (void) WriteBlobString(image,buffer);
2513 (void) WriteBlobString(image,"<<\n");
cristy57015272010-12-30 01:16:38 +00002514 GetPathComponent(image->filename,BasePath,basename);
cristy3ed852e2009-09-05 21:47:34 +00002515 (void) FormatMagickString(buffer,MaxTextExtent,"/Title (%s)\n",
cristy57015272010-12-30 01:16:38 +00002516 EscapeParenthesis(basename));
cristy3ed852e2009-09-05 21:47:34 +00002517 (void) WriteBlobString(image,buffer);
2518 seconds=time((time_t *) NULL);
2519#if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2520 (void) localtime_r(&seconds,&local_time);
2521#else
2522 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2523#endif
2524 (void) FormatMagickString(date,MaxTextExtent,"D:%04d%02d%02d%02d%02d%02d",
2525 local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2526 local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2527 (void) FormatMagickString(buffer,MaxTextExtent,"/CreationDate (%s)\n",date);
2528 (void) WriteBlobString(image,buffer);
2529 (void) FormatMagickString(buffer,MaxTextExtent,"/ModDate (%s)\n",date);
2530 (void) WriteBlobString(image,buffer);
2531 (void) FormatMagickString(buffer,MaxTextExtent,"/Producer (%s)\n",
cristybb503372010-05-27 20:51:26 +00002532 EscapeParenthesis(GetMagickVersion((size_t *) NULL)));
cristy3ed852e2009-09-05 21:47:34 +00002533 (void) WriteBlobString(image,buffer);
2534 (void) WriteBlobString(image,">>\n");
2535 (void) WriteBlobString(image,"endobj\n");
2536 /*
2537 Write Xref object.
2538 */
2539 offset=TellBlob(image)-xref[0]+10;
2540 (void) WriteBlobString(image,"xref\n");
cristye8c25f92010-06-03 00:53:06 +00002541 (void) FormatMagickString(buffer,MaxTextExtent,"0 %.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002542 object+1);
cristy3ed852e2009-09-05 21:47:34 +00002543 (void) WriteBlobString(image,buffer);
2544 (void) WriteBlobString(image,"0000000000 65535 f \n");
cristybb503372010-05-27 20:51:26 +00002545 for (i=0; i < (ssize_t) object; i++)
cristy3ed852e2009-09-05 21:47:34 +00002546 {
2547 (void) FormatMagickString(buffer,MaxTextExtent,"%010lu 00000 n \n",
cristyf2faecf2010-05-28 19:19:36 +00002548 (unsigned long) xref[i]);
cristy3ed852e2009-09-05 21:47:34 +00002549 (void) WriteBlobString(image,buffer);
2550 }
2551 (void) WriteBlobString(image,"trailer\n");
2552 (void) WriteBlobString(image,"<<\n");
cristye8c25f92010-06-03 00:53:06 +00002553 (void) FormatMagickString(buffer,MaxTextExtent,"/Size %.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002554 object+1);
cristy3ed852e2009-09-05 21:47:34 +00002555 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002556 (void) FormatMagickString(buffer,MaxTextExtent,"/Info %.20g 0 R\n",(double)
2557 info_id);
cristy3ed852e2009-09-05 21:47:34 +00002558 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +00002559 (void) FormatMagickString(buffer,MaxTextExtent,"/Root %.20g 0 R\n",(double)
2560 root_id);
cristy3ed852e2009-09-05 21:47:34 +00002561 (void) WriteBlobString(image,buffer);
2562 (void) WriteBlobString(image,">>\n");
2563 (void) WriteBlobString(image,"startxref\n");
cristye8c25f92010-06-03 00:53:06 +00002564 (void) FormatMagickString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002565 (void) WriteBlobString(image,buffer);
2566 (void) WriteBlobString(image,"%%EOF\n");
2567 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2568 (void) CloseBlob(image);
2569 return(MagickTrue);
2570}