blob: 498d5ad73ff684498df62a75fbd9769a7e3014a6 [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% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 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 }
cristy3ed852e2009-09-05 21:47:34 +0000178 argv=StringToArgv(command,&argc);
cristydefb3f02009-09-10 02:18:35 +0000179 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
cristy3ed852e2009-09-05 21:47:34 +0000180 if (status == 0)
cristydefb3f02009-09-10 02:18:35 +0000181 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
182 0,&code);
183 (ghost_info->exit)(interpreter);
184 (ghost_info->delete_instance)(interpreter);
cristy0157aea2010-04-24 21:12:18 +0000185#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000186 NTGhostscriptUnLoadDLL();
187#endif
cristybb503372010-05-27 20:51:26 +0000188 for (i=0; i < (ssize_t) argc; i++)
cristy3ed852e2009-09-05 21:47:34 +0000189 argv[i]=DestroyString(argv[i]);
190 argv=(char **) RelinquishMagickMemory(argv);
cristy41083a42009-09-07 23:47:59 +0000191 if ((status != 0) && (status != -101))
192 {
193 char
194 *message;
cristyb32b90a2009-09-07 21:45:48 +0000195
cristy41083a42009-09-07 23:47:59 +0000196 message=GetExceptionMessage(errno);
197 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
198 "`%s': %s",command,message);
199 message=DestroyString(message);
200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
201 "Ghostscript returns status %d, exit code %d",status,code);
202 return(MagickFalse);
203 }
cristy3ed852e2009-09-05 21:47:34 +0000204 return(MagickTrue);
205#else
cristy6de4bc22010-01-12 17:10:35 +0000206 status=SystemCommand(MagickFalse,verbose,command,exception);
cristy41083a42009-09-07 23:47:59 +0000207 return(status == 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000208#endif
209}
210
211/*
212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213% %
214% %
215% %
216% I s P D F %
217% %
218% %
219% %
220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221%
222% IsPDF() returns MagickTrue if the image format type, identified by the
223% magick string, is PDF.
224%
225% The format of the IsPDF method is:
226%
227% MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
228%
229% A description of each parameter follows:
230%
231% o magick: compare image format pattern against these bytes.
232%
233% o offset: Specifies the offset of the magick string.
234%
235*/
236static MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
237{
238 if (offset < 5)
239 return(MagickFalse);
cristy41083a42009-09-07 23:47:59 +0000240 if (LocaleNCompare((const char *) magick,"%PDF-",5) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000241 return(MagickTrue);
242 return(MagickFalse);
243}
244
245/*
246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247% %
248% %
249% %
250% R e a d P D F I m a g e %
251% %
252% %
253% %
254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255%
256% ReadPDFImage() reads a Portable Document Format image file and
257% returns it. It allocates the memory necessary for the new Image structure
258% and returns a pointer to the new image.
259%
260% The format of the ReadPDFImage method is:
261%
262% Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
263%
264% A description of each parameter follows:
265%
266% o image_info: the image info.
267%
268% o exception: return any errors or warnings in this structure.
269%
270*/
271
272static MagickBooleanType IsPDFRendered(const char *path)
273{
274 MagickBooleanType
275 status;
276
277 struct stat
278 attributes;
279
280 if ((path == (const char *) NULL) || (*path == '\0'))
281 return(MagickFalse);
282 status=GetPathAttributes(path,&attributes);
283 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
284 (attributes.st_size > 0))
285 return(MagickTrue);
286 return(MagickFalse);
287}
288
289static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
290{
291#define CropBox "CropBox"
292#define DeviceCMYK "DeviceCMYK"
293#define MediaBox "MediaBox"
294#define RenderPostscriptText "Rendering Postscript... "
295#define PDFRotate "Rotate"
296#define SpotColor "Separation"
297#define TrimBox "TrimBox"
298#define PDFVersion "PDF-"
299
300 char
301 command[MaxTextExtent],
302 density[MaxTextExtent],
303 filename[MaxTextExtent],
304 geometry[MaxTextExtent],
305 options[MaxTextExtent],
306 input_filename[MaxTextExtent],
307 postscript_filename[MaxTextExtent];
308
309 const char
310 *option;
311
312 const DelegateInfo
313 *delegate_info;
314
315 double
316 angle;
317
cristydba40d42010-03-25 18:31:50 +0000318 GeometryInfo
319 geometry_info;
320
cristy3ed852e2009-09-05 21:47:34 +0000321 Image
322 *image,
323 *next,
324 *pdf_image;
325
326 ImageInfo
327 *read_info;
328
329 int
330 file;
331
332 MagickBooleanType
333 cmyk,
334 cropbox,
335 trimbox,
336 status;
337
cristydba40d42010-03-25 18:31:50 +0000338 MagickStatusType
339 flags;
340
cristy3ed852e2009-09-05 21:47:34 +0000341 PointInfo
342 delta;
343
344 RectangleInfo
345 bounding_box,
346 page;
347
348 register char
349 *p;
350
351 register int
352 c;
353
354 SegmentInfo
355 bounds,
356 hires_bounds;
357
358 ssize_t
359 count;
360
cristybb503372010-05-27 20:51:26 +0000361 size_t
cristy3ed852e2009-09-05 21:47:34 +0000362 scene,
363 spotcolor;
364
365 assert(image_info != (const ImageInfo *) NULL);
366 assert(image_info->signature == MagickSignature);
367 if (image_info->debug != MagickFalse)
368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
369 image_info->filename);
370 assert(exception != (ExceptionInfo *) NULL);
371 assert(exception->signature == MagickSignature);
372 /*
373 Open image file.
374 */
375 image=AcquireImage(image_info);
376 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
377 if (status == MagickFalse)
378 {
379 image=DestroyImageList(image);
380 return((Image *) NULL);
381 }
382 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
383 if (status == MagickFalse)
384 {
385 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
386 image_info->filename);
387 image=DestroyImageList(image);
388 return((Image *) NULL);
389 }
390 /*
391 Set the page density.
392 */
393 delta.x=DefaultResolution;
394 delta.y=DefaultResolution;
395 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
396 {
cristy3ed852e2009-09-05 21:47:34 +0000397 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
398 image->x_resolution=geometry_info.rho;
399 image->y_resolution=geometry_info.sigma;
400 if ((flags & SigmaValue) == 0)
401 image->y_resolution=image->x_resolution;
402 }
403 /*
404 Determine page geometry from the PDF media box.
405 */
406 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
407 cropbox=MagickFalse;
408 option=GetImageOption(image_info,"pdf:use-cropbox");
409 if (option != (const char *) NULL)
410 cropbox=IsMagickTrue(option);
411 trimbox=MagickFalse;
412 option=GetImageOption(image_info,"pdf:use-trimbox");
413 if (option != (const char *) NULL)
414 trimbox=IsMagickTrue(option);
415 count=0;
416 spotcolor=0;
417 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
418 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
419 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
420 (void) ResetMagickMemory(&page,0,sizeof(page));
421 (void) ResetMagickMemory(command,0,sizeof(command));
422 hires_bounds.x2=0.0;
423 hires_bounds.y2=0.0;
424 angle=0.0;
425 p=command;
426 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
427 {
428 /*
429 Note PDF elements.
430 */
431 if (c == '\n')
432 c=' ';
433 *p++=(char) c;
434 if ((c != (int) '/') && (c != (int) '%') &&
435 ((size_t) (p-command) < (MaxTextExtent-1)))
436 continue;
437 *(--p)='\0';
438 p=command;
439 if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
440 count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
441 /*
442 Is this a CMYK document?
443 */
444 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
445 cmyk=MagickTrue;
446 if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)
447 {
448 char
449 name[MaxTextExtent],
450 property[MaxTextExtent],
451 *value;
452
cristybb503372010-05-27 20:51:26 +0000453 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000454 i;
455
456 /*
457 Note spot names.
458 */
459 (void) FormatMagickString(property,MaxTextExtent,"pdf:SpotColor-%lu",
460 spotcolor++);
461 i=0;
462 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
463 {
464 if ((isspace(c) != 0) || (c == '/') || ((i+1) == MaxTextExtent))
465 break;
466 name[i++]=(char) c;
467 }
468 name[i]='\0';
469 value=AcquireString(name);
470 (void) SubstituteString(&value,"#20"," ");
471 (void) SetImageProperty(image,property,value);
472 value=DestroyString(value);
473 continue;
474 }
475 if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0)
476 (void) SetImageProperty(image,"pdf:Version",command);
477 count=0;
478 if (cropbox != MagickFalse)
479 {
480 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
481 {
482 /*
483 Note region defined by crop box.
484 */
485 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
486 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
487 if (count != 4)
488 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
489 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
490 }
491 }
492 else
493 if (trimbox != MagickFalse)
494 {
495 if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0)
496 {
497 /*
498 Note region defined by trim box.
499 */
500 count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf",
501 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
502 if (count != 4)
503 count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf",
504 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
505 }
506 }
507 else
508 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
509 {
510 /*
511 Note region defined by media box.
512 */
513 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
514 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
515 if (count != 4)
516 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
517 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
518 }
519 if (count != 4)
520 continue;
521 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
522 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
523 {
524 /*
525 Set PDF render geometry.
526 */
cristy8cd5b312010-01-07 01:10:24 +0000527 (void) FormatMagickString(geometry,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +0000528 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +0000529 bounds.x1,bounds.y1);
cristy3ed852e2009-09-05 21:47:34 +0000530 (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry);
cristybb503372010-05-27 20:51:26 +0000531 page.width=(size_t) floor(bounds.x2-bounds.x1+0.5);
532 page.height=(size_t) floor(bounds.y2-bounds.y1+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000533 hires_bounds=bounds;
534 }
535 }
536 (void) CloseBlob(image);
537 if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0))
538 {
cristybb503372010-05-27 20:51:26 +0000539 size_t
cristy3ed852e2009-09-05 21:47:34 +0000540 swap;
541
542 swap=page.width;
543 page.width=page.height;
544 page.height=swap;
545 }
546 if (image_info->colorspace == RGBColorspace)
547 cmyk=MagickFalse;
548 /*
549 Create Ghostscript control file.
550 */
551 file=AcquireUniqueFileResource(postscript_filename);
552 if (file == -1)
553 {
554 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
555 image_info->filename);
556 image=DestroyImage(image);
557 return((Image *) NULL);
558 }
559 count=write(file," ",1);
560 file=close(file)-1;
561 /*
562 Render Postscript with the Ghostscript delegate.
563 */
564 if ((image_info->ping != MagickFalse) ||
565 (image_info->monochrome != MagickFalse))
566 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
567 else
568 if (cmyk != MagickFalse)
569 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
570 else
cristyf1849f82009-09-08 14:37:22 +0000571 if (LocaleCompare(image_info->magick,"AI") == 0)
572 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
573 else
574 delegate_info=GetDelegateInfo("ps:color",(char *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (delegate_info == (const DelegateInfo *) NULL)
576 {
577 (void) RelinquishUniqueFileResource(postscript_filename);
578 image=DestroyImage(image);
579 return((Image *) NULL);
580 }
581 *options='\0';
cristydba40d42010-03-25 18:31:50 +0000582 if (image_info->density != (char *) NULL)
583 {
584 flags=ParseGeometry(image_info->density,&geometry_info);
585 image->x_resolution=geometry_info.rho;
586 image->y_resolution=geometry_info.sigma;
587 if ((flags & SigmaValue) == 0)
588 image->y_resolution=image->x_resolution;
589 }
cristye7f51092010-01-17 00:39:37 +0000590 (void) FormatMagickString(density,MaxTextExtent,"%gx%g",
cristy8cd5b312010-01-07 01:10:24 +0000591 image->x_resolution,image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000592 if (image_info->page != (char *) NULL)
593 {
594 (void) ParseAbsoluteGeometry(image_info->page,&page);
cristybb503372010-05-27 20:51:26 +0000595 page.width=(size_t) floor(page.width*image->x_resolution/delta.x+
cristy06609ee2010-03-17 20:21:27 +0000596 0.5);
cristybb503372010-05-27 20:51:26 +0000597 page.height=(size_t) floor(page.height*image->y_resolution/delta.y+
cristy06609ee2010-03-17 20:21:27 +0000598 0.5);
cristy3ed852e2009-09-05 21:47:34 +0000599 (void) FormatMagickString(options,MaxTextExtent,"-g%lux%lu ",page.width,
600 page.height);
601 }
602 if (cmyk != MagickFalse)
603 (void) ConcatenateMagickString(options,"-dUseCIEColor ",MaxTextExtent);
604 if (cropbox != MagickFalse)
605 (void) ConcatenateMagickString(options,"-dUseCropBox ",MaxTextExtent);
606 if (trimbox != MagickFalse)
607 (void) ConcatenateMagickString(options,"-dUseTrimBox ",MaxTextExtent);
608 read_info=CloneImageInfo(image_info);
609 *read_info->magick='\0';
610 if (read_info->number_scenes != 0)
611 {
612 char
613 pages[MaxTextExtent];
614
615 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%lu "
616 "-dLastPage=%lu",read_info->scene+1,read_info->scene+
617 read_info->number_scenes);
618 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
619 read_info->number_scenes=0;
620 if (read_info->scenes != (char *) NULL)
621 *read_info->scenes='\0';
622 }
623 if (read_info->authenticate != (char *) NULL)
624 (void) FormatMagickString(options+strlen(options),MaxTextExtent,
625 " -sPDFPassword=%s",read_info->authenticate);
626 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
627 (void) AcquireUniqueFilename(read_info->filename);
628 (void) FormatMagickString(command,MaxTextExtent,
629 GetDelegateCommands(delegate_info),
630 read_info->antialias != MagickFalse ? 4 : 1,
631 read_info->antialias != MagickFalse ? 4 : 1,density,options,
632 read_info->filename,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 pdf_image=(Image *) NULL;
cristy41083a42009-09-07 23:47:59 +0000635 if ((status != MagickFalse) &&
cristy3ed852e2009-09-05 21:47:34 +0000636 (IsPDFRendered(read_info->filename) != MagickFalse))
637 pdf_image=ReadImage(read_info,exception);
638 (void) RelinquishUniqueFileResource(postscript_filename);
639 (void) RelinquishUniqueFileResource(read_info->filename);
640 (void) RelinquishUniqueFileResource(input_filename);
641 read_info=DestroyImageInfo(read_info);
642 if (pdf_image == (Image *) NULL)
643 {
644 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
645 image_info->filename);
646 return((Image *) NULL);
647 }
648 if (LocaleCompare(pdf_image->magick,"BMP") == 0)
649 {
650 Image
651 *cmyk_image;
652
653 cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
654 if (cmyk_image != (Image *) NULL)
655 {
656 pdf_image=DestroyImageList(pdf_image);
657 pdf_image=cmyk_image;
658 }
659 }
660 if (image_info->number_scenes != 0)
661 {
662 Image
663 *clone_image;
664
cristybb503372010-05-27 20:51:26 +0000665 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000666 i;
667
668 /*
669 Add place holder images to meet the subimage specification requirement.
670 */
cristybb503372010-05-27 20:51:26 +0000671 for (i=0; i < (ssize_t) image_info->scene; i++)
cristy3ed852e2009-09-05 21:47:34 +0000672 {
673 clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
674 if (clone_image != (Image *) NULL)
675 PrependImageToList(&pdf_image,clone_image);
676 }
677 }
678 do
679 {
680 (void) CopyMagickString(pdf_image->filename,filename,MaxTextExtent);
681 pdf_image->page=page;
682 (void) CloneImageProfiles(pdf_image,image);
683 (void) CloneImageProperties(pdf_image,image);
684 next=SyncNextImageInList(pdf_image);
685 if (next != (Image *) NULL)
686 pdf_image=next;
687 } while (next != (Image *) NULL);
688 image=DestroyImage(image);
689 scene=0;
690 for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
691 {
692 next->scene=scene++;
693 next=GetNextImageInList(next);
694 }
695 return(GetFirstImageInList(pdf_image));
696}
697
698/*
699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700% %
701% %
702% %
703% R e g i s t e r P D F I m a g e %
704% %
705% %
706% %
707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708%
709% RegisterPDFImage() adds properties for the PDF image format to
710% the list of supported formats. The properties include the image format
711% tag, a method to read and/or write the format, whether the format
712% supports the saving of more than one frame to the same file or blob,
713% whether the format supports native in-memory I/O, and a brief
714% description of the format.
715%
716% The format of the RegisterPDFImage method is:
717%
cristybb503372010-05-27 20:51:26 +0000718% size_t RegisterPDFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000719%
720*/
cristybb503372010-05-27 20:51:26 +0000721ModuleExport size_t RegisterPDFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000722{
723 MagickInfo
724 *entry;
725
726 entry=SetMagickInfo("AI");
727 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
728 entry->encoder=(EncodeImageHandler *) WritePDFImage;
729 entry->adjoin=MagickFalse;
730 entry->blob_support=MagickFalse;
731 entry->seekable_stream=MagickTrue;
732 entry->thread_support=EncoderThreadSupport;
733 entry->description=ConstantString("Adobe Illustrator CS2");
734 entry->module=ConstantString("PDF");
735 (void) RegisterMagickInfo(entry);
736 entry=SetMagickInfo("EPDF");
737 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
738 entry->encoder=(EncodeImageHandler *) WritePDFImage;
739 entry->adjoin=MagickFalse;
740 entry->blob_support=MagickFalse;
741 entry->seekable_stream=MagickTrue;
742 entry->thread_support=EncoderThreadSupport;
743 entry->description=ConstantString("Encapsulated Portable Document Format");
744 entry->module=ConstantString("PDF");
745 (void) RegisterMagickInfo(entry);
746 entry=SetMagickInfo("PDF");
747 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
748 entry->encoder=(EncodeImageHandler *) WritePDFImage;
749 entry->magick=(IsImageFormatHandler *) IsPDF;
750 entry->blob_support=MagickFalse;
751 entry->seekable_stream=MagickTrue;
752 entry->thread_support=EncoderThreadSupport;
753 entry->description=ConstantString("Portable Document Format");
754 entry->module=ConstantString("PDF");
755 (void) RegisterMagickInfo(entry);
756 entry=SetMagickInfo("PDFA");
757 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
758 entry->encoder=(EncodeImageHandler *) WritePDFImage;
759 entry->magick=(IsImageFormatHandler *) IsPDF;
760 entry->blob_support=MagickFalse;
761 entry->seekable_stream=MagickTrue;
762 entry->thread_support=EncoderThreadSupport;
763 entry->description=ConstantString("Portable Document Archive Format");
764 entry->module=ConstantString("PDF");
765 (void) RegisterMagickInfo(entry);
766 return(MagickImageCoderSignature);
767}
768
769/*
770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771% %
772% %
773% %
774% U n r e g i s t e r P D F I m a g e %
775% %
776% %
777% %
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779%
780% UnregisterPDFImage() removes format registrations made by the
781% PDF module from the list of supported formats.
782%
783% The format of the UnregisterPDFImage method is:
784%
785% UnregisterPDFImage(void)
786%
787*/
788ModuleExport void UnregisterPDFImage(void)
789{
790 (void) UnregisterMagickInfo("AI");
791 (void) UnregisterMagickInfo("EPDF");
792 (void) UnregisterMagickInfo("PDF");
793 (void) UnregisterMagickInfo("PDFA");
794}
795
796/*
797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798% %
799% %
800% %
801% W r i t e P D F I m a g e %
802% %
803% %
804% %
805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
806%
807% WritePDFImage() writes an image in the Portable Document image
808% format.
809%
810% The format of the WritePDFImage method is:
811%
812% MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image)
813%
814% A description of each parameter follows.
815%
816% o image_info: the image info.
817%
818% o image: The image.
819%
820*/
821
822static inline size_t MagickMax(const size_t x,const size_t y)
823{
824 if (x > y)
825 return(x);
826 return(y);
827}
828
829static inline size_t MagickMin(const size_t x,const size_t y)
830{
831 if (x < y)
832 return(x);
833 return(y);
834}
835
836static char *EscapeParenthesis(const char *text)
837{
838 register char
839 *p;
840
cristybb503372010-05-27 20:51:26 +0000841 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000842 i;
843
844 static char
845 buffer[MaxTextExtent];
846
cristybb503372010-05-27 20:51:26 +0000847 size_t
cristy3ed852e2009-09-05 21:47:34 +0000848 escapes;
849
850 escapes=0;
851 p=buffer;
cristybb503372010-05-27 20:51:26 +0000852 for (i=0; i < (ssize_t) MagickMin(strlen(text),(MaxTextExtent-escapes-1)); i++)
cristy3ed852e2009-09-05 21:47:34 +0000853 {
854 if ((text[i] == '(') || (text[i] == ')'))
855 {
856 *p++='\\';
857 escapes++;
858 }
859 *p++=text[i];
860 }
861 *p='\0';
862 return(buffer);
863}
864
cristy47b838c2009-09-19 16:09:30 +0000865static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
866 Image *image,Image *inject_image)
867{
cristy47b838c2009-09-19 16:09:30 +0000868 Image
cristy80975862009-09-25 14:34:31 +0000869 *group4_image;
cristy47b838c2009-09-19 16:09:30 +0000870
871 ImageInfo
872 *write_info;
873
cristy47b838c2009-09-19 16:09:30 +0000874 MagickBooleanType
875 status;
876
cristy80975862009-09-25 14:34:31 +0000877 size_t
878 length;
cristy47b838c2009-09-19 16:09:30 +0000879
880 unsigned char
cristy80975862009-09-25 14:34:31 +0000881 *group4;
cristy47b838c2009-09-19 16:09:30 +0000882
cristy42751fe2009-10-05 00:15:50 +0000883 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +0000884 write_info=CloneImageInfo(image_info);
cristy80975862009-09-25 14:34:31 +0000885 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
886 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
887 group4_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
888 if (group4_image == (Image *) NULL)
889 return(MagickFalse);
890 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
891 &image->exception);
892 group4_image=DestroyImage(group4_image);
893 if (group4 == (unsigned char *) NULL)
894 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +0000895 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +0000896 if (WriteBlob(image,length,group4) != (ssize_t) length)
897 status=MagickFalse;
898 group4=(unsigned char *) RelinquishMagickMemory(group4);
899 return(status);
cristy47b838c2009-09-19 16:09:30 +0000900}
901
cristy3ed852e2009-09-05 21:47:34 +0000902static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image)
903{
904#define CFormat "/Filter [ /%s ]\n"
905#define ObjectsPerImage 14
906
907 static const char
908 XMPProfile[]=
909 {
910 "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
911 "<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"
912 " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
913 " <rdf:Description rdf:about=\"\"\n"
914 " xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
915 " <xap:ModifyDate>%s</xap:ModifyDate>\n"
916 " <xap:CreateDate>%s</xap:CreateDate>\n"
917 " <xap:MetadataDate>%s</xap:MetadataDate>\n"
918 " <xap:CreatorTool>%s</xap:CreatorTool>\n"
919 " </rdf:Description>\n"
920 " <rdf:Description rdf:about=\"\"\n"
921 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
922 " <dc:format>application/pdf</dc:format>\n"
923 " </rdf:Description>\n"
924 " <rdf:Description rdf:about=\"\"\n"
925 " xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
926 " <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
927 " <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
928 " </rdf:Description>\n"
929 " <rdf:Description rdf:about=\"\"\n"
930 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
931 " <pdf:Producer>%s</pdf:Producer>\n"
932 " </rdf:Description>\n"
933 " <rdf:Description rdf:about=\"\"\n"
934 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
935 " <pdfaid:part>1</pdfaid:part>\n"
936 " <pdfaid:conformance>B</pdfaid:conformance>\n"
937 " </rdf:Description>\n"
938 " </rdf:RDF>\n"
939 "</x:xmpmeta>\n"
940 "<?xpacket end=\"w\"?>\n"
941 },
942 XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
943
944 char
945 buffer[MaxTextExtent],
946 date[MaxTextExtent],
947 **labels,
948 page_geometry[MaxTextExtent];
949
950 CompressionType
951 compression;
952
953 const char
954 *value;
955
956 double
957 pointsize;
958
959 GeometryInfo
960 geometry_info;
961
cristybb503372010-05-27 20:51:26 +0000962 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000963 count,
964 y;
965
966 Image
967 *next,
968 *tile_image;
969
970 MagickBooleanType
971 status;
972
973 MagickOffsetType
974 offset,
975 scene,
976 *xref;
977
978 MagickSizeType
979 number_pixels;
980
981 MagickStatusType
982 flags;
983
984 PointInfo
985 delta,
986 resolution,
987 scale;
988
989 RectangleInfo
990 geometry,
991 media_info,
992 page_info;
993
994 register const IndexPacket
995 *indexes;
996
997 register const PixelPacket
998 *p;
999
1000 register unsigned char
1001 *q;
1002
cristybb503372010-05-27 20:51:26 +00001003 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001004 i,
1005 x;
1006
1007 size_t
1008 length;
1009
1010 struct tm
1011 local_time;
1012
1013 time_t
1014 seconds;
1015
1016 unsigned char
1017 *pixels;
1018
cristybb503372010-05-27 20:51:26 +00001019 size_t
cristy3ed852e2009-09-05 21:47:34 +00001020 info_id,
1021 object,
1022 pages_id,
1023 root_id,
1024 text_size,
1025 version;
1026
1027 /*
1028 Open output image file.
1029 */
1030 assert(image_info != (const ImageInfo *) NULL);
1031 assert(image_info->signature == MagickSignature);
1032 assert(image != (Image *) NULL);
1033 assert(image->signature == MagickSignature);
1034 if (image->debug != MagickFalse)
1035 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1036 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1037 if (status == MagickFalse)
1038 return(status);
1039 /*
1040 Allocate X ref memory.
1041 */
1042 xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1043 if (xref == (MagickOffsetType *) NULL)
1044 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1045 (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1046 /*
1047 Write Info object.
1048 */
1049 object=0;
1050 version=3;
1051 if (image_info->compression == JPEG2000Compression)
cristybb503372010-05-27 20:51:26 +00001052 version=(size_t) MagickMax(version,5);
cristy3ed852e2009-09-05 21:47:34 +00001053 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1054 if (next->matte != MagickFalse)
cristybb503372010-05-27 20:51:26 +00001055 version=(size_t) MagickMax(version,4);
cristy3ed852e2009-09-05 21:47:34 +00001056 if (LocaleCompare(image_info->magick,"PDFA") == 0)
cristybb503372010-05-27 20:51:26 +00001057 version=(size_t) MagickMax(version,6);
cristy3ed852e2009-09-05 21:47:34 +00001058 (void) FormatMagickString(buffer,MaxTextExtent,"%%PDF-1.%lu \n",version);
1059 (void) WriteBlobString(image,buffer);
1060 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1061 (void) WriteBlobString(image,"%âãÏÓ\n");
1062 /*
1063 Write Catalog object.
1064 */
1065 xref[object++]=TellBlob(image);
1066 root_id=object;
1067 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1068 (void) WriteBlobString(image,buffer);
1069 (void) WriteBlobString(image,"<<\n");
1070 if (LocaleCompare(image_info->magick,"PDFA") != 0)
1071 (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %lu 0 R\n",
1072 object+1);
1073 else
1074 {
1075 (void) FormatMagickString(buffer,MaxTextExtent,"/Metadata %lu 0 R\n",
1076 object+1);
1077 (void) WriteBlobString(image,buffer);
1078 (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %lu 0 R\n",
1079 object+2);
1080 }
1081 (void) WriteBlobString(image,buffer);
1082 (void) WriteBlobString(image,"/Type /Catalog\n");
1083 (void) WriteBlobString(image,">>\n");
1084 (void) WriteBlobString(image,"endobj\n");
1085 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1086 {
1087 char
1088 create_date[MaxTextExtent],
1089 modify_date[MaxTextExtent],
1090 timestamp[MaxTextExtent],
1091 xmp_profile[MaxTextExtent];
1092
cristybb503372010-05-27 20:51:26 +00001093 size_t
cristy3ed852e2009-09-05 21:47:34 +00001094 version;
1095
1096 /*
1097 Write XMP object.
1098 */
1099 xref[object++]=TellBlob(image);
1100 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1101 (void) WriteBlobString(image,buffer);
1102 (void) WriteBlobString(image,"<<\n");
1103 (void) WriteBlobString(image,"/Subtype /XML\n");
1104 *modify_date='\0';
1105 value=GetImageProperty(image,"date:modify");
1106 if (value != (const char *) NULL)
1107 (void) CopyMagickString(modify_date,value,MaxTextExtent);
1108 *create_date='\0';
1109 value=GetImageProperty(image,"date:create");
1110 if (value != (const char *) NULL)
1111 (void) CopyMagickString(create_date,value,MaxTextExtent);
1112 (void) FormatMagickTime(time((time_t *) NULL),MaxTextExtent,timestamp);
1113 i=FormatMagickString(xmp_profile,MaxTextExtent,XMPProfile,
1114 XMPProfileMagick,modify_date,create_date,timestamp,
1115 GetMagickVersion(&version),GetMagickVersion(&version));
1116 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu\n",1UL*i);
1117 (void) WriteBlobString(image,buffer);
1118 (void) WriteBlobString(image,"/Type /Metadata\n");
1119 (void) WriteBlobString(image,">>\nstream\n");
1120 (void) WriteBlobString(image,xmp_profile);
1121 (void) WriteBlobString(image,"endstream\n");
1122 (void) WriteBlobString(image,"endobj\n");
1123 }
1124 /*
1125 Write Pages object.
1126 */
1127 xref[object++]=TellBlob(image);
1128 pages_id=object;
1129 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1130 (void) WriteBlobString(image,buffer);
1131 (void) WriteBlobString(image,"<<\n");
1132 (void) WriteBlobString(image,"/Type /Pages\n");
1133 (void) FormatMagickString(buffer,MaxTextExtent,"/Kids [ %lu 0 R ",object+1);
1134 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001135 count=(ssize_t) (pages_id+ObjectsPerImage+1);
cristy3ed852e2009-09-05 21:47:34 +00001136 if (image_info->adjoin != MagickFalse)
1137 {
1138 Image
1139 *kid_image;
1140
1141 /*
1142 Predict page object id's.
1143 */
1144 kid_image=image;
1145 for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1146 {
1147 (void) FormatMagickString(buffer,MaxTextExtent,"%ld 0 R ",count);
1148 (void) WriteBlobString(image,buffer);
1149 kid_image=GetNextImageInList(kid_image);
1150 }
1151 xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1152 sizeof(*xref));
1153 if (xref == (MagickOffsetType *) NULL)
1154 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1155 }
1156 (void) WriteBlobString(image,"]\n");
1157 (void) FormatMagickString(buffer,MaxTextExtent,"/Count %lu\n",
1158 (count-pages_id)/ObjectsPerImage);
1159 (void) WriteBlobString(image,buffer);
1160 (void) WriteBlobString(image,">>\n");
1161 (void) WriteBlobString(image,"endobj\n");
1162 scene=0;
1163 do
1164 {
1165 compression=image->compression;
1166 if (image_info->compression != UndefinedCompression)
1167 compression=image_info->compression;
1168 switch (compression)
1169 {
1170 case FaxCompression:
1171 case Group4Compression:
1172 {
1173 if ((IsMonochromeImage(image,&image->exception) == MagickFalse) ||
1174 (image->matte != MagickFalse))
1175 compression=RLECompression;
1176 break;
1177 }
1178#if !defined(MAGICKCORE_JPEG_DELEGATE)
1179 case JPEGCompression:
1180 {
1181 compression=RLECompression;
1182 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1183 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1184 image->filename);
1185 break;
1186 }
1187#endif
1188#if !defined(MAGICKCORE_JP2_DELEGATE)
1189 case JPEG2000Compression:
1190 {
1191 compression=RLECompression;
1192 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1193 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1194 image->filename);
1195 break;
1196 }
1197#endif
1198#if !defined(MAGICKCORE_ZLIB_DELEGATE)
1199 case ZipCompression:
1200 {
1201 compression=RLECompression;
1202 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1203 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1204 image->filename);
1205 break;
1206 }
1207#endif
1208 case LZWCompression:
1209 {
1210 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1211 compression=RLECompression; /* LZW compression is forbidden */
1212 break;
1213 }
1214 case NoCompression:
1215 {
1216 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1217 compression=RLECompression; /* ASCII 85 compression is forbidden */
1218 break;
1219 }
1220 default:
1221 break;
1222 }
1223 if (compression == JPEG2000Compression)
1224 {
1225 if (image->colorspace != RGBColorspace)
1226 (void) TransformImageColorspace(image,RGBColorspace);
1227 }
1228 /*
1229 Scale relative to dots-per-inch.
1230 */
1231 delta.x=DefaultResolution;
1232 delta.y=DefaultResolution;
1233 resolution.x=image->x_resolution;
1234 resolution.y=image->y_resolution;
1235 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1236 {
1237 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1238 resolution.x=geometry_info.rho;
1239 resolution.y=geometry_info.sigma;
1240 if ((flags & SigmaValue) == 0)
1241 resolution.y=resolution.x;
1242 }
1243 if (image_info->density != (char *) NULL)
1244 {
1245 flags=ParseGeometry(image_info->density,&geometry_info);
1246 resolution.x=geometry_info.rho;
1247 resolution.y=geometry_info.sigma;
1248 if ((flags & SigmaValue) == 0)
1249 resolution.y=resolution.x;
1250 }
1251 if (image->units == PixelsPerCentimeterResolution)
1252 {
cristybb503372010-05-27 20:51:26 +00001253 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0;
1254 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +00001255 }
1256 SetGeometry(image,&geometry);
1257 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu",
1258 image->columns,image->rows);
1259 if (image_info->page != (char *) NULL)
1260 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1261 else
1262 if ((image->page.width != 0) && (image->page.height != 0))
1263 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
1264 image->page.width,image->page.height,image->page.x,image->page.y);
1265 else
1266 if ((image->gravity != UndefinedGravity) &&
1267 (LocaleCompare(image_info->magick,"PDF") == 0))
1268 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1269 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1270 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1271 &geometry.width,&geometry.height);
1272 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +00001273 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001274 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +00001275 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001276 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1277 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1278 &image->exception);
1279 if (image->gravity != UndefinedGravity)
1280 {
1281 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +00001282 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001283 }
1284 pointsize=12.0;
1285 if (image_info->pointsize != 0.0)
1286 pointsize=image_info->pointsize;
1287 text_size=0;
1288 value=GetImageProperty(image,"Label");
1289 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +00001290 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristy3ed852e2009-09-05 21:47:34 +00001291 /*
1292 Write Page object.
1293 */
1294 xref[object++]=TellBlob(image);
1295 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1296 (void) WriteBlobString(image,buffer);
1297 (void) WriteBlobString(image,"<<\n");
1298 (void) WriteBlobString(image,"/Type /Page\n");
1299 (void) FormatMagickString(buffer,MaxTextExtent,"/Parent %lu 0 R\n",
1300 pages_id);
1301 (void) WriteBlobString(image,buffer);
1302 (void) WriteBlobString(image,"/Resources <<\n");
1303 labels=(char **) NULL;
1304 value=GetImageProperty(image,"Label");
1305 if (value != (const char *) NULL)
1306 labels=StringToList(value);
1307 if (labels != (char **) NULL)
1308 {
1309 (void) FormatMagickString(buffer,MaxTextExtent,
1310 "/Font << /F%lu %lu 0 R >>\n",image->scene,object+4);
1311 (void) WriteBlobString(image,buffer);
1312 }
1313 (void) FormatMagickString(buffer,MaxTextExtent,
1314 "/XObject << /Im%lu %lu 0 R >>\n",image->scene,object+5);
1315 (void) WriteBlobString(image,buffer);
1316 (void) FormatMagickString(buffer,MaxTextExtent,"/ProcSet %lu 0 R >>\n",
1317 object+3);
1318 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001319 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001320 "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001321 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001322 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001323 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001324 "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001325 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001326 (void) WriteBlobString(image,buffer);
1327 (void) FormatMagickString(buffer,MaxTextExtent,"/Contents %lu 0 R\n",
1328 object+1);
1329 (void) WriteBlobString(image,buffer);
1330 (void) FormatMagickString(buffer,MaxTextExtent,"/Thumb %lu 0 R\n",
1331 object+8);
1332 (void) WriteBlobString(image,buffer);
1333 (void) WriteBlobString(image,">>\n");
1334 (void) WriteBlobString(image,"endobj\n");
1335 /*
1336 Write Contents object.
1337 */
1338 xref[object++]=TellBlob(image);
1339 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1340 (void) WriteBlobString(image,buffer);
1341 (void) WriteBlobString(image,"<<\n");
1342 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1343 object+1);
1344 (void) WriteBlobString(image,buffer);
1345 (void) WriteBlobString(image,">>\n");
1346 (void) WriteBlobString(image,"stream\n");
1347 offset=TellBlob(image);
1348 (void) WriteBlobString(image,"q\n");
1349 if (labels != (char **) NULL)
1350 for (i=0; labels[i] != (char *) NULL; i++)
1351 {
1352 (void) WriteBlobString(image,"BT\n");
cristye7f51092010-01-17 00:39:37 +00001353 (void) FormatMagickString(buffer,MaxTextExtent,"/F%lu %g Tf\n",
cristy3ed852e2009-09-05 21:47:34 +00001354 image->scene,pointsize);
1355 (void) WriteBlobString(image,buffer);
1356 (void) FormatMagickString(buffer,MaxTextExtent,"%ld %ld Td\n",
cristybb503372010-05-27 20:51:26 +00001357 geometry.x,(ssize_t) (geometry.y+geometry.height+i*pointsize+12));
cristy3ed852e2009-09-05 21:47:34 +00001358 (void) WriteBlobString(image,buffer);
1359 (void) FormatMagickString(buffer,MaxTextExtent,"(%s) Tj\n",labels[i]);
1360 (void) WriteBlobString(image,buffer);
1361 (void) WriteBlobString(image,"ET\n");
1362 labels[i]=DestroyString(labels[i]);
1363 }
cristy8cd5b312010-01-07 01:10:24 +00001364 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001365 "%g 0 0 %g %ld %ld cm\n",scale.x,scale.y,geometry.x,geometry.y);
cristy3ed852e2009-09-05 21:47:34 +00001366 (void) WriteBlobString(image,buffer);
1367 (void) FormatMagickString(buffer,MaxTextExtent,"/Im%lu Do\n",image->scene);
1368 (void) WriteBlobString(image,buffer);
1369 (void) WriteBlobString(image,"Q\n");
1370 offset=TellBlob(image)-offset;
1371 (void) WriteBlobString(image,"endstream\n");
1372 (void) WriteBlobString(image,"endobj\n");
1373 /*
1374 Write Length object.
1375 */
1376 xref[object++]=TellBlob(image);
1377 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1378 (void) WriteBlobString(image,buffer);
1379 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00001380 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00001381 (void) WriteBlobString(image,buffer);
1382 (void) WriteBlobString(image,"endobj\n");
1383 /*
1384 Write Procset object.
1385 */
1386 xref[object++]=TellBlob(image);
1387 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1388 (void) WriteBlobString(image,buffer);
1389 if ((image->storage_class == DirectClass) || (image->colors > 256))
1390 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MaxTextExtent);
1391 else
1392 if ((compression == FaxCompression) || (compression == Group4Compression))
1393 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MaxTextExtent);
1394 else
1395 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MaxTextExtent);
1396 (void) WriteBlobString(image,buffer);
1397 (void) WriteBlobString(image," ]\n");
1398 (void) WriteBlobString(image,"endobj\n");
1399 /*
1400 Write Font object.
1401 */
1402 xref[object++]=TellBlob(image);
1403 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1404 (void) WriteBlobString(image,buffer);
1405 (void) WriteBlobString(image,"<<\n");
1406 if (labels != (char **) NULL)
1407 {
1408 (void) WriteBlobString(image,"/Type /Font\n");
1409 (void) WriteBlobString(image,"/Subtype /Type1\n");
1410 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /F%lu\n",
1411 image->scene);
1412 (void) WriteBlobString(image,buffer);
1413 (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1414 (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1415 labels=(char **) RelinquishMagickMemory(labels);
1416 }
1417 (void) WriteBlobString(image,">>\n");
1418 (void) WriteBlobString(image,"endobj\n");
1419 /*
1420 Write XObject object.
1421 */
1422 xref[object++]=TellBlob(image);
1423 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1424 (void) WriteBlobString(image,buffer);
1425 (void) WriteBlobString(image,"<<\n");
1426 (void) WriteBlobString(image,"/Type /XObject\n");
1427 (void) WriteBlobString(image,"/Subtype /Image\n");
1428 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Im%lu\n",
1429 image->scene);
1430 (void) WriteBlobString(image,buffer);
1431 switch (compression)
1432 {
1433 case NoCompression:
1434 {
1435 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1436 break;
1437 }
1438 case JPEGCompression:
1439 {
1440 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1441 if (image->colorspace != CMYKColorspace)
1442 break;
1443 (void) WriteBlobString(image,buffer);
1444 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1445 MaxTextExtent);
1446 break;
1447 }
1448 case JPEG2000Compression:
1449 {
1450 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1451 if (image->colorspace != CMYKColorspace)
1452 break;
1453 (void) WriteBlobString(image,buffer);
1454 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1455 MaxTextExtent);
1456 break;
1457 }
1458 case LZWCompression:
1459 {
cristyfa7becb2009-09-13 02:44:40 +00001460 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1461 break;
cristy3ed852e2009-09-05 21:47:34 +00001462 }
1463 case ZipCompression:
1464 {
cristyfa7becb2009-09-13 02:44:40 +00001465 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1466 break;
cristy3ed852e2009-09-05 21:47:34 +00001467 }
1468 case FaxCompression:
1469 case Group4Compression:
1470 {
1471 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1472 MaxTextExtent);
1473 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001474 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristy80975862009-09-25 14:34:31 +00001475 "/K %s /BlackIs1 false /Columns %ld /Rows %ld >> ]\n",CCITTParam,
cristya55e1092009-09-13 02:41:40 +00001476 image->columns,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001477 break;
1478 }
1479 default:
1480 {
1481 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1482 "RunLengthDecode");
1483 break;
1484 }
1485 }
1486 (void) WriteBlobString(image,buffer);
1487 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
1488 image->columns);
1489 (void) WriteBlobString(image,buffer);
1490 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",image->rows);
1491 (void) WriteBlobString(image,buffer);
1492 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %lu 0 R\n",
1493 object+2);
1494 (void) WriteBlobString(image,buffer);
1495 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1496 (compression == FaxCompression) || (compression == Group4Compression) ?
1497 1 : 8);
1498 (void) WriteBlobString(image,buffer);
1499 if (image->matte != MagickFalse)
1500 {
1501 (void) FormatMagickString(buffer,MaxTextExtent,"/SMask %lu 0 R\n",
1502 object+7);
1503 (void) WriteBlobString(image,buffer);
1504 }
1505 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1506 object+1);
1507 (void) WriteBlobString(image,buffer);
1508 (void) WriteBlobString(image,">>\n");
1509 (void) WriteBlobString(image,"stream\n");
1510 offset=TellBlob(image);
1511 number_pixels=(MagickSizeType) image->columns*image->rows;
1512 if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1513 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1514 if ((compression == FaxCompression) || (compression == Group4Compression) ||
1515 ((image_info->type != TrueColorType) &&
1516 (IsGrayImage(image,&image->exception) != MagickFalse)))
1517 {
1518 switch (compression)
1519 {
1520 case FaxCompression:
1521 case Group4Compression:
1522 {
1523 if (LocaleCompare(CCITTParam,"0") == 0)
1524 {
1525 (void) HuffmanEncodeImage(image_info,image,image);
1526 break;
1527 }
1528 (void) Huffman2DEncodeImage(image_info,image,image);
1529 break;
1530 }
1531 case JPEGCompression:
1532 {
1533 status=InjectImageBlob(image_info,image,image,"jpeg",
1534 &image->exception);
1535 if (status == MagickFalse)
1536 ThrowWriterException(CoderError,image->exception.reason);
1537 break;
1538 }
1539 case JPEG2000Compression:
1540 {
1541 status=InjectImageBlob(image_info,image,image,"jp2",
1542 &image->exception);
1543 if (status == MagickFalse)
1544 ThrowWriterException(CoderError,image->exception.reason);
1545 break;
1546 }
1547 case RLECompression:
1548 default:
1549 {
1550 /*
1551 Allocate pixel array.
1552 */
1553 length=(size_t) number_pixels;
1554 pixels=(unsigned char *) AcquireQuantumMemory(length,
1555 sizeof(*pixels));
1556 if (pixels == (unsigned char *) NULL)
1557 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1558 /*
1559 Dump Runlength encoded pixels.
1560 */
1561 q=pixels;
cristybb503372010-05-27 20:51:26 +00001562 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001563 {
1564 p=GetVirtualPixels(image,0,y,image->columns,1,
1565 &image->exception);
1566 if (p == (const PixelPacket *) NULL)
1567 break;
cristybb503372010-05-27 20:51:26 +00001568 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001569 {
1570 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1571 p++;
1572 }
1573 if (image->previous == (Image *) NULL)
1574 {
1575 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1576 if (status == MagickFalse)
1577 break;
1578 }
1579 }
1580#if defined(MAGICKCORE_ZLIB_DELEGATE)
1581 if (compression == ZipCompression)
1582 status=ZLIBEncodeImage(image,length,pixels);
1583 else
1584#endif
1585 if (compression == LZWCompression)
1586 status=LZWEncodeImage(image,length,pixels);
1587 else
1588 status=PackbitsEncodeImage(image,length,pixels);
1589 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1590 if (status == MagickFalse)
1591 {
1592 (void) CloseBlob(image);
1593 return(MagickFalse);
1594 }
1595 break;
1596 }
1597 case NoCompression:
1598 {
1599 /*
1600 Dump uncompressed PseudoColor packets.
1601 */
1602 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001603 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001604 {
1605 p=GetVirtualPixels(image,0,y,image->columns,1,
1606 &image->exception);
1607 if (p == (const PixelPacket *) NULL)
1608 break;
cristybb503372010-05-27 20:51:26 +00001609 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001610 {
1611 Ascii85Encode(image,
1612 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
1613 p++;
1614 }
1615 if (image->previous == (Image *) NULL)
1616 {
1617 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1618 if (status == MagickFalse)
1619 break;
1620 }
1621 }
1622 Ascii85Flush(image);
1623 break;
1624 }
1625 }
1626 }
1627 else
1628 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1629 (compression == JPEGCompression) ||
1630 (compression == JPEG2000Compression))
1631 switch (compression)
1632 {
1633 case JPEGCompression:
1634 {
1635 status=InjectImageBlob(image_info,image,image,"jpeg",
1636 &image->exception);
1637 if (status == MagickFalse)
1638 ThrowWriterException(CoderError,image->exception.reason);
1639 break;
1640 }
1641 case JPEG2000Compression:
1642 {
1643 status=InjectImageBlob(image_info,image,image,"jp2",
1644 &image->exception);
1645 if (status == MagickFalse)
1646 ThrowWriterException(CoderError,image->exception.reason);
1647 break;
1648 }
1649 case RLECompression:
1650 default:
1651 {
1652 /*
1653 Allocate pixel array.
1654 */
1655 length=(size_t) number_pixels;
1656 pixels=(unsigned char *) AcquireQuantumMemory(length,
1657 4*sizeof(*pixels));
1658 length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1659 if (pixels == (unsigned char *) NULL)
1660 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1661 /*
1662 Dump runoffset encoded pixels.
1663 */
1664 q=pixels;
cristybb503372010-05-27 20:51:26 +00001665 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001666 {
1667 p=GetVirtualPixels(image,0,y,image->columns,1,
1668 &image->exception);
1669 if (p == (const PixelPacket *) NULL)
1670 break;
1671 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001672 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001673 {
cristyce70c172010-01-07 17:15:30 +00001674 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
1675 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
1676 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001677 if (image->colorspace == CMYKColorspace)
1678 *q++=ScaleQuantumToChar(indexes[x]);
1679 p++;
1680 }
1681 if (image->previous == (Image *) NULL)
1682 {
1683 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1684 if (status == MagickFalse)
1685 break;
1686 }
1687 }
1688#if defined(MAGICKCORE_ZLIB_DELEGATE)
1689 if (compression == ZipCompression)
1690 status=ZLIBEncodeImage(image,length,pixels);
1691 else
1692#endif
1693 if (compression == LZWCompression)
1694 status=LZWEncodeImage(image,length,pixels);
1695 else
1696 status=PackbitsEncodeImage(image,length,pixels);
1697 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1698 if (status == MagickFalse)
1699 {
1700 (void) CloseBlob(image);
1701 return(MagickFalse);
1702 }
1703 break;
1704 }
1705 case NoCompression:
1706 {
1707 /*
1708 Dump uncompressed DirectColor packets.
1709 */
1710 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001711 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001712 {
1713 p=GetVirtualPixels(image,0,y,image->columns,1,
1714 &image->exception);
1715 if (p == (const PixelPacket *) NULL)
1716 break;
1717 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001718 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001719 {
cristyce70c172010-01-07 17:15:30 +00001720 Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p)));
1721 Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p)));
1722 Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00001723 if (image->colorspace == CMYKColorspace)
1724 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
1725 p++;
1726 }
1727 if (image->previous == (Image *) NULL)
1728 {
1729 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1730 if (status == MagickFalse)
1731 break;
1732 }
1733 }
1734 Ascii85Flush(image);
1735 break;
1736 }
1737 }
1738 else
1739 {
1740 /*
1741 Dump number of colors and colormap.
1742 */
1743 switch (compression)
1744 {
1745 case RLECompression:
1746 default:
1747 {
1748 /*
1749 Allocate pixel array.
1750 */
1751 length=(size_t) number_pixels;
1752 pixels=(unsigned char *) AcquireQuantumMemory(length,
1753 sizeof(*pixels));
1754 if (pixels == (unsigned char *) NULL)
1755 ThrowWriterException(ResourceLimitError,
1756 "MemoryAllocationFailed");
1757 /*
1758 Dump Runlength encoded pixels.
1759 */
1760 q=pixels;
cristybb503372010-05-27 20:51:26 +00001761 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001762 {
1763 p=GetVirtualPixels(image,0,y,image->columns,1,
1764 &image->exception);
1765 if (p == (const PixelPacket *) NULL)
1766 break;
1767 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001768 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001769 *q++=(unsigned char) indexes[x];
1770 if (image->previous == (Image *) NULL)
1771 {
1772 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1773 if (status == MagickFalse)
1774 break;
1775 }
1776 }
1777#if defined(MAGICKCORE_ZLIB_DELEGATE)
1778 if (compression == ZipCompression)
1779 status=ZLIBEncodeImage(image,length,pixels);
1780 else
1781#endif
1782 if (compression == LZWCompression)
1783 status=LZWEncodeImage(image,length,pixels);
1784 else
1785 status=PackbitsEncodeImage(image,length,pixels);
1786 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1787 if (status == MagickFalse)
1788 {
1789 (void) CloseBlob(image);
1790 return(MagickFalse);
1791 }
1792 break;
1793 }
1794 case NoCompression:
1795 {
1796 /*
1797 Dump uncompressed PseudoColor packets.
1798 */
1799 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001800 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001801 {
1802 p=GetVirtualPixels(image,0,y,image->columns,1,
1803 &image->exception);
1804 if (p == (const PixelPacket *) NULL)
1805 break;
1806 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001807 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001808 Ascii85Encode(image,(unsigned char) indexes[x]);
1809 if (image->previous == (Image *) NULL)
1810 {
1811 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1812 if (status == MagickFalse)
1813 break;
1814 }
1815 }
1816 Ascii85Flush(image);
1817 break;
1818 }
1819 }
1820 }
1821 offset=TellBlob(image)-offset;
1822 (void) WriteBlobString(image,"\nendstream\n");
1823 (void) WriteBlobString(image,"endobj\n");
1824 /*
1825 Write Length object.
1826 */
1827 xref[object++]=TellBlob(image);
1828 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1829 (void) WriteBlobString(image,buffer);
1830 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00001831 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00001832 (void) WriteBlobString(image,buffer);
1833 (void) WriteBlobString(image,"endobj\n");
1834 /*
1835 Write Colorspace object.
1836 */
1837 xref[object++]=TellBlob(image);
1838 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1839 (void) WriteBlobString(image,buffer);
1840 if (image->colorspace == CMYKColorspace)
1841 (void) CopyMagickString(buffer,"/DeviceCMYK\n",MaxTextExtent);
1842 else
1843 if ((compression == FaxCompression) ||
1844 (compression == Group4Compression) ||
1845 ((image_info->type != TrueColorType) &&
1846 (IsGrayImage(image,&image->exception) != MagickFalse)))
1847 (void) CopyMagickString(buffer,"/DeviceGray\n",MaxTextExtent);
1848 else
1849 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1850 (compression == JPEGCompression) ||
1851 (compression == JPEG2000Compression))
1852 (void) CopyMagickString(buffer,"/DeviceRGB\n",MaxTextExtent);
1853 else
1854 (void) FormatMagickString(buffer,MaxTextExtent,
1855 "[ /Indexed /DeviceRGB %lu %lu 0 R ]\n",
1856 image->colors-1,object+3);
1857 (void) WriteBlobString(image,buffer);
1858 (void) WriteBlobString(image,"endobj\n");
1859 /*
1860 Write Thumb object.
1861 */
1862 SetGeometry(image,&geometry);
1863 (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
1864 &geometry.width,&geometry.height);
1865 tile_image=ThumbnailImage(image,geometry.width,geometry.height,
1866 &image->exception);
1867 if (tile_image == (Image *) NULL)
1868 ThrowWriterException(ResourceLimitError,image->exception.reason);
1869 xref[object++]=TellBlob(image);
1870 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1871 (void) WriteBlobString(image,buffer);
1872 (void) WriteBlobString(image,"<<\n");
1873 switch (compression)
1874 {
1875 case NoCompression:
1876 {
1877 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1878 break;
1879 }
1880 case JPEGCompression:
1881 {
1882 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1883 if (image->colorspace != CMYKColorspace)
1884 break;
1885 (void) WriteBlobString(image,buffer);
1886 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1887 MaxTextExtent);
1888 break;
1889 }
1890 case JPEG2000Compression:
1891 {
1892 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1893 if (image->colorspace != CMYKColorspace)
1894 break;
1895 (void) WriteBlobString(image,buffer);
1896 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1897 MaxTextExtent);
1898 break;
1899 }
1900 case LZWCompression:
1901 {
1902 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1903 break;
1904 }
1905 case ZipCompression:
1906 {
1907 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1908 break;
1909 }
1910 case FaxCompression:
1911 case Group4Compression:
1912 {
1913 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1914 MaxTextExtent);
1915 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001916 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristy80975862009-09-25 14:34:31 +00001917 "/K %s /BlackIs1 false /Columns %lu /Rows %lu >> ]\n",CCITTParam,
cristya55e1092009-09-13 02:41:40 +00001918 tile_image->columns,tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001919 break;
1920 }
1921 default:
1922 {
1923 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1924 "RunLengthDecode");
1925 break;
1926 }
1927 }
1928 (void) WriteBlobString(image,buffer);
1929 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
1930 tile_image->columns);
1931 (void) WriteBlobString(image,buffer);
1932 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",
1933 tile_image->rows);
1934 (void) WriteBlobString(image,buffer);
1935 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %lu 0 R\n",
1936 object-1);
1937 (void) WriteBlobString(image,buffer);
1938 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1939 (compression == FaxCompression) || (compression == Group4Compression) ?
1940 1 : 8);
1941 (void) WriteBlobString(image,buffer);
1942 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1943 object+1);
1944 (void) WriteBlobString(image,buffer);
1945 (void) WriteBlobString(image,">>\n");
1946 (void) WriteBlobString(image,"stream\n");
1947 offset=TellBlob(image);
1948 number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
1949 if ((compression == FaxCompression) ||
1950 (compression == Group4Compression) ||
1951 ((image_info->type != TrueColorType) &&
1952 (IsGrayImage(tile_image,&image->exception) != MagickFalse)))
1953 {
1954 switch (compression)
1955 {
1956 case FaxCompression:
1957 case Group4Compression:
1958 {
1959 if (LocaleCompare(CCITTParam,"0") == 0)
1960 {
1961 (void) HuffmanEncodeImage(image_info,image,tile_image);
1962 break;
1963 }
1964 (void) Huffman2DEncodeImage(image_info,image,tile_image);
1965 break;
1966 }
1967 case JPEGCompression:
1968 {
1969 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
1970 &image->exception);
1971 if (status == MagickFalse)
1972 ThrowWriterException(CoderError,tile_image->exception.reason);
1973 break;
1974 }
1975 case JPEG2000Compression:
1976 {
1977 status=InjectImageBlob(image_info,image,tile_image,"jp2",
1978 &image->exception);
1979 if (status == MagickFalse)
1980 ThrowWriterException(CoderError,tile_image->exception.reason);
1981 break;
1982 }
1983 case RLECompression:
1984 default:
1985 {
1986 /*
1987 Allocate pixel array.
1988 */
1989 length=(size_t) number_pixels;
1990 pixels=(unsigned char *) AcquireQuantumMemory(length,
1991 sizeof(*pixels));
1992 if (pixels == (unsigned char *) NULL)
1993 {
1994 tile_image=DestroyImage(tile_image);
1995 ThrowWriterException(ResourceLimitError,
1996 "MemoryAllocationFailed");
1997 }
1998 /*
1999 Dump Runlength encoded pixels.
2000 */
2001 q=pixels;
cristybb503372010-05-27 20:51:26 +00002002 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002003 {
2004 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2005 &tile_image->exception);
2006 if (p == (const PixelPacket *) NULL)
2007 break;
cristybb503372010-05-27 20:51:26 +00002008 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002009 {
2010 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
2011 p++;
2012 }
2013 }
2014#if defined(MAGICKCORE_ZLIB_DELEGATE)
2015 if (compression == ZipCompression)
2016 status=ZLIBEncodeImage(image,length,pixels);
2017 else
2018#endif
2019 if (compression == LZWCompression)
2020 status=LZWEncodeImage(image,length,pixels);
2021 else
2022 status=PackbitsEncodeImage(image,length,pixels);
2023 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2024 if (status == MagickFalse)
2025 {
2026 (void) CloseBlob(image);
2027 return(MagickFalse);
2028 }
2029 break;
2030 }
2031 case NoCompression:
2032 {
2033 /*
2034 Dump uncompressed PseudoColor packets.
2035 */
2036 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002037 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002038 {
2039 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2040 &tile_image->exception);
2041 if (p == (const PixelPacket *) NULL)
2042 break;
cristybb503372010-05-27 20:51:26 +00002043 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002044 {
2045 Ascii85Encode(image,
2046 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
2047 p++;
2048 }
2049 }
2050 Ascii85Flush(image);
2051 break;
2052 }
2053 }
2054 }
2055 else
2056 if ((tile_image->storage_class == DirectClass) ||
2057 (tile_image->colors > 256) || (compression == JPEGCompression) ||
2058 (compression == JPEG2000Compression))
2059 switch (compression)
2060 {
2061 case JPEGCompression:
2062 {
2063 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2064 &image->exception);
2065 if (status == MagickFalse)
2066 ThrowWriterException(CoderError,tile_image->exception.reason);
2067 break;
2068 }
2069 case JPEG2000Compression:
2070 {
2071 status=InjectImageBlob(image_info,image,tile_image,"jp2",
2072 &image->exception);
2073 if (status == MagickFalse)
2074 ThrowWriterException(CoderError,tile_image->exception.reason);
2075 break;
2076 }
2077 case RLECompression:
2078 default:
2079 {
2080 /*
2081 Allocate pixel array.
2082 */
2083 length=(size_t) number_pixels;
2084 pixels=(unsigned char *) AcquireQuantumMemory(length,4*
2085 sizeof(*pixels));
2086 length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2087 if (pixels == (unsigned char *) NULL)
2088 {
2089 tile_image=DestroyImage(tile_image);
2090 ThrowWriterException(ResourceLimitError,
2091 "MemoryAllocationFailed");
2092 }
2093 /*
2094 Dump runoffset encoded pixels.
2095 */
2096 q=pixels;
cristybb503372010-05-27 20:51:26 +00002097 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002098 {
2099 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2100 &tile_image->exception);
2101 if (p == (const PixelPacket *) NULL)
2102 break;
2103 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002104 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002105 {
cristyce70c172010-01-07 17:15:30 +00002106 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
2107 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
2108 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00002109 if (image->colorspace == CMYKColorspace)
2110 *q++=ScaleQuantumToChar(indexes[x]);
2111 p++;
2112 }
2113 }
2114#if defined(MAGICKCORE_ZLIB_DELEGATE)
2115 if (compression == ZipCompression)
2116 status=ZLIBEncodeImage(image,length,pixels);
2117 else
2118#endif
2119 if (compression == LZWCompression)
2120 status=LZWEncodeImage(image,length,pixels);
2121 else
2122 status=PackbitsEncodeImage(image,length,pixels);
2123 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2124 if (status == MagickFalse)
2125 {
2126 (void) CloseBlob(image);
2127 return(MagickFalse);
2128 }
2129 break;
2130 }
2131 case NoCompression:
2132 {
2133 /*
2134 Dump uncompressed DirectColor packets.
2135 */
2136 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002137 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002138 {
2139 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2140 &tile_image->exception);
2141 if (p == (const PixelPacket *) NULL)
2142 break;
2143 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002144 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002145 {
cristyce70c172010-01-07 17:15:30 +00002146 Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p)));
2147 Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p)));
2148 Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002149 if (image->colorspace == CMYKColorspace)
2150 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
2151 p++;
2152 }
2153 }
2154 Ascii85Flush(image);
2155 break;
2156 }
2157 }
2158 else
2159 {
2160 /*
2161 Dump number of colors and colormap.
2162 */
2163 switch (compression)
2164 {
2165 case RLECompression:
2166 default:
2167 {
2168 /*
2169 Allocate pixel array.
2170 */
2171 length=(size_t) number_pixels;
2172 pixels=(unsigned char *) AcquireQuantumMemory(length,
2173 sizeof(*pixels));
2174 if (pixels == (unsigned char *) NULL)
2175 {
2176 tile_image=DestroyImage(tile_image);
2177 ThrowWriterException(ResourceLimitError,
2178 "MemoryAllocationFailed");
2179 }
2180 /*
2181 Dump Runlength encoded pixels.
2182 */
2183 q=pixels;
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 *q++=(unsigned char) indexes[x];
2193 }
2194#if defined(MAGICKCORE_ZLIB_DELEGATE)
2195 if (compression == ZipCompression)
2196 status=ZLIBEncodeImage(image,length,pixels);
2197 else
2198#endif
2199 if (compression == LZWCompression)
2200 status=LZWEncodeImage(image,length,pixels);
2201 else
2202 status=PackbitsEncodeImage(image,length,pixels);
2203 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2204 if (status == MagickFalse)
2205 {
2206 (void) CloseBlob(image);
2207 return(MagickFalse);
2208 }
2209 break;
2210 }
2211 case NoCompression:
2212 {
2213 /*
2214 Dump uncompressed PseudoColor packets.
2215 */
2216 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002217 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002218 {
2219 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2220 &tile_image->exception);
2221 if (p == (const PixelPacket *) NULL)
2222 break;
2223 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002224 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002225 Ascii85Encode(image,(unsigned char) indexes[x]);
2226 }
2227 Ascii85Flush(image);
2228 break;
2229 }
2230 }
2231 }
2232 tile_image=DestroyImage(tile_image);
2233 offset=TellBlob(image)-offset;
2234 (void) WriteBlobString(image,"\nendstream\n");
2235 (void) WriteBlobString(image,"endobj\n");
2236 /*
2237 Write Length object.
2238 */
2239 xref[object++]=TellBlob(image);
2240 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2241 (void) WriteBlobString(image,buffer);
2242 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00002243 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00002244 (void) WriteBlobString(image,buffer);
2245 (void) WriteBlobString(image,"endobj\n");
2246 xref[object++]=TellBlob(image);
2247 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2248 (void) WriteBlobString(image,buffer);
2249 if ((image->storage_class != DirectClass) && (image->colors <= 256) &&
2250 (compression != FaxCompression) && (compression != Group4Compression))
2251 {
2252 /*
2253 Write Colormap object.
2254 */
2255 (void) WriteBlobString(image,"<<\n");
2256 if (compression == NoCompression)
2257 (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
2258 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
2259 object+1);
2260 (void) WriteBlobString(image,buffer);
2261 (void) WriteBlobString(image,">>\n");
2262 (void) WriteBlobString(image,"stream\n");
2263 offset=TellBlob(image);
2264 if (compression == NoCompression)
2265 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002266 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002267 {
2268 if (compression == NoCompression)
2269 {
2270 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].red));
2271 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].green));
2272 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].blue));
2273 continue;
2274 }
2275 (void) WriteBlobByte(image,
2276 ScaleQuantumToChar(image->colormap[i].red));
2277 (void) WriteBlobByte(image,
2278 ScaleQuantumToChar(image->colormap[i].green));
2279 (void) WriteBlobByte(image,
2280 ScaleQuantumToChar(image->colormap[i].blue));
2281 }
2282 if (compression == NoCompression)
2283 Ascii85Flush(image);
2284 offset=TellBlob(image)-offset;
2285 (void) WriteBlobString(image,"\nendstream\n");
2286 }
2287 (void) WriteBlobString(image,"endobj\n");
2288 /*
2289 Write Length object.
2290 */
2291 xref[object++]=TellBlob(image);
2292 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2293 (void) WriteBlobString(image,buffer);
2294 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00002295 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00002296 (void) WriteBlobString(image,buffer);
2297 (void) WriteBlobString(image,"endobj\n");
2298 /*
2299 Write softmask object.
2300 */
2301 xref[object++]=TellBlob(image);
2302 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2303 (void) WriteBlobString(image,buffer);
2304 (void) WriteBlobString(image,"<<\n");
2305 if (image->matte == MagickFalse)
2306 (void) WriteBlobString(image,">>\n");
2307 else
2308 {
2309 (void) WriteBlobString(image,"/Type /XObject\n");
2310 (void) WriteBlobString(image,"/Subtype /Image\n");
2311 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Ma%lu\n",
2312 image->scene);
2313 (void) WriteBlobString(image,buffer);
2314 switch (compression)
2315 {
2316 case NoCompression:
2317 {
2318 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2319 "ASCII85Decode");
2320 break;
2321 }
2322 case LZWCompression:
2323 {
2324 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
2325 break;
2326 }
2327 case ZipCompression:
2328 {
2329 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2330 "FlateDecode");
2331 break;
2332 }
2333 default:
2334 {
2335 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2336 "RunLengthDecode");
2337 break;
2338 }
2339 }
2340 (void) WriteBlobString(image,buffer);
2341 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
2342 image->columns);
2343 (void) WriteBlobString(image,buffer);
2344 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",
2345 image->rows);
2346 (void) WriteBlobString(image,buffer);
2347 (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2348 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
2349 (compression == FaxCompression) || (compression == Group4Compression)
2350 ? 1 : 8);
2351 (void) WriteBlobString(image,buffer);
2352 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
2353 object+1);
2354 (void) WriteBlobString(image,buffer);
2355 (void) WriteBlobString(image,">>\n");
2356 (void) WriteBlobString(image,"stream\n");
2357 offset=TellBlob(image);
2358 number_pixels=(MagickSizeType) image->columns*image->rows;
2359 switch (compression)
2360 {
2361 case RLECompression:
2362 default:
2363 {
2364 /*
2365 Allocate pixel array.
2366 */
2367 length=(size_t) number_pixels;
2368 pixels=(unsigned char *) AcquireQuantumMemory(length,
2369 sizeof(*pixels));
2370 if (pixels == (unsigned char *) NULL)
2371 {
2372 image=DestroyImage(image);
2373 ThrowWriterException(ResourceLimitError,
2374 "MemoryAllocationFailed");
2375 }
2376 /*
2377 Dump Runlength encoded pixels.
2378 */
2379 q=pixels;
cristybb503372010-05-27 20:51:26 +00002380 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002381 {
2382 p=GetVirtualPixels(image,0,y,image->columns,1,
2383 &image->exception);
2384 if (p == (const PixelPacket *) NULL)
2385 break;
cristybb503372010-05-27 20:51:26 +00002386 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002387 {
cristy46f08202010-01-10 04:04:21 +00002388 *q++=ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002389 p++;
2390 }
2391 }
2392#if defined(MAGICKCORE_ZLIB_DELEGATE)
2393 if (compression == ZipCompression)
2394 status=ZLIBEncodeImage(image,length,pixels);
2395 else
2396#endif
2397 if (compression == LZWCompression)
2398 status=LZWEncodeImage(image,length,pixels);
2399 else
2400 status=PackbitsEncodeImage(image,length,pixels);
2401 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2402 if (status == MagickFalse)
2403 {
2404 (void) CloseBlob(image);
2405 return(MagickFalse);
2406 }
2407 break;
2408 }
2409 case NoCompression:
2410 {
2411 /*
2412 Dump uncompressed PseudoColor packets.
2413 */
2414 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002415 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002416 {
2417 p=GetVirtualPixels(image,0,y,image->columns,1,
2418 &image->exception);
2419 if (p == (const PixelPacket *) NULL)
2420 break;
cristybb503372010-05-27 20:51:26 +00002421 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002422 {
2423 Ascii85Encode(image,ScaleQuantumToChar((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002424 GetOpacityPixelComponent(p))));
cristy3ed852e2009-09-05 21:47:34 +00002425 p++;
2426 }
2427 }
2428 Ascii85Flush(image);
2429 break;
2430 }
2431 }
2432 offset=TellBlob(image)-offset;
2433 (void) WriteBlobString(image,"\nendstream\n");
2434 }
2435 (void) WriteBlobString(image,"endobj\n");
2436 /*
2437 Write Length object.
2438 */
2439 xref[object++]=TellBlob(image);
2440 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2441 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00002442 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(size_t)
cristy3ed852e2009-09-05 21:47:34 +00002443 offset);
2444 (void) WriteBlobString(image,buffer);
2445 (void) WriteBlobString(image,"endobj\n");
2446 if (GetNextImageInList(image) == (Image *) NULL)
2447 break;
2448 image=SyncNextImageInList(image);
2449 status=SetImageProgress(image,SaveImagesTag,scene++,
2450 GetImageListLength(image));
2451 if (status == MagickFalse)
2452 break;
2453 } while (image_info->adjoin != MagickFalse);
2454 /*
2455 Write Metadata object.
2456 */
2457 xref[object++]=TellBlob(image);
2458 info_id=object;
2459 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2460 (void) WriteBlobString(image,buffer);
2461 (void) WriteBlobString(image,"<<\n");
2462 (void) FormatMagickString(buffer,MaxTextExtent,"/Title (%s)\n",
2463 EscapeParenthesis(image->filename));
2464 (void) WriteBlobString(image,buffer);
2465 seconds=time((time_t *) NULL);
2466#if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2467 (void) localtime_r(&seconds,&local_time);
2468#else
2469 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2470#endif
2471 (void) FormatMagickString(date,MaxTextExtent,"D:%04d%02d%02d%02d%02d%02d",
2472 local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2473 local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2474 (void) FormatMagickString(buffer,MaxTextExtent,"/CreationDate (%s)\n",date);
2475 (void) WriteBlobString(image,buffer);
2476 (void) FormatMagickString(buffer,MaxTextExtent,"/ModDate (%s)\n",date);
2477 (void) WriteBlobString(image,buffer);
2478 (void) FormatMagickString(buffer,MaxTextExtent,"/Producer (%s)\n",
cristybb503372010-05-27 20:51:26 +00002479 EscapeParenthesis(GetMagickVersion((size_t *) NULL)));
cristy3ed852e2009-09-05 21:47:34 +00002480 (void) WriteBlobString(image,buffer);
2481 (void) WriteBlobString(image,">>\n");
2482 (void) WriteBlobString(image,"endobj\n");
2483 /*
2484 Write Xref object.
2485 */
2486 offset=TellBlob(image)-xref[0]+10;
2487 (void) WriteBlobString(image,"xref\n");
2488 (void) FormatMagickString(buffer,MaxTextExtent,"0 %lu\n",object+1);
2489 (void) WriteBlobString(image,buffer);
2490 (void) WriteBlobString(image,"0000000000 65535 f \n");
cristybb503372010-05-27 20:51:26 +00002491 for (i=0; i < (ssize_t) object; i++)
cristy3ed852e2009-09-05 21:47:34 +00002492 {
2493 (void) FormatMagickString(buffer,MaxTextExtent,"%010lu 00000 n \n",
cristybb503372010-05-27 20:51:26 +00002494 (size_t) xref[i]);
cristy3ed852e2009-09-05 21:47:34 +00002495 (void) WriteBlobString(image,buffer);
2496 }
2497 (void) WriteBlobString(image,"trailer\n");
2498 (void) WriteBlobString(image,"<<\n");
2499 (void) FormatMagickString(buffer,MaxTextExtent,"/Size %lu\n",object+1);
2500 (void) WriteBlobString(image,buffer);
2501 (void) FormatMagickString(buffer,MaxTextExtent,"/Info %lu 0 R\n",info_id);
2502 (void) WriteBlobString(image,buffer);
2503 (void) FormatMagickString(buffer,MaxTextExtent,"/Root %lu 0 R\n",root_id);
2504 (void) WriteBlobString(image,buffer);
2505 (void) WriteBlobString(image,">>\n");
2506 (void) WriteBlobString(image,"startxref\n");
2507 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00002508 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00002509 (void) WriteBlobString(image,buffer);
2510 (void) WriteBlobString(image,"%%EOF\n");
2511 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2512 (void) CloseBlob(image);
2513 return(MagickTrue);
2514}