blob: ce93506a28856c6fb40d06383cf1fa9e67f74749 [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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
cristyfe676ee2013-11-18 13:03:38 +000020% Copyright 1999-2014 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/attribute.h"
cristy76ce6e12013-04-05 14:33:38 +000044#include "MagickCore/artifact.h"
cristy4c08aed2011-07-01 19:47:50 +000045#include "MagickCore/blob.h"
46#include "MagickCore/blob-private.h"
47#include "MagickCore/cache.h"
48#include "MagickCore/color.h"
49#include "MagickCore/color-private.h"
50#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000051#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/compress.h"
53#include "MagickCore/constitute.h"
54#include "MagickCore/delegate.h"
55#include "MagickCore/delegate-private.h"
56#include "MagickCore/draw.h"
57#include "MagickCore/exception.h"
58#include "MagickCore/exception-private.h"
59#include "MagickCore/geometry.h"
60#include "MagickCore/image.h"
61#include "MagickCore/image-private.h"
62#include "MagickCore/list.h"
63#include "MagickCore/magick.h"
64#include "MagickCore/memory_.h"
65#include "MagickCore/monitor.h"
66#include "MagickCore/monitor-private.h"
cristy1e37e8f2014-02-21 17:05:37 +000067#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000068#include "MagickCore/option.h"
69#include "MagickCore/pixel-accessor.h"
70#include "MagickCore/profile.h"
71#include "MagickCore/property.h"
72#include "MagickCore/quantum-private.h"
73#include "MagickCore/resource_.h"
74#include "MagickCore/resize.h"
cristy1b70dc82012-07-01 23:15:05 +000075#include "MagickCore/signature.h"
cristy4c08aed2011-07-01 19:47:50 +000076#include "MagickCore/static.h"
77#include "MagickCore/string_.h"
78#include "MagickCore/module.h"
cristye40005d2012-03-23 12:18:45 +000079#include "MagickCore/token.h"
cristy4c08aed2011-07-01 19:47:50 +000080#include "MagickCore/transform.h"
81#include "MagickCore/utility.h"
82#include "MagickCore/module.h"
cristy80975862009-09-25 14:34:31 +000083
84/*
85 Define declarations.
86*/
cristy3ed852e2009-09-05 21:47:34 +000087#if defined(MAGICKCORE_TIFF_DELEGATE)
88#define CCITTParam "-1"
89#else
90#define CCITTParam "0"
91#endif
92
93/*
94 Forward declarations.
95*/
96static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000097 WritePDFImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000098
99/*
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101% %
102% %
103% %
cristy817f4cd2013-02-06 11:45:42 +0000104% I n v o k e P D F D e l e g a t e %
105% %
106% %
107% %
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109%
110% InvokePDFDelegate() executes the PDF interpreter with the specified command.
111%
112% The format of the InvokePDFDelegate method is:
113%
114% MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
115% const char *command,ExceptionInfo *exception)
116%
117% A description of each parameter follows:
118%
119% o verbose: A value other than zero displays the command prior to
120% executing it.
121%
122% o command: the address of a character string containing the command to
123% execute.
124%
125% o exception: return any errors or warnings in this structure.
126%
127*/
dirkfdec0e72014-05-09 18:45:41 +0000128#if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy26842022014-10-05 19:18:23 +0000129static int MagickDLLCall PDFDelegateMessage(void *handle,const char *message,
130 int length)
dirk52784992014-05-03 13:00:18 +0000131{
132 char
133 **messages;
134
cristy26842022014-10-05 19:18:23 +0000135 ssize_t
136 offset;
dirk52784992014-05-03 13:00:18 +0000137
138 offset=0;
cristy26842022014-10-05 19:18:23 +0000139 messages=(char **) handle;
dirk52784992014-05-03 13:00:18 +0000140 if (*messages == (char *) NULL)
cristy26842022014-10-05 19:18:23 +0000141 *messages=(char *) AcquireQuantumMemory(length+1,sizeof(char *));
dirk52784992014-05-03 13:00:18 +0000142 else
143 {
144 offset=strlen(*messages);
cristy26842022014-10-05 19:18:23 +0000145 *messages=(char *) ResizeQuantumMemory(*messages,offset+length+1,
dirk52784992014-05-03 13:00:18 +0000146 sizeof(char *));
147 }
cristy26842022014-10-05 19:18:23 +0000148 (void) memcpy(*messages+offset,message,length);
149 (*messages)[length+offset] ='\0';
150 return(length);
dirk52784992014-05-03 13:00:18 +0000151}
dirkfdec0e72014-05-09 18:45:41 +0000152#endif
dirk52784992014-05-03 13:00:18 +0000153
cristy817f4cd2013-02-06 11:45:42 +0000154static MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
dirk4dd75672014-10-12 12:52:42 +0000155 const char *command,char *output,ExceptionInfo *exception)
cristy817f4cd2013-02-06 11:45:42 +0000156{
dirkfdec0e72014-05-09 18:45:41 +0000157 int
158 status;
159
160#if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy26842022014-10-05 19:18:23 +0000161#define SetArgsStart(command,args_start) \
dirk52784992014-05-03 13:00:18 +0000162 if (args_start == (const char *) NULL) \
163 { \
cristy26842022014-10-05 19:18:23 +0000164 if (*command != '"') \
dirk52784992014-05-03 13:00:18 +0000165 args_start=strchr(command,' '); \
166 else \
167 { \
168 args_start=strchr(command+1,'"'); \
169 if (args_start != (const char *) NULL) \
170 args_start++; \
171 } \
172 }
173
cristy26842022014-10-05 19:18:23 +0000174#define ExecuteGhostscriptCommand(command,status) \
175{ \
dirk4dd75672014-10-12 12:52:42 +0000176 status=SystemCommand(MagickFalse,verbose,command,output,exception); \
cristy26842022014-10-05 19:18:23 +0000177 if (status == 0) \
178 return(MagickTrue); \
179 if (status < 0) \
dirkf3682e92014-05-03 16:00:28 +0000180 return(MagickFalse); \
cristy26842022014-10-05 19:18:23 +0000181 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, \
182 "FailedToExecuteCommand","`%s' (%d)",command,status); \
183 return(MagickFalse); \
184}
dirkf3682e92014-05-03 16:00:28 +0000185
cristy817f4cd2013-02-06 11:45:42 +0000186 char
dirk52784992014-05-03 13:00:18 +0000187 **argv,
188 *errors;
cristy817f4cd2013-02-06 11:45:42 +0000189
dirkfdec0e72014-05-09 18:45:41 +0000190 const char
cristy26842022014-10-05 19:18:23 +0000191 *args_start = (const char *) NULL;
dirkfdec0e72014-05-09 18:45:41 +0000192
cristy817f4cd2013-02-06 11:45:42 +0000193 const GhostInfo
194 *ghost_info;
195
196 gs_main_instance
197 *interpreter;
198
199 int
200 argc,
201 code;
202
203 register ssize_t
204 i;
205
206#if defined(MAGICKCORE_WINDOWS_SUPPORT)
207 ghost_info=NTGhostscriptDLLVectors();
208#else
209 GhostInfo
210 ghost_info_struct;
211
212 ghost_info=(&ghost_info_struct);
dirkefd45a02014-05-03 14:00:09 +0000213 (void) ResetMagickMemory(&ghost_info_struct,0,sizeof(ghost_info_struct));
dirk52784992014-05-03 13:00:18 +0000214 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
215 gsapi_delete_instance;
216 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
cristy817f4cd2013-02-06 11:45:42 +0000217 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
218 gsapi_new_instance;
219 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
220 gsapi_init_with_args;
221 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
222 int *)) gsapi_run_string;
dirk52784992014-05-03 13:00:18 +0000223 ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int(*)(void *,char *,
224 int),int(*)(void *,const char *,int),int(*)(void *, const char *, int)))
225 gsapi_set_stdio;
cristy817f4cd2013-02-06 11:45:42 +0000226#endif
227 if (ghost_info == (GhostInfo *) NULL)
dirk4dd75672014-10-12 12:52:42 +0000228 ExecuteGhostscriptCommand(command,status);
cristy817f4cd2013-02-06 11:45:42 +0000229 if (verbose != MagickFalse)
230 {
231 (void) fputs("[ghostscript library]",stdout);
cristy26842022014-10-05 19:18:23 +0000232 SetArgsStart(command,args_start);
dirk52784992014-05-03 13:00:18 +0000233 (void) fputs(args_start,stdout);
cristy817f4cd2013-02-06 11:45:42 +0000234 }
dirk52784992014-05-03 13:00:18 +0000235 errors=(char *) NULL;
236 status=(ghost_info->new_instance)(&interpreter,(void *) &errors);
cristy817f4cd2013-02-06 11:45:42 +0000237 if (status < 0)
cristy26842022014-10-05 19:18:23 +0000238 ExecuteGhostscriptCommand(command,status);
cristy817f4cd2013-02-06 11:45:42 +0000239 code=0;
240 argv=StringToArgv(command,&argc);
241 if (argv == (char **) NULL)
242 return(MagickFalse);
dirk52784992014-05-03 13:00:18 +0000243 (void) (ghost_info->set_stdio)(interpreter,(int(MagickDLLCall *)(void *,
244 char *,int)) NULL,PDFDelegateMessage,PDFDelegateMessage);
cristy817f4cd2013-02-06 11:45:42 +0000245 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
246 if (status == 0)
247 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
248 0,&code);
249 (ghost_info->exit)(interpreter);
250 (ghost_info->delete_instance)(interpreter);
cristy817f4cd2013-02-06 11:45:42 +0000251 for (i=0; i < (ssize_t) argc; i++)
252 argv[i]=DestroyString(argv[i]);
253 argv=(char **) RelinquishMagickMemory(argv);
dirk4dd75672014-10-12 12:52:42 +0000254 if (status != 0)
cristy817f4cd2013-02-06 11:45:42 +0000255 {
cristy26842022014-10-05 19:18:23 +0000256 SetArgsStart(command,args_start);
dirk2267d492014-10-12 18:32:02 +0000257 if (status == -101) /* quit */
dirk4dd75672014-10-12 12:52:42 +0000258 (void) FormatLocaleString(output,MaxTextExtent,
259 "[ghostscript library]%s: %s",args_start,errors);
260 else
261 {
262 (void) ThrowMagickException(exception,GetMagickModule(),
263 DelegateError,"PDFDelegateFailed","`[ghostscript library]%s': %s",
264 args_start,errors);
265 if (errors != (char *) NULL)
266 errors=DestroyString(errors);
267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
268 "Ghostscript returns status %d, exit code %d",status,code);
269 return(MagickFalse);
270 }
cristy817f4cd2013-02-06 11:45:42 +0000271 }
dirk52784992014-05-03 13:00:18 +0000272 if (errors != (char *) NULL)
273 errors=DestroyString(errors);
cristy817f4cd2013-02-06 11:45:42 +0000274 return(MagickTrue);
275#else
276 status=SystemCommand(MagickFalse,verbose,command,exception);
277 return(status == 0 ? MagickTrue : MagickFalse);
278#endif
279}
280
281/*
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283% %
284% %
285% %
cristy3ed852e2009-09-05 21:47:34 +0000286% I s P D F %
287% %
288% %
289% %
290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291%
292% IsPDF() returns MagickTrue if the image format type, identified by the
293% magick string, is PDF.
294%
295% The format of the IsPDF method is:
296%
297% MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
298%
299% A description of each parameter follows:
300%
301% o magick: compare image format pattern against these bytes.
302%
303% o offset: Specifies the offset of the magick string.
304%
305*/
306static MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
307{
308 if (offset < 5)
309 return(MagickFalse);
cristy41083a42009-09-07 23:47:59 +0000310 if (LocaleNCompare((const char *) magick,"%PDF-",5) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000311 return(MagickTrue);
312 return(MagickFalse);
313}
314
315/*
316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317% %
318% %
319% %
320% R e a d P D F I m a g e %
321% %
322% %
323% %
324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325%
326% ReadPDFImage() reads a Portable Document Format image file and
327% returns it. It allocates the memory necessary for the new Image structure
328% and returns a pointer to the new image.
329%
330% The format of the ReadPDFImage method is:
331%
332% Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
333%
334% A description of each parameter follows:
335%
336% o image_info: the image info.
337%
338% o exception: return any errors or warnings in this structure.
339%
340*/
341
342static MagickBooleanType IsPDFRendered(const char *path)
343{
344 MagickBooleanType
345 status;
346
347 struct stat
348 attributes;
349
350 if ((path == (const char *) NULL) || (*path == '\0'))
351 return(MagickFalse);
352 status=GetPathAttributes(path,&attributes);
353 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
354 (attributes.st_size > 0))
355 return(MagickTrue);
356 return(MagickFalse);
357}
358
359static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
360{
cristy0a39a5c2012-06-27 12:51:45 +0000361#define CMYKProcessColor "CMYKProcessColor"
cristy3ed852e2009-09-05 21:47:34 +0000362#define CropBox "CropBox"
cristy0a39a5c2012-06-27 12:51:45 +0000363#define DefaultCMYK "DefaultCMYK"
cristy3ed852e2009-09-05 21:47:34 +0000364#define DeviceCMYK "DeviceCMYK"
365#define MediaBox "MediaBox"
366#define RenderPostscriptText "Rendering Postscript... "
367#define PDFRotate "Rotate"
368#define SpotColor "Separation"
369#define TrimBox "TrimBox"
370#define PDFVersion "PDF-"
371
372 char
373 command[MaxTextExtent],
374 density[MaxTextExtent],
375 filename[MaxTextExtent],
376 geometry[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +0000377 input_filename[MaxTextExtent],
dirk4dd75672014-10-12 12:52:42 +0000378 options[MaxTextExtent],
379 output[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +0000380 postscript_filename[MaxTextExtent];
381
382 const char
383 *option;
384
385 const DelegateInfo
386 *delegate_info;
387
388 double
389 angle;
390
cristydba40d42010-03-25 18:31:50 +0000391 GeometryInfo
392 geometry_info;
393
cristy3ed852e2009-09-05 21:47:34 +0000394 Image
395 *image,
396 *next,
397 *pdf_image;
398
399 ImageInfo
400 *read_info;
401
402 int
cristya97426c2011-02-04 01:41:27 +0000403 c,
cristy3ed852e2009-09-05 21:47:34 +0000404 file;
405
406 MagickBooleanType
407 cmyk,
408 cropbox,
dirk83c36b12014-02-23 13:07:22 +0000409 fitPage,
cristy3ed852e2009-09-05 21:47:34 +0000410 trimbox,
411 status;
412
cristydba40d42010-03-25 18:31:50 +0000413 MagickStatusType
414 flags;
415
cristy3ed852e2009-09-05 21:47:34 +0000416 PointInfo
417 delta;
418
419 RectangleInfo
420 bounding_box,
421 page;
422
423 register char
424 *p;
425
cristya97426c2011-02-04 01:41:27 +0000426 register ssize_t
427 i;
cristy3ed852e2009-09-05 21:47:34 +0000428
429 SegmentInfo
430 bounds,
431 hires_bounds;
432
cristybb503372010-05-27 20:51:26 +0000433 size_t
cristy3ed852e2009-09-05 21:47:34 +0000434 scene,
435 spotcolor;
436
cristyaff6d802011-04-26 01:46:31 +0000437 ssize_t
438 count;
439
cristy3ed852e2009-09-05 21:47:34 +0000440 assert(image_info != (const ImageInfo *) NULL);
441 assert(image_info->signature == MagickSignature);
442 if (image_info->debug != MagickFalse)
443 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
444 image_info->filename);
445 assert(exception != (ExceptionInfo *) NULL);
446 assert(exception->signature == MagickSignature);
447 /*
448 Open image file.
449 */
cristy9950d572011-10-01 18:22:35 +0000450 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000451 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
452 if (status == MagickFalse)
453 {
454 image=DestroyImageList(image);
455 return((Image *) NULL);
456 }
457 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
458 if (status == MagickFalse)
459 {
460 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
461 image_info->filename);
462 image=DestroyImageList(image);
463 return((Image *) NULL);
464 }
465 /*
466 Set the page density.
467 */
468 delta.x=DefaultResolution;
469 delta.y=DefaultResolution;
cristy2a11bef2011-10-28 18:33:11 +0000470 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
cristy3ed852e2009-09-05 21:47:34 +0000471 {
cristy3ed852e2009-09-05 21:47:34 +0000472 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000473 image->resolution.x=geometry_info.rho;
474 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000475 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000476 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000477 }
cristydeb50be2011-11-24 00:19:33 +0000478 if (image_info->density != (char *) NULL)
479 {
480 flags=ParseGeometry(image_info->density,&geometry_info);
481 image->resolution.x=geometry_info.rho;
482 image->resolution.y=geometry_info.sigma;
483 if ((flags & SigmaValue) == 0)
484 image->resolution.y=image->resolution.x;
485 }
486 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
487 if (image_info->page != (char *) NULL)
488 (void) ParseAbsoluteGeometry(image_info->page,&page);
489 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)-
490 0.5);
491 page.height=(size_t) ceil((double) (page.height*image->resolution.y/delta.y)-
492 0.5);
cristy3ed852e2009-09-05 21:47:34 +0000493 /*
494 Determine page geometry from the PDF media box.
495 */
496 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
cristy092ec8d2013-04-26 13:46:22 +0000497 cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
498 trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
cristy3ed852e2009-09-05 21:47:34 +0000499 count=0;
500 spotcolor=0;
501 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
502 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
503 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds));
cristy3ed852e2009-09-05 21:47:34 +0000504 (void) ResetMagickMemory(command,0,sizeof(command));
cristy3ed852e2009-09-05 21:47:34 +0000505 angle=0.0;
506 p=command;
507 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
508 {
509 /*
510 Note PDF elements.
511 */
512 if (c == '\n')
513 c=' ';
514 *p++=(char) c;
cristyfd6e87b2011-02-03 18:48:17 +0000515 if ((c != (int) '/') && (c != (int) '%') &&
cristy3ed852e2009-09-05 21:47:34 +0000516 ((size_t) (p-command) < (MaxTextExtent-1)))
517 continue;
518 *(--p)='\0';
519 p=command;
520 if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
521 count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
522 /*
523 Is this a CMYK document?
524 */
cristy0a39a5c2012-06-27 12:51:45 +0000525 if (LocaleNCompare(DefaultCMYK,command,strlen(DefaultCMYK)) == 0)
526 cmyk=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000527 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
528 cmyk=MagickTrue;
cristy0a39a5c2012-06-27 12:51:45 +0000529 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
530 cmyk=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000531 if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)
532 {
533 char
534 name[MaxTextExtent],
535 property[MaxTextExtent],
536 *value;
537
cristybb503372010-05-27 20:51:26 +0000538 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000539 i;
540
541 /*
542 Note spot names.
543 */
cristyb51dff52011-05-19 16:55:47 +0000544 (void) FormatLocaleString(property,MaxTextExtent,"pdf:SpotColor-%.20g",
cristye8c25f92010-06-03 00:53:06 +0000545 (double) spotcolor++);
cristy3ed852e2009-09-05 21:47:34 +0000546 i=0;
547 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
548 {
549 if ((isspace(c) != 0) || (c == '/') || ((i+1) == MaxTextExtent))
550 break;
551 name[i++]=(char) c;
552 }
553 name[i]='\0';
554 value=AcquireString(name);
555 (void) SubstituteString(&value,"#20"," ");
cristyd15e6592011-10-15 00:13:06 +0000556 (void) SetImageProperty(image,property,value,exception);
cristy3ed852e2009-09-05 21:47:34 +0000557 value=DestroyString(value);
558 continue;
559 }
560 if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0)
cristyd15e6592011-10-15 00:13:06 +0000561 (void) SetImageProperty(image,"pdf:Version",command,exception);
cristydeb50be2011-11-24 00:19:33 +0000562 if (image_info->page != (char *) NULL)
563 continue;
cristy3ed852e2009-09-05 21:47:34 +0000564 count=0;
565 if (cropbox != MagickFalse)
566 {
567 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
568 {
569 /*
570 Note region defined by crop box.
571 */
572 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
573 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
574 if (count != 4)
575 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
576 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
577 }
578 }
579 else
580 if (trimbox != MagickFalse)
581 {
582 if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0)
583 {
584 /*
585 Note region defined by trim box.
586 */
587 count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf",
588 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
589 if (count != 4)
590 count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf",
591 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
592 }
593 }
594 else
595 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
596 {
597 /*
598 Note region defined by media box.
599 */
600 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
601 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
602 if (count != 4)
603 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
604 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
605 }
606 if (count != 4)
607 continue;
cristyad29a8c2012-01-25 23:06:43 +0000608 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
cristyc2038532011-12-29 16:43:05 +0000609 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
610 continue;
cristy48853f12011-11-11 15:47:57 +0000611 hires_bounds=bounds;
cristy3ed852e2009-09-05 21:47:34 +0000612 }
cristy7b0fcf12011-11-24 00:24:07 +0000613 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
cristy614bc082011-11-24 00:49:08 +0000614 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
cristy48853f12011-11-11 15:47:57 +0000615 {
616 /*
617 Set PDF render geometry.
618 */
619 (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g%+.15g%+.15g",
620 hires_bounds.x2-bounds.x1,hires_bounds.y2-hires_bounds.y1,
621 hires_bounds.x1,hires_bounds.y1);
622 (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry,exception);
cristydeb50be2011-11-24 00:19:33 +0000623 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
624 image->resolution.x/delta.x)-0.5);
625 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
626 image->resolution.y/delta.y)-0.5);
cristy48853f12011-11-11 15:47:57 +0000627 }
dirk83c36b12014-02-23 13:07:22 +0000628 fitPage=MagickFalse;
629 option=GetImageOption(image_info,"pdf:fit-page");
630 if (option != (char *) NULL)
631 {
632 char
633 *geometry;
634
635 MagickStatusType
636 flags;
637
638 geometry=GetPageGeometry(option);
639 flags=ParseMetaGeometry(geometry,&page.x,&page.y,&page.width,&page.height);
640 if (flags == NoValue)
641 {
642 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
643 "InvalidGeometry","`%s'",option);
644 image=DestroyImage(image);
645 return((Image *) NULL);
646 }
647 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)
648 -0.5);
649 page.height=(size_t) ceil((double) (page.height*image->resolution.y/
650 delta.y) -0.5);
651 geometry=DestroyString(geometry);
652 fitPage=MagickTrue;
653 }
cristy3ed852e2009-09-05 21:47:34 +0000654 (void) CloseBlob(image);
655 if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0))
656 {
cristybb503372010-05-27 20:51:26 +0000657 size_t
cristy3ed852e2009-09-05 21:47:34 +0000658 swap;
659
660 swap=page.width;
661 page.width=page.height;
662 page.height=swap;
663 }
cristy3d9f5ba2012-06-26 13:37:31 +0000664 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000665 cmyk=MagickFalse;
666 /*
667 Create Ghostscript control file.
668 */
669 file=AcquireUniqueFileResource(postscript_filename);
670 if (file == -1)
671 {
672 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
673 image_info->filename);
674 image=DestroyImage(image);
675 return((Image *) NULL);
676 }
677 count=write(file," ",1);
678 file=close(file)-1;
679 /*
680 Render Postscript with the Ghostscript delegate.
681 */
682 if ((image_info->ping != MagickFalse) ||
683 (image_info->monochrome != MagickFalse))
684 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
685 else
686 if (cmyk != MagickFalse)
687 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
688 else
cristya97426c2011-02-04 01:41:27 +0000689 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000690 if (delegate_info == (const DelegateInfo *) NULL)
691 {
692 (void) RelinquishUniqueFileResource(postscript_filename);
693 image=DestroyImage(image);
694 return((Image *) NULL);
695 }
696 *options='\0';
cristy2a11bef2011-10-28 18:33:11 +0000697 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",image->resolution.x,
698 image->resolution.y);
dirk83c36b12014-02-23 13:07:22 +0000699 if ((image_info->page != (char *) NULL) || (fitPage != MagickFalse))
cristyf58e2732012-02-13 15:50:15 +0000700 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
cristybe0063d2013-02-01 01:33:47 +0000701 page.width,(double) page.height);
dirk83c36b12014-02-23 13:07:22 +0000702 if (fitPage != MagickFalse)
dirk3b2bfed2014-03-13 16:13:39 +0000703 (void) ConcatenateMagickString(options,"-dPSFitPage ",MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000704 if (cmyk != MagickFalse)
705 (void) ConcatenateMagickString(options,"-dUseCIEColor ",MaxTextExtent);
706 if (cropbox != MagickFalse)
707 (void) ConcatenateMagickString(options,"-dUseCropBox ",MaxTextExtent);
708 if (trimbox != MagickFalse)
709 (void) ConcatenateMagickString(options,"-dUseTrimBox ",MaxTextExtent);
710 read_info=CloneImageInfo(image_info);
711 *read_info->magick='\0';
712 if (read_info->number_scenes != 0)
713 {
714 char
715 pages[MaxTextExtent];
716
cristyb51dff52011-05-19 16:55:47 +0000717 (void) FormatLocaleString(pages,MaxTextExtent,"-dFirstPage=%.20g "
cristye8c25f92010-06-03 00:53:06 +0000718 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
cristyf2faecf2010-05-28 19:19:36 +0000719 (read_info->scene+read_info->number_scenes));
cristy3ed852e2009-09-05 21:47:34 +0000720 (void) ConcatenateMagickString(options,pages,MaxTextExtent);
721 read_info->number_scenes=0;
722 if (read_info->scenes != (char *) NULL)
723 *read_info->scenes='\0';
724 }
cristy092ec8d2013-04-26 13:46:22 +0000725 option=GetImageOption(image_info,"authenticate");
anthony1afdc7a2011-10-05 11:54:28 +0000726 if (option != (const char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000727 (void) FormatLocaleString(options+strlen(options),MaxTextExtent,
anthony1afdc7a2011-10-05 11:54:28 +0000728 " -sPCLPassword=%s",option);
cristy3ed852e2009-09-05 21:47:34 +0000729 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
cristya97426c2011-02-04 01:41:27 +0000730 (void) AcquireUniqueFilename(filename);
dirkfd826fc2014-06-04 21:11:30 +0000731 (void) RelinquishUniqueFileResource(filename);
cristybe0063d2013-02-01 01:33:47 +0000732 (void) ConcatenateMagickString(filename,"%d",MaxTextExtent);
cristyb51dff52011-05-19 16:55:47 +0000733 (void) FormatLocaleString(command,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000734 GetDelegateCommands(delegate_info),
735 read_info->antialias != MagickFalse ? 4 : 1,
cristy209d4692014-03-19 12:40:01 +0000736 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
cristya97426c2011-02-04 01:41:27 +0000737 postscript_filename,input_filename);
dirk4dd75672014-10-12 12:52:42 +0000738 *output='\0';
739 status=InvokePDFDelegate(read_info->verbose,command,output,exception);
cristy3ed852e2009-09-05 21:47:34 +0000740 (void) RelinquishUniqueFileResource(postscript_filename);
cristy3ed852e2009-09-05 21:47:34 +0000741 (void) RelinquishUniqueFileResource(input_filename);
cristya97426c2011-02-04 01:41:27 +0000742 pdf_image=(Image *) NULL;
743 if (status == MagickFalse)
744 for (i=1; ; i++)
745 {
cristya97426c2011-02-04 01:41:27 +0000746 (void) InterpretImageFilename(image_info,image,filename,(int) i,
cristy6fccee12011-10-20 18:43:18 +0000747 read_info->filename,exception);
cristya97426c2011-02-04 01:41:27 +0000748 if (IsPDFRendered(read_info->filename) == MagickFalse)
749 break;
750 (void) RelinquishUniqueFileResource(read_info->filename);
751 }
752 else
753 for (i=1; ; i++)
754 {
cristya97426c2011-02-04 01:41:27 +0000755 (void) InterpretImageFilename(image_info,image,filename,(int) i,
cristy6fccee12011-10-20 18:43:18 +0000756 read_info->filename,exception);
cristya97426c2011-02-04 01:41:27 +0000757 if (IsPDFRendered(read_info->filename) == MagickFalse)
758 break;
cristyb0ffea22012-06-17 20:22:01 +0000759 read_info->blob=NULL;
760 read_info->length=0;
cristya97426c2011-02-04 01:41:27 +0000761 next=ReadImage(read_info,exception);
762 (void) RelinquishUniqueFileResource(read_info->filename);
763 if (next == (Image *) NULL)
764 break;
765 AppendImageToList(&pdf_image,next);
766 }
cristy3ed852e2009-09-05 21:47:34 +0000767 read_info=DestroyImageInfo(read_info);
768 if (pdf_image == (Image *) NULL)
769 {
dirk4dd75672014-10-12 12:52:42 +0000770 if (*output != '\0')
771 (void) ThrowMagickException(exception,GetMagickModule(),
772 DelegateError,"PDFDelegateFailed","`%s'",output);
cristyb6cabe82011-03-18 13:25:59 +0000773 image=DestroyImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000774 return((Image *) NULL);
775 }
776 if (LocaleCompare(pdf_image->magick,"BMP") == 0)
777 {
778 Image
779 *cmyk_image;
780
781 cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
782 if (cmyk_image != (Image *) NULL)
783 {
784 pdf_image=DestroyImageList(pdf_image);
785 pdf_image=cmyk_image;
786 }
787 }
788 if (image_info->number_scenes != 0)
789 {
790 Image
791 *clone_image;
792
cristybb503372010-05-27 20:51:26 +0000793 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000794 i;
795
796 /*
797 Add place holder images to meet the subimage specification requirement.
798 */
cristybb503372010-05-27 20:51:26 +0000799 for (i=0; i < (ssize_t) image_info->scene; i++)
cristy3ed852e2009-09-05 21:47:34 +0000800 {
801 clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
802 if (clone_image != (Image *) NULL)
803 PrependImageToList(&pdf_image,clone_image);
804 }
805 }
806 do
807 {
808 (void) CopyMagickString(pdf_image->filename,filename,MaxTextExtent);
809 pdf_image->page=page;
810 (void) CloneImageProfiles(pdf_image,image);
811 (void) CloneImageProperties(pdf_image,image);
812 next=SyncNextImageInList(pdf_image);
813 if (next != (Image *) NULL)
814 pdf_image=next;
815 } while (next != (Image *) NULL);
816 image=DestroyImage(image);
817 scene=0;
818 for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
819 {
820 next->scene=scene++;
821 next=GetNextImageInList(next);
822 }
823 return(GetFirstImageInList(pdf_image));
824}
825
826/*
827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828% %
829% %
830% %
831% R e g i s t e r P D F I m a g e %
832% %
833% %
834% %
835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
836%
837% RegisterPDFImage() adds properties for the PDF image format to
838% the list of supported formats. The properties include the image format
839% tag, a method to read and/or write the format, whether the format
840% supports the saving of more than one frame to the same file or blob,
841% whether the format supports native in-memory I/O, and a brief
842% description of the format.
843%
844% The format of the RegisterPDFImage method is:
845%
cristybb503372010-05-27 20:51:26 +0000846% size_t RegisterPDFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000847%
848*/
cristybb503372010-05-27 20:51:26 +0000849ModuleExport size_t RegisterPDFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000850{
851 MagickInfo
852 *entry;
853
854 entry=SetMagickInfo("AI");
855 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
856 entry->encoder=(EncodeImageHandler *) WritePDFImage;
857 entry->adjoin=MagickFalse;
858 entry->blob_support=MagickFalse;
859 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000860 entry->description=ConstantString("Adobe Illustrator CS2");
cristy5aefbeb2013-08-09 12:13:32 +0000861 entry->mime_type=ConstantString("application/pdf");
cristy3ed852e2009-09-05 21:47:34 +0000862 entry->module=ConstantString("PDF");
863 (void) RegisterMagickInfo(entry);
864 entry=SetMagickInfo("EPDF");
865 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
866 entry->encoder=(EncodeImageHandler *) WritePDFImage;
867 entry->adjoin=MagickFalse;
868 entry->blob_support=MagickFalse;
869 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000870 entry->description=ConstantString("Encapsulated Portable Document Format");
cristy5aefbeb2013-08-09 12:13:32 +0000871 entry->mime_type=ConstantString("application/pdf");
cristy3ed852e2009-09-05 21:47:34 +0000872 entry->module=ConstantString("PDF");
873 (void) RegisterMagickInfo(entry);
874 entry=SetMagickInfo("PDF");
875 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
876 entry->encoder=(EncodeImageHandler *) WritePDFImage;
877 entry->magick=(IsImageFormatHandler *) IsPDF;
878 entry->blob_support=MagickFalse;
879 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000880 entry->description=ConstantString("Portable Document Format");
cristy5aefbeb2013-08-09 12:13:32 +0000881 entry->mime_type=ConstantString("application/pdf");
cristy3ed852e2009-09-05 21:47:34 +0000882 entry->module=ConstantString("PDF");
883 (void) RegisterMagickInfo(entry);
884 entry=SetMagickInfo("PDFA");
885 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
886 entry->encoder=(EncodeImageHandler *) WritePDFImage;
887 entry->magick=(IsImageFormatHandler *) IsPDF;
888 entry->blob_support=MagickFalse;
889 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000890 entry->description=ConstantString("Portable Document Archive Format");
cristy5aefbeb2013-08-09 12:13:32 +0000891 entry->mime_type=ConstantString("application/pdf");
cristy3ed852e2009-09-05 21:47:34 +0000892 entry->module=ConstantString("PDF");
893 (void) RegisterMagickInfo(entry);
894 return(MagickImageCoderSignature);
895}
896
897/*
898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899% %
900% %
901% %
902% U n r e g i s t e r P D F I m a g e %
903% %
904% %
905% %
906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907%
908% UnregisterPDFImage() removes format registrations made by the
909% PDF module from the list of supported formats.
910%
911% The format of the UnregisterPDFImage method is:
912%
913% UnregisterPDFImage(void)
914%
915*/
916ModuleExport void UnregisterPDFImage(void)
917{
918 (void) UnregisterMagickInfo("AI");
919 (void) UnregisterMagickInfo("EPDF");
920 (void) UnregisterMagickInfo("PDF");
921 (void) UnregisterMagickInfo("PDFA");
922}
923
924/*
925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926% %
927% %
928% %
929% W r i t e P D F I m a g e %
930% %
931% %
932% %
933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934%
935% WritePDFImage() writes an image in the Portable Document image
936% format.
937%
938% The format of the WritePDFImage method is:
939%
cristy1e178e72011-08-28 19:44:34 +0000940% MagickBooleanType WritePDFImage(const ImageInfo *image_info,
941% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000942%
943% A description of each parameter follows.
944%
945% o image_info: the image info.
946%
947% o image: The image.
948%
cristy1e178e72011-08-28 19:44:34 +0000949% o exception: return any errors or warnings in this structure.
950%
cristy3ed852e2009-09-05 21:47:34 +0000951*/
952
953static inline size_t MagickMax(const size_t x,const size_t y)
954{
955 if (x > y)
956 return(x);
957 return(y);
958}
959
960static inline size_t MagickMin(const size_t x,const size_t y)
961{
962 if (x < y)
963 return(x);
964 return(y);
965}
966
967static char *EscapeParenthesis(const char *text)
968{
969 register char
970 *p;
971
cristybb503372010-05-27 20:51:26 +0000972 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000973 i;
974
cristybb503372010-05-27 20:51:26 +0000975 size_t
cristy3ed852e2009-09-05 21:47:34 +0000976 escapes;
977
cristyaff6d802011-04-26 01:46:31 +0000978 static char
979 buffer[MaxTextExtent];
980
cristy3ed852e2009-09-05 21:47:34 +0000981 escapes=0;
982 p=buffer;
cristybb503372010-05-27 20:51:26 +0000983 for (i=0; i < (ssize_t) MagickMin(strlen(text),(MaxTextExtent-escapes-1)); i++)
cristy3ed852e2009-09-05 21:47:34 +0000984 {
985 if ((text[i] == '(') || (text[i] == ')'))
986 {
987 *p++='\\';
988 escapes++;
989 }
990 *p++=text[i];
991 }
992 *p='\0';
993 return(buffer);
994}
995
cristy47b838c2009-09-19 16:09:30 +0000996static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
cristy018f07f2011-09-04 21:15:19 +0000997 Image *image,Image *inject_image,ExceptionInfo *exception)
cristy47b838c2009-09-19 16:09:30 +0000998{
cristy47b838c2009-09-19 16:09:30 +0000999 Image
cristy80975862009-09-25 14:34:31 +00001000 *group4_image;
cristy47b838c2009-09-19 16:09:30 +00001001
1002 ImageInfo
1003 *write_info;
1004
cristy47b838c2009-09-19 16:09:30 +00001005 MagickBooleanType
1006 status;
1007
cristy80975862009-09-25 14:34:31 +00001008 size_t
1009 length;
cristy47b838c2009-09-19 16:09:30 +00001010
1011 unsigned char
cristy80975862009-09-25 14:34:31 +00001012 *group4;
cristy47b838c2009-09-19 16:09:30 +00001013
cristy42751fe2009-10-05 00:15:50 +00001014 status=MagickTrue;
cristy47b838c2009-09-19 16:09:30 +00001015 write_info=CloneImageInfo(image_info);
cristy80975862009-09-25 14:34:31 +00001016 (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
1017 (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
cristy018f07f2011-09-04 21:15:19 +00001018 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
cristy80975862009-09-25 14:34:31 +00001019 if (group4_image == (Image *) NULL)
1020 return(MagickFalse);
1021 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
cristy018f07f2011-09-04 21:15:19 +00001022 exception);
cristy80975862009-09-25 14:34:31 +00001023 group4_image=DestroyImage(group4_image);
1024 if (group4 == (unsigned char *) NULL)
1025 return(MagickFalse);
cristy47b838c2009-09-19 16:09:30 +00001026 write_info=DestroyImageInfo(write_info);
cristy80975862009-09-25 14:34:31 +00001027 if (WriteBlob(image,length,group4) != (ssize_t) length)
1028 status=MagickFalse;
1029 group4=(unsigned char *) RelinquishMagickMemory(group4);
1030 return(status);
cristy47b838c2009-09-19 16:09:30 +00001031}
1032
cristy1e178e72011-08-28 19:44:34 +00001033static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image,
1034 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001035{
1036#define CFormat "/Filter [ /%s ]\n"
1037#define ObjectsPerImage 14
1038
dirk93b02b72013-11-16 16:03:36 +00001039DisableMSCWarning(4310)
cristy3ed852e2009-09-05 21:47:34 +00001040 static const char
1041 XMPProfile[]=
1042 {
1043 "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
1044 "<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"
1045 " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
1046 " <rdf:Description rdf:about=\"\"\n"
1047 " xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
1048 " <xap:ModifyDate>%s</xap:ModifyDate>\n"
1049 " <xap:CreateDate>%s</xap:CreateDate>\n"
1050 " <xap:MetadataDate>%s</xap:MetadataDate>\n"
1051 " <xap:CreatorTool>%s</xap:CreatorTool>\n"
1052 " </rdf:Description>\n"
1053 " <rdf:Description rdf:about=\"\"\n"
1054 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
1055 " <dc:format>application/pdf</dc:format>\n"
cristy1b70dc82012-07-01 23:15:05 +00001056 " <dc:title>\n"
1057 " <rdf:Alt>\n"
1058 " <rdf:li xml:lang=\"x-default\">%s</rdf:li>\n"
1059 " </rdf:Alt>\n"
1060 " </dc:title>\n"
cristy3ed852e2009-09-05 21:47:34 +00001061 " </rdf:Description>\n"
1062 " <rdf:Description rdf:about=\"\"\n"
1063 " xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
1064 " <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
1065 " <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
1066 " </rdf:Description>\n"
1067 " <rdf:Description rdf:about=\"\"\n"
1068 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
1069 " <pdf:Producer>%s</pdf:Producer>\n"
1070 " </rdf:Description>\n"
1071 " <rdf:Description rdf:about=\"\"\n"
1072 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
cristyba5f54b2014-05-19 22:10:08 +00001073 " <pdfaid:part>3</pdfaid:part>\n"
cristy3ed852e2009-09-05 21:47:34 +00001074 " <pdfaid:conformance>B</pdfaid:conformance>\n"
1075 " </rdf:Description>\n"
1076 " </rdf:RDF>\n"
1077 "</x:xmpmeta>\n"
1078 "<?xpacket end=\"w\"?>\n"
1079 },
1080 XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
dirk93b02b72013-11-16 16:03:36 +00001081RestoreMSCWarning
cristy3ed852e2009-09-05 21:47:34 +00001082
1083 char
cristy57015272010-12-30 01:16:38 +00001084 basename[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +00001085 buffer[MaxTextExtent],
1086 date[MaxTextExtent],
1087 **labels,
1088 page_geometry[MaxTextExtent];
1089
1090 CompressionType
1091 compression;
1092
1093 const char
1094 *value;
1095
1096 double
1097 pointsize;
1098
1099 GeometryInfo
1100 geometry_info;
1101
cristy3ed852e2009-09-05 21:47:34 +00001102 Image
1103 *next,
1104 *tile_image;
1105
1106 MagickBooleanType
1107 status;
1108
1109 MagickOffsetType
1110 offset,
1111 scene,
1112 *xref;
1113
1114 MagickSizeType
1115 number_pixels;
1116
1117 MagickStatusType
1118 flags;
1119
1120 PointInfo
1121 delta,
1122 resolution,
1123 scale;
1124
1125 RectangleInfo
1126 geometry,
1127 media_info,
1128 page_info;
1129
cristy4c08aed2011-07-01 19:47:50 +00001130 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001131 *p;
1132
1133 register unsigned char
1134 *q;
1135
cristybb503372010-05-27 20:51:26 +00001136 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001137 i,
1138 x;
1139
1140 size_t
cristyaff6d802011-04-26 01:46:31 +00001141 info_id,
1142 length,
1143 object,
1144 pages_id,
1145 root_id,
1146 text_size,
1147 version;
1148
1149 ssize_t
1150 count,
1151 y;
cristy3ed852e2009-09-05 21:47:34 +00001152
1153 struct tm
1154 local_time;
1155
1156 time_t
1157 seconds;
1158
1159 unsigned char
1160 *pixels;
1161
cristy3ed852e2009-09-05 21:47:34 +00001162 /*
1163 Open output image file.
1164 */
1165 assert(image_info != (const ImageInfo *) NULL);
1166 assert(image_info->signature == MagickSignature);
1167 assert(image != (Image *) NULL);
1168 assert(image->signature == MagickSignature);
1169 if (image->debug != MagickFalse)
1170 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001171 assert(exception != (ExceptionInfo *) NULL);
1172 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001173 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001174 if (status == MagickFalse)
1175 return(status);
1176 /*
1177 Allocate X ref memory.
1178 */
1179 xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1180 if (xref == (MagickOffsetType *) NULL)
1181 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1182 (void) ResetMagickMemory(xref,0,2048UL*sizeof(*xref));
1183 /*
1184 Write Info object.
1185 */
1186 object=0;
1187 version=3;
1188 if (image_info->compression == JPEG2000Compression)
cristybb503372010-05-27 20:51:26 +00001189 version=(size_t) MagickMax(version,5);
cristy3ed852e2009-09-05 21:47:34 +00001190 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
cristy8a46d822012-08-28 23:32:39 +00001191 if (next->alpha_trait == BlendPixelTrait)
cristybb503372010-05-27 20:51:26 +00001192 version=(size_t) MagickMax(version,4);
cristy3ed852e2009-09-05 21:47:34 +00001193 if (LocaleCompare(image_info->magick,"PDFA") == 0)
cristyc04c60e2011-05-31 23:58:45 +00001194 version=(size_t) MagickMax(version,6);
cristyf40010e2012-05-13 13:52:20 +00001195 (void) FormatLocaleString(buffer,MaxTextExtent,"%%PDF-1.%.20g \n",(double)
1196 version);
cristy3ed852e2009-09-05 21:47:34 +00001197 (void) WriteBlobString(image,buffer);
1198 if (LocaleCompare(image_info->magick,"PDFA") == 0)
cristy42bd8002014-01-26 02:06:27 +00001199 {
1200 (void) WriteBlobByte(image,'%');
1201 (void) WriteBlobByte(image,0xe2);
1202 (void) WriteBlobByte(image,0xe3);
1203 (void) WriteBlobByte(image,0xcf);
1204 (void) WriteBlobByte(image,0xd3);
1205 (void) WriteBlobByte(image,'\n');
1206 }
cristy3ed852e2009-09-05 21:47:34 +00001207 /*
1208 Write Catalog object.
1209 */
1210 xref[object++]=TellBlob(image);
1211 root_id=object;
cristyb51dff52011-05-19 16:55:47 +00001212 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristye8c25f92010-06-03 00:53:06 +00001213 object);
cristy3ed852e2009-09-05 21:47:34 +00001214 (void) WriteBlobString(image,buffer);
1215 (void) WriteBlobString(image,"<<\n");
1216 if (LocaleCompare(image_info->magick,"PDFA") != 0)
cristyf40010e2012-05-13 13:52:20 +00001217 (void) FormatLocaleString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n",(double)
1218 object+1);
cristy3ed852e2009-09-05 21:47:34 +00001219 else
1220 {
cristyb51dff52011-05-19 16:55:47 +00001221 (void) FormatLocaleString(buffer,MaxTextExtent,"/Metadata %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001222 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001223 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001224 (void) FormatLocaleString(buffer,MaxTextExtent,"/Pages %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001225 (double) object+2);
cristy3ed852e2009-09-05 21:47:34 +00001226 }
1227 (void) WriteBlobString(image,buffer);
1228 (void) WriteBlobString(image,"/Type /Catalog\n");
1229 (void) WriteBlobString(image,">>\n");
1230 (void) WriteBlobString(image,"endobj\n");
cristy1b70dc82012-07-01 23:15:05 +00001231 GetPathComponent(image->filename,BasePath,basename);
cristy3ed852e2009-09-05 21:47:34 +00001232 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1233 {
1234 char
1235 create_date[MaxTextExtent],
1236 modify_date[MaxTextExtent],
1237 timestamp[MaxTextExtent],
1238 xmp_profile[MaxTextExtent];
1239
cristybb503372010-05-27 20:51:26 +00001240 size_t
cristy3ed852e2009-09-05 21:47:34 +00001241 version;
1242
1243 /*
1244 Write XMP object.
1245 */
1246 xref[object++]=TellBlob(image);
cristyf40010e2012-05-13 13:52:20 +00001247 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1248 object);
cristy3ed852e2009-09-05 21:47:34 +00001249 (void) WriteBlobString(image,buffer);
1250 (void) WriteBlobString(image,"<<\n");
1251 (void) WriteBlobString(image,"/Subtype /XML\n");
1252 *modify_date='\0';
cristyd15e6592011-10-15 00:13:06 +00001253 value=GetImageProperty(image,"date:modify",exception);
cristy3ed852e2009-09-05 21:47:34 +00001254 if (value != (const char *) NULL)
1255 (void) CopyMagickString(modify_date,value,MaxTextExtent);
1256 *create_date='\0';
cristyd15e6592011-10-15 00:13:06 +00001257 value=GetImageProperty(image,"date:create",exception);
cristy3ed852e2009-09-05 21:47:34 +00001258 if (value != (const char *) NULL)
1259 (void) CopyMagickString(create_date,value,MaxTextExtent);
1260 (void) FormatMagickTime(time((time_t *) NULL),MaxTextExtent,timestamp);
cristyb51dff52011-05-19 16:55:47 +00001261 i=FormatLocaleString(xmp_profile,MaxTextExtent,XMPProfile,
cristy3ed852e2009-09-05 21:47:34 +00001262 XMPProfileMagick,modify_date,create_date,timestamp,
cristy1b70dc82012-07-01 23:15:05 +00001263 GetMagickVersion(&version),EscapeParenthesis(basename),
1264 GetMagickVersion(&version));
cristyf40010e2012-05-13 13:52:20 +00001265 (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g\n",(double)
1266 i);
cristy3ed852e2009-09-05 21:47:34 +00001267 (void) WriteBlobString(image,buffer);
1268 (void) WriteBlobString(image,"/Type /Metadata\n");
1269 (void) WriteBlobString(image,">>\nstream\n");
1270 (void) WriteBlobString(image,xmp_profile);
cristy1b70dc82012-07-01 23:15:05 +00001271 (void) WriteBlobString(image,"\nendstream\n");
cristy3ed852e2009-09-05 21:47:34 +00001272 (void) WriteBlobString(image,"endobj\n");
1273 }
1274 /*
1275 Write Pages object.
1276 */
1277 xref[object++]=TellBlob(image);
1278 pages_id=object;
cristyb51dff52011-05-19 16:55:47 +00001279 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001280 object);
cristy3ed852e2009-09-05 21:47:34 +00001281 (void) WriteBlobString(image,buffer);
1282 (void) WriteBlobString(image,"<<\n");
1283 (void) WriteBlobString(image,"/Type /Pages\n");
cristyf40010e2012-05-13 13:52:20 +00001284 (void) FormatLocaleString(buffer,MaxTextExtent,"/Kids [ %.20g 0 R ",(double)
1285 object+1);
cristy3ed852e2009-09-05 21:47:34 +00001286 (void) WriteBlobString(image,buffer);
cristybb503372010-05-27 20:51:26 +00001287 count=(ssize_t) (pages_id+ObjectsPerImage+1);
cristy3ed852e2009-09-05 21:47:34 +00001288 if (image_info->adjoin != MagickFalse)
1289 {
1290 Image
1291 *kid_image;
1292
1293 /*
1294 Predict page object id's.
1295 */
1296 kid_image=image;
1297 for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1298 {
cristyb51dff52011-05-19 16:55:47 +00001299 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 R ",(double)
cristye8c25f92010-06-03 00:53:06 +00001300 count);
cristy3ed852e2009-09-05 21:47:34 +00001301 (void) WriteBlobString(image,buffer);
1302 kid_image=GetNextImageInList(kid_image);
1303 }
1304 xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1305 sizeof(*xref));
1306 if (xref == (MagickOffsetType *) NULL)
1307 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1308 }
1309 (void) WriteBlobString(image,"]\n");
cristyf40010e2012-05-13 13:52:20 +00001310 (void) FormatLocaleString(buffer,MaxTextExtent,"/Count %.20g\n",(double)
1311 ((count-pages_id)/ObjectsPerImage));
cristy3ed852e2009-09-05 21:47:34 +00001312 (void) WriteBlobString(image,buffer);
1313 (void) WriteBlobString(image,">>\n");
1314 (void) WriteBlobString(image,"endobj\n");
1315 scene=0;
1316 do
1317 {
cristyaf8d3912014-02-21 14:50:33 +00001318 compression=image->compression;
cristy3ed852e2009-09-05 21:47:34 +00001319 if (image_info->compression != UndefinedCompression)
1320 compression=image_info->compression;
1321 switch (compression)
1322 {
1323 case FaxCompression:
1324 case Group4Compression:
1325 {
cristy1e178e72011-08-28 19:44:34 +00001326 if ((IsImageMonochrome(image,exception) == MagickFalse) ||
cristy8a46d822012-08-28 23:32:39 +00001327 (image->alpha_trait == BlendPixelTrait))
cristy3ed852e2009-09-05 21:47:34 +00001328 compression=RLECompression;
1329 break;
1330 }
1331#if !defined(MAGICKCORE_JPEG_DELEGATE)
1332 case JPEGCompression:
1333 {
1334 compression=RLECompression;
cristy1e178e72011-08-28 19:44:34 +00001335 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00001336 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1337 image->filename);
1338 break;
1339 }
1340#endif
cristyf95d7c12014-04-08 07:35:08 +00001341#if !defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
cristy3ed852e2009-09-05 21:47:34 +00001342 case JPEG2000Compression:
1343 {
1344 compression=RLECompression;
cristy1e178e72011-08-28 19:44:34 +00001345 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00001346 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1347 image->filename);
1348 break;
1349 }
1350#endif
1351#if !defined(MAGICKCORE_ZLIB_DELEGATE)
1352 case ZipCompression:
1353 {
1354 compression=RLECompression;
cristy1e178e72011-08-28 19:44:34 +00001355 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00001356 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1357 image->filename);
1358 break;
1359 }
1360#endif
1361 case LZWCompression:
1362 {
1363 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1364 compression=RLECompression; /* LZW compression is forbidden */
1365 break;
1366 }
1367 case NoCompression:
1368 {
1369 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1370 compression=RLECompression; /* ASCII 85 compression is forbidden */
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 if (compression == JPEG2000Compression)
cristyaf8d3912014-02-21 14:50:33 +00001377 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001378 /*
1379 Scale relative to dots-per-inch.
1380 */
1381 delta.x=DefaultResolution;
1382 delta.y=DefaultResolution;
cristy2a11bef2011-10-28 18:33:11 +00001383 resolution.x=image->resolution.x;
1384 resolution.y=image->resolution.y;
cristy3ed852e2009-09-05 21:47:34 +00001385 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1386 {
1387 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1388 resolution.x=geometry_info.rho;
1389 resolution.y=geometry_info.sigma;
1390 if ((flags & SigmaValue) == 0)
1391 resolution.y=resolution.x;
1392 }
1393 if (image_info->density != (char *) NULL)
1394 {
1395 flags=ParseGeometry(image_info->density,&geometry_info);
1396 resolution.x=geometry_info.rho;
1397 resolution.y=geometry_info.sigma;
1398 if ((flags & SigmaValue) == 0)
1399 resolution.y=resolution.x;
1400 }
1401 if (image->units == PixelsPerCentimeterResolution)
1402 {
cristya97426c2011-02-04 01:41:27 +00001403 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1404 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
cristy3ed852e2009-09-05 21:47:34 +00001405 }
1406 SetGeometry(image,&geometry);
cristyf40010e2012-05-13 13:52:20 +00001407 (void) FormatLocaleString(page_geometry,MaxTextExtent,"%.20gx%.20g",(double)
1408 image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001409 if (image_info->page != (char *) NULL)
1410 (void) CopyMagickString(page_geometry,image_info->page,MaxTextExtent);
1411 else
1412 if ((image->page.width != 0) && (image->page.height != 0))
cristyb51dff52011-05-19 16:55:47 +00001413 (void) FormatLocaleString(page_geometry,MaxTextExtent,
cristyf40010e2012-05-13 13:52:20 +00001414 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1415 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001416 else
1417 if ((image->gravity != UndefinedGravity) &&
1418 (LocaleCompare(image_info->magick,"PDF") == 0))
1419 (void) CopyMagickString(page_geometry,PSPageGeometry,MaxTextExtent);
1420 (void) ConcatenateMagickString(page_geometry,">",MaxTextExtent);
1421 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1422 &geometry.width,&geometry.height);
1423 scale.x=(double) (geometry.width*delta.x)/resolution.x;
cristybb503372010-05-27 20:51:26 +00001424 geometry.width=(size_t) floor(scale.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001425 scale.y=(double) (geometry.height*delta.y)/resolution.y;
cristybb503372010-05-27 20:51:26 +00001426 geometry.height=(size_t) floor(scale.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00001427 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
cristy1e178e72011-08-28 19:44:34 +00001428 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001429 if (image->gravity != UndefinedGravity)
1430 {
1431 geometry.x=(-page_info.x);
cristybb503372010-05-27 20:51:26 +00001432 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001433 }
1434 pointsize=12.0;
1435 if (image_info->pointsize != 0.0)
1436 pointsize=image_info->pointsize;
1437 text_size=0;
cristyd15e6592011-10-15 00:13:06 +00001438 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00001439 if (value != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +00001440 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
cristyda16f162011-02-19 23:52:17 +00001441 (void) text_size;
cristy3ed852e2009-09-05 21:47:34 +00001442 /*
1443 Write Page object.
1444 */
1445 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00001446 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001447 object);
cristy3ed852e2009-09-05 21:47:34 +00001448 (void) WriteBlobString(image,buffer);
1449 (void) WriteBlobString(image,"<<\n");
1450 (void) WriteBlobString(image,"/Type /Page\n");
cristyb51dff52011-05-19 16:55:47 +00001451 (void) FormatLocaleString(buffer,MaxTextExtent,"/Parent %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001452 (double) pages_id);
cristy3ed852e2009-09-05 21:47:34 +00001453 (void) WriteBlobString(image,buffer);
1454 (void) WriteBlobString(image,"/Resources <<\n");
1455 labels=(char **) NULL;
cristyd15e6592011-10-15 00:13:06 +00001456 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00001457 if (value != (const char *) NULL)
1458 labels=StringToList(value);
1459 if (labels != (char **) NULL)
1460 {
cristyb51dff52011-05-19 16:55:47 +00001461 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001462 "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1463 object+4);
cristy3ed852e2009-09-05 21:47:34 +00001464 (void) WriteBlobString(image,buffer);
1465 }
cristyb51dff52011-05-19 16:55:47 +00001466 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001467 "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1468 object+5);
cristy3ed852e2009-09-05 21:47:34 +00001469 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001470 (void) FormatLocaleString(buffer,MaxTextExtent,"/ProcSet %.20g 0 R >>\n",
cristye8c25f92010-06-03 00:53:06 +00001471 (double) object+3);
cristy3ed852e2009-09-05 21:47:34 +00001472 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001473 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001474 "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001475 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001476 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001477 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001478 "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
cristy8cd5b312010-01-07 01:10:24 +00001479 72.0*media_info.height/resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001480 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001481 (void) FormatLocaleString(buffer,MaxTextExtent,"/Contents %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001482 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001483 (void) WriteBlobString(image,buffer);
cristyf40010e2012-05-13 13:52:20 +00001484 (void) FormatLocaleString(buffer,MaxTextExtent,"/Thumb %.20g 0 R\n",(double)
1485 object+8);
cristy3ed852e2009-09-05 21:47:34 +00001486 (void) WriteBlobString(image,buffer);
1487 (void) WriteBlobString(image,">>\n");
1488 (void) WriteBlobString(image,"endobj\n");
1489 /*
1490 Write Contents object.
1491 */
1492 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00001493 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001494 object);
cristy3ed852e2009-09-05 21:47:34 +00001495 (void) WriteBlobString(image,buffer);
1496 (void) WriteBlobString(image,"<<\n");
cristyb51dff52011-05-19 16:55:47 +00001497 (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001498 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001499 (void) WriteBlobString(image,buffer);
1500 (void) WriteBlobString(image,">>\n");
1501 (void) WriteBlobString(image,"stream\n");
1502 offset=TellBlob(image);
1503 (void) WriteBlobString(image,"q\n");
1504 if (labels != (char **) NULL)
1505 for (i=0; labels[i] != (char *) NULL; i++)
1506 {
1507 (void) WriteBlobString(image,"BT\n");
cristyb51dff52011-05-19 16:55:47 +00001508 (void) FormatLocaleString(buffer,MaxTextExtent,"/F%.20g %g Tf\n",
cristye8c25f92010-06-03 00:53:06 +00001509 (double) image->scene,pointsize);
cristy3ed852e2009-09-05 21:47:34 +00001510 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001511 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g %.20g Td\n",
cristye8c25f92010-06-03 00:53:06 +00001512 (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+
1513 12));
cristy3ed852e2009-09-05 21:47:34 +00001514 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001515 (void) FormatLocaleString(buffer,MaxTextExtent,"(%s) Tj\n",labels[i]);
cristy3ed852e2009-09-05 21:47:34 +00001516 (void) WriteBlobString(image,buffer);
1517 (void) WriteBlobString(image,"ET\n");
1518 labels[i]=DestroyString(labels[i]);
1519 }
cristyb51dff52011-05-19 16:55:47 +00001520 (void) FormatLocaleString(buffer,MaxTextExtent,"%g 0 0 %g %.20g %.20g cm\n",
cristye8c25f92010-06-03 00:53:06 +00001521 scale.x,scale.y,(double) geometry.x,(double) geometry.y);
cristy3ed852e2009-09-05 21:47:34 +00001522 (void) WriteBlobString(image,buffer);
cristyf40010e2012-05-13 13:52:20 +00001523 (void) FormatLocaleString(buffer,MaxTextExtent,"/Im%.20g Do\n",(double)
1524 image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001525 (void) WriteBlobString(image,buffer);
1526 (void) WriteBlobString(image,"Q\n");
1527 offset=TellBlob(image)-offset;
cristy1b70dc82012-07-01 23:15:05 +00001528 (void) WriteBlobString(image,"\nendstream\n");
cristy3ed852e2009-09-05 21:47:34 +00001529 (void) WriteBlobString(image,"endobj\n");
1530 /*
1531 Write Length object.
1532 */
1533 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00001534 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001535 object);
cristy3ed852e2009-09-05 21:47:34 +00001536 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001537 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00001538 (void) WriteBlobString(image,buffer);
1539 (void) WriteBlobString(image,"endobj\n");
1540 /*
1541 Write Procset object.
1542 */
1543 xref[object++]=TellBlob(image);
cristyf40010e2012-05-13 13:52:20 +00001544 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1545 object);
cristy3ed852e2009-09-05 21:47:34 +00001546 (void) WriteBlobString(image,buffer);
1547 if ((image->storage_class == DirectClass) || (image->colors > 256))
1548 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MaxTextExtent);
1549 else
1550 if ((compression == FaxCompression) || (compression == Group4Compression))
1551 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MaxTextExtent);
1552 else
1553 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MaxTextExtent);
1554 (void) WriteBlobString(image,buffer);
1555 (void) WriteBlobString(image," ]\n");
1556 (void) WriteBlobString(image,"endobj\n");
1557 /*
1558 Write Font object.
1559 */
1560 xref[object++]=TellBlob(image);
cristyf40010e2012-05-13 13:52:20 +00001561 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
1562 object);
cristy3ed852e2009-09-05 21:47:34 +00001563 (void) WriteBlobString(image,buffer);
1564 (void) WriteBlobString(image,"<<\n");
1565 if (labels != (char **) NULL)
1566 {
1567 (void) WriteBlobString(image,"/Type /Font\n");
1568 (void) WriteBlobString(image,"/Subtype /Type1\n");
cristyb51dff52011-05-19 16:55:47 +00001569 (void) FormatLocaleString(buffer,MaxTextExtent,"/Name /F%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001570 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001571 (void) WriteBlobString(image,buffer);
1572 (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1573 (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1574 labels=(char **) RelinquishMagickMemory(labels);
1575 }
1576 (void) WriteBlobString(image,">>\n");
1577 (void) WriteBlobString(image,"endobj\n");
1578 /*
1579 Write XObject object.
1580 */
1581 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00001582 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00001583 object);
cristy3ed852e2009-09-05 21:47:34 +00001584 (void) WriteBlobString(image,buffer);
1585 (void) WriteBlobString(image,"<<\n");
1586 (void) WriteBlobString(image,"/Type /XObject\n");
1587 (void) WriteBlobString(image,"/Subtype /Image\n");
cristyf40010e2012-05-13 13:52:20 +00001588 (void) FormatLocaleString(buffer,MaxTextExtent,"/Name /Im%.20g\n",(double)
1589 image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001590 (void) WriteBlobString(image,buffer);
1591 switch (compression)
1592 {
1593 case NoCompression:
1594 {
cristyb51dff52011-05-19 16:55:47 +00001595 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
cristy3ed852e2009-09-05 21:47:34 +00001596 break;
1597 }
1598 case JPEGCompression:
1599 {
cristyb51dff52011-05-19 16:55:47 +00001600 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"DCTDecode");
cristy3ed852e2009-09-05 21:47:34 +00001601 if (image->colorspace != CMYKColorspace)
1602 break;
1603 (void) WriteBlobString(image,buffer);
1604 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1605 MaxTextExtent);
1606 break;
1607 }
1608 case JPEG2000Compression:
1609 {
cristyb51dff52011-05-19 16:55:47 +00001610 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"JPXDecode");
cristy3ed852e2009-09-05 21:47:34 +00001611 if (image->colorspace != CMYKColorspace)
1612 break;
1613 (void) WriteBlobString(image,buffer);
1614 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1615 MaxTextExtent);
1616 break;
1617 }
1618 case LZWCompression:
1619 {
cristyb51dff52011-05-19 16:55:47 +00001620 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"LZWDecode");
cristyfa7becb2009-09-13 02:44:40 +00001621 break;
cristy3ed852e2009-09-05 21:47:34 +00001622 }
1623 case ZipCompression:
1624 {
cristyb51dff52011-05-19 16:55:47 +00001625 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"FlateDecode");
cristyfa7becb2009-09-13 02:44:40 +00001626 break;
cristy3ed852e2009-09-05 21:47:34 +00001627 }
1628 case FaxCompression:
1629 case Group4Compression:
1630 {
1631 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1632 MaxTextExtent);
1633 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001634 (void) FormatLocaleString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristye8c25f92010-06-03 00:53:06 +00001635 "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1636 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001637 break;
1638 }
1639 default:
1640 {
cristyb51dff52011-05-19 16:55:47 +00001641 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,
cristy3ed852e2009-09-05 21:47:34 +00001642 "RunLengthDecode");
1643 break;
1644 }
1645 }
1646 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001647 (void) FormatLocaleString(buffer,MaxTextExtent,"/Width %.20g\n",(double)
cristye8c25f92010-06-03 00:53:06 +00001648 image->columns);
cristy3ed852e2009-09-05 21:47:34 +00001649 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001650 (void) FormatLocaleString(buffer,MaxTextExtent,"/Height %.20g\n",(double)
cristye8c25f92010-06-03 00:53:06 +00001651 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001652 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001653 (void) FormatLocaleString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001654 (double) object+2);
cristy3ed852e2009-09-05 21:47:34 +00001655 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001656 (void) FormatLocaleString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
cristy3ed852e2009-09-05 21:47:34 +00001657 (compression == FaxCompression) || (compression == Group4Compression) ?
1658 1 : 8);
1659 (void) WriteBlobString(image,buffer);
cristy8a46d822012-08-28 23:32:39 +00001660 if (image->alpha_trait == BlendPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001661 {
cristyb51dff52011-05-19 16:55:47 +00001662 (void) FormatLocaleString(buffer,MaxTextExtent,"/SMask %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001663 (double) object+7);
cristy3ed852e2009-09-05 21:47:34 +00001664 (void) WriteBlobString(image,buffer);
1665 }
cristyb51dff52011-05-19 16:55:47 +00001666 (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00001667 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00001668 (void) WriteBlobString(image,buffer);
1669 (void) WriteBlobString(image,">>\n");
1670 (void) WriteBlobString(image,"stream\n");
1671 offset=TellBlob(image);
1672 number_pixels=(MagickSizeType) image->columns*image->rows;
1673 if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1674 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1675 if ((compression == FaxCompression) || (compression == Group4Compression) ||
1676 ((image_info->type != TrueColorType) &&
cristy1e178e72011-08-28 19:44:34 +00001677 (IsImageGray(image,exception) != MagickFalse)))
cristy3ed852e2009-09-05 21:47:34 +00001678 {
1679 switch (compression)
1680 {
1681 case FaxCompression:
1682 case Group4Compression:
1683 {
1684 if (LocaleCompare(CCITTParam,"0") == 0)
1685 {
cristy018f07f2011-09-04 21:15:19 +00001686 (void) HuffmanEncodeImage(image_info,image,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001687 break;
1688 }
cristy018f07f2011-09-04 21:15:19 +00001689 (void) Huffman2DEncodeImage(image_info,image,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001690 break;
1691 }
1692 case JPEGCompression:
1693 {
cristy1e178e72011-08-28 19:44:34 +00001694 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +00001695 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00001696 {
1697 (void) CloseBlob(image);
1698 return(MagickFalse);
1699 }
cristy3ed852e2009-09-05 21:47:34 +00001700 break;
1701 }
1702 case JPEG2000Compression:
1703 {
cristy1e178e72011-08-28 19:44:34 +00001704 status=InjectImageBlob(image_info,image,image,"jp2",exception);
cristy3ed852e2009-09-05 21:47:34 +00001705 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00001706 {
1707 (void) CloseBlob(image);
1708 return(MagickFalse);
1709 }
cristy3ed852e2009-09-05 21:47:34 +00001710 break;
1711 }
1712 case RLECompression:
1713 default:
1714 {
cristy0553bd52013-06-30 15:53:50 +00001715 MemoryInfo
1716 *pixel_info;
1717
cristy3ed852e2009-09-05 21:47:34 +00001718 /*
1719 Allocate pixel array.
1720 */
1721 length=(size_t) number_pixels;
cristy0553bd52013-06-30 15:53:50 +00001722 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1723 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001724 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +00001725 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001726 /*
1727 Dump Runlength encoded pixels.
1728 */
1729 q=pixels;
cristybb503372010-05-27 20:51:26 +00001730 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001731 {
cristy1e178e72011-08-28 19:44:34 +00001732 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001733 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001734 break;
cristybb503372010-05-27 20:51:26 +00001735 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001736 {
cristyd0323222013-04-07 16:13:21 +00001737 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
cristyed231572011-07-14 02:18:59 +00001738 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001739 }
1740 if (image->previous == (Image *) NULL)
1741 {
cristyf5c61ba2010-12-17 00:58:04 +00001742 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1743 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001744 if (status == MagickFalse)
1745 break;
1746 }
1747 }
1748#if defined(MAGICKCORE_ZLIB_DELEGATE)
1749 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00001750 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001751 else
1752#endif
1753 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00001754 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001755 else
cristy018f07f2011-09-04 21:15:19 +00001756 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00001757 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001758 if (status == MagickFalse)
1759 {
1760 (void) CloseBlob(image);
1761 return(MagickFalse);
1762 }
1763 break;
1764 }
1765 case NoCompression:
1766 {
1767 /*
1768 Dump uncompressed PseudoColor packets.
1769 */
1770 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001771 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001772 {
cristy1e178e72011-08-28 19:44:34 +00001773 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001774 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001775 break;
cristybb503372010-05-27 20:51:26 +00001776 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001777 {
cristyd0323222013-04-07 16:13:21 +00001778 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
1779 GetPixelLuma(image,p))));
cristyed231572011-07-14 02:18:59 +00001780 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001781 }
1782 if (image->previous == (Image *) NULL)
1783 {
cristyf5c61ba2010-12-17 00:58:04 +00001784 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1785 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001786 if (status == MagickFalse)
1787 break;
1788 }
1789 }
1790 Ascii85Flush(image);
1791 break;
1792 }
1793 }
1794 }
1795 else
1796 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
1797 (compression == JPEGCompression) ||
1798 (compression == JPEG2000Compression))
1799 switch (compression)
1800 {
1801 case JPEGCompression:
1802 {
cristy1e178e72011-08-28 19:44:34 +00001803 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
cristy3ed852e2009-09-05 21:47:34 +00001804 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00001805 {
1806 (void) CloseBlob(image);
1807 return(MagickFalse);
1808 }
cristy3ed852e2009-09-05 21:47:34 +00001809 break;
1810 }
1811 case JPEG2000Compression:
1812 {
cristy1e178e72011-08-28 19:44:34 +00001813 status=InjectImageBlob(image_info,image,image,"jp2",exception);
cristy3ed852e2009-09-05 21:47:34 +00001814 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00001815 {
1816 (void) CloseBlob(image);
1817 return(MagickFalse);
1818 }
cristy3ed852e2009-09-05 21:47:34 +00001819 break;
1820 }
1821 case RLECompression:
1822 default:
1823 {
cristy0553bd52013-06-30 15:53:50 +00001824 MemoryInfo
1825 *pixel_info;
1826
cristy3ed852e2009-09-05 21:47:34 +00001827 /*
1828 Allocate pixel array.
1829 */
1830 length=(size_t) number_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001831 length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
cristy0553bd52013-06-30 15:53:50 +00001832 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1833 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001834 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +00001835 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001836 /*
1837 Dump runoffset encoded pixels.
1838 */
1839 q=pixels;
cristybb503372010-05-27 20:51:26 +00001840 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001841 {
cristy1e178e72011-08-28 19:44:34 +00001842 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001843 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001844 break;
cristybb503372010-05-27 20:51:26 +00001845 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001846 {
cristy4c08aed2011-07-01 19:47:50 +00001847 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1848 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1849 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
cristy3ed852e2009-09-05 21:47:34 +00001850 if (image->colorspace == CMYKColorspace)
cristy4c08aed2011-07-01 19:47:50 +00001851 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
cristyed231572011-07-14 02:18:59 +00001852 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001853 }
1854 if (image->previous == (Image *) NULL)
1855 {
cristyf5c61ba2010-12-17 00:58:04 +00001856 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1857 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001858 if (status == MagickFalse)
1859 break;
1860 }
1861 }
1862#if defined(MAGICKCORE_ZLIB_DELEGATE)
1863 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00001864 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001865 else
1866#endif
1867 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00001868 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001869 else
cristy018f07f2011-09-04 21:15:19 +00001870 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00001871 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001872 if (status == MagickFalse)
1873 {
1874 (void) CloseBlob(image);
1875 return(MagickFalse);
1876 }
1877 break;
1878 }
1879 case NoCompression:
1880 {
1881 /*
1882 Dump uncompressed DirectColor packets.
1883 */
1884 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001885 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001886 {
cristy1e178e72011-08-28 19:44:34 +00001887 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001888 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001889 break;
cristybb503372010-05-27 20:51:26 +00001890 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001891 {
cristy4c08aed2011-07-01 19:47:50 +00001892 Ascii85Encode(image,ScaleQuantumToChar(GetPixelRed(image,p)));
1893 Ascii85Encode(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
1894 Ascii85Encode(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
cristy3ed852e2009-09-05 21:47:34 +00001895 if (image->colorspace == CMYKColorspace)
cristyaff6d802011-04-26 01:46:31 +00001896 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00001897 GetPixelBlack(image,p)));
cristyed231572011-07-14 02:18:59 +00001898 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001899 }
1900 if (image->previous == (Image *) NULL)
1901 {
cristyf5c61ba2010-12-17 00:58:04 +00001902 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1903 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001904 if (status == MagickFalse)
1905 break;
1906 }
1907 }
1908 Ascii85Flush(image);
1909 break;
1910 }
1911 }
1912 else
1913 {
1914 /*
1915 Dump number of colors and colormap.
1916 */
1917 switch (compression)
1918 {
1919 case RLECompression:
1920 default:
1921 {
cristy0553bd52013-06-30 15:53:50 +00001922 MemoryInfo
1923 *pixel_info;
1924
cristy3ed852e2009-09-05 21:47:34 +00001925 /*
1926 Allocate pixel array.
1927 */
1928 length=(size_t) number_pixels;
cristy0553bd52013-06-30 15:53:50 +00001929 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1930 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001931 ThrowWriterException(ResourceLimitError,
1932 "MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +00001933 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001934 /*
1935 Dump Runlength encoded pixels.
1936 */
1937 q=pixels;
cristybb503372010-05-27 20:51:26 +00001938 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001939 {
cristy1e178e72011-08-28 19:44:34 +00001940 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001941 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001942 break;
cristybb503372010-05-27 20:51:26 +00001943 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001944 {
1945 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001946 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001947 }
cristy3ed852e2009-09-05 21:47:34 +00001948 if (image->previous == (Image *) NULL)
1949 {
cristyf5c61ba2010-12-17 00:58:04 +00001950 status=SetImageProgress(image,SaveImageTag,
1951 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001952 if (status == MagickFalse)
1953 break;
1954 }
1955 }
1956#if defined(MAGICKCORE_ZLIB_DELEGATE)
1957 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00001958 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001959 else
1960#endif
1961 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00001962 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001963 else
cristy018f07f2011-09-04 21:15:19 +00001964 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00001965 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001966 if (status == MagickFalse)
1967 {
1968 (void) CloseBlob(image);
1969 return(MagickFalse);
1970 }
1971 break;
1972 }
1973 case NoCompression:
1974 {
1975 /*
1976 Dump uncompressed PseudoColor packets.
1977 */
1978 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00001979 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001980 {
cristy1e178e72011-08-28 19:44:34 +00001981 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001982 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001983 break;
cristybb503372010-05-27 20:51:26 +00001984 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001985 {
1986 Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
cristyed231572011-07-14 02:18:59 +00001987 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001988 }
cristy3ed852e2009-09-05 21:47:34 +00001989 if (image->previous == (Image *) NULL)
1990 {
cristyf5c61ba2010-12-17 00:58:04 +00001991 status=SetImageProgress(image,SaveImageTag,
1992 (MagickOffsetType) y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001993 if (status == MagickFalse)
1994 break;
1995 }
1996 }
1997 Ascii85Flush(image);
1998 break;
1999 }
2000 }
2001 }
2002 offset=TellBlob(image)-offset;
2003 (void) WriteBlobString(image,"\nendstream\n");
2004 (void) WriteBlobString(image,"endobj\n");
2005 /*
2006 Write Length object.
2007 */
2008 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002009 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002010 object);
cristy3ed852e2009-09-05 21:47:34 +00002011 (void) WriteBlobString(image,buffer);
cristyf40010e2012-05-13 13:52:20 +00002012 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002013 (void) WriteBlobString(image,buffer);
2014 (void) WriteBlobString(image,"endobj\n");
2015 /*
2016 Write Colorspace object.
2017 */
2018 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002019 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002020 object);
cristy3ed852e2009-09-05 21:47:34 +00002021 (void) WriteBlobString(image,buffer);
2022 if (image->colorspace == CMYKColorspace)
2023 (void) CopyMagickString(buffer,"/DeviceCMYK\n",MaxTextExtent);
2024 else
2025 if ((compression == FaxCompression) ||
2026 (compression == Group4Compression) ||
2027 ((image_info->type != TrueColorType) &&
cristy1e178e72011-08-28 19:44:34 +00002028 (IsImageGray(image,exception) != MagickFalse)))
cristy3ed852e2009-09-05 21:47:34 +00002029 (void) CopyMagickString(buffer,"/DeviceGray\n",MaxTextExtent);
2030 else
2031 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2032 (compression == JPEGCompression) ||
2033 (compression == JPEG2000Compression))
2034 (void) CopyMagickString(buffer,"/DeviceRGB\n",MaxTextExtent);
2035 else
cristyb51dff52011-05-19 16:55:47 +00002036 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00002037 "[ /Indexed /DeviceRGB %.20g %.20g 0 R ]\n",(double) image->colors-
2038 1,(double) object+3);
cristy3ed852e2009-09-05 21:47:34 +00002039 (void) WriteBlobString(image,buffer);
2040 (void) WriteBlobString(image,"endobj\n");
2041 /*
2042 Write Thumb object.
2043 */
2044 SetGeometry(image,&geometry);
2045 (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
2046 &geometry.width,&geometry.height);
cristy1e178e72011-08-28 19:44:34 +00002047 tile_image=ThumbnailImage(image,geometry.width,geometry.height,exception);
cristy3ed852e2009-09-05 21:47:34 +00002048 if (tile_image == (Image *) NULL)
cristy1e178e72011-08-28 19:44:34 +00002049 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00002050 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002051 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002052 object);
cristy3ed852e2009-09-05 21:47:34 +00002053 (void) WriteBlobString(image,buffer);
2054 (void) WriteBlobString(image,"<<\n");
2055 switch (compression)
2056 {
2057 case NoCompression:
2058 {
cristyb51dff52011-05-19 16:55:47 +00002059 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"ASCII85Decode");
cristy3ed852e2009-09-05 21:47:34 +00002060 break;
2061 }
2062 case JPEGCompression:
2063 {
cristyb51dff52011-05-19 16:55:47 +00002064 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"DCTDecode");
cristy3ed852e2009-09-05 21:47:34 +00002065 if (image->colorspace != CMYKColorspace)
2066 break;
2067 (void) WriteBlobString(image,buffer);
2068 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2069 MaxTextExtent);
2070 break;
2071 }
2072 case JPEG2000Compression:
2073 {
cristyb51dff52011-05-19 16:55:47 +00002074 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"JPXDecode");
cristy3ed852e2009-09-05 21:47:34 +00002075 if (image->colorspace != CMYKColorspace)
2076 break;
2077 (void) WriteBlobString(image,buffer);
2078 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2079 MaxTextExtent);
2080 break;
2081 }
2082 case LZWCompression:
2083 {
cristyb51dff52011-05-19 16:55:47 +00002084 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"LZWDecode");
cristy3ed852e2009-09-05 21:47:34 +00002085 break;
2086 }
2087 case ZipCompression:
2088 {
cristyb51dff52011-05-19 16:55:47 +00002089 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"FlateDecode");
cristy3ed852e2009-09-05 21:47:34 +00002090 break;
2091 }
2092 case FaxCompression:
2093 case Group4Compression:
2094 {
2095 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
2096 MaxTextExtent);
2097 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002098 (void) FormatLocaleString(buffer,MaxTextExtent,"/DecodeParms [ << "
cristye8c25f92010-06-03 00:53:06 +00002099 "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
2100 (double) tile_image->columns,(double) tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002101 break;
2102 }
2103 default:
2104 {
cristyb51dff52011-05-19 16:55:47 +00002105 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,
cristy3ed852e2009-09-05 21:47:34 +00002106 "RunLengthDecode");
2107 break;
2108 }
2109 }
2110 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002111 (void) FormatLocaleString(buffer,MaxTextExtent,"/Width %.20g\n",(double)
cristye8c25f92010-06-03 00:53:06 +00002112 tile_image->columns);
cristy3ed852e2009-09-05 21:47:34 +00002113 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002114 (void) FormatLocaleString(buffer,MaxTextExtent,"/Height %.20g\n",(double)
cristye8c25f92010-06-03 00:53:06 +00002115 tile_image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002116 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002117 (void) FormatLocaleString(buffer,MaxTextExtent,"/ColorSpace %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00002118 (double) object-1);
cristy3ed852e2009-09-05 21:47:34 +00002119 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002120 (void) FormatLocaleString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
cristy3ed852e2009-09-05 21:47:34 +00002121 (compression == FaxCompression) || (compression == Group4Compression) ?
2122 1 : 8);
2123 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002124 (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00002125 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00002126 (void) WriteBlobString(image,buffer);
2127 (void) WriteBlobString(image,">>\n");
2128 (void) WriteBlobString(image,"stream\n");
2129 offset=TellBlob(image);
2130 number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
2131 if ((compression == FaxCompression) ||
2132 (compression == Group4Compression) ||
2133 ((image_info->type != TrueColorType) &&
cristy1e178e72011-08-28 19:44:34 +00002134 (IsImageGray(tile_image,exception) != MagickFalse)))
cristy3ed852e2009-09-05 21:47:34 +00002135 {
2136 switch (compression)
2137 {
2138 case FaxCompression:
2139 case Group4Compression:
2140 {
2141 if (LocaleCompare(CCITTParam,"0") == 0)
2142 {
cristy018f07f2011-09-04 21:15:19 +00002143 (void) HuffmanEncodeImage(image_info,image,tile_image,
2144 exception);
cristy3ed852e2009-09-05 21:47:34 +00002145 break;
2146 }
cristy018f07f2011-09-04 21:15:19 +00002147 (void) Huffman2DEncodeImage(image_info,image,tile_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002148 break;
2149 }
2150 case JPEGCompression:
2151 {
2152 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
cristy1e178e72011-08-28 19:44:34 +00002153 exception);
cristy3ed852e2009-09-05 21:47:34 +00002154 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00002155 {
2156 (void) CloseBlob(image);
2157 return(MagickFalse);
2158 }
cristy3ed852e2009-09-05 21:47:34 +00002159 break;
2160 }
2161 case JPEG2000Compression:
2162 {
cristy1e178e72011-08-28 19:44:34 +00002163 status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
cristy3ed852e2009-09-05 21:47:34 +00002164 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00002165 {
2166 (void) CloseBlob(image);
2167 return(MagickFalse);
2168 }
cristy3ed852e2009-09-05 21:47:34 +00002169 break;
2170 }
2171 case RLECompression:
2172 default:
2173 {
cristy0553bd52013-06-30 15:53:50 +00002174 MemoryInfo
2175 *pixel_info;
2176
cristy3ed852e2009-09-05 21:47:34 +00002177 /*
2178 Allocate pixel array.
2179 */
2180 length=(size_t) number_pixels;
cristy0553bd52013-06-30 15:53:50 +00002181 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2182 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002183 {
2184 tile_image=DestroyImage(tile_image);
2185 ThrowWriterException(ResourceLimitError,
2186 "MemoryAllocationFailed");
2187 }
cristy0553bd52013-06-30 15:53:50 +00002188 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002189 /*
cristy0553bd52013-06-30 15:53:50 +00002190 Dump runlength encoded pixels.
cristy3ed852e2009-09-05 21:47:34 +00002191 */
2192 q=pixels;
cristybb503372010-05-27 20:51:26 +00002193 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002194 {
2195 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00002196 exception);
cristy4c08aed2011-07-01 19:47:50 +00002197 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002198 break;
cristybb503372010-05-27 20:51:26 +00002199 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002200 {
cristyd0323222013-04-07 16:13:21 +00002201 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2202 tile_image,p)));
cristyed231572011-07-14 02:18:59 +00002203 p+=GetPixelChannels(tile_image);
cristy3ed852e2009-09-05 21:47:34 +00002204 }
2205 }
2206#if defined(MAGICKCORE_ZLIB_DELEGATE)
2207 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00002208 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002209 else
2210#endif
2211 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00002212 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002213 else
cristy018f07f2011-09-04 21:15:19 +00002214 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00002215 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002216 if (status == MagickFalse)
2217 {
2218 (void) CloseBlob(image);
2219 return(MagickFalse);
2220 }
2221 break;
2222 }
2223 case NoCompression:
2224 {
2225 /*
2226 Dump uncompressed PseudoColor packets.
2227 */
2228 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002229 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002230 {
2231 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00002232 exception);
cristy4c08aed2011-07-01 19:47:50 +00002233 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002234 break;
cristybb503372010-05-27 20:51:26 +00002235 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002236 {
cristyd0323222013-04-07 16:13:21 +00002237 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2238 GetPixelLuma(tile_image,p))));
cristyed231572011-07-14 02:18:59 +00002239 p+=GetPixelChannels(tile_image);
cristy3ed852e2009-09-05 21:47:34 +00002240 }
2241 }
2242 Ascii85Flush(image);
2243 break;
2244 }
2245 }
2246 }
2247 else
2248 if ((tile_image->storage_class == DirectClass) ||
2249 (tile_image->colors > 256) || (compression == JPEGCompression) ||
2250 (compression == JPEG2000Compression))
2251 switch (compression)
2252 {
2253 case JPEGCompression:
2254 {
2255 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
cristy1e178e72011-08-28 19:44:34 +00002256 exception);
cristy3ed852e2009-09-05 21:47:34 +00002257 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00002258 {
2259 (void) CloseBlob(image);
2260 return(MagickFalse);
2261 }
cristy3ed852e2009-09-05 21:47:34 +00002262 break;
2263 }
2264 case JPEG2000Compression:
2265 {
cristy1e178e72011-08-28 19:44:34 +00002266 status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
cristy3ed852e2009-09-05 21:47:34 +00002267 if (status == MagickFalse)
cristy1e178e72011-08-28 19:44:34 +00002268 {
2269 (void) CloseBlob(image);
2270 return(MagickFalse);
2271 }
cristy3ed852e2009-09-05 21:47:34 +00002272 break;
2273 }
2274 case RLECompression:
2275 default:
2276 {
cristy0553bd52013-06-30 15:53:50 +00002277 MemoryInfo
2278 *pixel_info;
2279
cristy3ed852e2009-09-05 21:47:34 +00002280 /*
2281 Allocate pixel array.
2282 */
2283 length=(size_t) number_pixels;
cristy3ed852e2009-09-05 21:47:34 +00002284 length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
cristy0553bd52013-06-30 15:53:50 +00002285 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2286 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002287 {
2288 tile_image=DestroyImage(tile_image);
2289 ThrowWriterException(ResourceLimitError,
2290 "MemoryAllocationFailed");
2291 }
cristy0553bd52013-06-30 15:53:50 +00002292 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002293 /*
cristy0553bd52013-06-30 15:53:50 +00002294 Dump runlength encoded pixels.
cristy3ed852e2009-09-05 21:47:34 +00002295 */
2296 q=pixels;
cristybb503372010-05-27 20:51:26 +00002297 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002298 {
2299 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00002300 exception);
cristy4c08aed2011-07-01 19:47:50 +00002301 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002302 break;
cristybb503372010-05-27 20:51:26 +00002303 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002304 {
cristy4c08aed2011-07-01 19:47:50 +00002305 *q++=ScaleQuantumToChar(GetPixelRed(tile_image,p));
2306 *q++=ScaleQuantumToChar(GetPixelGreen(tile_image,p));
2307 *q++=ScaleQuantumToChar(GetPixelBlue(tile_image,p));
cristy4d0ca342014-05-01 00:42:09 +00002308 if (tile_image->colorspace == CMYKColorspace)
cristy4c08aed2011-07-01 19:47:50 +00002309 *q++=ScaleQuantumToChar(GetPixelBlack(tile_image,p));
cristyed231572011-07-14 02:18:59 +00002310 p+=GetPixelChannels(tile_image);
cristy3ed852e2009-09-05 21:47:34 +00002311 }
2312 }
2313#if defined(MAGICKCORE_ZLIB_DELEGATE)
2314 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00002315 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002316 else
2317#endif
2318 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00002319 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002320 else
cristy018f07f2011-09-04 21:15:19 +00002321 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00002322 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002323 if (status == MagickFalse)
2324 {
2325 (void) CloseBlob(image);
2326 return(MagickFalse);
2327 }
2328 break;
2329 }
2330 case NoCompression:
2331 {
2332 /*
2333 Dump uncompressed DirectColor packets.
2334 */
2335 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002336 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002337 {
2338 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00002339 exception);
cristy4c08aed2011-07-01 19:47:50 +00002340 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002341 break;
cristybb503372010-05-27 20:51:26 +00002342 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002343 {
cristyf5c61ba2010-12-17 00:58:04 +00002344 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00002345 GetPixelRed(tile_image,p)));
cristyf5c61ba2010-12-17 00:58:04 +00002346 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00002347 GetPixelGreen(tile_image,p)));
cristyf5c61ba2010-12-17 00:58:04 +00002348 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00002349 GetPixelBlue(tile_image,p)));
cristy3ed852e2009-09-05 21:47:34 +00002350 if (image->colorspace == CMYKColorspace)
cristyaff6d802011-04-26 01:46:31 +00002351 Ascii85Encode(image,ScaleQuantumToChar(
cristy4c08aed2011-07-01 19:47:50 +00002352 GetPixelBlack(tile_image,p)));
cristyed231572011-07-14 02:18:59 +00002353 p+=GetPixelChannels(tile_image);
cristy3ed852e2009-09-05 21:47:34 +00002354 }
2355 }
2356 Ascii85Flush(image);
2357 break;
2358 }
2359 }
2360 else
2361 {
2362 /*
2363 Dump number of colors and colormap.
2364 */
2365 switch (compression)
2366 {
2367 case RLECompression:
2368 default:
2369 {
cristy0553bd52013-06-30 15:53:50 +00002370 MemoryInfo
2371 *pixel_info;
2372
cristy3ed852e2009-09-05 21:47:34 +00002373 /*
2374 Allocate pixel array.
2375 */
2376 length=(size_t) number_pixels;
cristy0553bd52013-06-30 15:53:50 +00002377 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2378 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002379 {
2380 tile_image=DestroyImage(tile_image);
2381 ThrowWriterException(ResourceLimitError,
2382 "MemoryAllocationFailed");
2383 }
cristy0553bd52013-06-30 15:53:50 +00002384 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002385 /*
cristy0553bd52013-06-30 15:53:50 +00002386 Dump runlength encoded pixels.
cristy3ed852e2009-09-05 21:47:34 +00002387 */
2388 q=pixels;
cristybb503372010-05-27 20:51:26 +00002389 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002390 {
2391 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00002392 exception);
cristy4c08aed2011-07-01 19:47:50 +00002393 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002394 break;
cristybb503372010-05-27 20:51:26 +00002395 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002396 {
2397 *q++=(unsigned char) GetPixelIndex(tile_image,p);
cristy6307d372012-06-17 20:07:34 +00002398 p+=GetPixelChannels(tile_image);
cristy4c08aed2011-07-01 19:47:50 +00002399 }
cristy3ed852e2009-09-05 21:47:34 +00002400 }
2401#if defined(MAGICKCORE_ZLIB_DELEGATE)
2402 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00002403 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002404 else
2405#endif
2406 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00002407 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002408 else
cristy018f07f2011-09-04 21:15:19 +00002409 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00002410 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002411 if (status == MagickFalse)
2412 {
2413 (void) CloseBlob(image);
2414 return(MagickFalse);
2415 }
2416 break;
2417 }
2418 case NoCompression:
2419 {
2420 /*
2421 Dump uncompressed PseudoColor packets.
2422 */
2423 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002424 for (y=0; y < (ssize_t) tile_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002425 {
2426 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
cristy1e178e72011-08-28 19:44:34 +00002427 exception);
cristy4c08aed2011-07-01 19:47:50 +00002428 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002429 break;
cristybb503372010-05-27 20:51:26 +00002430 for (x=0; x < (ssize_t) tile_image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002431 {
cristyaff6d802011-04-26 01:46:31 +00002432 Ascii85Encode(image,(unsigned char)
cristy4c08aed2011-07-01 19:47:50 +00002433 GetPixelIndex(tile_image,p));
cristyed231572011-07-14 02:18:59 +00002434 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002435 }
cristy3ed852e2009-09-05 21:47:34 +00002436 }
2437 Ascii85Flush(image);
2438 break;
2439 }
2440 }
2441 }
2442 tile_image=DestroyImage(tile_image);
2443 offset=TellBlob(image)-offset;
2444 (void) WriteBlobString(image,"\nendstream\n");
2445 (void) WriteBlobString(image,"endobj\n");
2446 /*
2447 Write Length object.
2448 */
2449 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002450 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002451 object);
cristy3ed852e2009-09-05 21:47:34 +00002452 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002453 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002454 (void) WriteBlobString(image,buffer);
2455 (void) WriteBlobString(image,"endobj\n");
2456 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002457 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002458 object);
cristy3ed852e2009-09-05 21:47:34 +00002459 (void) WriteBlobString(image,buffer);
cristy59427d32013-01-23 19:19:11 +00002460 (void) WriteBlobString(image,"<<\n");
cristy3152b6b2013-01-23 19:21:48 +00002461 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2462 (compression == FaxCompression) || (compression == Group4Compression))
2463 (void) WriteBlobString(image,">>\n");
2464 else
cristy3ed852e2009-09-05 21:47:34 +00002465 {
2466 /*
2467 Write Colormap object.
2468 */
cristy3ed852e2009-09-05 21:47:34 +00002469 if (compression == NoCompression)
2470 (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
cristyb51dff52011-05-19 16:55:47 +00002471 (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00002472 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00002473 (void) WriteBlobString(image,buffer);
2474 (void) WriteBlobString(image,">>\n");
2475 (void) WriteBlobString(image,"stream\n");
2476 offset=TellBlob(image);
2477 if (compression == NoCompression)
2478 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002479 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002480 {
2481 if (compression == NoCompression)
2482 {
cristyd0323222013-04-07 16:13:21 +00002483 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2484 image->colormap[i].red)));
2485 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2486 image->colormap[i].green)));
2487 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2488 image->colormap[i].blue)));
cristy3ed852e2009-09-05 21:47:34 +00002489 continue;
2490 }
cristyd0323222013-04-07 16:13:21 +00002491 (void) WriteBlobByte(image,ScaleQuantumToChar(
2492 ClampToQuantum(image->colormap[i].red)));
2493 (void) WriteBlobByte(image,ScaleQuantumToChar(
2494 ClampToQuantum(image->colormap[i].green)));
2495 (void) WriteBlobByte(image,ScaleQuantumToChar(
2496 ClampToQuantum(image->colormap[i].blue)));
cristy3ed852e2009-09-05 21:47:34 +00002497 }
2498 if (compression == NoCompression)
2499 Ascii85Flush(image);
2500 offset=TellBlob(image)-offset;
2501 (void) WriteBlobString(image,"\nendstream\n");
2502 }
2503 (void) WriteBlobString(image,"endobj\n");
2504 /*
2505 Write Length object.
2506 */
2507 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002508 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002509 object);
cristy3ed852e2009-09-05 21:47:34 +00002510 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002511 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002512 offset);
cristy3ed852e2009-09-05 21:47:34 +00002513 (void) WriteBlobString(image,buffer);
2514 (void) WriteBlobString(image,"endobj\n");
2515 /*
2516 Write softmask object.
2517 */
2518 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002519 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002520 object);
cristy3ed852e2009-09-05 21:47:34 +00002521 (void) WriteBlobString(image,buffer);
2522 (void) WriteBlobString(image,"<<\n");
cristy8a46d822012-08-28 23:32:39 +00002523 if (image->alpha_trait != BlendPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00002524 (void) WriteBlobString(image,">>\n");
2525 else
2526 {
2527 (void) WriteBlobString(image,"/Type /XObject\n");
2528 (void) WriteBlobString(image,"/Subtype /Image\n");
cristyb51dff52011-05-19 16:55:47 +00002529 (void) FormatLocaleString(buffer,MaxTextExtent,"/Name /Ma%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00002530 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00002531 (void) WriteBlobString(image,buffer);
2532 switch (compression)
2533 {
2534 case NoCompression:
2535 {
cristyb51dff52011-05-19 16:55:47 +00002536 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,
cristy3ed852e2009-09-05 21:47:34 +00002537 "ASCII85Decode");
2538 break;
2539 }
2540 case LZWCompression:
2541 {
cristyb51dff52011-05-19 16:55:47 +00002542 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,"LZWDecode");
cristy3ed852e2009-09-05 21:47:34 +00002543 break;
2544 }
2545 case ZipCompression:
2546 {
cristyb51dff52011-05-19 16:55:47 +00002547 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,
cristy3ed852e2009-09-05 21:47:34 +00002548 "FlateDecode");
2549 break;
2550 }
2551 default:
2552 {
cristyb51dff52011-05-19 16:55:47 +00002553 (void) FormatLocaleString(buffer,MaxTextExtent,CFormat,
cristy3ed852e2009-09-05 21:47:34 +00002554 "RunLengthDecode");
2555 break;
2556 }
2557 }
2558 (void) WriteBlobString(image,buffer);
cristyf40010e2012-05-13 13:52:20 +00002559 (void) FormatLocaleString(buffer,MaxTextExtent,"/Width %.20g\n",(double)
2560 image->columns);
cristy3ed852e2009-09-05 21:47:34 +00002561 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002562 (void) FormatLocaleString(buffer,MaxTextExtent,"/Height %.20g\n",
cristye8c25f92010-06-03 00:53:06 +00002563 (double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002564 (void) WriteBlobString(image,buffer);
2565 (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
cristyb51dff52011-05-19 16:55:47 +00002566 (void) FormatLocaleString(buffer,MaxTextExtent,"/BitsPerComponent %d\n",
cristy3ed852e2009-09-05 21:47:34 +00002567 (compression == FaxCompression) || (compression == Group4Compression)
2568 ? 1 : 8);
2569 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002570 (void) FormatLocaleString(buffer,MaxTextExtent,"/Length %.20g 0 R\n",
cristye8c25f92010-06-03 00:53:06 +00002571 (double) object+1);
cristy3ed852e2009-09-05 21:47:34 +00002572 (void) WriteBlobString(image,buffer);
2573 (void) WriteBlobString(image,">>\n");
2574 (void) WriteBlobString(image,"stream\n");
2575 offset=TellBlob(image);
2576 number_pixels=(MagickSizeType) image->columns*image->rows;
2577 switch (compression)
2578 {
2579 case RLECompression:
2580 default:
2581 {
cristy0553bd52013-06-30 15:53:50 +00002582 MemoryInfo
2583 *pixel_info;
2584
cristy3ed852e2009-09-05 21:47:34 +00002585 /*
2586 Allocate pixel array.
2587 */
2588 length=(size_t) number_pixels;
cristy0553bd52013-06-30 15:53:50 +00002589 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2590 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002591 {
2592 image=DestroyImage(image);
2593 ThrowWriterException(ResourceLimitError,
2594 "MemoryAllocationFailed");
2595 }
cristy0553bd52013-06-30 15:53:50 +00002596 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002597 /*
2598 Dump Runlength encoded pixels.
2599 */
2600 q=pixels;
cristybb503372010-05-27 20:51:26 +00002601 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002602 {
cristy1e178e72011-08-28 19:44:34 +00002603 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002604 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002605 break;
cristybb503372010-05-27 20:51:26 +00002606 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002607 {
cristy4c08aed2011-07-01 19:47:50 +00002608 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00002609 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002610 }
2611 }
2612#if defined(MAGICKCORE_ZLIB_DELEGATE)
2613 if (compression == ZipCompression)
cristy018f07f2011-09-04 21:15:19 +00002614 status=ZLIBEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002615 else
2616#endif
2617 if (compression == LZWCompression)
cristy018f07f2011-09-04 21:15:19 +00002618 status=LZWEncodeImage(image,length,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002619 else
cristy018f07f2011-09-04 21:15:19 +00002620 status=PackbitsEncodeImage(image,length,pixels,exception);
cristy0553bd52013-06-30 15:53:50 +00002621 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002622 if (status == MagickFalse)
2623 {
2624 (void) CloseBlob(image);
2625 return(MagickFalse);
2626 }
2627 break;
2628 }
2629 case NoCompression:
2630 {
2631 /*
2632 Dump uncompressed PseudoColor packets.
2633 */
2634 Ascii85Initialize(image);
cristybb503372010-05-27 20:51:26 +00002635 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002636 {
cristy1e178e72011-08-28 19:44:34 +00002637 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002638 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002639 break;
cristybb503372010-05-27 20:51:26 +00002640 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002641 {
cristy4c08aed2011-07-01 19:47:50 +00002642 Ascii85Encode(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
cristyed231572011-07-14 02:18:59 +00002643 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002644 }
2645 }
2646 Ascii85Flush(image);
2647 break;
2648 }
2649 }
2650 offset=TellBlob(image)-offset;
2651 (void) WriteBlobString(image,"\nendstream\n");
2652 }
2653 (void) WriteBlobString(image,"endobj\n");
2654 /*
2655 Write Length object.
2656 */
2657 xref[object++]=TellBlob(image);
cristyb51dff52011-05-19 16:55:47 +00002658 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002659 object);
cristy3ed852e2009-09-05 21:47:34 +00002660 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002661 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002662 (void) WriteBlobString(image,buffer);
2663 (void) WriteBlobString(image,"endobj\n");
2664 if (GetNextImageInList(image) == (Image *) NULL)
2665 break;
2666 image=SyncNextImageInList(image);
2667 status=SetImageProgress(image,SaveImagesTag,scene++,
2668 GetImageListLength(image));
2669 if (status == MagickFalse)
2670 break;
2671 } while (image_info->adjoin != MagickFalse);
2672 /*
2673 Write Metadata object.
2674 */
2675 xref[object++]=TellBlob(image);
2676 info_id=object;
cristyb51dff52011-05-19 16:55:47 +00002677 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g 0 obj\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002678 object);
cristy3ed852e2009-09-05 21:47:34 +00002679 (void) WriteBlobString(image,buffer);
2680 (void) WriteBlobString(image,"<<\n");
cristyb51dff52011-05-19 16:55:47 +00002681 (void) FormatLocaleString(buffer,MaxTextExtent,"/Title (%s)\n",
cristy57015272010-12-30 01:16:38 +00002682 EscapeParenthesis(basename));
cristy3ed852e2009-09-05 21:47:34 +00002683 (void) WriteBlobString(image,buffer);
2684 seconds=time((time_t *) NULL);
2685#if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2686 (void) localtime_r(&seconds,&local_time);
2687#else
2688 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2689#endif
cristyb51dff52011-05-19 16:55:47 +00002690 (void) FormatLocaleString(date,MaxTextExtent,"D:%04d%02d%02d%02d%02d%02d",
cristy3ed852e2009-09-05 21:47:34 +00002691 local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2692 local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
cristyb51dff52011-05-19 16:55:47 +00002693 (void) FormatLocaleString(buffer,MaxTextExtent,"/CreationDate (%s)\n",date);
cristy3ed852e2009-09-05 21:47:34 +00002694 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002695 (void) FormatLocaleString(buffer,MaxTextExtent,"/ModDate (%s)\n",date);
cristy3ed852e2009-09-05 21:47:34 +00002696 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002697 (void) FormatLocaleString(buffer,MaxTextExtent,"/Producer (%s)\n",
cristybb503372010-05-27 20:51:26 +00002698 EscapeParenthesis(GetMagickVersion((size_t *) NULL)));
cristy3ed852e2009-09-05 21:47:34 +00002699 (void) WriteBlobString(image,buffer);
2700 (void) WriteBlobString(image,">>\n");
2701 (void) WriteBlobString(image,"endobj\n");
2702 /*
2703 Write Xref object.
2704 */
cristyf40010e2012-05-13 13:52:20 +00002705 offset=TellBlob(image)-xref[0]+
2706 (LocaleCompare(image_info->magick,"PDFA") == 0 ? 6 : 0)+10;
cristy3ed852e2009-09-05 21:47:34 +00002707 (void) WriteBlobString(image,"xref\n");
cristyb51dff52011-05-19 16:55:47 +00002708 (void) FormatLocaleString(buffer,MaxTextExtent,"0 %.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002709 object+1);
cristy3ed852e2009-09-05 21:47:34 +00002710 (void) WriteBlobString(image,buffer);
2711 (void) WriteBlobString(image,"0000000000 65535 f \n");
cristybb503372010-05-27 20:51:26 +00002712 for (i=0; i < (ssize_t) object; i++)
cristy3ed852e2009-09-05 21:47:34 +00002713 {
cristyb51dff52011-05-19 16:55:47 +00002714 (void) FormatLocaleString(buffer,MaxTextExtent,"%010lu 00000 n \n",
cristyf2faecf2010-05-28 19:19:36 +00002715 (unsigned long) xref[i]);
cristy3ed852e2009-09-05 21:47:34 +00002716 (void) WriteBlobString(image,buffer);
2717 }
2718 (void) WriteBlobString(image,"trailer\n");
2719 (void) WriteBlobString(image,"<<\n");
cristyb51dff52011-05-19 16:55:47 +00002720 (void) FormatLocaleString(buffer,MaxTextExtent,"/Size %.20g\n",(double)
cristyf2faecf2010-05-28 19:19:36 +00002721 object+1);
cristy3ed852e2009-09-05 21:47:34 +00002722 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002723 (void) FormatLocaleString(buffer,MaxTextExtent,"/Info %.20g 0 R\n",(double)
cristye8c25f92010-06-03 00:53:06 +00002724 info_id);
cristy3ed852e2009-09-05 21:47:34 +00002725 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002726 (void) FormatLocaleString(buffer,MaxTextExtent,"/Root %.20g 0 R\n",(double)
cristye8c25f92010-06-03 00:53:06 +00002727 root_id);
cristy3ed852e2009-09-05 21:47:34 +00002728 (void) WriteBlobString(image,buffer);
cristy1b70dc82012-07-01 23:15:05 +00002729 (void) SignatureImage(image,exception);
2730 (void) FormatLocaleString(buffer,MaxTextExtent,"/ID [<%s> <%s>]\n",
2731 GetImageProperty(image,"signature",exception),
2732 GetImageProperty(image,"signature",exception));
2733 (void) WriteBlobString(image,buffer);
cristy3ed852e2009-09-05 21:47:34 +00002734 (void) WriteBlobString(image,">>\n");
2735 (void) WriteBlobString(image,"startxref\n");
cristyb51dff52011-05-19 16:55:47 +00002736 (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g\n",(double) offset);
cristy3ed852e2009-09-05 21:47:34 +00002737 (void) WriteBlobString(image,buffer);
2738 (void) WriteBlobString(image,"%%EOF\n");
2739 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2740 (void) CloseBlob(image);
2741 return(MagickTrue);
2742}