blob: 6fcd1c3583802da892f5af50e6b1225d92113bc8 [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
141 register long
142 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
188 for (i=0; i < (long) argc; i++)
189 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"
cristy66920e82010-02-18 14:33:30 +0000293#define ICCBased "ICCBased"
cristy3ed852e2009-09-05 21:47:34 +0000294#define MediaBox "MediaBox"
295#define RenderPostscriptText "Rendering Postscript... "
296#define PDFRotate "Rotate"
297#define SpotColor "Separation"
298#define TrimBox "TrimBox"
299#define PDFVersion "PDF-"
300
301 char
302 command[MaxTextExtent],
303 density[MaxTextExtent],
304 filename[MaxTextExtent],
305 geometry[MaxTextExtent],
306 options[MaxTextExtent],
307 input_filename[MaxTextExtent],
308 postscript_filename[MaxTextExtent];
309
310 const char
311 *option;
312
313 const DelegateInfo
314 *delegate_info;
315
316 double
317 angle;
318
cristydba40d42010-03-25 18:31:50 +0000319 GeometryInfo
320 geometry_info;
321
cristy3ed852e2009-09-05 21:47:34 +0000322 Image
323 *image,
324 *next,
325 *pdf_image;
326
327 ImageInfo
328 *read_info;
329
330 int
331 file;
332
333 MagickBooleanType
334 cmyk,
335 cropbox,
336 trimbox,
337 status;
338
cristydba40d42010-03-25 18:31:50 +0000339 MagickStatusType
340 flags;
341
cristy3ed852e2009-09-05 21:47:34 +0000342 PointInfo
343 delta;
344
345 RectangleInfo
346 bounding_box,
347 page;
348
349 register char
350 *p;
351
352 register int
353 c;
354
355 SegmentInfo
356 bounds,
357 hires_bounds;
358
359 ssize_t
360 count;
361
362 unsigned long
363 scene,
364 spotcolor;
365
366 assert(image_info != (const ImageInfo *) NULL);
367 assert(image_info->signature == MagickSignature);
368 if (image_info->debug != MagickFalse)
369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
370 image_info->filename);
371 assert(exception != (ExceptionInfo *) NULL);
372 assert(exception->signature == MagickSignature);
373 /*
374 Open image file.
375 */
376 image=AcquireImage(image_info);
377 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
378 if (status == MagickFalse)
379 {
380 image=DestroyImageList(image);
381 return((Image *) NULL);
382 }
383 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
384 if (status == MagickFalse)
385 {
386 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
387 image_info->filename);
388 image=DestroyImageList(image);
389 return((Image *) NULL);
390 }
391 /*
392 Set the page density.
393 */
394 delta.x=DefaultResolution;
395 delta.y=DefaultResolution;
396 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
397 {
cristy3ed852e2009-09-05 21:47:34 +0000398 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
399 image->x_resolution=geometry_info.rho;
400 image->y_resolution=geometry_info.sigma;
401 if ((flags & SigmaValue) == 0)
402 image->y_resolution=image->x_resolution;
403 }
404 /*
405 Determine page geometry from the PDF media box.
406 */
407 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
408 cropbox=MagickFalse;
409 option=GetImageOption(image_info,"pdf:use-cropbox");
410 if (option != (const char *) NULL)
411 cropbox=IsMagickTrue(option);
412 trimbox=MagickFalse;
413 option=GetImageOption(image_info,"pdf:use-trimbox");
414 if (option != (const char *) NULL)
415 trimbox=IsMagickTrue(option);
416 count=0;
417 spotcolor=0;
418 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
419 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
420 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
421 (void) ResetMagickMemory(&page,0,sizeof(page));
422 (void) ResetMagickMemory(command,0,sizeof(command));
423 hires_bounds.x2=0.0;
424 hires_bounds.y2=0.0;
425 angle=0.0;
426 p=command;
427 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
428 {
429 /*
430 Note PDF elements.
431 */
432 if (c == '\n')
433 c=' ';
434 *p++=(char) c;
435 if ((c != (int) '/') && (c != (int) '%') &&
436 ((size_t) (p-command) < (MaxTextExtent-1)))
437 continue;
438 *(--p)='\0';
439 p=command;
440 if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
441 count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
442 /*
443 Is this a CMYK document?
444 */
445 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
446 cmyk=MagickTrue;
cristy64246a02010-02-18 16:08:50 +0000447 if (LocaleNCompare(ICCBased,command,strlen(ICCBased)) == 0)
cristy66920e82010-02-18 14:33:30 +0000448 cmyk=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000449 if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)
450 {
451 char
452 name[MaxTextExtent],
453 property[MaxTextExtent],
454 *value;
455
456 register long
457 i;
458
459 /*
460 Note spot names.
461 */
462 (void) FormatMagickString(property,MaxTextExtent,"pdf:SpotColor-%lu",
463 spotcolor++);
464 i=0;
465 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
466 {
467 if ((isspace(c) != 0) || (c == '/') || ((i+1) == MaxTextExtent))
468 break;
469 name[i++]=(char) c;
470 }
471 name[i]='\0';
472 value=AcquireString(name);
473 (void) SubstituteString(&value,"#20"," ");
474 (void) SetImageProperty(image,property,value);
475 value=DestroyString(value);
476 continue;
477 }
478 if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0)
479 (void) SetImageProperty(image,"pdf:Version",command);
480 count=0;
481 if (cropbox != MagickFalse)
482 {
483 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
484 {
485 /*
486 Note region defined by crop box.
487 */
488 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
489 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
490 if (count != 4)
491 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
492 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
493 }
494 }
495 else
496 if (trimbox != MagickFalse)
497 {
498 if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0)
499 {
500 /*
501 Note region defined by trim box.
502 */
503 count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf",
504 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
505 if (count != 4)
506 count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf",
507 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
508 }
509 }
510 else
511 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
512 {
513 /*
514 Note region defined by media box.
515 */
516 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
517 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
518 if (count != 4)
519 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
520 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
521 }
522 if (count != 4)
523 continue;
524 if (((bounds.x2 > hires_bounds.x2) && (bounds.y2 > hires_bounds.y2)) ||
525 ((hires_bounds.x2 == 0.0) && (hires_bounds.y2 == 0.0)))
526 {
527 /*
528 Set PDF render geometry.
529 */
cristy8cd5b312010-01-07 01:10:24 +0000530 (void) FormatMagickString(geometry,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +0000531 "%gx%g%+.15g%+.15g",bounds.x2-bounds.x1,bounds.y2-bounds.y1,
cristy8cd5b312010-01-07 01:10:24 +0000532 bounds.x1,bounds.y1);
cristy3ed852e2009-09-05 21:47:34 +0000533 (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry);
cristy06609ee2010-03-17 20:21:27 +0000534 page.width=(unsigned long) floor(bounds.x2-bounds.x1+0.5);
535 page.height=(unsigned long) floor(bounds.y2-bounds.y1+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000536 hires_bounds=bounds;
537 }
538 }
539 (void) CloseBlob(image);
540 if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0))
541 {
542 unsigned long
543 swap;
544
545 swap=page.width;
546 page.width=page.height;
547 page.height=swap;
548 }
549 if (image_info->colorspace == RGBColorspace)
550 cmyk=MagickFalse;
551 /*
552 Create Ghostscript control file.
553 */
554 file=AcquireUniqueFileResource(postscript_filename);
555 if (file == -1)
556 {
557 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
558 image_info->filename);
559 image=DestroyImage(image);
560 return((Image *) NULL);
561 }
562 count=write(file," ",1);
563 file=close(file)-1;
564 /*
565 Render Postscript with the Ghostscript delegate.
566 */
567 if ((image_info->ping != MagickFalse) ||
568 (image_info->monochrome != MagickFalse))
569 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
570 else
571 if (cmyk != MagickFalse)
572 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
573 else
cristyf1849f82009-09-08 14:37:22 +0000574 if (LocaleCompare(image_info->magick,"AI") == 0)
575 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
576 else
577 delegate_info=GetDelegateInfo("ps:color",(char *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (delegate_info == (const DelegateInfo *) NULL)
579 {
580 (void) RelinquishUniqueFileResource(postscript_filename);
581 image=DestroyImage(image);
582 return((Image *) NULL);
583 }
584 *options='\0';
cristydba40d42010-03-25 18:31:50 +0000585 if (image_info->density != (char *) NULL)
586 {
587 flags=ParseGeometry(image_info->density,&geometry_info);
588 image->x_resolution=geometry_info.rho;
589 image->y_resolution=geometry_info.sigma;
590 if ((flags & SigmaValue) == 0)
591 image->y_resolution=image->x_resolution;
592 }
cristye7f51092010-01-17 00:39:37 +0000593 (void) FormatMagickString(density,MaxTextExtent,"%gx%g",
cristy8cd5b312010-01-07 01:10:24 +0000594 image->x_resolution,image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000595 if (image_info->page != (char *) NULL)
596 {
597 (void) ParseAbsoluteGeometry(image_info->page,&page);
cristy06609ee2010-03-17 20:21:27 +0000598 page.width=(unsigned long) floor(page.width*image->x_resolution/delta.x+
599 0.5);
600 page.height=(unsigned long) floor(page.height*image->y_resolution/delta.y+
601 0.5);
cristy3ed852e2009-09-05 21:47:34 +0000602 (void) FormatMagickString(options,MaxTextExtent,"-g%lux%lu ",page.width,
603 page.height);
604 }
605 if (cmyk != MagickFalse)
606 (void) ConcatenateMagickString(options,"-dUseCIEColor ",MaxTextExtent);
607 if (cropbox != MagickFalse)
608 (void) ConcatenateMagickString(options,"-dUseCropBox ",MaxTextExtent);
609 if (trimbox != MagickFalse)
610 (void) ConcatenateMagickString(options,"-dUseTrimBox ",MaxTextExtent);
611 read_info=CloneImageInfo(image_info);
612 *read_info->magick='\0';
613 if (read_info->number_scenes != 0)
614 {
615 char
616 pages[MaxTextExtent];
617
618 (void) FormatMagickString(pages,MaxTextExtent,"-dFirstPage=%lu "
619 "-dLastPage=%lu",read_info->scene+1,read_info->scene+
620 read_info->number_scenes);
621 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
622 read_info->number_scenes=0;
623 if (read_info->scenes != (char *) NULL)
624 *read_info->scenes='\0';
625 }
626 if (read_info->authenticate != (char *) NULL)
627 (void) FormatMagickString(options+strlen(options),MaxTextExtent,
628 " -sPDFPassword=%s",read_info->authenticate);
629 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
630 (void) AcquireUniqueFilename(read_info->filename);
631 (void) FormatMagickString(command,MaxTextExtent,
632 GetDelegateCommands(delegate_info),
633 read_info->antialias != MagickFalse ? 4 : 1,
634 read_info->antialias != MagickFalse ? 4 : 1,density,options,
635 read_info->filename,postscript_filename,input_filename);
cristydefb3f02009-09-10 02:18:35 +0000636 status=InvokePDFDelegate(read_info->verbose,command,exception);
cristy3ed852e2009-09-05 21:47:34 +0000637 pdf_image=(Image *) NULL;
cristy41083a42009-09-07 23:47:59 +0000638 if ((status != MagickFalse) &&
cristy3ed852e2009-09-05 21:47:34 +0000639 (IsPDFRendered(read_info->filename) != MagickFalse))
640 pdf_image=ReadImage(read_info,exception);
641 (void) RelinquishUniqueFileResource(postscript_filename);
642 (void) RelinquishUniqueFileResource(read_info->filename);
643 (void) RelinquishUniqueFileResource(input_filename);
644 read_info=DestroyImageInfo(read_info);
645 if (pdf_image == (Image *) NULL)
646 {
647 ThrowFileException(exception,DelegateError,"PostscriptDelegateFailed",
648 image_info->filename);
649 return((Image *) NULL);
650 }
651 if (LocaleCompare(pdf_image->magick,"BMP") == 0)
652 {
653 Image
654 *cmyk_image;
655
656 cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
657 if (cmyk_image != (Image *) NULL)
658 {
659 pdf_image=DestroyImageList(pdf_image);
660 pdf_image=cmyk_image;
661 }
662 }
663 if (image_info->number_scenes != 0)
664 {
665 Image
666 *clone_image;
667
668 register long
669 i;
670
671 /*
672 Add place holder images to meet the subimage specification requirement.
673 */
674 for (i=0; i < (long) image_info->scene; i++)
675 {
676 clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
677 if (clone_image != (Image *) NULL)
678 PrependImageToList(&pdf_image,clone_image);
679 }
680 }
681 do
682 {
683 (void) CopyMagickString(pdf_image->filename,filename,MaxTextExtent);
684 pdf_image->page=page;
685 (void) CloneImageProfiles(pdf_image,image);
686 (void) CloneImageProperties(pdf_image,image);
687 next=SyncNextImageInList(pdf_image);
688 if (next != (Image *) NULL)
689 pdf_image=next;
690 } while (next != (Image *) NULL);
691 image=DestroyImage(image);
692 scene=0;
693 for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
694 {
695 next->scene=scene++;
696 next=GetNextImageInList(next);
697 }
698 return(GetFirstImageInList(pdf_image));
699}
700
701/*
702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703% %
704% %
705% %
706% R e g i s t e r P D F I m a g e %
707% %
708% %
709% %
710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711%
712% RegisterPDFImage() adds properties for the PDF image format to
713% the list of supported formats. The properties include the image format
714% tag, a method to read and/or write the format, whether the format
715% supports the saving of more than one frame to the same file or blob,
716% whether the format supports native in-memory I/O, and a brief
717% description of the format.
718%
719% The format of the RegisterPDFImage method is:
720%
721% unsigned long RegisterPDFImage(void)
722%
723*/
724ModuleExport unsigned long RegisterPDFImage(void)
725{
726 MagickInfo
727 *entry;
728
729 entry=SetMagickInfo("AI");
730 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
731 entry->encoder=(EncodeImageHandler *) WritePDFImage;
732 entry->adjoin=MagickFalse;
733 entry->blob_support=MagickFalse;
734 entry->seekable_stream=MagickTrue;
735 entry->thread_support=EncoderThreadSupport;
736 entry->description=ConstantString("Adobe Illustrator CS2");
737 entry->module=ConstantString("PDF");
738 (void) RegisterMagickInfo(entry);
739 entry=SetMagickInfo("EPDF");
740 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
741 entry->encoder=(EncodeImageHandler *) WritePDFImage;
742 entry->adjoin=MagickFalse;
743 entry->blob_support=MagickFalse;
744 entry->seekable_stream=MagickTrue;
745 entry->thread_support=EncoderThreadSupport;
746 entry->description=ConstantString("Encapsulated Portable Document Format");
747 entry->module=ConstantString("PDF");
748 (void) RegisterMagickInfo(entry);
749 entry=SetMagickInfo("PDF");
750 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
751 entry->encoder=(EncodeImageHandler *) WritePDFImage;
752 entry->magick=(IsImageFormatHandler *) IsPDF;
753 entry->blob_support=MagickFalse;
754 entry->seekable_stream=MagickTrue;
755 entry->thread_support=EncoderThreadSupport;
756 entry->description=ConstantString("Portable Document Format");
757 entry->module=ConstantString("PDF");
758 (void) RegisterMagickInfo(entry);
759 entry=SetMagickInfo("PDFA");
760 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
761 entry->encoder=(EncodeImageHandler *) WritePDFImage;
762 entry->magick=(IsImageFormatHandler *) IsPDF;
763 entry->blob_support=MagickFalse;
764 entry->seekable_stream=MagickTrue;
765 entry->thread_support=EncoderThreadSupport;
766 entry->description=ConstantString("Portable Document Archive Format");
767 entry->module=ConstantString("PDF");
768 (void) RegisterMagickInfo(entry);
769 return(MagickImageCoderSignature);
770}
771
772/*
773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774% %
775% %
776% %
777% U n r e g i s t e r P D F I m a g e %
778% %
779% %
780% %
781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782%
783% UnregisterPDFImage() removes format registrations made by the
784% PDF module from the list of supported formats.
785%
786% The format of the UnregisterPDFImage method is:
787%
788% UnregisterPDFImage(void)
789%
790*/
791ModuleExport void UnregisterPDFImage(void)
792{
793 (void) UnregisterMagickInfo("AI");
794 (void) UnregisterMagickInfo("EPDF");
795 (void) UnregisterMagickInfo("PDF");
796 (void) UnregisterMagickInfo("PDFA");
797}
798
799/*
800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801% %
802% %
803% %
804% W r i t e P D F I m a g e %
805% %
806% %
807% %
808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
809%
810% WritePDFImage() writes an image in the Portable Document image
811% format.
812%
813% The format of the WritePDFImage method is:
814%
815% MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image)
816%
817% A description of each parameter follows.
818%
819% o image_info: the image info.
820%
821% o image: The image.
822%
823*/
824
825static inline size_t MagickMax(const size_t x,const size_t y)
826{
827 if (x > y)
828 return(x);
829 return(y);
830}
831
832static inline size_t MagickMin(const size_t x,const size_t y)
833{
834 if (x < y)
835 return(x);
836 return(y);
837}
838
839static char *EscapeParenthesis(const char *text)
840{
841 register char
842 *p;
843
844 register long
845 i;
846
847 static char
848 buffer[MaxTextExtent];
849
850 unsigned long
851 escapes;
852
853 escapes=0;
854 p=buffer;
855 for (i=0; i < (long) MagickMin(strlen(text),(MaxTextExtent-escapes-1)); i++)
856 {
857 if ((text[i] == '(') || (text[i] == ')'))
858 {
859 *p++='\\';
860 escapes++;
861 }
862 *p++=text[i];
863 }
864 *p='\0';
865 return(buffer);
866}
867
cristy47b838c2009-09-19 16:09:30 +0000868static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
869 Image *image,Image *inject_image)
870{
cristy47b838c2009-09-19 16:09:30 +0000871 Image
cristy80975862009-09-25 14:34:31 +0000872 *group4_image;
cristy47b838c2009-09-19 16:09:30 +0000873
874 ImageInfo
875 *write_info;
876
cristy47b838c2009-09-19 16:09:30 +0000877 MagickBooleanType
878 status;
879
cristy80975862009-09-25 14:34:31 +0000880 size_t
881 length;
cristy47b838c2009-09-19 16:09:30 +0000882
883 unsigned char
cristy80975862009-09-25 14:34:31 +0000884 *group4;
cristy47b838c2009-09-19 16:09:30 +0000885
cristy42751fe2009-10-05 00:15:50 +0000886 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +0000887 write_info=CloneImageInfo(image_info);
cristy80975862009-09-25 14:34:31 +0000888 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
889 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
890 group4_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
891 if (group4_image == (Image *) NULL)
892 return(MagickFalse);
893 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
894 &image->exception);
895 group4_image=DestroyImage(group4_image);
896 if (group4 == (unsigned char *) NULL)
897 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +0000898 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +0000899 if (WriteBlob(image,length,group4) != (ssize_t) length)
900 status=MagickFalse;
901 group4=(unsigned char *) RelinquishMagickMemory(group4);
902 return(status);
cristy47b838c2009-09-19 16:09:30 +0000903}
904
cristy3ed852e2009-09-05 21:47:34 +0000905static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image)
906{
907#define CFormat "/Filter [ /%s ]\n"
908#define ObjectsPerImage 14
909
910 static const char
911 XMPProfile[]=
912 {
913 "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
914 "<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"
915 " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
916 " <rdf:Description rdf:about=\"\"\n"
917 " xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
918 " <xap:ModifyDate>%s</xap:ModifyDate>\n"
919 " <xap:CreateDate>%s</xap:CreateDate>\n"
920 " <xap:MetadataDate>%s</xap:MetadataDate>\n"
921 " <xap:CreatorTool>%s</xap:CreatorTool>\n"
922 " </rdf:Description>\n"
923 " <rdf:Description rdf:about=\"\"\n"
924 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
925 " <dc:format>application/pdf</dc:format>\n"
926 " </rdf:Description>\n"
927 " <rdf:Description rdf:about=\"\"\n"
928 " xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
929 " <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
930 " <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
931 " </rdf:Description>\n"
932 " <rdf:Description rdf:about=\"\"\n"
933 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
934 " <pdf:Producer>%s</pdf:Producer>\n"
935 " </rdf:Description>\n"
936 " <rdf:Description rdf:about=\"\"\n"
937 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
938 " <pdfaid:part>1</pdfaid:part>\n"
939 " <pdfaid:conformance>B</pdfaid:conformance>\n"
940 " </rdf:Description>\n"
941 " </rdf:RDF>\n"
942 "</x:xmpmeta>\n"
943 "<?xpacket end=\"w\"?>\n"
944 },
945 XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
946
947 char
948 buffer[MaxTextExtent],
949 date[MaxTextExtent],
950 **labels,
951 page_geometry[MaxTextExtent];
952
953 CompressionType
954 compression;
955
956 const char
957 *value;
958
959 double
960 pointsize;
961
962 GeometryInfo
963 geometry_info;
964
965 long
966 count,
967 y;
968
969 Image
970 *next,
971 *tile_image;
972
973 MagickBooleanType
974 status;
975
976 MagickOffsetType
977 offset,
978 scene,
979 *xref;
980
981 MagickSizeType
982 number_pixels;
983
984 MagickStatusType
985 flags;
986
987 PointInfo
988 delta,
989 resolution,
990 scale;
991
992 RectangleInfo
993 geometry,
994 media_info,
995 page_info;
996
997 register const IndexPacket
998 *indexes;
999
1000 register const PixelPacket
1001 *p;
1002
1003 register unsigned char
1004 *q;
1005
1006 register long
1007 i,
1008 x;
1009
1010 size_t
1011 length;
1012
1013 struct tm
1014 local_time;
1015
1016 time_t
1017 seconds;
1018
1019 unsigned char
1020 *pixels;
1021
1022 unsigned long
1023 info_id,
1024 object,
1025 pages_id,
1026 root_id,
1027 text_size,
1028 version;
1029
1030 /*
1031 Open output image file.
1032 */
1033 assert(image_info != (const ImageInfo *) NULL);
1034 assert(image_info->signature == MagickSignature);
1035 assert(image != (Image *) NULL);
1036 assert(image->signature == MagickSignature);
1037 if (image->debug != MagickFalse)
1038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1039 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1040 if (status == MagickFalse)
1041 return(status);
1042 /*
1043 Allocate X ref memory.
1044 */
1045 xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1046 if (xref == (MagickOffsetType *) NULL)
1047 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1048 (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1049 /*
1050 Write Info object.
1051 */
1052 object=0;
1053 version=3;
1054 if (image_info->compression == JPEG2000Compression)
1055 version=(unsigned long) MagickMax(version,5);
1056 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1057 if (next->matte != MagickFalse)
1058 version=(unsigned long) MagickMax(version,4);
1059 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1060 version=(unsigned long) MagickMax(version,6);
1061 (void) FormatMagickString(buffer,MaxTextExtent,"%%PDF-1.%lu \n",version);
1062 (void) WriteBlobString(image,buffer);
1063 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1064 (void) WriteBlobString(image,"%âãÏÓ\n");
1065 /*
1066 Write Catalog object.
1067 */
1068 xref[object++]=TellBlob(image);
1069 root_id=object;
1070 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1071 (void) WriteBlobString(image,buffer);
1072 (void) WriteBlobString(image,"<<\n");
1073 if (LocaleCompare(image_info->magick,"PDFA") != 0)
1074 (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %lu 0 R\n",
1075 object+1);
1076 else
1077 {
1078 (void) FormatMagickString(buffer,MaxTextExtent,"/Metadata %lu 0 R\n",
1079 object+1);
1080 (void) WriteBlobString(image,buffer);
1081 (void) FormatMagickString(buffer,MaxTextExtent,"/Pages %lu 0 R\n",
1082 object+2);
1083 }
1084 (void) WriteBlobString(image,buffer);
1085 (void) WriteBlobString(image,"/Type /Catalog\n");
1086 (void) WriteBlobString(image,">>\n");
1087 (void) WriteBlobString(image,"endobj\n");
1088 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1089 {
1090 char
1091 create_date[MaxTextExtent],
1092 modify_date[MaxTextExtent],
1093 timestamp[MaxTextExtent],
1094 xmp_profile[MaxTextExtent];
1095
1096 unsigned long
1097 version;
1098
1099 /*
1100 Write XMP object.
1101 */
1102 xref[object++]=TellBlob(image);
1103 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1104 (void) WriteBlobString(image,buffer);
1105 (void) WriteBlobString(image,"<<\n");
1106 (void) WriteBlobString(image,"/Subtype /XML\n");
1107 *modify_date='\0';
1108 value=GetImageProperty(image,"date:modify");
1109 if (value != (const char *) NULL)
1110 (void) CopyMagickString(modify_date,value,MaxTextExtent);
1111 *create_date='\0';
1112 value=GetImageProperty(image,"date:create");
1113 if (value != (const char *) NULL)
1114 (void) CopyMagickString(create_date,value,MaxTextExtent);
1115 (void) FormatMagickTime(time((time_t *) NULL),MaxTextExtent,timestamp);
1116 i=FormatMagickString(xmp_profile,MaxTextExtent,XMPProfile,
1117 XMPProfileMagick,modify_date,create_date,timestamp,
1118 GetMagickVersion(&version),GetMagickVersion(&version));
1119 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu\n",1UL*i);
1120 (void) WriteBlobString(image,buffer);
1121 (void) WriteBlobString(image,"/Type /Metadata\n");
1122 (void) WriteBlobString(image,">>\nstream\n");
1123 (void) WriteBlobString(image,xmp_profile);
1124 (void) WriteBlobString(image,"endstream\n");
1125 (void) WriteBlobString(image,"endobj\n");
1126 }
1127 /*
1128 Write Pages object.
1129 */
1130 xref[object++]=TellBlob(image);
1131 pages_id=object;
1132 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1133 (void) WriteBlobString(image,buffer);
1134 (void) WriteBlobString(image,"<<\n");
1135 (void) WriteBlobString(image,"/Type /Pages\n");
1136 (void) FormatMagickString(buffer,MaxTextExtent,"/Kids [ %lu 0 R ",object+1);
1137 (void) WriteBlobString(image,buffer);
1138 count=(long) (pages_id+ObjectsPerImage+1);
1139 if (image_info->adjoin != MagickFalse)
1140 {
1141 Image
1142 *kid_image;
1143
1144 /*
1145 Predict page object id's.
1146 */
1147 kid_image=image;
1148 for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1149 {
1150 (void) FormatMagickString(buffer,MaxTextExtent,"%ld 0 R ",count);
1151 (void) WriteBlobString(image,buffer);
1152 kid_image=GetNextImageInList(kid_image);
1153 }
1154 xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1155 sizeof(*xref));
1156 if (xref == (MagickOffsetType *) NULL)
1157 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1158 }
1159 (void) WriteBlobString(image,"]\n");
1160 (void) FormatMagickString(buffer,MaxTextExtent,"/Count %lu\n",
1161 (count-pages_id)/ObjectsPerImage);
1162 (void) WriteBlobString(image,buffer);
1163 (void) WriteBlobString(image,">>\n");
1164 (void) WriteBlobString(image,"endobj\n");
1165 scene=0;
1166 do
1167 {
1168 compression=image->compression;
1169 if (image_info->compression != UndefinedCompression)
1170 compression=image_info->compression;
1171 switch (compression)
1172 {
1173 case FaxCompression:
1174 case Group4Compression:
1175 {
1176 if ((IsMonochromeImage(image,&image->exception) == MagickFalse) ||
1177 (image->matte != MagickFalse))
1178 compression=RLECompression;
1179 break;
1180 }
1181#if !defined(MAGICKCORE_JPEG_DELEGATE)
1182 case JPEGCompression:
1183 {
1184 compression=RLECompression;
1185 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1186 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1187 image->filename);
1188 break;
1189 }
1190#endif
1191#if !defined(MAGICKCORE_JP2_DELEGATE)
1192 case JPEG2000Compression:
1193 {
1194 compression=RLECompression;
1195 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1196 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1197 image->filename);
1198 break;
1199 }
1200#endif
1201#if !defined(MAGICKCORE_ZLIB_DELEGATE)
1202 case ZipCompression:
1203 {
1204 compression=RLECompression;
1205 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1206 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1207 image->filename);
1208 break;
1209 }
1210#endif
1211 case LZWCompression:
1212 {
1213 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1214 compression=RLECompression; /* LZW compression is forbidden */
1215 break;
1216 }
1217 case NoCompression:
1218 {
1219 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1220 compression=RLECompression; /* ASCII 85 compression is forbidden */
1221 break;
1222 }
1223 default:
1224 break;
1225 }
1226 if (compression == JPEG2000Compression)
1227 {
1228 if (image->colorspace != RGBColorspace)
1229 (void) TransformImageColorspace(image,RGBColorspace);
1230 }
1231 /*
1232 Scale relative to dots-per-inch.
1233 */
1234 delta.x=DefaultResolution;
1235 delta.y=DefaultResolution;
1236 resolution.x=image->x_resolution;
1237 resolution.y=image->y_resolution;
1238 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1239 {
1240 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1241 resolution.x=geometry_info.rho;
1242 resolution.y=geometry_info.sigma;
1243 if ((flags & SigmaValue) == 0)
1244 resolution.y=resolution.x;
1245 }
1246 if (image_info->density != (char *) NULL)
1247 {
1248 flags=ParseGeometry(image_info->density,&geometry_info);
1249 resolution.x=geometry_info.rho;
1250 resolution.y=geometry_info.sigma;
1251 if ((flags & SigmaValue) == 0)
1252 resolution.y=resolution.x;
1253 }
1254 if (image->units == PixelsPerCentimeterResolution)
1255 {
1256 resolution.x*=2.54;
1257 resolution.y*=2.54;
1258 }
1259 SetGeometry(image,&geometry);
1260 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu",
1261 image->columns,image->rows);
1262 if (image_info->page != (char *) NULL)
1263 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1264 else
1265 if ((image->page.width != 0) && (image->page.height != 0))
1266 (void) FormatMagickString(page_geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
1267 image->page.width,image->page.height,image->page.x,image->page.y);
1268 else
1269 if ((image->gravity != UndefinedGravity) &&
1270 (LocaleCompare(image_info->magick,"PDF") == 0))
1271 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1272 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1273 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1274 &geometry.width,&geometry.height);
1275 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristy06609ee2010-03-17 20:21:27 +00001276 geometry.width=(unsigned long) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001277 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristy06609ee2010-03-17 20:21:27 +00001278 geometry.height=(unsigned long) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001279 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1280 (void) ParseGravityGeometry(image,page_geometry,&page_info,
1281 &image->exception);
1282 if (image->gravity != UndefinedGravity)
1283 {
1284 geometry.x=(-page_info.x);
1285 geometry.y=(long) (media_info.height+page_info.y-image->rows);
1286 }
1287 pointsize=12.0;
1288 if (image_info->pointsize != 0.0)
1289 pointsize=image_info->pointsize;
1290 text_size=0;
1291 value=GetImageProperty(image,"Label");
1292 if (value != (const char *) NULL)
1293 text_size=(unsigned long) (MultilineCensus(value)*pointsize+12);
1294 /*
1295 Write Page object.
1296 */
1297 xref[object++]=TellBlob(image);
1298 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1299 (void) WriteBlobString(image,buffer);
1300 (void) WriteBlobString(image,"<<\n");
1301 (void) WriteBlobString(image,"/Type /Page\n");
1302 (void) FormatMagickString(buffer,MaxTextExtent,"/Parent %lu 0 R\n",
1303 pages_id);
1304 (void) WriteBlobString(image,buffer);
1305 (void) WriteBlobString(image,"/Resources <<\n");
1306 labels=(char **) NULL;
1307 value=GetImageProperty(image,"Label");
1308 if (value != (const char *) NULL)
1309 labels=StringToList(value);
1310 if (labels != (char **) NULL)
1311 {
1312 (void) FormatMagickString(buffer,MaxTextExtent,
1313 "/Font << /F%lu %lu 0 R >>\n",image->scene,object+4);
1314 (void) WriteBlobString(image,buffer);
1315 }
1316 (void) FormatMagickString(buffer,MaxTextExtent,
1317 "/XObject << /Im%lu %lu 0 R >>\n",image->scene,object+5);
1318 (void) WriteBlobString(image,buffer);
1319 (void) FormatMagickString(buffer,MaxTextExtent,"/ProcSet %lu 0 R >>\n",
1320 object+3);
1321 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001322 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001323 "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001324 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001325 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001326 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001327 "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001328 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001329 (void) WriteBlobString(image,buffer);
1330 (void) FormatMagickString(buffer,MaxTextExtent,"/Contents %lu 0 R\n",
1331 object+1);
1332 (void) WriteBlobString(image,buffer);
1333 (void) FormatMagickString(buffer,MaxTextExtent,"/Thumb %lu 0 R\n",
1334 object+8);
1335 (void) WriteBlobString(image,buffer);
1336 (void) WriteBlobString(image,">>\n");
1337 (void) WriteBlobString(image,"endobj\n");
1338 /*
1339 Write Contents object.
1340 */
1341 xref[object++]=TellBlob(image);
1342 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1343 (void) WriteBlobString(image,buffer);
1344 (void) WriteBlobString(image,"<<\n");
1345 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1346 object+1);
1347 (void) WriteBlobString(image,buffer);
1348 (void) WriteBlobString(image,">>\n");
1349 (void) WriteBlobString(image,"stream\n");
1350 offset=TellBlob(image);
1351 (void) WriteBlobString(image,"q\n");
1352 if (labels != (char **) NULL)
1353 for (i=0; labels[i] != (char *) NULL; i++)
1354 {
1355 (void) WriteBlobString(image,"BT\n");
cristye7f51092010-01-17 00:39:37 +00001356 (void) FormatMagickString(buffer,MaxTextExtent,"/F%lu %g Tf\n",
cristy3ed852e2009-09-05 21:47:34 +00001357 image->scene,pointsize);
1358 (void) WriteBlobString(image,buffer);
1359 (void) FormatMagickString(buffer,MaxTextExtent,"%ld %ld Td\n",
1360 geometry.x,(long) (geometry.y+geometry.height+i*pointsize+12));
1361 (void) WriteBlobString(image,buffer);
1362 (void) FormatMagickString(buffer,MaxTextExtent,"(%s) Tj\n",labels[i]);
1363 (void) WriteBlobString(image,buffer);
1364 (void) WriteBlobString(image,"ET\n");
1365 labels[i]=DestroyString(labels[i]);
1366 }
cristy8cd5b312010-01-07 01:10:24 +00001367 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001368 "%g 0 0 %g %ld %ld cm\n",scale.x,scale.y,geometry.x,geometry.y);
cristy3ed852e2009-09-05 21:47:34 +00001369 (void) WriteBlobString(image,buffer);
1370 (void) FormatMagickString(buffer,MaxTextExtent,"/Im%lu Do\n",image->scene);
1371 (void) WriteBlobString(image,buffer);
1372 (void) WriteBlobString(image,"Q\n");
1373 offset=TellBlob(image)-offset;
1374 (void) WriteBlobString(image,"endstream\n");
1375 (void) WriteBlobString(image,"endobj\n");
1376 /*
1377 Write Length object.
1378 */
1379 xref[object++]=TellBlob(image);
1380 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1381 (void) WriteBlobString(image,buffer);
1382 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
1383 (unsigned long) offset);
1384 (void) WriteBlobString(image,buffer);
1385 (void) WriteBlobString(image,"endobj\n");
1386 /*
1387 Write Procset object.
1388 */
1389 xref[object++]=TellBlob(image);
1390 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1391 (void) WriteBlobString(image,buffer);
1392 if ((image->storage_class == DirectClass) || (image->colors > 256))
1393 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MaxTextExtent);
1394 else
1395 if ((compression == FaxCompression) || (compression == Group4Compression))
1396 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MaxTextExtent);
1397 else
1398 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MaxTextExtent);
1399 (void) WriteBlobString(image,buffer);
1400 (void) WriteBlobString(image," ]\n");
1401 (void) WriteBlobString(image,"endobj\n");
1402 /*
1403 Write Font object.
1404 */
1405 xref[object++]=TellBlob(image);
1406 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1407 (void) WriteBlobString(image,buffer);
1408 (void) WriteBlobString(image,"<<\n");
1409 if (labels != (char **) NULL)
1410 {
1411 (void) WriteBlobString(image,"/Type /Font\n");
1412 (void) WriteBlobString(image,"/Subtype /Type1\n");
1413 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /F%lu\n",
1414 image->scene);
1415 (void) WriteBlobString(image,buffer);
1416 (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1417 (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1418 labels=(char **) RelinquishMagickMemory(labels);
1419 }
1420 (void) WriteBlobString(image,">>\n");
1421 (void) WriteBlobString(image,"endobj\n");
1422 /*
1423 Write XObject object.
1424 */
1425 xref[object++]=TellBlob(image);
1426 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1427 (void) WriteBlobString(image,buffer);
1428 (void) WriteBlobString(image,"<<\n");
1429 (void) WriteBlobString(image,"/Type /XObject\n");
1430 (void) WriteBlobString(image,"/Subtype /Image\n");
1431 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Im%lu\n",
1432 image->scene);
1433 (void) WriteBlobString(image,buffer);
1434 switch (compression)
1435 {
1436 case NoCompression:
1437 {
1438 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1439 break;
1440 }
1441 case JPEGCompression:
1442 {
1443 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1444 if (image->colorspace != CMYKColorspace)
1445 break;
1446 (void) WriteBlobString(image,buffer);
1447 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1448 MaxTextExtent);
1449 break;
1450 }
1451 case JPEG2000Compression:
1452 {
1453 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1454 if (image->colorspace != CMYKColorspace)
1455 break;
1456 (void) WriteBlobString(image,buffer);
1457 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1458 MaxTextExtent);
1459 break;
1460 }
1461 case LZWCompression:
1462 {
cristyfa7becb2009-09-13 02:44:40 +00001463 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1464 break;
cristy3ed852e2009-09-05 21:47:34 +00001465 }
1466 case ZipCompression:
1467 {
cristyfa7becb2009-09-13 02:44:40 +00001468 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1469 break;
cristy3ed852e2009-09-05 21:47:34 +00001470 }
1471 case FaxCompression:
1472 case Group4Compression:
1473 {
1474 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1475 MaxTextExtent);
1476 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001477 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristy80975862009-09-25 14:34:31 +00001478 "/K %s /BlackIs1 false /Columns %ld /Rows %ld >> ]\n",CCITTParam,
cristya55e1092009-09-13 02:41:40 +00001479 image->columns,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001480 break;
1481 }
1482 default:
1483 {
1484 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1485 "RunLengthDecode");
1486 break;
1487 }
1488 }
1489 (void) WriteBlobString(image,buffer);
1490 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
1491 image->columns);
1492 (void) WriteBlobString(image,buffer);
1493 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",image->rows);
1494 (void) WriteBlobString(image,buffer);
1495 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %lu 0 R\n",
1496 object+2);
1497 (void) WriteBlobString(image,buffer);
1498 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1499 (compression == FaxCompression) || (compression == Group4Compression) ?
1500 1 : 8);
1501 (void) WriteBlobString(image,buffer);
1502 if (image->matte != MagickFalse)
1503 {
1504 (void) FormatMagickString(buffer,MaxTextExtent,"/SMask %lu 0 R\n",
1505 object+7);
1506 (void) WriteBlobString(image,buffer);
1507 }
1508 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1509 object+1);
1510 (void) WriteBlobString(image,buffer);
1511 (void) WriteBlobString(image,">>\n");
1512 (void) WriteBlobString(image,"stream\n");
1513 offset=TellBlob(image);
1514 number_pixels=(MagickSizeType) image->columns*image->rows;
1515 if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1516 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1517 if ((compression == FaxCompression) || (compression == Group4Compression) ||
1518 ((image_info->type != TrueColorType) &&
1519 (IsGrayImage(image,&image->exception) != MagickFalse)))
1520 {
1521 switch (compression)
1522 {
1523 case FaxCompression:
1524 case Group4Compression:
1525 {
1526 if (LocaleCompare(CCITTParam,"0") == 0)
1527 {
1528 (void) HuffmanEncodeImage(image_info,image,image);
1529 break;
1530 }
1531 (void) Huffman2DEncodeImage(image_info,image,image);
1532 break;
1533 }
1534 case JPEGCompression:
1535 {
1536 status=InjectImageBlob(image_info,image,image,"jpeg",
1537 &image->exception);
1538 if (status == MagickFalse)
1539 ThrowWriterException(CoderError,image->exception.reason);
1540 break;
1541 }
1542 case JPEG2000Compression:
1543 {
1544 status=InjectImageBlob(image_info,image,image,"jp2",
1545 &image->exception);
1546 if (status == MagickFalse)
1547 ThrowWriterException(CoderError,image->exception.reason);
1548 break;
1549 }
1550 case RLECompression:
1551 default:
1552 {
1553 /*
1554 Allocate pixel array.
1555 */
1556 length=(size_t) number_pixels;
1557 pixels=(unsigned char *) AcquireQuantumMemory(length,
1558 sizeof(*pixels));
1559 if (pixels == (unsigned char *) NULL)
1560 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1561 /*
1562 Dump Runlength encoded pixels.
1563 */
1564 q=pixels;
1565 for (y=0; y < (long) image->rows; y++)
1566 {
1567 p=GetVirtualPixels(image,0,y,image->columns,1,
1568 &image->exception);
1569 if (p == (const PixelPacket *) NULL)
1570 break;
1571 for (x=0; x < (long) image->columns; x++)
1572 {
1573 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
1574 p++;
1575 }
1576 if (image->previous == (Image *) NULL)
1577 {
1578 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1579 if (status == MagickFalse)
1580 break;
1581 }
1582 }
1583#if defined(MAGICKCORE_ZLIB_DELEGATE)
1584 if (compression == ZipCompression)
1585 status=ZLIBEncodeImage(image,length,pixels);
1586 else
1587#endif
1588 if (compression == LZWCompression)
1589 status=LZWEncodeImage(image,length,pixels);
1590 else
1591 status=PackbitsEncodeImage(image,length,pixels);
1592 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1593 if (status == MagickFalse)
1594 {
1595 (void) CloseBlob(image);
1596 return(MagickFalse);
1597 }
1598 break;
1599 }
1600 case NoCompression:
1601 {
1602 /*
1603 Dump uncompressed PseudoColor packets.
1604 */
1605 Ascii85Initialize(image);
1606 for (y=0; y < (long) image->rows; y++)
1607 {
1608 p=GetVirtualPixels(image,0,y,image->columns,1,
1609 &image->exception);
1610 if (p == (const PixelPacket *) NULL)
1611 break;
1612 for (x=0; x < (long) image->columns; x++)
1613 {
1614 Ascii85Encode(image,
1615 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
1616 p++;
1617 }
1618 if (image->previous == (Image *) NULL)
1619 {
1620 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1621 if (status == MagickFalse)
1622 break;
1623 }
1624 }
1625 Ascii85Flush(image);
1626 break;
1627 }
1628 }
1629 }
1630 else
1631 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1632 (compression == JPEGCompression) ||
1633 (compression == JPEG2000Compression))
1634 switch (compression)
1635 {
1636 case JPEGCompression:
1637 {
1638 status=InjectImageBlob(image_info,image,image,"jpeg",
1639 &image->exception);
1640 if (status == MagickFalse)
1641 ThrowWriterException(CoderError,image->exception.reason);
1642 break;
1643 }
1644 case JPEG2000Compression:
1645 {
1646 status=InjectImageBlob(image_info,image,image,"jp2",
1647 &image->exception);
1648 if (status == MagickFalse)
1649 ThrowWriterException(CoderError,image->exception.reason);
1650 break;
1651 }
1652 case RLECompression:
1653 default:
1654 {
1655 /*
1656 Allocate pixel array.
1657 */
1658 length=(size_t) number_pixels;
1659 pixels=(unsigned char *) AcquireQuantumMemory(length,
1660 4*sizeof(*pixels));
1661 length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
1662 if (pixels == (unsigned char *) NULL)
1663 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1664 /*
1665 Dump runoffset encoded pixels.
1666 */
1667 q=pixels;
1668 for (y=0; y < (long) image->rows; y++)
1669 {
1670 p=GetVirtualPixels(image,0,y,image->columns,1,
1671 &image->exception);
1672 if (p == (const PixelPacket *) NULL)
1673 break;
1674 indexes=GetVirtualIndexQueue(image);
1675 for (x=0; x < (long) image->columns; x++)
1676 {
cristyce70c172010-01-07 17:15:30 +00001677 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
1678 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
1679 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001680 if (image->colorspace == CMYKColorspace)
1681 *q++=ScaleQuantumToChar(indexes[x]);
1682 p++;
1683 }
1684 if (image->previous == (Image *) NULL)
1685 {
1686 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1687 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);
1714 for (y=0; y < (long) image->rows; y++)
1715 {
1716 p=GetVirtualPixels(image,0,y,image->columns,1,
1717 &image->exception);
1718 if (p == (const PixelPacket *) NULL)
1719 break;
1720 indexes=GetVirtualIndexQueue(image);
1721 for (x=0; x < (long) image->columns; x++)
1722 {
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 {
1732 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1733 if (status == MagickFalse)
1734 break;
1735 }
1736 }
1737 Ascii85Flush(image);
1738 break;
1739 }
1740 }
1741 else
1742 {
1743 /*
1744 Dump number of colors and colormap.
1745 */
1746 switch (compression)
1747 {
1748 case RLECompression:
1749 default:
1750 {
1751 /*
1752 Allocate pixel array.
1753 */
1754 length=(size_t) number_pixels;
1755 pixels=(unsigned char *) AcquireQuantumMemory(length,
1756 sizeof(*pixels));
1757 if (pixels == (unsigned char *) NULL)
1758 ThrowWriterException(ResourceLimitError,
1759 "MemoryAllocationFailed");
1760 /*
1761 Dump Runlength encoded pixels.
1762 */
1763 q=pixels;
1764 for (y=0; y < (long) image->rows; y++)
1765 {
1766 p=GetVirtualPixels(image,0,y,image->columns,1,
1767 &image->exception);
1768 if (p == (const PixelPacket *) NULL)
1769 break;
1770 indexes=GetVirtualIndexQueue(image);
1771 for (x=0; x < (long) image->columns; x++)
1772 *q++=(unsigned char) indexes[x];
1773 if (image->previous == (Image *) NULL)
1774 {
1775 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1776 if (status == MagickFalse)
1777 break;
1778 }
1779 }
1780#if defined(MAGICKCORE_ZLIB_DELEGATE)
1781 if (compression == ZipCompression)
1782 status=ZLIBEncodeImage(image,length,pixels);
1783 else
1784#endif
1785 if (compression == LZWCompression)
1786 status=LZWEncodeImage(image,length,pixels);
1787 else
1788 status=PackbitsEncodeImage(image,length,pixels);
1789 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1790 if (status == MagickFalse)
1791 {
1792 (void) CloseBlob(image);
1793 return(MagickFalse);
1794 }
1795 break;
1796 }
1797 case NoCompression:
1798 {
1799 /*
1800 Dump uncompressed PseudoColor packets.
1801 */
1802 Ascii85Initialize(image);
1803 for (y=0; y < (long) image->rows; y++)
1804 {
1805 p=GetVirtualPixels(image,0,y,image->columns,1,
1806 &image->exception);
1807 if (p == (const PixelPacket *) NULL)
1808 break;
1809 indexes=GetVirtualIndexQueue(image);
1810 for (x=0; x < (long) image->columns; x++)
1811 Ascii85Encode(image,(unsigned char) indexes[x]);
1812 if (image->previous == (Image *) NULL)
1813 {
1814 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1815 if (status == MagickFalse)
1816 break;
1817 }
1818 }
1819 Ascii85Flush(image);
1820 break;
1821 }
1822 }
1823 }
1824 offset=TellBlob(image)-offset;
1825 (void) WriteBlobString(image,"\nendstream\n");
1826 (void) WriteBlobString(image,"endobj\n");
1827 /*
1828 Write Length object.
1829 */
1830 xref[object++]=TellBlob(image);
1831 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1832 (void) WriteBlobString(image,buffer);
1833 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
1834 (unsigned long) offset);
1835 (void) WriteBlobString(image,buffer);
1836 (void) WriteBlobString(image,"endobj\n");
1837 /*
1838 Write Colorspace object.
1839 */
1840 xref[object++]=TellBlob(image);
1841 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1842 (void) WriteBlobString(image,buffer);
1843 if (image->colorspace == CMYKColorspace)
1844 (void) CopyMagickString(buffer,"/DeviceCMYK\n",MaxTextExtent);
1845 else
1846 if ((compression == FaxCompression) ||
1847 (compression == Group4Compression) ||
1848 ((image_info->type != TrueColorType) &&
1849 (IsGrayImage(image,&image->exception) != MagickFalse)))
1850 (void) CopyMagickString(buffer,"/DeviceGray\n",MaxTextExtent);
1851 else
1852 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1853 (compression == JPEGCompression) ||
1854 (compression == JPEG2000Compression))
1855 (void) CopyMagickString(buffer,"/DeviceRGB\n",MaxTextExtent);
1856 else
1857 (void) FormatMagickString(buffer,MaxTextExtent,
1858 "[ /Indexed /DeviceRGB %lu %lu 0 R ]\n",
1859 image->colors-1,object+3);
1860 (void) WriteBlobString(image,buffer);
1861 (void) WriteBlobString(image,"endobj\n");
1862 /*
1863 Write Thumb object.
1864 */
1865 SetGeometry(image,&geometry);
1866 (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
1867 &geometry.width,&geometry.height);
1868 tile_image=ThumbnailImage(image,geometry.width,geometry.height,
1869 &image->exception);
1870 if (tile_image == (Image *) NULL)
1871 ThrowWriterException(ResourceLimitError,image->exception.reason);
1872 xref[object++]=TellBlob(image);
1873 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
1874 (void) WriteBlobString(image,buffer);
1875 (void) WriteBlobString(image,"<<\n");
1876 switch (compression)
1877 {
1878 case NoCompression:
1879 {
1880 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
1881 break;
1882 }
1883 case JPEGCompression:
1884 {
1885 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"DCTDecode");
1886 if (image->colorspace != CMYKColorspace)
1887 break;
1888 (void) WriteBlobString(image,buffer);
1889 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1890 MaxTextExtent);
1891 break;
1892 }
1893 case JPEG2000Compression:
1894 {
1895 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"JPXDecode");
1896 if (image->colorspace != CMYKColorspace)
1897 break;
1898 (void) WriteBlobString(image,buffer);
1899 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1900 MaxTextExtent);
1901 break;
1902 }
1903 case LZWCompression:
1904 {
1905 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
1906 break;
1907 }
1908 case ZipCompression:
1909 {
1910 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"FlateDecode");
1911 break;
1912 }
1913 case FaxCompression:
1914 case Group4Compression:
1915 {
1916 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1917 MaxTextExtent);
1918 (void) WriteBlobString(image,buffer);
cristya55e1092009-09-13 02:41:40 +00001919 (void) FormatMagickString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristy80975862009-09-25 14:34:31 +00001920 "/K %s /BlackIs1 false /Columns %lu /Rows %lu >> ]\n",CCITTParam,
cristya55e1092009-09-13 02:41:40 +00001921 tile_image->columns,tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001922 break;
1923 }
1924 default:
1925 {
1926 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
1927 "RunLengthDecode");
1928 break;
1929 }
1930 }
1931 (void) WriteBlobString(image,buffer);
1932 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
1933 tile_image->columns);
1934 (void) WriteBlobString(image,buffer);
1935 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",
1936 tile_image->rows);
1937 (void) WriteBlobString(image,buffer);
1938 (void) FormatMagickString(buffer,MaxTextExtent,"/ColorSpace %lu 0 R\n",
1939 object-1);
1940 (void) WriteBlobString(image,buffer);
1941 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
1942 (compression == FaxCompression) || (compression == Group4Compression) ?
1943 1 : 8);
1944 (void) WriteBlobString(image,buffer);
1945 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
1946 object+1);
1947 (void) WriteBlobString(image,buffer);
1948 (void) WriteBlobString(image,">>\n");
1949 (void) WriteBlobString(image,"stream\n");
1950 offset=TellBlob(image);
1951 number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
1952 if ((compression == FaxCompression) ||
1953 (compression == Group4Compression) ||
1954 ((image_info->type != TrueColorType) &&
1955 (IsGrayImage(tile_image,&image->exception) != MagickFalse)))
1956 {
1957 switch (compression)
1958 {
1959 case FaxCompression:
1960 case Group4Compression:
1961 {
1962 if (LocaleCompare(CCITTParam,"0") == 0)
1963 {
1964 (void) HuffmanEncodeImage(image_info,image,tile_image);
1965 break;
1966 }
1967 (void) Huffman2DEncodeImage(image_info,image,tile_image);
1968 break;
1969 }
1970 case JPEGCompression:
1971 {
1972 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
1973 &image->exception);
1974 if (status == MagickFalse)
1975 ThrowWriterException(CoderError,tile_image->exception.reason);
1976 break;
1977 }
1978 case JPEG2000Compression:
1979 {
1980 status=InjectImageBlob(image_info,image,tile_image,"jp2",
1981 &image->exception);
1982 if (status == MagickFalse)
1983 ThrowWriterException(CoderError,tile_image->exception.reason);
1984 break;
1985 }
1986 case RLECompression:
1987 default:
1988 {
1989 /*
1990 Allocate pixel array.
1991 */
1992 length=(size_t) number_pixels;
1993 pixels=(unsigned char *) AcquireQuantumMemory(length,
1994 sizeof(*pixels));
1995 if (pixels == (unsigned char *) NULL)
1996 {
1997 tile_image=DestroyImage(tile_image);
1998 ThrowWriterException(ResourceLimitError,
1999 "MemoryAllocationFailed");
2000 }
2001 /*
2002 Dump Runlength encoded pixels.
2003 */
2004 q=pixels;
2005 for (y=0; y < (long) tile_image->rows; y++)
2006 {
2007 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2008 &tile_image->exception);
2009 if (p == (const PixelPacket *) NULL)
2010 break;
2011 for (x=0; x < (long) tile_image->columns; x++)
2012 {
2013 *q++=ScaleQuantumToChar(PixelIntensityToQuantum(p));
2014 p++;
2015 }
2016 }
2017#if defined(MAGICKCORE_ZLIB_DELEGATE)
2018 if (compression == ZipCompression)
2019 status=ZLIBEncodeImage(image,length,pixels);
2020 else
2021#endif
2022 if (compression == LZWCompression)
2023 status=LZWEncodeImage(image,length,pixels);
2024 else
2025 status=PackbitsEncodeImage(image,length,pixels);
2026 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2027 if (status == MagickFalse)
2028 {
2029 (void) CloseBlob(image);
2030 return(MagickFalse);
2031 }
2032 break;
2033 }
2034 case NoCompression:
2035 {
2036 /*
2037 Dump uncompressed PseudoColor packets.
2038 */
2039 Ascii85Initialize(image);
2040 for (y=0; y < (long) tile_image->rows; y++)
2041 {
2042 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2043 &tile_image->exception);
2044 if (p == (const PixelPacket *) NULL)
2045 break;
2046 for (x=0; x < (long) tile_image->columns; x++)
2047 {
2048 Ascii85Encode(image,
2049 ScaleQuantumToChar(PixelIntensityToQuantum(p)));
2050 p++;
2051 }
2052 }
2053 Ascii85Flush(image);
2054 break;
2055 }
2056 }
2057 }
2058 else
2059 if ((tile_image->storage_class == DirectClass) ||
2060 (tile_image->colors > 256) || (compression == JPEGCompression) ||
2061 (compression == JPEG2000Compression))
2062 switch (compression)
2063 {
2064 case JPEGCompression:
2065 {
2066 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2067 &image->exception);
2068 if (status == MagickFalse)
2069 ThrowWriterException(CoderError,tile_image->exception.reason);
2070 break;
2071 }
2072 case JPEG2000Compression:
2073 {
2074 status=InjectImageBlob(image_info,image,tile_image,"jp2",
2075 &image->exception);
2076 if (status == MagickFalse)
2077 ThrowWriterException(CoderError,tile_image->exception.reason);
2078 break;
2079 }
2080 case RLECompression:
2081 default:
2082 {
2083 /*
2084 Allocate pixel array.
2085 */
2086 length=(size_t) number_pixels;
2087 pixels=(unsigned char *) AcquireQuantumMemory(length,4*
2088 sizeof(*pixels));
2089 length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2090 if (pixels == (unsigned char *) NULL)
2091 {
2092 tile_image=DestroyImage(tile_image);
2093 ThrowWriterException(ResourceLimitError,
2094 "MemoryAllocationFailed");
2095 }
2096 /*
2097 Dump runoffset encoded pixels.
2098 */
2099 q=pixels;
2100 for (y=0; y < (long) tile_image->rows; y++)
2101 {
2102 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2103 &tile_image->exception);
2104 if (p == (const PixelPacket *) NULL)
2105 break;
2106 indexes=GetVirtualIndexQueue(tile_image);
2107 for (x=0; x < (long) tile_image->columns; x++)
2108 {
cristyce70c172010-01-07 17:15:30 +00002109 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
2110 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
2111 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00002112 if (image->colorspace == CMYKColorspace)
2113 *q++=ScaleQuantumToChar(indexes[x]);
2114 p++;
2115 }
2116 }
2117#if defined(MAGICKCORE_ZLIB_DELEGATE)
2118 if (compression == ZipCompression)
2119 status=ZLIBEncodeImage(image,length,pixels);
2120 else
2121#endif
2122 if (compression == LZWCompression)
2123 status=LZWEncodeImage(image,length,pixels);
2124 else
2125 status=PackbitsEncodeImage(image,length,pixels);
2126 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2127 if (status == MagickFalse)
2128 {
2129 (void) CloseBlob(image);
2130 return(MagickFalse);
2131 }
2132 break;
2133 }
2134 case NoCompression:
2135 {
2136 /*
2137 Dump uncompressed DirectColor packets.
2138 */
2139 Ascii85Initialize(image);
2140 for (y=0; y < (long) tile_image->rows; y++)
2141 {
2142 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2143 &tile_image->exception);
2144 if (p == (const PixelPacket *) NULL)
2145 break;
2146 indexes=GetVirtualIndexQueue(tile_image);
2147 for (x=0; x < (long) tile_image->columns; x++)
2148 {
cristyce70c172010-01-07 17:15:30 +00002149 Ascii85Encode(image,ScaleQuantumToChar(GetRedPixelComponent(p)));
2150 Ascii85Encode(image,ScaleQuantumToChar(GetGreenPixelComponent(p)));
2151 Ascii85Encode(image,ScaleQuantumToChar(GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002152 if (image->colorspace == CMYKColorspace)
2153 Ascii85Encode(image,ScaleQuantumToChar(indexes[x]));
2154 p++;
2155 }
2156 }
2157 Ascii85Flush(image);
2158 break;
2159 }
2160 }
2161 else
2162 {
2163 /*
2164 Dump number of colors and colormap.
2165 */
2166 switch (compression)
2167 {
2168 case RLECompression:
2169 default:
2170 {
2171 /*
2172 Allocate pixel array.
2173 */
2174 length=(size_t) number_pixels;
2175 pixels=(unsigned char *) AcquireQuantumMemory(length,
2176 sizeof(*pixels));
2177 if (pixels == (unsigned char *) NULL)
2178 {
2179 tile_image=DestroyImage(tile_image);
2180 ThrowWriterException(ResourceLimitError,
2181 "MemoryAllocationFailed");
2182 }
2183 /*
2184 Dump Runlength encoded pixels.
2185 */
2186 q=pixels;
2187 for (y=0; y < (long) tile_image->rows; y++)
2188 {
2189 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2190 &tile_image->exception);
2191 if (p == (const PixelPacket *) NULL)
2192 break;
2193 indexes=GetVirtualIndexQueue(tile_image);
2194 for (x=0; x < (long) tile_image->columns; x++)
2195 *q++=(unsigned char) indexes[x];
2196 }
2197#if defined(MAGICKCORE_ZLIB_DELEGATE)
2198 if (compression == ZipCompression)
2199 status=ZLIBEncodeImage(image,length,pixels);
2200 else
2201#endif
2202 if (compression == LZWCompression)
2203 status=LZWEncodeImage(image,length,pixels);
2204 else
2205 status=PackbitsEncodeImage(image,length,pixels);
2206 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2207 if (status == MagickFalse)
2208 {
2209 (void) CloseBlob(image);
2210 return(MagickFalse);
2211 }
2212 break;
2213 }
2214 case NoCompression:
2215 {
2216 /*
2217 Dump uncompressed PseudoColor packets.
2218 */
2219 Ascii85Initialize(image);
2220 for (y=0; y < (long) tile_image->rows; y++)
2221 {
2222 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2223 &tile_image->exception);
2224 if (p == (const PixelPacket *) NULL)
2225 break;
2226 indexes=GetVirtualIndexQueue(tile_image);
2227 for (x=0; x < (long) tile_image->columns; x++)
2228 Ascii85Encode(image,(unsigned char) indexes[x]);
2229 }
2230 Ascii85Flush(image);
2231 break;
2232 }
2233 }
2234 }
2235 tile_image=DestroyImage(tile_image);
2236 offset=TellBlob(image)-offset;
2237 (void) WriteBlobString(image,"\nendstream\n");
2238 (void) WriteBlobString(image,"endobj\n");
2239 /*
2240 Write Length object.
2241 */
2242 xref[object++]=TellBlob(image);
2243 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2244 (void) WriteBlobString(image,buffer);
2245 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
2246 (unsigned long) offset);
2247 (void) WriteBlobString(image,buffer);
2248 (void) WriteBlobString(image,"endobj\n");
2249 xref[object++]=TellBlob(image);
2250 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2251 (void) WriteBlobString(image,buffer);
2252 if ((image->storage_class != DirectClass) && (image->colors <= 256) &&
2253 (compression != FaxCompression) && (compression != Group4Compression))
2254 {
2255 /*
2256 Write Colormap object.
2257 */
2258 (void) WriteBlobString(image,"<<\n");
2259 if (compression == NoCompression)
2260 (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
2261 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
2262 object+1);
2263 (void) WriteBlobString(image,buffer);
2264 (void) WriteBlobString(image,">>\n");
2265 (void) WriteBlobString(image,"stream\n");
2266 offset=TellBlob(image);
2267 if (compression == NoCompression)
2268 Ascii85Initialize(image);
2269 for (i=0; i < (long) image->colors; i++)
2270 {
2271 if (compression == NoCompression)
2272 {
2273 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].red));
2274 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].green));
2275 Ascii85Encode(image,ScaleQuantumToChar(image->colormap[i].blue));
2276 continue;
2277 }
2278 (void) WriteBlobByte(image,
2279 ScaleQuantumToChar(image->colormap[i].red));
2280 (void) WriteBlobByte(image,
2281 ScaleQuantumToChar(image->colormap[i].green));
2282 (void) WriteBlobByte(image,
2283 ScaleQuantumToChar(image->colormap[i].blue));
2284 }
2285 if (compression == NoCompression)
2286 Ascii85Flush(image);
2287 offset=TellBlob(image)-offset;
2288 (void) WriteBlobString(image,"\nendstream\n");
2289 }
2290 (void) WriteBlobString(image,"endobj\n");
2291 /*
2292 Write Length object.
2293 */
2294 xref[object++]=TellBlob(image);
2295 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2296 (void) WriteBlobString(image,buffer);
2297 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
2298 (unsigned long) offset);
2299 (void) WriteBlobString(image,buffer);
2300 (void) WriteBlobString(image,"endobj\n");
2301 /*
2302 Write softmask object.
2303 */
2304 xref[object++]=TellBlob(image);
2305 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2306 (void) WriteBlobString(image,buffer);
2307 (void) WriteBlobString(image,"<<\n");
2308 if (image->matte == MagickFalse)
2309 (void) WriteBlobString(image,">>\n");
2310 else
2311 {
2312 (void) WriteBlobString(image,"/Type /XObject\n");
2313 (void) WriteBlobString(image,"/Subtype /Image\n");
2314 (void) FormatMagickString(buffer,MaxTextExtent,"/Name /Ma%lu\n",
2315 image->scene);
2316 (void) WriteBlobString(image,buffer);
2317 switch (compression)
2318 {
2319 case NoCompression:
2320 {
2321 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2322 "ASCII85Decode");
2323 break;
2324 }
2325 case LZWCompression:
2326 {
2327 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,"LZWDecode");
2328 break;
2329 }
2330 case ZipCompression:
2331 {
2332 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2333 "FlateDecode");
2334 break;
2335 }
2336 default:
2337 {
2338 (void) FormatMagickString(buffer,MaxTextExtent,CFormat,
2339 "RunLengthDecode");
2340 break;
2341 }
2342 }
2343 (void) WriteBlobString(image,buffer);
2344 (void) FormatMagickString(buffer,MaxTextExtent,"/Width %lu\n",
2345 image->columns);
2346 (void) WriteBlobString(image,buffer);
2347 (void) FormatMagickString(buffer,MaxTextExtent,"/Height %lu\n",
2348 image->rows);
2349 (void) WriteBlobString(image,buffer);
2350 (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2351 (void) FormatMagickString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
2352 (compression == FaxCompression) || (compression == Group4Compression)
2353 ? 1 : 8);
2354 (void) WriteBlobString(image,buffer);
2355 (void) FormatMagickString(buffer,MaxTextExtent,"/Length %lu 0 R\n",
2356 object+1);
2357 (void) WriteBlobString(image,buffer);
2358 (void) WriteBlobString(image,">>\n");
2359 (void) WriteBlobString(image,"stream\n");
2360 offset=TellBlob(image);
2361 number_pixels=(MagickSizeType) image->columns*image->rows;
2362 switch (compression)
2363 {
2364 case RLECompression:
2365 default:
2366 {
2367 /*
2368 Allocate pixel array.
2369 */
2370 length=(size_t) number_pixels;
2371 pixels=(unsigned char *) AcquireQuantumMemory(length,
2372 sizeof(*pixels));
2373 if (pixels == (unsigned char *) NULL)
2374 {
2375 image=DestroyImage(image);
2376 ThrowWriterException(ResourceLimitError,
2377 "MemoryAllocationFailed");
2378 }
2379 /*
2380 Dump Runlength encoded pixels.
2381 */
2382 q=pixels;
2383 for (y=0; y < (long) image->rows; y++)
2384 {
2385 p=GetVirtualPixels(image,0,y,image->columns,1,
2386 &image->exception);
2387 if (p == (const PixelPacket *) NULL)
2388 break;
2389 for (x=0; x < (long) image->columns; x++)
2390 {
cristy46f08202010-01-10 04:04:21 +00002391 *q++=ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00002392 p++;
2393 }
2394 }
2395#if defined(MAGICKCORE_ZLIB_DELEGATE)
2396 if (compression == ZipCompression)
2397 status=ZLIBEncodeImage(image,length,pixels);
2398 else
2399#endif
2400 if (compression == LZWCompression)
2401 status=LZWEncodeImage(image,length,pixels);
2402 else
2403 status=PackbitsEncodeImage(image,length,pixels);
2404 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2405 if (status == MagickFalse)
2406 {
2407 (void) CloseBlob(image);
2408 return(MagickFalse);
2409 }
2410 break;
2411 }
2412 case NoCompression:
2413 {
2414 /*
2415 Dump uncompressed PseudoColor packets.
2416 */
2417 Ascii85Initialize(image);
2418 for (y=0; y < (long) image->rows; y++)
2419 {
2420 p=GetVirtualPixels(image,0,y,image->columns,1,
2421 &image->exception);
2422 if (p == (const PixelPacket *) NULL)
2423 break;
2424 for (x=0; x < (long) image->columns; x++)
2425 {
2426 Ascii85Encode(image,ScaleQuantumToChar((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002427 GetOpacityPixelComponent(p))));
cristy3ed852e2009-09-05 21:47:34 +00002428 p++;
2429 }
2430 }
2431 Ascii85Flush(image);
2432 break;
2433 }
2434 }
2435 offset=TellBlob(image)-offset;
2436 (void) WriteBlobString(image,"\nendstream\n");
2437 }
2438 (void) WriteBlobString(image,"endobj\n");
2439 /*
2440 Write Length object.
2441 */
2442 xref[object++]=TellBlob(image);
2443 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2444 (void) WriteBlobString(image,buffer);
2445 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
2446 offset);
2447 (void) WriteBlobString(image,buffer);
2448 (void) WriteBlobString(image,"endobj\n");
2449 if (GetNextImageInList(image) == (Image *) NULL)
2450 break;
2451 image=SyncNextImageInList(image);
2452 status=SetImageProgress(image,SaveImagesTag,scene++,
2453 GetImageListLength(image));
2454 if (status == MagickFalse)
2455 break;
2456 } while (image_info->adjoin != MagickFalse);
2457 /*
2458 Write Metadata object.
2459 */
2460 xref[object++]=TellBlob(image);
2461 info_id=object;
2462 (void) FormatMagickString(buffer,MaxTextExtent,"%lu 0 obj\n",object);
2463 (void) WriteBlobString(image,buffer);
2464 (void) WriteBlobString(image,"<<\n");
2465 (void) FormatMagickString(buffer,MaxTextExtent,"/Title (%s)\n",
2466 EscapeParenthesis(image->filename));
2467 (void) WriteBlobString(image,buffer);
2468 seconds=time((time_t *) NULL);
2469#if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2470 (void) localtime_r(&seconds,&local_time);
2471#else
2472 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2473#endif
2474 (void) FormatMagickString(date,MaxTextExtent,"D:%04d%02d%02d%02d%02d%02d",
2475 local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2476 local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2477 (void) FormatMagickString(buffer,MaxTextExtent,"/CreationDate (%s)\n",date);
2478 (void) WriteBlobString(image,buffer);
2479 (void) FormatMagickString(buffer,MaxTextExtent,"/ModDate (%s)\n",date);
2480 (void) WriteBlobString(image,buffer);
2481 (void) FormatMagickString(buffer,MaxTextExtent,"/Producer (%s)\n",
2482 EscapeParenthesis(GetMagickVersion((unsigned long *) NULL)));
2483 (void) WriteBlobString(image,buffer);
2484 (void) WriteBlobString(image,">>\n");
2485 (void) WriteBlobString(image,"endobj\n");
2486 /*
2487 Write Xref object.
2488 */
2489 offset=TellBlob(image)-xref[0]+10;
2490 (void) WriteBlobString(image,"xref\n");
2491 (void) FormatMagickString(buffer,MaxTextExtent,"0 %lu\n",object+1);
2492 (void) WriteBlobString(image,buffer);
2493 (void) WriteBlobString(image,"0000000000 65535 f \n");
2494 for (i=0; i < (long) object; i++)
2495 {
2496 (void) FormatMagickString(buffer,MaxTextExtent,"%010lu 00000 n \n",
2497 (unsigned long) xref[i]);
2498 (void) WriteBlobString(image,buffer);
2499 }
2500 (void) WriteBlobString(image,"trailer\n");
2501 (void) WriteBlobString(image,"<<\n");
2502 (void) FormatMagickString(buffer,MaxTextExtent,"/Size %lu\n",object+1);
2503 (void) WriteBlobString(image,buffer);
2504 (void) FormatMagickString(buffer,MaxTextExtent,"/Info %lu 0 R\n",info_id);
2505 (void) WriteBlobString(image,buffer);
2506 (void) FormatMagickString(buffer,MaxTextExtent,"/Root %lu 0 R\n",root_id);
2507 (void) WriteBlobString(image,buffer);
2508 (void) WriteBlobString(image,">>\n");
2509 (void) WriteBlobString(image,"startxref\n");
2510 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",
2511 (unsigned long) offset);
2512 (void) WriteBlobString(image,buffer);
2513 (void) WriteBlobString(image,"%%EOF\n");
2514 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2515 (void) CloseBlob(image);
2516 return(MagickTrue);
2517}