blob: a759b38cef556aba6d4ad94a40321b248a1bcaf1 [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 {
cristycee97112010-05-28 00:44:52 +00001575 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1576 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001577 if (status == MagickFalse)
1578 break;
1579 }
1580 }
1581#if defined(MAGICKCORE_ZLIB_DELEGATE)
1582 if (compression == ZipCompression)
1583 status=ZLIBEncodeImage(image,length,pixels);
1584 else
1585#endif
1586 if (compression == LZWCompression)
1587 status=LZWEncodeImage(image,length,pixels);
1588 else
1589 status=PackbitsEncodeImage(image,length,pixels);
1590 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1591 if (status == MagickFalse)
1592 {
1593 (void) CloseBlob(image);
1594 return(MagickFalse);
1595 }
1596 break;
1597 }
1598 case NoCompression:
1599 {
1600 /*
1601 Dump uncompressed PseudoColor packets.
1602 */
1603 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001604 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001605 {
1606 p=GetVirtualPixels(image,0,y,image->columns,1,
1607 &image->exception);
1608 if (p == (const PixelPacket *) NULL)
1609 break;
cristybb503372010-05-27 20:51:26 +00001610 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001611 {
1612 Ascii85Encode(image,
1613 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
1614 p++;
1615 }
1616 if (image->previous == (Image *) NULL)
1617 {
cristycee97112010-05-28 00:44:52 +00001618 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1619 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001620 if (status == MagickFalse)
1621 break;
1622 }
1623 }
1624 Ascii85Flush(image);
1625 break;
1626 }
1627 }
1628 }
1629 else
1630 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1631 (compression == JPEGCompression) ||
1632 (compression == JPEG2000Compression))
1633 switch (compression)
1634 {
1635 case JPEGCompression:
1636 {
1637 status=InjectImageBlob(image_info,image,image,"jpeg",
1638 &image->exception);
1639 if (status == MagickFalse)
1640 ThrowWriterException(CoderError,image->exception.reason);
1641 break;
1642 }
1643 case JPEG2000Compression:
1644 {
1645 status=InjectImageBlob(image_info,image,image,"jp2",
1646 &image->exception);
1647 if (status == MagickFalse)
1648 ThrowWriterException(CoderError,image->exception.reason);
1649 break;
1650 }
1651 case RLECompression:
1652 default:
1653 {
1654 /*
1655 Allocate pixel array.
1656 */
1657 length=(size_t) number_pixels;
1658 pixels=(unsigned char *) AcquireQuantumMemory(length,
1659 4*sizeof(*pixels));
1660 length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1661 if (pixels == (unsigned char *) NULL)
1662 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1663 /*
1664 Dump runoffset encoded pixels.
1665 */
1666 q=pixels;
cristybb503372010-05-27 20:51:26 +00001667 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001668 {
1669 p=GetVirtualPixels(image,0,y,image->columns,1,
1670 &image->exception);
1671 if (p == (const PixelPacket *) NULL)
1672 break;
1673 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001674 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001675 {
cristyce70c172010-01-07 17:15:30 +00001676 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
1677 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
1678 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001679 if (image->colorspace == CMYKColorspace)
1680 *q++=ScaleQuantumToChar(indexes[x]);
1681 p++;
1682 }
1683 if (image->previous == (Image *) NULL)
1684 {
cristycee97112010-05-28 00:44:52 +00001685 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1686 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001687 if (status == MagickFalse)
1688 break;
1689 }
1690 }
1691#if defined(MAGICKCORE_ZLIB_DELEGATE)
1692 if (compression == ZipCompression)
1693 status=ZLIBEncodeImage(image,length,pixels);
1694 else
1695#endif
1696 if (compression == LZWCompression)
1697 status=LZWEncodeImage(image,length,pixels);
1698 else
1699 status=PackbitsEncodeImage(image,length,pixels);
1700 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1701 if (status == MagickFalse)
1702 {
1703 (void) CloseBlob(image);
1704 return(MagickFalse);
1705 }
1706 break;
1707 }
1708 case NoCompression:
1709 {
1710 /*
1711 Dump uncompressed DirectColor packets.
1712 */
1713 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001714 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001715 {
1716 p=GetVirtualPixels(image,0,y,image->columns,1,
1717 &image->exception);
1718 if (p == (const PixelPacket *) NULL)
1719 break;
1720 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001721 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001722 {
cristyce70c172010-01-07 17:15:30 +00001723 Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p)));
1724 Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p)));
1725 Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00001726 if (image->colorspace == CMYKColorspace)
1727 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
1728 p++;
1729 }
1730 if (image->previous == (Image *) NULL)
1731 {
cristycee97112010-05-28 00:44:52 +00001732 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1733 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001734 if (status == MagickFalse)
1735 break;
1736 }
1737 }
1738 Ascii85Flush(image);
1739 break;
1740 }
1741 }
1742 else
1743 {
1744 /*
1745 Dump number of colors and colormap.
1746 */
1747 switch (compression)
1748 {
1749 case RLECompression:
1750 default:
1751 {
1752 /*
1753 Allocate pixel array.
1754 */
1755 length=(size_t) number_pixels;
1756 pixels=(unsigned char *) AcquireQuantumMemory(length,
1757 sizeof(*pixels));
1758 if (pixels == (unsigned char *) NULL)
1759 ThrowWriterException(ResourceLimitError,
1760 "MemoryAllocationFailed");
1761 /*
1762 Dump Runlength encoded pixels.
1763 */
1764 q=pixels;
cristybb503372010-05-27 20:51:26 +00001765 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001766 {
1767 p=GetVirtualPixels(image,0,y,image->columns,1,
1768 &image->exception);
1769 if (p == (const PixelPacket *) NULL)
1770 break;
1771 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001772 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001773 *q++=(unsigned char) indexes[x];
1774 if (image->previous == (Image *) NULL)
1775 {
cristycee97112010-05-28 00:44:52 +00001776 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1777 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001778 if (status == MagickFalse)
1779 break;
1780 }
1781 }
1782#if defined(MAGICKCORE_ZLIB_DELEGATE)
1783 if (compression == ZipCompression)
1784 status=ZLIBEncodeImage(image,length,pixels);
1785 else
1786#endif
1787 if (compression == LZWCompression)
1788 status=LZWEncodeImage(image,length,pixels);
1789 else
1790 status=PackbitsEncodeImage(image,length,pixels);
1791 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1792 if (status == MagickFalse)
1793 {
1794 (void) CloseBlob(image);
1795 return(MagickFalse);
1796 }
1797 break;
1798 }
1799 case NoCompression:
1800 {
1801 /*
1802 Dump uncompressed PseudoColor packets.
1803 */
1804 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001805 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001806 {
1807 p=GetVirtualPixels(image,0,y,image->columns,1,
1808 &image->exception);
1809 if (p == (const PixelPacket *) NULL)
1810 break;
1811 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +00001812 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001813 Ascii85Encode(image,(unsigned char) indexes[x]);
1814 if (image->previous == (Image *) NULL)
1815 {
cristycee97112010-05-28 00:44:52 +00001816 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1817 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001818 if (status == MagickFalse)
1819 break;
1820 }
1821 }
1822 Ascii85Flush(image);
1823 break;
1824 }
1825 }
1826 }
1827 offset=TellBlob(image)-offset;
1828 (void) WriteBlobString(image,"\nendstream\n");
1829 (void) WriteBlobString(image,"endobj\n");
1830 /*
1831 Write Length object.
1832 */
1833 xref[object++]=TellBlob(image);
1834 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1835 (void) WriteBlobString(image,buffer);
1836 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00001837 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00001838 (void) WriteBlobString(image,buffer);
1839 (void) WriteBlobString(image,"endobj\n");
1840 /*
1841 Write Colorspace object.
1842 */
1843 xref[object++]=TellBlob(image);
1844 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1845 (void) WriteBlobString(image,buffer);
1846 if (image->colorspace == CMYKColorspace)
1847 (void) CopyMagickString(buffer,"/DeviceCMYK\n",MaxTextExtent);
1848 else
1849 if ((compression == FaxCompression) ||
1850 (compression == Group4Compression) ||
1851 ((image_info->type != TrueColorType) &&
1852 (IsGrayImage(image,&image->exception) != MagickFalse)))
1853 (void) CopyMagickString(buffer,"/DeviceGray\n",MaxTextExtent);
1854 else
1855 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1856 (compression == JPEGCompression) ||
1857 (compression == JPEG2000Compression))
1858 (void) CopyMagickString(buffer,"/DeviceRGB\n",MaxTextExtent);
1859 else
1860 (void) FormatMagickString(buffer,MaxTextExtent,
1861 "[ /Indexed /DeviceRGB %lu %lu 0 R ]\n",
1862 image->colors-1,object+3);
1863 (void) WriteBlobString(image,buffer);
1864 (void) WriteBlobString(image,"endobj\n");
1865 /*
1866 Write Thumb object.
1867 */
1868 SetGeometry(image,&geometry);
1869 (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
1870 &geometry.width,&geometry.height);
1871 tile_image=ThumbnailImage(image,geometry.width,geometry.height,
1872 &image->exception);
1873 if (tile_image == (Image *) NULL)
1874 ThrowWriterException(ResourceLimitError,image->exception.reason);
1875 xref[object++]=TellBlob(image);
1876 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1877 (void) WriteBlobString(image,buffer);
1878 (void) WriteBlobString(image,"<<\n");
1879 switch (compression)
1880 {
1881 case NoCompression:
1882 {
1883 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1884 break;
1885 }
1886 case JPEGCompression:
1887 {
1888 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1889 if (image->colorspace != CMYKColorspace)
1890 break;
1891 (void) WriteBlobString(image,buffer);
1892 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1893 MaxTextExtent);
1894 break;
1895 }
1896 case JPEG2000Compression:
1897 {
1898 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1899 if (image->colorspace != CMYKColorspace)
1900 break;
1901 (void) WriteBlobString(image,buffer);
1902 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1903 MaxTextExtent);
1904 break;
1905 }
1906 case LZWCompression:
1907 {
1908 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1909 break;
1910 }
1911 case ZipCompression:
1912 {
1913 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1914 break;
1915 }
1916 case FaxCompression:
1917 case Group4Compression:
1918 {
1919 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1920 MaxTextExtent);
1921 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001922 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristy80975862009-09-25 14:34:31 +00001923 "/K %s /BlackIs1 false /Columns %lu /Rows %lu >> ]\n",CCITTParam,
cristya55e1092009-09-13 02:41:40 +00001924 tile_image->columns,tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001925 break;
1926 }
1927 default:
1928 {
1929 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1930 "RunLengthDecode");
1931 break;
1932 }
1933 }
1934 (void) WriteBlobString(image,buffer);
1935 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
1936 tile_image->columns);
1937 (void) WriteBlobString(image,buffer);
1938 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",
1939 tile_image->rows);
1940 (void) WriteBlobString(image,buffer);
1941 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %lu 0 R\n",
1942 object-1);
1943 (void) WriteBlobString(image,buffer);
1944 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1945 (compression == FaxCompression) || (compression == Group4Compression) ?
1946 1 : 8);
1947 (void) WriteBlobString(image,buffer);
1948 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1949 object+1);
1950 (void) WriteBlobString(image,buffer);
1951 (void) WriteBlobString(image,">>\n");
1952 (void) WriteBlobString(image,"stream\n");
1953 offset=TellBlob(image);
1954 number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
1955 if ((compression == FaxCompression) ||
1956 (compression == Group4Compression) ||
1957 ((image_info->type != TrueColorType) &&
1958 (IsGrayImage(tile_image,&image->exception) != MagickFalse)))
1959 {
1960 switch (compression)
1961 {
1962 case FaxCompression:
1963 case Group4Compression:
1964 {
1965 if (LocaleCompare(CCITTParam,"0") == 0)
1966 {
1967 (void) HuffmanEncodeImage(image_info,image,tile_image);
1968 break;
1969 }
1970 (void) Huffman2DEncodeImage(image_info,image,tile_image);
1971 break;
1972 }
1973 case JPEGCompression:
1974 {
1975 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
1976 &image->exception);
1977 if (status == MagickFalse)
1978 ThrowWriterException(CoderError,tile_image->exception.reason);
1979 break;
1980 }
1981 case JPEG2000Compression:
1982 {
1983 status=InjectImageBlob(image_info,image,tile_image,"jp2",
1984 &image->exception);
1985 if (status == MagickFalse)
1986 ThrowWriterException(CoderError,tile_image->exception.reason);
1987 break;
1988 }
1989 case RLECompression:
1990 default:
1991 {
1992 /*
1993 Allocate pixel array.
1994 */
1995 length=(size_t) number_pixels;
1996 pixels=(unsigned char *) AcquireQuantumMemory(length,
1997 sizeof(*pixels));
1998 if (pixels == (unsigned char *) NULL)
1999 {
2000 tile_image=DestroyImage(tile_image);
2001 ThrowWriterException(ResourceLimitError,
2002 "MemoryAllocationFailed");
2003 }
2004 /*
2005 Dump Runlength encoded pixels.
2006 */
2007 q=pixels;
cristybb503372010-05-27 20:51:26 +00002008 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002009 {
2010 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2011 &tile_image->exception);
2012 if (p == (const PixelPacket *) NULL)
2013 break;
cristybb503372010-05-27 20:51:26 +00002014 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002015 {
2016 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
2017 p++;
2018 }
2019 }
2020#if defined(MAGICKCORE_ZLIB_DELEGATE)
2021 if (compression == ZipCompression)
2022 status=ZLIBEncodeImage(image,length,pixels);
2023 else
2024#endif
2025 if (compression == LZWCompression)
2026 status=LZWEncodeImage(image,length,pixels);
2027 else
2028 status=PackbitsEncodeImage(image,length,pixels);
2029 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2030 if (status == MagickFalse)
2031 {
2032 (void) CloseBlob(image);
2033 return(MagickFalse);
2034 }
2035 break;
2036 }
2037 case NoCompression:
2038 {
2039 /*
2040 Dump uncompressed PseudoColor packets.
2041 */
2042 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002043 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002044 {
2045 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2046 &tile_image->exception);
2047 if (p == (const PixelPacket *) NULL)
2048 break;
cristybb503372010-05-27 20:51:26 +00002049 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002050 {
2051 Ascii85Encode(image,
2052 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
2053 p++;
2054 }
2055 }
2056 Ascii85Flush(image);
2057 break;
2058 }
2059 }
2060 }
2061 else
2062 if ((tile_image->storage_class == DirectClass) ||
2063 (tile_image->colors > 256) || (compression == JPEGCompression) ||
2064 (compression == JPEG2000Compression))
2065 switch (compression)
2066 {
2067 case JPEGCompression:
2068 {
2069 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2070 &image->exception);
2071 if (status == MagickFalse)
2072 ThrowWriterException(CoderError,tile_image->exception.reason);
2073 break;
2074 }
2075 case JPEG2000Compression:
2076 {
2077 status=InjectImageBlob(image_info,image,tile_image,"jp2",
2078 &image->exception);
2079 if (status == MagickFalse)
2080 ThrowWriterException(CoderError,tile_image->exception.reason);
2081 break;
2082 }
2083 case RLECompression:
2084 default:
2085 {
2086 /*
2087 Allocate pixel array.
2088 */
2089 length=(size_t) number_pixels;
2090 pixels=(unsigned char *) AcquireQuantumMemory(length,4*
2091 sizeof(*pixels));
2092 length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2093 if (pixels == (unsigned char *) NULL)
2094 {
2095 tile_image=DestroyImage(tile_image);
2096 ThrowWriterException(ResourceLimitError,
2097 "MemoryAllocationFailed");
2098 }
2099 /*
2100 Dump runoffset encoded pixels.
2101 */
2102 q=pixels;
cristybb503372010-05-27 20:51:26 +00002103 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002104 {
2105 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2106 &tile_image->exception);
2107 if (p == (const PixelPacket *) NULL)
2108 break;
2109 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002110 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002111 {
cristyce70c172010-01-07 17:15:30 +00002112 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
2113 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
2114 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00002115 if (image->colorspace == CMYKColorspace)
2116 *q++=ScaleQuantumToChar(indexes[x]);
2117 p++;
2118 }
2119 }
2120#if defined(MAGICKCORE_ZLIB_DELEGATE)
2121 if (compression == ZipCompression)
2122 status=ZLIBEncodeImage(image,length,pixels);
2123 else
2124#endif
2125 if (compression == LZWCompression)
2126 status=LZWEncodeImage(image,length,pixels);
2127 else
2128 status=PackbitsEncodeImage(image,length,pixels);
2129 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2130 if (status == MagickFalse)
2131 {
2132 (void) CloseBlob(image);
2133 return(MagickFalse);
2134 }
2135 break;
2136 }
2137 case NoCompression:
2138 {
2139 /*
2140 Dump uncompressed DirectColor packets.
2141 */
2142 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002143 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002144 {
2145 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2146 &tile_image->exception);
2147 if (p == (const PixelPacket *) NULL)
2148 break;
2149 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002150 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002151 {
cristyce70c172010-01-07 17:15:30 +00002152 Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p)));
2153 Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p)));
2154 Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002155 if (image->colorspace == CMYKColorspace)
2156 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
2157 p++;
2158 }
2159 }
2160 Ascii85Flush(image);
2161 break;
2162 }
2163 }
2164 else
2165 {
2166 /*
2167 Dump number of colors and colormap.
2168 */
2169 switch (compression)
2170 {
2171 case RLECompression:
2172 default:
2173 {
2174 /*
2175 Allocate pixel array.
2176 */
2177 length=(size_t) number_pixels;
2178 pixels=(unsigned char *) AcquireQuantumMemory(length,
2179 sizeof(*pixels));
2180 if (pixels == (unsigned char *) NULL)
2181 {
2182 tile_image=DestroyImage(tile_image);
2183 ThrowWriterException(ResourceLimitError,
2184 "MemoryAllocationFailed");
2185 }
2186 /*
2187 Dump Runlength encoded pixels.
2188 */
2189 q=pixels;
cristybb503372010-05-27 20:51:26 +00002190 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002191 {
2192 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2193 &tile_image->exception);
2194 if (p == (const PixelPacket *) NULL)
2195 break;
2196 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002197 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002198 *q++=(unsigned char) indexes[x];
2199 }
2200#if defined(MAGICKCORE_ZLIB_DELEGATE)
2201 if (compression == ZipCompression)
2202 status=ZLIBEncodeImage(image,length,pixels);
2203 else
2204#endif
2205 if (compression == LZWCompression)
2206 status=LZWEncodeImage(image,length,pixels);
2207 else
2208 status=PackbitsEncodeImage(image,length,pixels);
2209 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2210 if (status == MagickFalse)
2211 {
2212 (void) CloseBlob(image);
2213 return(MagickFalse);
2214 }
2215 break;
2216 }
2217 case NoCompression:
2218 {
2219 /*
2220 Dump uncompressed PseudoColor packets.
2221 */
2222 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002223 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002224 {
2225 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2226 &tile_image->exception);
2227 if (p == (const PixelPacket *) NULL)
2228 break;
2229 indexes=GetVirtualIndexQueue(tile_image);
cristybb503372010-05-27 20:51:26 +00002230 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002231 Ascii85Encode(image,(unsigned char) indexes[x]);
2232 }
2233 Ascii85Flush(image);
2234 break;
2235 }
2236 }
2237 }
2238 tile_image=DestroyImage(tile_image);
2239 offset=TellBlob(image)-offset;
2240 (void) WriteBlobString(image,"\nendstream\n");
2241 (void) WriteBlobString(image,"endobj\n");
2242 /*
2243 Write Length object.
2244 */
2245 xref[object++]=TellBlob(image);
2246 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2247 (void) WriteBlobString(image,buffer);
2248 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00002249 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00002250 (void) WriteBlobString(image,buffer);
2251 (void) WriteBlobString(image,"endobj\n");
2252 xref[object++]=TellBlob(image);
2253 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2254 (void) WriteBlobString(image,buffer);
2255 if ((image->storage_class != DirectClass) && (image->colors <= 256) &&
2256 (compression != FaxCompression) && (compression != Group4Compression))
2257 {
2258 /*
2259 Write Colormap object.
2260 */
2261 (void) WriteBlobString(image,"<<\n");
2262 if (compression == NoCompression)
2263 (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
2264 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
2265 object+1);
2266 (void) WriteBlobString(image,buffer);
2267 (void) WriteBlobString(image,">>\n");
2268 (void) WriteBlobString(image,"stream\n");
2269 offset=TellBlob(image);
2270 if (compression == NoCompression)
2271 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002272 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002273 {
2274 if (compression == NoCompression)
2275 {
2276 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].red));
2277 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].green));
2278 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].blue));
2279 continue;
2280 }
2281 (void) WriteBlobByte(image,
2282 ScaleQuantumToChar(image->colormap[i].red));
2283 (void) WriteBlobByte(image,
2284 ScaleQuantumToChar(image->colormap[i].green));
2285 (void) WriteBlobByte(image,
2286 ScaleQuantumToChar(image->colormap[i].blue));
2287 }
2288 if (compression == NoCompression)
2289 Ascii85Flush(image);
2290 offset=TellBlob(image)-offset;
2291 (void) WriteBlobString(image,"\nendstream\n");
2292 }
2293 (void) WriteBlobString(image,"endobj\n");
2294 /*
2295 Write Length object.
2296 */
2297 xref[object++]=TellBlob(image);
2298 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2299 (void) WriteBlobString(image,buffer);
2300 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00002301 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00002302 (void) WriteBlobString(image,buffer);
2303 (void) WriteBlobString(image,"endobj\n");
2304 /*
2305 Write softmask object.
2306 */
2307 xref[object++]=TellBlob(image);
2308 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2309 (void) WriteBlobString(image,buffer);
2310 (void) WriteBlobString(image,"<<\n");
2311 if (image->matte == MagickFalse)
2312 (void) WriteBlobString(image,">>\n");
2313 else
2314 {
2315 (void) WriteBlobString(image,"/Type /XObject\n");
2316 (void) WriteBlobString(image,"/Subtype /Image\n");
2317 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Ma%lu\n",
2318 image->scene);
2319 (void) WriteBlobString(image,buffer);
2320 switch (compression)
2321 {
2322 case NoCompression:
2323 {
2324 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2325 "ASCII85Decode");
2326 break;
2327 }
2328 case LZWCompression:
2329 {
2330 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
2331 break;
2332 }
2333 case ZipCompression:
2334 {
2335 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2336 "FlateDecode");
2337 break;
2338 }
2339 default:
2340 {
2341 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2342 "RunLengthDecode");
2343 break;
2344 }
2345 }
2346 (void) WriteBlobString(image,buffer);
2347 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
2348 image->columns);
2349 (void) WriteBlobString(image,buffer);
2350 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",
2351 image->rows);
2352 (void) WriteBlobString(image,buffer);
2353 (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2354 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
2355 (compression == FaxCompression) || (compression == Group4Compression)
2356 ? 1 : 8);
2357 (void) WriteBlobString(image,buffer);
2358 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
2359 object+1);
2360 (void) WriteBlobString(image,buffer);
2361 (void) WriteBlobString(image,">>\n");
2362 (void) WriteBlobString(image,"stream\n");
2363 offset=TellBlob(image);
2364 number_pixels=(MagickSizeType) image->columns*image->rows;
2365 switch (compression)
2366 {
2367 case RLECompression:
2368 default:
2369 {
2370 /*
2371 Allocate pixel array.
2372 */
2373 length=(size_t) number_pixels;
2374 pixels=(unsigned char *) AcquireQuantumMemory(length,
2375 sizeof(*pixels));
2376 if (pixels == (unsigned char *) NULL)
2377 {
2378 image=DestroyImage(image);
2379 ThrowWriterException(ResourceLimitError,
2380 "MemoryAllocationFailed");
2381 }
2382 /*
2383 Dump Runlength encoded pixels.
2384 */
2385 q=pixels;
cristybb503372010-05-27 20:51:26 +00002386 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002387 {
2388 p=GetVirtualPixels(image,0,y,image->columns,1,
2389 &image->exception);
2390 if (p == (const PixelPacket *) NULL)
2391 break;
cristybb503372010-05-27 20:51:26 +00002392 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002393 {
cristy46f08202010-01-10 04:04:21 +00002394 *q++=ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002395 p++;
2396 }
2397 }
2398#if defined(MAGICKCORE_ZLIB_DELEGATE)
2399 if (compression == ZipCompression)
2400 status=ZLIBEncodeImage(image,length,pixels);
2401 else
2402#endif
2403 if (compression == LZWCompression)
2404 status=LZWEncodeImage(image,length,pixels);
2405 else
2406 status=PackbitsEncodeImage(image,length,pixels);
2407 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2408 if (status == MagickFalse)
2409 {
2410 (void) CloseBlob(image);
2411 return(MagickFalse);
2412 }
2413 break;
2414 }
2415 case NoCompression:
2416 {
2417 /*
2418 Dump uncompressed PseudoColor packets.
2419 */
2420 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002421 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002422 {
2423 p=GetVirtualPixels(image,0,y,image->columns,1,
2424 &image->exception);
2425 if (p == (const PixelPacket *) NULL)
2426 break;
cristybb503372010-05-27 20:51:26 +00002427 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002428 {
2429 Ascii85Encode(image,ScaleQuantumToChar((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002430 GetOpacityPixelComponent(p))));
cristy3ed852e2009-09-05 21:47:34 +00002431 p++;
2432 }
2433 }
2434 Ascii85Flush(image);
2435 break;
2436 }
2437 }
2438 offset=TellBlob(image)-offset;
2439 (void) WriteBlobString(image,"\nendstream\n");
2440 }
2441 (void) WriteBlobString(image,"endobj\n");
2442 /*
2443 Write Length object.
2444 */
2445 xref[object++]=TellBlob(image);
2446 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2447 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00002448 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(size_t)
cristy3ed852e2009-09-05 21:47:34 +00002449 offset);
2450 (void) WriteBlobString(image,buffer);
2451 (void) WriteBlobString(image,"endobj\n");
2452 if (GetNextImageInList(image) == (Image *) NULL)
2453 break;
2454 image=SyncNextImageInList(image);
2455 status=SetImageProgress(image,SaveImagesTag,scene++,
2456 GetImageListLength(image));
2457 if (status == MagickFalse)
2458 break;
2459 } while (image_info->adjoin != MagickFalse);
2460 /*
2461 Write Metadata object.
2462 */
2463 xref[object++]=TellBlob(image);
2464 info_id=object;
2465 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2466 (void) WriteBlobString(image,buffer);
2467 (void) WriteBlobString(image,"<<\n");
2468 (void) FormatMagickString(buffer,MaxTextExtent,"/Title (%s)\n",
2469 EscapeParenthesis(image->filename));
2470 (void) WriteBlobString(image,buffer);
2471 seconds=time((time_t *) NULL);
2472#if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2473 (void) localtime_r(&seconds,&local_time);
2474#else
2475 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2476#endif
2477 (void) FormatMagickString(date,MaxTextExtent,"D:%04d%02d%02d%02d%02d%02d",
2478 local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2479 local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2480 (void) FormatMagickString(buffer,MaxTextExtent,"/CreationDate (%s)\n",date);
2481 (void) WriteBlobString(image,buffer);
2482 (void) FormatMagickString(buffer,MaxTextExtent,"/ModDate (%s)\n",date);
2483 (void) WriteBlobString(image,buffer);
2484 (void) FormatMagickString(buffer,MaxTextExtent,"/Producer (%s)\n",
cristybb503372010-05-27 20:51:26 +00002485 EscapeParenthesis(GetMagickVersion((size_t *) NULL)));
cristy3ed852e2009-09-05 21:47:34 +00002486 (void) WriteBlobString(image,buffer);
2487 (void) WriteBlobString(image,">>\n");
2488 (void) WriteBlobString(image,"endobj\n");
2489 /*
2490 Write Xref object.
2491 */
2492 offset=TellBlob(image)-xref[0]+10;
2493 (void) WriteBlobString(image,"xref\n");
2494 (void) FormatMagickString(buffer,MaxTextExtent,"0 %lu\n",object+1);
2495 (void) WriteBlobString(image,buffer);
2496 (void) WriteBlobString(image,"0000000000 65535 f \n");
cristybb503372010-05-27 20:51:26 +00002497 for (i=0; i < (ssize_t) object; i++)
cristy3ed852e2009-09-05 21:47:34 +00002498 {
2499 (void) FormatMagickString(buffer,MaxTextExtent,"%010lu 00000 n \n",
cristybb503372010-05-27 20:51:26 +00002500 (size_t) xref[i]);
cristy3ed852e2009-09-05 21:47:34 +00002501 (void) WriteBlobString(image,buffer);
2502 }
2503 (void) WriteBlobString(image,"trailer\n");
2504 (void) WriteBlobString(image,"<<\n");
2505 (void) FormatMagickString(buffer,MaxTextExtent,"/Size %lu\n",object+1);
2506 (void) WriteBlobString(image,buffer);
2507 (void) FormatMagickString(buffer,MaxTextExtent,"/Info %lu 0 R\n",info_id);
2508 (void) WriteBlobString(image,buffer);
2509 (void) FormatMagickString(buffer,MaxTextExtent,"/Root %lu 0 R\n",root_id);
2510 (void) WriteBlobString(image,buffer);
2511 (void) WriteBlobString(image,">>\n");
2512 (void) WriteBlobString(image,"startxref\n");
2513 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
cristybb503372010-05-27 20:51:26 +00002514 (size_t) offset);
cristy3ed852e2009-09-05 21:47:34 +00002515 (void) WriteBlobString(image,buffer);
2516 (void) WriteBlobString(image,"%%EOF\n");
2517 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2518 (void) CloseBlob(image);
2519 return(MagickTrue);
2520}