1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % PPPP DDDD FFFFF %
7 % P P D D F %
8 % PPPP D D FFF %
9 % P D D F %
10 % P DDDD F %
11 % %
12 % %
13 % Read/Write Portable Document Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % 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 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/artifact.h"
45 #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"
51 #include "MagickCore/colorspace-private.h"
52 #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"
67 #include "MagickCore/nt-base-private.h"
68 #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"
75 #include "MagickCore/signature.h"
76 #include "MagickCore/static.h"
77 #include "MagickCore/string_.h"
78 #include "MagickCore/module.h"
79 #include "MagickCore/token.h"
80 #include "MagickCore/transform.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/module.h"
83
84 /*
85 Define declarations.
86 */
87 #if defined(MAGICKCORE_TIFF_DELEGATE)
88 #define CCITTParam "-1"
89 #else
90 #define CCITTParam "0"
91 #endif
92
93 /*
94 Forward declarations.
95 */
96 static MagickBooleanType
97 WritePDFImage(const ImageInfo *,Image *,ExceptionInfo *);
98
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 % %
102 % %
103 % %
104 % 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 */
128 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
PDFDelegateMessage(void * handle,const char * message,int length)129 static int MagickDLLCall PDFDelegateMessage(void *handle,const char *message,
130 int length)
131 {
132 char
133 **messages;
134
135 ssize_t
136 offset;
137
138 offset=0;
139 messages=(char **) handle;
140 if (*messages == (char *) NULL)
141 *messages=(char *) AcquireQuantumMemory(length+1,sizeof(char *));
142 else
143 {
144 offset=strlen(*messages);
145 *messages=(char *) ResizeQuantumMemory(*messages,offset+length+1,
146 sizeof(char *));
147 }
148 if (*messages == (char *) NULL)
149 return(0);
150 (void) memcpy(*messages+offset,message,length);
151 (*messages)[length+offset] ='\0';
152 return(length);
153 }
154 #endif
155
InvokePDFDelegate(const MagickBooleanType verbose,const char * command,char * message,ExceptionInfo * exception)156 static MagickBooleanType InvokePDFDelegate(const MagickBooleanType verbose,
157 const char *command,char *message,ExceptionInfo *exception)
158 {
159 int
160 status;
161
162 #define ExecuteGhostscriptCommand(command,status) \
163 { \
164 status=ExternalDelegateCommand(MagickFalse,verbose,command,message, \
165 exception); \
166 if (status == 0) \
167 return(MagickTrue); \
168 if (status < 0) \
169 return(MagickFalse); \
170 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, \
171 "FailedToExecuteCommand","`%s' (%d)",command,status); \
172 return(MagickFalse); \
173 }
174
175 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
176 #define SetArgsStart(command,args_start) \
177 if (args_start == (const char *) NULL) \
178 { \
179 if (*command != '"') \
180 args_start=strchr(command,' '); \
181 else \
182 { \
183 args_start=strchr(command+1,'"'); \
184 if (args_start != (const char *) NULL) \
185 args_start++; \
186 } \
187 }
188
189 char
190 **argv,
191 *errors;
192
193 const char
194 *args_start = (const char *) NULL;
195
196 const GhostInfo
197 *ghost_info;
198
199 gs_main_instance
200 *interpreter;
201
202 gsapi_revision_t
203 revision;
204
205 int
206 argc,
207 code;
208
209 register ssize_t
210 i;
211
212 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
213 ghost_info=NTGhostscriptDLLVectors();
214 #else
215 GhostInfo
216 ghost_info_struct;
217
218 ghost_info=(&ghost_info_struct);
219 (void) memset(&ghost_info_struct,0,sizeof(ghost_info_struct));
220 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
221 gsapi_delete_instance;
222 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
223 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
224 gsapi_new_instance;
225 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
226 gsapi_init_with_args;
227 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
228 int *)) gsapi_run_string;
229 ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int (*)(void *,char *,
230 int),int (*)(void *,const char *,int),int (*)(void *, const char *, int)))
231 gsapi_set_stdio;
232 ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision;
233 #endif
234 if (ghost_info == (GhostInfo *) NULL)
235 ExecuteGhostscriptCommand(command,status);
236 if ((ghost_info->revision)(&revision,sizeof(revision)) != 0)
237 revision.revision=0;
238 if (verbose != MagickFalse)
239 {
240 (void) fprintf(stdout,"[ghostscript library %.2f]",(double)
241 revision.revision/100.0);
242 SetArgsStart(command,args_start);
243 (void) fputs(args_start,stdout);
244 }
245 errors=(char *) NULL;
246 status=(ghost_info->new_instance)(&interpreter,(void *) &errors);
247 if (status < 0)
248 ExecuteGhostscriptCommand(command,status);
249 code=0;
250 argv=StringToArgv(command,&argc);
251 if (argv == (char **) NULL)
252 {
253 (ghost_info->delete_instance)(interpreter);
254 return(MagickFalse);
255 }
256 (void) (ghost_info->set_stdio)(interpreter,(int (MagickDLLCall *)(void *,
257 char *,int)) NULL,PDFDelegateMessage,PDFDelegateMessage);
258 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
259 if (status == 0)
260 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
261 0,&code);
262 (ghost_info->exit)(interpreter);
263 (ghost_info->delete_instance)(interpreter);
264 for (i=0; i < (ssize_t) argc; i++)
265 argv[i]=DestroyString(argv[i]);
266 argv=(char **) RelinquishMagickMemory(argv);
267 if (status != 0)
268 {
269 SetArgsStart(command,args_start);
270 if (status == -101) /* quit */
271 (void) FormatLocaleString(message,MagickPathExtent,
272 "[ghostscript library %.2f]%s: %s",(double) revision.revision/100.0,
273 args_start,errors);
274 else
275 {
276 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
277 "PDFDelegateFailed","`[ghostscript library %.2f]%s': %s",(double)
278 revision.revision/100.0,args_start,errors);
279 if (errors != (char *) NULL)
280 errors=DestroyString(errors);
281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
282 "Ghostscript returns status %d, exit code %d",status,code);
283 return(MagickFalse);
284 }
285 }
286 if (errors != (char *) NULL)
287 errors=DestroyString(errors);
288 return(MagickTrue);
289 #else
290 ExecuteGhostscriptCommand(command,status);
291 #endif
292 }
293
294 /*
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 % %
297 % %
298 % %
299 % I s P D F %
300 % %
301 % %
302 % %
303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304 %
305 % IsPDF() returns MagickTrue if the image format type, identified by the
306 % magick string, is PDF.
307 %
308 % The format of the IsPDF method is:
309 %
310 % MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
311 %
312 % A description of each parameter follows:
313 %
314 % o magick: compare image format pattern against these bytes.
315 %
316 % o offset: Specifies the offset of the magick string.
317 %
318 */
IsPDF(const unsigned char * magick,const size_t offset)319 static MagickBooleanType IsPDF(const unsigned char *magick,const size_t offset)
320 {
321 if (offset < 5)
322 return(MagickFalse);
323 if (LocaleNCompare((const char *) magick,"%PDF-",5) == 0)
324 return(MagickTrue);
325 return(MagickFalse);
326 }
327
328 /*
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 % %
331 % %
332 % %
333 % R e a d P D F I m a g e %
334 % %
335 % %
336 % %
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338 %
339 % ReadPDFImage() reads a Portable Document Format image file and
340 % returns it. It allocates the memory necessary for the new Image structure
341 % and returns a pointer to the new image.
342 %
343 % The format of the ReadPDFImage method is:
344 %
345 % Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
346 %
347 % A description of each parameter follows:
348 %
349 % o image_info: the image info.
350 %
351 % o exception: return any errors or warnings in this structure.
352 %
353 */
354
IsPDFRendered(const char * path)355 static MagickBooleanType IsPDFRendered(const char *path)
356 {
357 MagickBooleanType
358 status;
359
360 struct stat
361 attributes;
362
363 if ((path == (const char *) NULL) || (*path == '\0'))
364 return(MagickFalse);
365 status=GetPathAttributes(path,&attributes);
366 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
367 (attributes.st_size > 0))
368 return(MagickTrue);
369 return(MagickFalse);
370 }
371
ReadPDFImage(const ImageInfo * image_info,ExceptionInfo * exception)372 static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
373 {
374 #define BeginXMPPacket "<?xpacket begin="
375 #define CMYKProcessColor "CMYKProcessColor"
376 #define CropBox "CropBox"
377 #define DefaultCMYK "DefaultCMYK"
378 #define DeviceCMYK "DeviceCMYK"
379 #define EndXMPPacket "<?xpacket end="
380 #define MediaBox "MediaBox"
381 #define RenderPostscriptText "Rendering Postscript... "
382 #define PDFRotate "Rotate"
383 #define SpotColor "Separation"
384 #define TrimBox "TrimBox"
385 #define PDFVersion "PDF-"
386
387 char
388 command[MagickPathExtent],
389 *density,
390 filename[MagickPathExtent],
391 geometry[MagickPathExtent],
392 input_filename[MagickPathExtent],
393 message[MagickPathExtent],
394 *options,
395 postscript_filename[MagickPathExtent];
396
397 const char
398 *option;
399
400 const DelegateInfo
401 *delegate_info;
402
403 double
404 angle;
405
406 GeometryInfo
407 geometry_info;
408
409 Image
410 *image,
411 *next,
412 *pdf_image;
413
414 ImageInfo
415 *read_info;
416
417 int
418 c,
419 file;
420
421 MagickBooleanType
422 cmyk,
423 cropbox,
424 fitPage,
425 status,
426 stop_on_error,
427 trimbox;
428
429 MagickStatusType
430 flags;
431
432 PointInfo
433 delta;
434
435 RectangleInfo
436 bounding_box,
437 page;
438
439 register char
440 *p;
441
442 register ssize_t
443 i;
444
445 SegmentInfo
446 bounds,
447 hires_bounds;
448
449 size_t
450 scene,
451 spotcolor;
452
453 ssize_t
454 count;
455
456 assert(image_info != (const ImageInfo *) NULL);
457 assert(image_info->signature == MagickCoreSignature);
458 if (image_info->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
460 image_info->filename);
461 assert(exception != (ExceptionInfo *) NULL);
462 assert(exception->signature == MagickCoreSignature);
463 /*
464 Open image file.
465 */
466 image=AcquireImage(image_info,exception);
467 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
468 if (status == MagickFalse)
469 {
470 image=DestroyImageList(image);
471 return((Image *) NULL);
472 }
473 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
474 if (status == MagickFalse)
475 {
476 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
477 image_info->filename);
478 image=DestroyImageList(image);
479 return((Image *) NULL);
480 }
481 /*
482 Set the page density.
483 */
484 delta.x=DefaultResolution;
485 delta.y=DefaultResolution;
486 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
487 {
488 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
489 image->resolution.x=geometry_info.rho;
490 image->resolution.y=geometry_info.sigma;
491 if ((flags & SigmaValue) == 0)
492 image->resolution.y=image->resolution.x;
493 }
494 if (image_info->density != (char *) NULL)
495 {
496 flags=ParseGeometry(image_info->density,&geometry_info);
497 image->resolution.x=geometry_info.rho;
498 image->resolution.y=geometry_info.sigma;
499 if ((flags & SigmaValue) == 0)
500 image->resolution.y=image->resolution.x;
501 }
502 (void) memset(&page,0,sizeof(page));
503 (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
504 if (image_info->page != (char *) NULL)
505 (void) ParseAbsoluteGeometry(image_info->page,&page);
506 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)-
507 0.5);
508 page.height=(size_t) ceil((double) (page.height*image->resolution.y/delta.y)-
509 0.5);
510 /*
511 Determine page geometry from the PDF media box.
512 */
513 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
514 cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
515 stop_on_error=IsStringTrue(GetImageOption(image_info,"pdf:stop-on-error"));
516 trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
517 count=0;
518 spotcolor=0;
519 (void) memset(&bounding_box,0,sizeof(bounding_box));
520 (void) memset(&bounds,0,sizeof(bounds));
521 (void) memset(&hires_bounds,0,sizeof(hires_bounds));
522 (void) memset(command,0,sizeof(command));
523 angle=0.0;
524 p=command;
525 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
526 {
527 /*
528 Note PDF elements.
529 */
530 if (c == '\n')
531 c=' ';
532 *p++=(char) c;
533 if ((c != (int) '/') && (c != (int) '%') &&
534 ((size_t) (p-command) < (MagickPathExtent-1)))
535 continue;
536 *(--p)='\0';
537 p=command;
538 if (LocaleNCompare(PDFRotate,command,strlen(PDFRotate)) == 0)
539 count=(ssize_t) sscanf(command,"Rotate %lf",&angle);
540 /*
541 Is this a CMYK document?
542 */
543 if (LocaleNCompare(DefaultCMYK,command,strlen(DefaultCMYK)) == 0)
544 cmyk=MagickTrue;
545 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
546 cmyk=MagickTrue;
547 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0)
548 cmyk=MagickTrue;
549 if (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)
550 {
551 char
552 name[MagickPathExtent],
553 property[MagickPathExtent],
554 *value;
555
556 /*
557 Note spot names.
558 */
559 (void) FormatLocaleString(property,MagickPathExtent,
560 "pdf:SpotColor-%.20g",(double) spotcolor++);
561 i=0;
562 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
563 {
564 if ((isspace(c) != 0) || (c == '/') || ((i+1) == MagickPathExtent))
565 break;
566 name[i++]=(char) c;
567 }
568 name[i]='\0';
569 value=ConstantString(name);
570 (void) SubstituteString(&value,"#20"," ");
571 if (*value != '\0')
572 (void) SetImageProperty(image,property,value,exception);
573 value=DestroyString(value);
574 continue;
575 }
576 if (LocaleNCompare(PDFVersion,command,strlen(PDFVersion)) == 0)
577 (void) SetImageProperty(image,"pdf:Version",command,exception);
578 if (image_info->page != (char *) NULL)
579 continue;
580 count=0;
581 if (cropbox != MagickFalse)
582 {
583 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
584 {
585 /*
586 Note region defined by crop box.
587 */
588 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
589 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
590 if (count != 4)
591 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
592 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
593 }
594 }
595 else
596 if (trimbox != MagickFalse)
597 {
598 if (LocaleNCompare(TrimBox,command,strlen(TrimBox)) == 0)
599 {
600 /*
601 Note region defined by trim box.
602 */
603 count=(ssize_t) sscanf(command,"TrimBox [%lf %lf %lf %lf",
604 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
605 if (count != 4)
606 count=(ssize_t) sscanf(command,"TrimBox[%lf %lf %lf %lf",
607 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
608 }
609 }
610 else
611 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
612 {
613 /*
614 Note region defined by media box.
615 */
616 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
617 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
618 if (count != 4)
619 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
620 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
621 }
622 if (count != 4)
623 continue;
624 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) ||
625 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1)))
626 continue;
627 hires_bounds=bounds;
628 }
629 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) &&
630 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon))
631 {
632 /*
633 Set PDF render geometry.
634 */
635 (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+.15g%+.15g",
636 hires_bounds.x2-bounds.x1,hires_bounds.y2-hires_bounds.y1,
637 hires_bounds.x1,hires_bounds.y1);
638 (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry,exception);
639 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)*
640 image->resolution.x/delta.x)-0.5);
641 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)*
642 image->resolution.y/delta.y)-0.5);
643 }
644 fitPage=MagickFalse;
645 option=GetImageOption(image_info,"pdf:fit-page");
646 if (option != (char *) NULL)
647 {
648 char
649 *page_geometry;
650
651 page_geometry=GetPageGeometry(option);
652 flags=ParseMetaGeometry(page_geometry,&page.x,&page.y,&page.width,
653 &page.height);
654 page_geometry=DestroyString(page_geometry);
655 if (flags == NoValue)
656 {
657 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
658 "InvalidGeometry","`%s'",option);
659 image=DestroyImage(image);
660 return((Image *) NULL);
661 }
662 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x)
663 -0.5);
664 page.height=(size_t) ceil((double) (page.height*image->resolution.y/
665 delta.y) -0.5);
666 fitPage=MagickTrue;
667 }
668 if ((fabs(angle) == 90.0) || (fabs(angle) == 270.0))
669 {
670 size_t
671 swap;
672
673 swap=page.width;
674 page.width=page.height;
675 page.height=swap;
676 }
677 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
678 cmyk=MagickFalse;
679 /*
680 Create Ghostscript control file.
681 */
682 file=AcquireUniqueFileResource(postscript_filename);
683 if (file == -1)
684 {
685 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
686 image_info->filename);
687 image=DestroyImage(image);
688 return((Image *) NULL);
689 }
690 count=write(file," ",1);
691 file=close(file)-1;
692 /*
693 Render Postscript with the Ghostscript delegate.
694 */
695 if (image_info->monochrome != MagickFalse)
696 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
697 else
698 if (cmyk != MagickFalse)
699 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
700 else
701 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
702 if (delegate_info == (const DelegateInfo *) NULL)
703 {
704 (void) RelinquishUniqueFileResource(postscript_filename);
705 image=DestroyImage(image);
706 return((Image *) NULL);
707 }
708 density=AcquireString("");
709 options=AcquireString("");
710 (void) FormatLocaleString(density,MagickPathExtent,"%gx%g",
711 image->resolution.x,image->resolution.y);
712 if ((image_info->page != (char *) NULL) || (fitPage != MagickFalse))
713 (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double)
714 page.width,(double) page.height);
715 if (fitPage != MagickFalse)
716 (void) ConcatenateMagickString(options,"-dPSFitPage ",MagickPathExtent);
717 if (cmyk != MagickFalse)
718 (void) ConcatenateMagickString(options,"-dUseCIEColor ",MagickPathExtent);
719 if (cropbox != MagickFalse)
720 (void) ConcatenateMagickString(options,"-dUseCropBox ",MagickPathExtent);
721 if (stop_on_error != MagickFalse)
722 (void) ConcatenateMagickString(options,"-dPDFSTOPONERROR ",
723 MagickPathExtent);
724 if (trimbox != MagickFalse)
725 (void) ConcatenateMagickString(options,"-dUseTrimBox ",MagickPathExtent);
726 option=GetImageOption(image_info,"authenticate");
727 if (option != (char *) NULL)
728 {
729 char
730 passphrase[MagickPathExtent];
731
732 (void) FormatLocaleString(passphrase,MagickPathExtent,
733 "\"-sPDFPassword=%s\" ",option);
734 (void) ConcatenateMagickString(options,passphrase,MagickPathExtent);
735 }
736 read_info=CloneImageInfo(image_info);
737 *read_info->magick='\0';
738 if (read_info->number_scenes != 0)
739 {
740 char
741 pages[MagickPathExtent];
742
743 (void) FormatLocaleString(pages,MagickPathExtent,"-dFirstPage=%.20g "
744 "-dLastPage=%.20g",(double) read_info->scene+1,(double)
745 (read_info->scene+read_info->number_scenes));
746 (void) ConcatenateMagickString(options,pages,MagickPathExtent);
747 read_info->number_scenes=0;
748 if (read_info->scenes != (char *) NULL)
749 *read_info->scenes='\0';
750 }
751 (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
752 (void) AcquireUniqueFilename(filename);
753 (void) RelinquishUniqueFileResource(filename);
754 (void) ConcatenateMagickString(filename,"%d",MagickPathExtent);
755 (void) FormatLocaleString(command,MagickPathExtent,
756 GetDelegateCommands(delegate_info),
757 read_info->antialias != MagickFalse ? 4 : 1,
758 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename,
759 postscript_filename,input_filename);
760 options=DestroyString(options);
761 density=DestroyString(density);
762 *message='\0';
763 status=InvokePDFDelegate(read_info->verbose,command,message,exception);
764 (void) RelinquishUniqueFileResource(postscript_filename);
765 (void) RelinquishUniqueFileResource(input_filename);
766 pdf_image=(Image *) NULL;
767 if (status == MagickFalse)
768 for (i=1; ; i++)
769 {
770 (void) InterpretImageFilename(image_info,image,filename,(int) i,
771 read_info->filename,exception);
772 if (IsPDFRendered(read_info->filename) == MagickFalse)
773 break;
774 (void) RelinquishUniqueFileResource(read_info->filename);
775 }
776 else
777 for (i=1; ; i++)
778 {
779 (void) InterpretImageFilename(image_info,image,filename,(int) i,
780 read_info->filename,exception);
781 if (IsPDFRendered(read_info->filename) == MagickFalse)
782 break;
783 read_info->blob=NULL;
784 read_info->length=0;
785 next=ReadImage(read_info,exception);
786 (void) RelinquishUniqueFileResource(read_info->filename);
787 if (next == (Image *) NULL)
788 break;
789 AppendImageToList(&pdf_image,next);
790 }
791 read_info=DestroyImageInfo(read_info);
792 if (pdf_image == (Image *) NULL)
793 {
794 if (*message != '\0')
795 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
796 "PDFDelegateFailed","`%s'",message);
797 image=DestroyImage(image);
798 return((Image *) NULL);
799 }
800 if (LocaleCompare(pdf_image->magick,"BMP") == 0)
801 {
802 Image
803 *cmyk_image;
804
805 cmyk_image=ConsolidateCMYKImages(pdf_image,exception);
806 if (cmyk_image != (Image *) NULL)
807 {
808 pdf_image=DestroyImageList(pdf_image);
809 pdf_image=cmyk_image;
810 }
811 }
812 (void) SeekBlob(image,0,SEEK_SET);
813 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
814 {
815 /*
816 Note document structuring comments.
817 */
818 *p++=(char) c;
819 if ((strchr("\n\r%",c) == (char *) NULL) &&
820 ((size_t) (p-command) < (MagickPathExtent-1)))
821 continue;
822 *p='\0';
823 p=command;
824 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0)
825 {
826 StringInfo
827 *profile;
828
829 /*
830 Read XMP profile.
831 */
832 p=command;
833 profile=StringToStringInfo(command);
834 for (i=(ssize_t) GetStringInfoLength(profile)-1; c != EOF; i++)
835 {
836 SetStringInfoLength(profile,(size_t) (i+1));
837 c=ReadBlobByte(image);
838 GetStringInfoDatum(profile)[i]=(unsigned char) c;
839 *p++=(char) c;
840 if ((strchr("\n\r%",c) == (char *) NULL) &&
841 ((size_t) (p-command) < (MagickPathExtent-1)))
842 continue;
843 *p='\0';
844 p=command;
845 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0)
846 break;
847 }
848 SetStringInfoLength(profile,(size_t) i);
849 (void) SetImageProfile(image,"xmp",profile,exception);
850 profile=DestroyStringInfo(profile);
851 continue;
852 }
853 }
854 (void) CloseBlob(image);
855 if (image_info->number_scenes != 0)
856 {
857 Image
858 *clone_image;
859
860 /*
861 Add place holder images to meet the subimage specification requirement.
862 */
863 for (i=0; i < (ssize_t) image_info->scene; i++)
864 {
865 clone_image=CloneImage(pdf_image,1,1,MagickTrue,exception);
866 if (clone_image != (Image *) NULL)
867 PrependImageToList(&pdf_image,clone_image);
868 }
869 }
870 do
871 {
872 (void) CopyMagickString(pdf_image->filename,filename,MagickPathExtent);
873 (void) CopyMagickString(pdf_image->magick,image->magick,MagickPathExtent);
874 pdf_image->page=page;
875 (void) CloneImageProfiles(pdf_image,image);
876 (void) CloneImageProperties(pdf_image,image);
877 next=SyncNextImageInList(pdf_image);
878 if (next != (Image *) NULL)
879 pdf_image=next;
880 } while (next != (Image *) NULL);
881 image=DestroyImage(image);
882 scene=0;
883 for (next=GetFirstImageInList(pdf_image); next != (Image *) NULL; )
884 {
885 next->scene=scene++;
886 next=GetNextImageInList(next);
887 }
888 return(GetFirstImageInList(pdf_image));
889 }
890
891 /*
892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893 % %
894 % %
895 % %
896 % R e g i s t e r P D F I m a g e %
897 % %
898 % %
899 % %
900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901 %
902 % RegisterPDFImage() adds properties for the PDF image format to
903 % the list of supported formats. The properties include the image format
904 % tag, a method to read and/or write the format, whether the format
905 % supports the saving of more than one frame to the same file or blob,
906 % whether the format supports native in-memory I/O, and a brief
907 % description of the format.
908 %
909 % The format of the RegisterPDFImage method is:
910 %
911 % size_t RegisterPDFImage(void)
912 %
913 */
RegisterPDFImage(void)914 ModuleExport size_t RegisterPDFImage(void)
915 {
916 MagickInfo
917 *entry;
918
919 entry=AcquireMagickInfo("PDF","AI","Adobe Illustrator CS2");
920 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
921 entry->encoder=(EncodeImageHandler *) WritePDFImage;
922 entry->flags|=CoderDecoderSeekableStreamFlag;
923 entry->flags^=CoderAdjoinFlag;
924 entry->flags^=CoderBlobSupportFlag;
925 entry->mime_type=ConstantString("application/pdf");
926 (void) RegisterMagickInfo(entry);
927 entry=AcquireMagickInfo("PDF","EPDF",
928 "Encapsulated Portable Document Format");
929 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
930 entry->encoder=(EncodeImageHandler *) WritePDFImage;
931 entry->flags|=CoderDecoderSeekableStreamFlag;
932 entry->flags^=CoderAdjoinFlag;
933 entry->flags^=CoderBlobSupportFlag;
934 entry->mime_type=ConstantString("application/pdf");
935 (void) RegisterMagickInfo(entry);
936 entry=AcquireMagickInfo("PDF","PDF","Portable Document Format");
937 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
938 entry->encoder=(EncodeImageHandler *) WritePDFImage;
939 entry->magick=(IsImageFormatHandler *) IsPDF;
940 entry->flags|=CoderDecoderSeekableStreamFlag;
941 entry->flags^=CoderBlobSupportFlag;
942 entry->mime_type=ConstantString("application/pdf");
943 (void) RegisterMagickInfo(entry);
944 entry=AcquireMagickInfo("PDF","PDFA","Portable Document Archive Format");
945 entry->decoder=(DecodeImageHandler *) ReadPDFImage;
946 entry->encoder=(EncodeImageHandler *) WritePDFImage;
947 entry->magick=(IsImageFormatHandler *) IsPDF;
948 entry->flags|=CoderDecoderSeekableStreamFlag;
949 entry->flags^=CoderBlobSupportFlag;
950 entry->mime_type=ConstantString("application/pdf");
951 (void) RegisterMagickInfo(entry);
952 return(MagickImageCoderSignature);
953 }
954
955 /*
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % %
958 % %
959 % %
960 % U n r e g i s t e r P D F I m a g e %
961 % %
962 % %
963 % %
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965 %
966 % UnregisterPDFImage() removes format registrations made by the
967 % PDF module from the list of supported formats.
968 %
969 % The format of the UnregisterPDFImage method is:
970 %
971 % UnregisterPDFImage(void)
972 %
973 */
UnregisterPDFImage(void)974 ModuleExport void UnregisterPDFImage(void)
975 {
976 (void) UnregisterMagickInfo("AI");
977 (void) UnregisterMagickInfo("EPDF");
978 (void) UnregisterMagickInfo("PDF");
979 (void) UnregisterMagickInfo("PDFA");
980 }
981
982 /*
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 % %
985 % %
986 % %
987 % W r i t e P D F I m a g e %
988 % %
989 % %
990 % %
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 %
993 % WritePDFImage() writes an image in the Portable Document image
994 % format.
995 %
996 % The format of the WritePDFImage method is:
997 %
998 % MagickBooleanType WritePDFImage(const ImageInfo *image_info,
999 % Image *image,ExceptionInfo *exception)
1000 %
1001 % A description of each parameter follows.
1002 %
1003 % o image_info: the image info.
1004 %
1005 % o image: The image.
1006 %
1007 % o exception: return any errors or warnings in this structure.
1008 %
1009 */
1010
EscapeParenthesis(const char * source)1011 static char *EscapeParenthesis(const char *source)
1012 {
1013 char
1014 *destination;
1015
1016 register char
1017 *q;
1018
1019 register const char
1020 *p;
1021
1022 size_t
1023 length;
1024
1025 assert(source != (const char *) NULL);
1026 length=0;
1027 for (p=source; *p != '\0'; p++)
1028 {
1029 if ((*p == '\\') || (*p == '(') || (*p == ')'))
1030 {
1031 if (~length < 1)
1032 ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
1033 length++;
1034 }
1035 length++;
1036 }
1037 destination=(char *) NULL;
1038 if (~length >= (MagickPathExtent-1))
1039 destination=(char *) AcquireQuantumMemory(length+MagickPathExtent,
1040 sizeof(*destination));
1041 if (destination == (char *) NULL)
1042 ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
1043 *destination='\0';
1044 q=destination;
1045 for (p=source; *p != '\0'; p++)
1046 {
1047 if ((*p == '\\') || (*p == '(') || (*p == ')'))
1048 *q++='\\';
1049 *q++=(*p);
1050 }
1051 *q='\0';
1052 return(destination);
1053 }
1054
UTF8ToUTF16(const unsigned char * utf8,wchar_t * utf16)1055 static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16)
1056 {
1057 register const unsigned char
1058 *p;
1059
1060 if (utf16 != (wchar_t *) NULL)
1061 {
1062 register wchar_t
1063 *q;
1064
1065 wchar_t
1066 c;
1067
1068 /*
1069 Convert UTF-8 to UTF-16.
1070 */
1071 q=utf16;
1072 for (p=utf8; *p != '\0'; p++)
1073 {
1074 if ((*p & 0x80) == 0)
1075 *q=(*p);
1076 else
1077 if ((*p & 0xE0) == 0xC0)
1078 {
1079 c=(*p);
1080 *q=(c & 0x1F) << 6;
1081 p++;
1082 if ((*p & 0xC0) != 0x80)
1083 return(0);
1084 *q|=(*p & 0x3F);
1085 }
1086 else
1087 if ((*p & 0xF0) == 0xE0)
1088 {
1089 c=(*p);
1090 *q=c << 12;
1091 p++;
1092 if ((*p & 0xC0) != 0x80)
1093 return(0);
1094 c=(*p);
1095 *q|=(c & 0x3F) << 6;
1096 p++;
1097 if ((*p & 0xC0) != 0x80)
1098 return(0);
1099 *q|=(*p & 0x3F);
1100 }
1101 else
1102 return(0);
1103 q++;
1104 }
1105 *q++=(wchar_t) '\0';
1106 return((size_t) (q-utf16));
1107 }
1108 /*
1109 Compute UTF-16 string length.
1110 */
1111 for (p=utf8; *p != '\0'; p++)
1112 {
1113 if ((*p & 0x80) == 0)
1114 ;
1115 else
1116 if ((*p & 0xE0) == 0xC0)
1117 {
1118 p++;
1119 if ((*p & 0xC0) != 0x80)
1120 return(0);
1121 }
1122 else
1123 if ((*p & 0xF0) == 0xE0)
1124 {
1125 p++;
1126 if ((*p & 0xC0) != 0x80)
1127 return(0);
1128 p++;
1129 if ((*p & 0xC0) != 0x80)
1130 return(0);
1131 }
1132 else
1133 return(0);
1134 }
1135 return((size_t) (p-utf8));
1136 }
1137
ConvertUTF8ToUTF16(const unsigned char * source,size_t * length)1138 static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source,size_t *length)
1139 {
1140 wchar_t
1141 *utf16;
1142
1143 *length=UTF8ToUTF16(source,(wchar_t *) NULL);
1144 if (*length == 0)
1145 {
1146 register ssize_t
1147 i;
1148
1149 /*
1150 Not UTF-8, just copy.
1151 */
1152 *length=strlen((const char *) source);
1153 utf16=(wchar_t *) AcquireQuantumMemory(*length+1,sizeof(*utf16));
1154 if (utf16 == (wchar_t *) NULL)
1155 return((wchar_t *) NULL);
1156 for (i=0; i <= (ssize_t) *length; i++)
1157 utf16[i]=source[i];
1158 return(utf16);
1159 }
1160 utf16=(wchar_t *) AcquireQuantumMemory(*length+1,sizeof(*utf16));
1161 if (utf16 == (wchar_t *) NULL)
1162 return((wchar_t *) NULL);
1163 *length=UTF8ToUTF16(source,utf16);
1164 return(utf16);
1165 }
1166
Huffman2DEncodeImage(const ImageInfo * image_info,Image * image,Image * inject_image,ExceptionInfo * exception)1167 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
1168 Image *image,Image *inject_image,ExceptionInfo *exception)
1169 {
1170 Image
1171 *group4_image;
1172
1173 ImageInfo
1174 *write_info;
1175
1176 MagickBooleanType
1177 status;
1178
1179 size_t
1180 length;
1181
1182 unsigned char
1183 *group4;
1184
1185 status=MagickTrue;
1186 write_info=CloneImageInfo(image_info);
1187 (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
1188 (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
1189 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception);
1190 if (group4_image == (Image *) NULL)
1191 return(MagickFalse);
1192 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
1193 exception);
1194 group4_image=DestroyImage(group4_image);
1195 if (group4 == (unsigned char *) NULL)
1196 return(MagickFalse);
1197 write_info=DestroyImageInfo(write_info);
1198 if (WriteBlob(image,length,group4) != (ssize_t) length)
1199 status=MagickFalse;
1200 group4=(unsigned char *) RelinquishMagickMemory(group4);
1201 return(status);
1202 }
1203
WritePDFImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1204 static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image,
1205 ExceptionInfo *exception)
1206 {
1207 #define CFormat "/Filter [ /%s ]\n"
1208 #define ObjectsPerImage 14
1209 #define ThrowPDFException(exception,message) \
1210 { \
1211 if (xref != (MagickOffsetType *) NULL) \
1212 xref=(MagickOffsetType *) RelinquishMagickMemory(xref); \
1213 ThrowWriterException((exception),(message)); \
1214 }
1215
1216 DisableMSCWarning(4310)
1217 static const char
1218 XMPProfile[]=
1219 {
1220 "<?xpacket begin=\"%s\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
1221 "<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"
1222 " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
1223 " <rdf:Description rdf:about=\"\"\n"
1224 " xmlns:xap=\"http://ns.adobe.com/xap/1.0/\">\n"
1225 " <xap:ModifyDate>%s</xap:ModifyDate>\n"
1226 " <xap:CreateDate>%s</xap:CreateDate>\n"
1227 " <xap:MetadataDate>%s</xap:MetadataDate>\n"
1228 " <xap:CreatorTool>%s</xap:CreatorTool>\n"
1229 " </rdf:Description>\n"
1230 " <rdf:Description rdf:about=\"\"\n"
1231 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
1232 " <dc:format>application/pdf</dc:format>\n"
1233 " <dc:title>\n"
1234 " <rdf:Alt>\n"
1235 " <rdf:li xml:lang=\"x-default\">%s</rdf:li>\n"
1236 " </rdf:Alt>\n"
1237 " </dc:title>\n"
1238 " </rdf:Description>\n"
1239 " <rdf:Description rdf:about=\"\"\n"
1240 " xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n"
1241 " <xapMM:DocumentID>uuid:6ec119d7-7982-4f56-808d-dfe64f5b35cf</xapMM:DocumentID>\n"
1242 " <xapMM:InstanceID>uuid:a79b99b4-6235-447f-9f6c-ec18ef7555cb</xapMM:InstanceID>\n"
1243 " </rdf:Description>\n"
1244 " <rdf:Description rdf:about=\"\"\n"
1245 " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
1246 " <pdf:Producer>%s</pdf:Producer>\n"
1247 " </rdf:Description>\n"
1248 " <rdf:Description rdf:about=\"\"\n"
1249 " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
1250 " <pdfaid:part>3</pdfaid:part>\n"
1251 " <pdfaid:conformance>B</pdfaid:conformance>\n"
1252 " </rdf:Description>\n"
1253 " </rdf:RDF>\n"
1254 "</x:xmpmeta>\n"
1255 "<?xpacket end=\"w\"?>\n"
1256 },
1257 XMPProfileMagick[4]= { (char) 0xef, (char) 0xbb, (char) 0xbf, (char) 0x00 };
1258 RestoreMSCWarning
1259
1260 char
1261 basename[MagickPathExtent],
1262 buffer[MagickPathExtent],
1263 *escape,
1264 date[MagickPathExtent],
1265 **labels,
1266 page_geometry[MagickPathExtent],
1267 *url;
1268
1269 CompressionType
1270 compression;
1271
1272 const char
1273 *device,
1274 *option,
1275 *value;
1276
1277 const StringInfo
1278 *profile;
1279
1280 double
1281 pointsize;
1282
1283 GeometryInfo
1284 geometry_info;
1285
1286 Image
1287 *next,
1288 *tile_image;
1289
1290 MagickBooleanType
1291 status;
1292
1293 MagickOffsetType
1294 offset,
1295 scene,
1296 *xref;
1297
1298 MagickSizeType
1299 number_pixels;
1300
1301 MagickStatusType
1302 flags;
1303
1304 PointInfo
1305 delta,
1306 resolution,
1307 scale;
1308
1309 RectangleInfo
1310 geometry,
1311 media_info,
1312 page_info;
1313
1314 register const Quantum
1315 *p;
1316
1317 register unsigned char
1318 *q;
1319
1320 register ssize_t
1321 i,
1322 x;
1323
1324 size_t
1325 channels,
1326 imageListLength,
1327 info_id,
1328 length,
1329 object,
1330 pages_id,
1331 root_id,
1332 text_size,
1333 version;
1334
1335 ssize_t
1336 count,
1337 page_count,
1338 y;
1339
1340 struct tm
1341 local_time;
1342
1343 time_t
1344 seconds;
1345
1346 unsigned char
1347 *pixels;
1348
1349 /*
1350 Open output image file.
1351 */
1352 assert(image_info != (const ImageInfo *) NULL);
1353 assert(image_info->signature == MagickCoreSignature);
1354 assert(image != (Image *) NULL);
1355 assert(image->signature == MagickCoreSignature);
1356 if (image->debug != MagickFalse)
1357 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1358 assert(exception != (ExceptionInfo *) NULL);
1359 assert(exception->signature == MagickCoreSignature);
1360 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1361 if (status == MagickFalse)
1362 return(status);
1363 /*
1364 Allocate X ref memory.
1365 */
1366 xref=(MagickOffsetType *) AcquireQuantumMemory(2048UL,sizeof(*xref));
1367 if (xref == (MagickOffsetType *) NULL)
1368 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1369 (void) memset(xref,0,2048UL*sizeof(*xref));
1370 /*
1371 Write Info object.
1372 */
1373 object=0;
1374 version=3;
1375 if (image_info->compression == JPEG2000Compression)
1376 version=(size_t) MagickMax(version,5);
1377 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1378 if (next->alpha_trait != UndefinedPixelTrait)
1379 version=(size_t) MagickMax(version,4);
1380 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1381 version=(size_t) MagickMax(version,6);
1382 profile=GetImageProfile(image,"icc");
1383 if (profile != (StringInfo *) NULL)
1384 version=(size_t) MagickMax(version,7);
1385 (void) FormatLocaleString(buffer,MagickPathExtent,"%%PDF-1.%.20g \n",(double)
1386 version);
1387 (void) WriteBlobString(image,buffer);
1388 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1389 {
1390 (void) WriteBlobByte(image,'%');
1391 (void) WriteBlobByte(image,0xe2);
1392 (void) WriteBlobByte(image,0xe3);
1393 (void) WriteBlobByte(image,0xcf);
1394 (void) WriteBlobByte(image,0xd3);
1395 (void) WriteBlobByte(image,'\n');
1396 }
1397 /*
1398 Write Catalog object.
1399 */
1400 xref[object++]=TellBlob(image);
1401 root_id=object;
1402 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1403 object);
1404 (void) WriteBlobString(image,buffer);
1405 (void) WriteBlobString(image,"<<\n");
1406 if (LocaleCompare(image_info->magick,"PDFA") != 0)
1407 (void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n",
1408 (double) object+1);
1409 else
1410 {
1411 (void) FormatLocaleString(buffer,MagickPathExtent,"/Metadata %.20g 0 R\n",
1412 (double) object+1);
1413 (void) WriteBlobString(image,buffer);
1414 (void) FormatLocaleString(buffer,MagickPathExtent,"/Pages %.20g 0 R\n",
1415 (double) object+2);
1416 }
1417 (void) WriteBlobString(image,buffer);
1418 (void) WriteBlobString(image,"/Type /Catalog");
1419 option=GetImageOption(image_info,"pdf:page-direction");
1420 if ((option != (const char *) NULL) &&
1421 (LocaleCompare(option,"right-to-left") == 0))
1422 (void) WriteBlobString(image,"/ViewerPreferences<</PageDirection/R2L>>\n");
1423 (void) WriteBlobString(image,"\n");
1424 (void) WriteBlobString(image,">>\n");
1425 (void) WriteBlobString(image,"endobj\n");
1426 GetPathComponent(image->filename,BasePath,basename);
1427 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1428 {
1429 char
1430 create_date[MagickPathExtent],
1431 modify_date[MagickPathExtent],
1432 timestamp[MagickPathExtent],
1433 *url,
1434 xmp_profile[MagickPathExtent];
1435
1436 /*
1437 Write XMP object.
1438 */
1439 xref[object++]=TellBlob(image);
1440 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1441 object);
1442 (void) WriteBlobString(image,buffer);
1443 (void) WriteBlobString(image,"<<\n");
1444 (void) WriteBlobString(image,"/Subtype /XML\n");
1445 *modify_date='\0';
1446 value=GetImageProperty(image,"date:modify",exception);
1447 if (value != (const char *) NULL)
1448 (void) CopyMagickString(modify_date,value,MagickPathExtent);
1449 *create_date='\0';
1450 value=GetImageProperty(image,"date:create",exception);
1451 if (value != (const char *) NULL)
1452 (void) CopyMagickString(create_date,value,MagickPathExtent);
1453 (void) FormatMagickTime(time((time_t *) NULL),MagickPathExtent,timestamp);
1454 url=(char *) MagickAuthoritativeURL;
1455 escape=EscapeParenthesis(basename);
1456 i=FormatLocaleString(xmp_profile,MagickPathExtent,XMPProfile,
1457 XMPProfileMagick,modify_date,create_date,timestamp,url,escape,url);
1458 escape=DestroyString(escape);
1459 (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g\n",
1460 (double) i);
1461 (void) WriteBlobString(image,buffer);
1462 (void) WriteBlobString(image,"/Type /Metadata\n");
1463 (void) WriteBlobString(image,">>\nstream\n");
1464 (void) WriteBlobString(image,xmp_profile);
1465 (void) WriteBlobString(image,"\nendstream\n");
1466 (void) WriteBlobString(image,"endobj\n");
1467 }
1468 /*
1469 Write Pages object.
1470 */
1471 xref[object++]=TellBlob(image);
1472 pages_id=object;
1473 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1474 object);
1475 (void) WriteBlobString(image,buffer);
1476 (void) WriteBlobString(image,"<<\n");
1477 (void) WriteBlobString(image,"/Type /Pages\n");
1478 (void) FormatLocaleString(buffer,MagickPathExtent,"/Kids [ %.20g 0 R ",
1479 (double) object+1);
1480 (void) WriteBlobString(image,buffer);
1481 count=(ssize_t) (pages_id+ObjectsPerImage+1);
1482 page_count=1;
1483 if (image_info->adjoin != MagickFalse)
1484 {
1485 Image
1486 *kid_image;
1487
1488 /*
1489 Predict page object id's.
1490 */
1491 kid_image=image;
1492 for ( ; GetNextImageInList(kid_image) != (Image *) NULL; count+=ObjectsPerImage)
1493 {
1494 page_count++;
1495 profile=GetImageProfile(kid_image,"icc");
1496 if (profile != (StringInfo *) NULL)
1497 count+=2;
1498 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 R ",(double)
1499 count);
1500 (void) WriteBlobString(image,buffer);
1501 kid_image=GetNextImageInList(kid_image);
1502 }
1503 xref=(MagickOffsetType *) ResizeQuantumMemory(xref,(size_t) count+2048UL,
1504 sizeof(*xref));
1505 if (xref == (MagickOffsetType *) NULL)
1506 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1507 }
1508 (void) WriteBlobString(image,"]\n");
1509 (void) FormatLocaleString(buffer,MagickPathExtent,"/Count %.20g\n",(double)
1510 page_count);
1511 (void) WriteBlobString(image,buffer);
1512 (void) WriteBlobString(image,">>\n");
1513 (void) WriteBlobString(image,"endobj\n");
1514 scene=0;
1515 imageListLength=GetImageListLength(image);
1516 do
1517 {
1518 MagickBooleanType
1519 has_icc_profile;
1520
1521 profile=GetImageProfile(image,"icc");
1522 has_icc_profile=(profile != (StringInfo *) NULL) ? MagickTrue : MagickFalse;
1523 compression=image->compression;
1524 if (image_info->compression != UndefinedCompression)
1525 compression=image_info->compression;
1526 switch (compression)
1527 {
1528 case FaxCompression:
1529 case Group4Compression:
1530 {
1531 if ((SetImageMonochrome(image,exception) == MagickFalse) ||
1532 (image->alpha_trait != UndefinedPixelTrait))
1533 compression=RLECompression;
1534 break;
1535 }
1536 #if !defined(MAGICKCORE_JPEG_DELEGATE)
1537 case JPEGCompression:
1538 {
1539 compression=RLECompression;
1540 (void) ThrowMagickException(exception,GetMagickModule(),
1541 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)",
1542 image->filename);
1543 break;
1544 }
1545 #endif
1546 #if !defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
1547 case JPEG2000Compression:
1548 {
1549 compression=RLECompression;
1550 (void) ThrowMagickException(exception,GetMagickModule(),
1551 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JP2)",
1552 image->filename);
1553 break;
1554 }
1555 #endif
1556 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1557 case ZipCompression:
1558 {
1559 compression=RLECompression;
1560 (void) ThrowMagickException(exception,GetMagickModule(),
1561 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZLIB)",
1562 image->filename);
1563 break;
1564 }
1565 #endif
1566 case LZWCompression:
1567 {
1568 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1569 compression=RLECompression; /* LZW compression is forbidden */
1570 break;
1571 }
1572 case NoCompression:
1573 {
1574 if (LocaleCompare(image_info->magick,"PDFA") == 0)
1575 compression=RLECompression; /* ASCII 85 compression is forbidden */
1576 break;
1577 }
1578 default:
1579 break;
1580 }
1581 if (compression == JPEG2000Compression)
1582 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1583 /*
1584 Scale relative to dots-per-inch.
1585 */
1586 delta.x=DefaultResolution;
1587 delta.y=DefaultResolution;
1588 resolution.x=image->resolution.x;
1589 resolution.y=image->resolution.y;
1590 if ((resolution.x == 0.0) || (resolution.y == 0.0))
1591 {
1592 flags=ParseGeometry(PSDensityGeometry,&geometry_info);
1593 resolution.x=geometry_info.rho;
1594 resolution.y=geometry_info.sigma;
1595 if ((flags & SigmaValue) == 0)
1596 resolution.y=resolution.x;
1597 }
1598 if (image_info->density != (char *) NULL)
1599 {
1600 flags=ParseGeometry(image_info->density,&geometry_info);
1601 resolution.x=geometry_info.rho;
1602 resolution.y=geometry_info.sigma;
1603 if ((flags & SigmaValue) == 0)
1604 resolution.y=resolution.x;
1605 }
1606 if (image->units == PixelsPerCentimeterResolution)
1607 {
1608 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0);
1609 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0);
1610 }
1611 SetGeometry(image,&geometry);
1612 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g",
1613 (double) image->columns,(double) image->rows);
1614 if (image_info->page != (char *) NULL)
1615 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent);
1616 else
1617 if ((image->page.width != 0) && (image->page.height != 0))
1618 (void) FormatLocaleString(page_geometry,MagickPathExtent,
1619 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
1620 image->page.height,(double) image->page.x,(double) image->page.y);
1621 else
1622 if ((image->gravity != UndefinedGravity) &&
1623 (LocaleCompare(image_info->magick,"PDF") == 0))
1624 (void) CopyMagickString(page_geometry,PSPageGeometry,
1625 MagickPathExtent);
1626 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent);
1627 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
1628 &geometry.width,&geometry.height);
1629 scale.x=(double) (geometry.width*delta.x)/resolution.x;
1630 geometry.width=(size_t) floor(scale.x+0.5);
1631 scale.y=(double) (geometry.height*delta.y)/resolution.y;
1632 geometry.height=(size_t) floor(scale.y+0.5);
1633 (void) ParseAbsoluteGeometry(page_geometry,&media_info);
1634 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception);
1635 if (image->gravity != UndefinedGravity)
1636 {
1637 geometry.x=(-page_info.x);
1638 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows);
1639 }
1640 pointsize=12.0;
1641 if (image_info->pointsize != 0.0)
1642 pointsize=image_info->pointsize;
1643 text_size=0;
1644 value=GetImageProperty(image,"label",exception);
1645 if (value != (const char *) NULL)
1646 text_size=(size_t) (MultilineCensus(value)*pointsize+12);
1647 (void) text_size;
1648 /*
1649 Write Page object.
1650 */
1651 xref[object++]=TellBlob(image);
1652 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1653 object);
1654 (void) WriteBlobString(image,buffer);
1655 (void) WriteBlobString(image,"<<\n");
1656 (void) WriteBlobString(image,"/Type /Page\n");
1657 (void) FormatLocaleString(buffer,MagickPathExtent,"/Parent %.20g 0 R\n",
1658 (double) pages_id);
1659 (void) WriteBlobString(image,buffer);
1660 (void) WriteBlobString(image,"/Resources <<\n");
1661 labels=(char **) NULL;
1662 value=GetImageProperty(image,"label",exception);
1663 if (value != (const char *) NULL)
1664 labels=StringToList(value);
1665 if (labels != (char **) NULL)
1666 {
1667 (void) FormatLocaleString(buffer,MagickPathExtent,
1668 "/Font << /F%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1669 object+4);
1670 (void) WriteBlobString(image,buffer);
1671 }
1672 (void) FormatLocaleString(buffer,MagickPathExtent,
1673 "/XObject << /Im%.20g %.20g 0 R >>\n",(double) image->scene,(double)
1674 object+5);
1675 (void) WriteBlobString(image,buffer);
1676 (void) FormatLocaleString(buffer,MagickPathExtent,"/ProcSet %.20g 0 R >>\n",
1677 (double) object+3);
1678 (void) WriteBlobString(image,buffer);
1679 (void) FormatLocaleString(buffer,MagickPathExtent,
1680 "/MediaBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1681 72.0*media_info.height/resolution.y);
1682 (void) WriteBlobString(image,buffer);
1683 (void) FormatLocaleString(buffer,MagickPathExtent,
1684 "/CropBox [0 0 %g %g]\n",72.0*media_info.width/resolution.x,
1685 72.0*media_info.height/resolution.y);
1686 (void) WriteBlobString(image,buffer);
1687 (void) FormatLocaleString(buffer,MagickPathExtent,"/Contents %.20g 0 R\n",
1688 (double) object+1);
1689 (void) WriteBlobString(image,buffer);
1690 (void) FormatLocaleString(buffer,MagickPathExtent,"/Thumb %.20g 0 R\n",
1691 (double) object+(has_icc_profile != MagickFalse ? 10 : 8));
1692 (void) WriteBlobString(image,buffer);
1693 (void) WriteBlobString(image,">>\n");
1694 (void) WriteBlobString(image,"endobj\n");
1695 /*
1696 Write Contents object.
1697 */
1698 xref[object++]=TellBlob(image);
1699 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1700 object);
1701 (void) WriteBlobString(image,buffer);
1702 (void) WriteBlobString(image,"<<\n");
1703 (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
1704 (double) object+1);
1705 (void) WriteBlobString(image,buffer);
1706 (void) WriteBlobString(image,">>\n");
1707 (void) WriteBlobString(image,"stream\n");
1708 offset=TellBlob(image);
1709 (void) WriteBlobString(image,"q\n");
1710 if (labels != (char **) NULL)
1711 for (i=0; labels[i] != (char *) NULL; i++)
1712 {
1713 (void) WriteBlobString(image,"BT\n");
1714 (void) FormatLocaleString(buffer,MagickPathExtent,"/F%.20g %g Tf\n",
1715 (double) image->scene,pointsize);
1716 (void) WriteBlobString(image,buffer);
1717 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g Td\n",
1718 (double) geometry.x,(double) (geometry.y+geometry.height+i*pointsize+
1719 12));
1720 (void) WriteBlobString(image,buffer);
1721 (void) FormatLocaleString(buffer,MagickPathExtent,"(%s) Tj\n",
1722 labels[i]);
1723 (void) WriteBlobString(image,buffer);
1724 (void) WriteBlobString(image,"ET\n");
1725 labels[i]=DestroyString(labels[i]);
1726 }
1727 (void) FormatLocaleString(buffer,MagickPathExtent,
1728 "%g 0 0 %g %.20g %.20g cm\n",scale.x,scale.y,(double) geometry.x,
1729 (double) geometry.y);
1730 (void) WriteBlobString(image,buffer);
1731 (void) FormatLocaleString(buffer,MagickPathExtent,"/Im%.20g Do\n",(double)
1732 image->scene);
1733 (void) WriteBlobString(image,buffer);
1734 (void) WriteBlobString(image,"Q\n");
1735 offset=TellBlob(image)-offset;
1736 (void) WriteBlobString(image,"\nendstream\n");
1737 (void) WriteBlobString(image,"endobj\n");
1738 /*
1739 Write Length object.
1740 */
1741 xref[object++]=TellBlob(image);
1742 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1743 object);
1744 (void) WriteBlobString(image,buffer);
1745 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
1746 offset);
1747 (void) WriteBlobString(image,buffer);
1748 (void) WriteBlobString(image,"endobj\n");
1749 /*
1750 Write Procset object.
1751 */
1752 xref[object++]=TellBlob(image);
1753 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1754 object);
1755 (void) WriteBlobString(image,buffer);
1756 if ((image->storage_class == DirectClass) || (image->colors > 256))
1757 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageC",MagickPathExtent);
1758 else
1759 if ((compression == FaxCompression) || (compression == Group4Compression))
1760 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageB",MagickPathExtent);
1761 else
1762 (void) CopyMagickString(buffer,"[ /PDF /Text /ImageI",MagickPathExtent);
1763 (void) WriteBlobString(image,buffer);
1764 (void) WriteBlobString(image," ]\n");
1765 (void) WriteBlobString(image,"endobj\n");
1766 /*
1767 Write Font object.
1768 */
1769 xref[object++]=TellBlob(image);
1770 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1771 object);
1772 (void) WriteBlobString(image,buffer);
1773 (void) WriteBlobString(image,"<<\n");
1774 if (labels != (char **) NULL)
1775 {
1776 (void) WriteBlobString(image,"/Type /Font\n");
1777 (void) WriteBlobString(image,"/Subtype /Type1\n");
1778 (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /F%.20g\n",
1779 (double) image->scene);
1780 (void) WriteBlobString(image,buffer);
1781 (void) WriteBlobString(image,"/BaseFont /Helvetica\n");
1782 (void) WriteBlobString(image,"/Encoding /MacRomanEncoding\n");
1783 labels=(char **) RelinquishMagickMemory(labels);
1784 }
1785 (void) WriteBlobString(image,">>\n");
1786 (void) WriteBlobString(image,"endobj\n");
1787 /*
1788 Write XObject object.
1789 */
1790 xref[object++]=TellBlob(image);
1791 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
1792 object);
1793 (void) WriteBlobString(image,buffer);
1794 (void) WriteBlobString(image,"<<\n");
1795 (void) WriteBlobString(image,"/Type /XObject\n");
1796 (void) WriteBlobString(image,"/Subtype /Image\n");
1797 (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Im%.20g\n",
1798 (double) image->scene);
1799 (void) WriteBlobString(image,buffer);
1800 switch (compression)
1801 {
1802 case NoCompression:
1803 {
1804 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1805 "ASCII85Decode");
1806 break;
1807 }
1808 case JPEGCompression:
1809 {
1810 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode");
1811 if (image->colorspace != CMYKColorspace)
1812 break;
1813 (void) WriteBlobString(image,buffer);
1814 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1815 MagickPathExtent);
1816 break;
1817 }
1818 case JPEG2000Compression:
1819 {
1820 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode");
1821 if (image->colorspace != CMYKColorspace)
1822 break;
1823 (void) WriteBlobString(image,buffer);
1824 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
1825 MagickPathExtent);
1826 break;
1827 }
1828 case LZWCompression:
1829 {
1830 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode");
1831 break;
1832 }
1833 case ZipCompression:
1834 {
1835 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1836 "FlateDecode");
1837 break;
1838 }
1839 case FaxCompression:
1840 case Group4Compression:
1841 {
1842 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
1843 MagickPathExtent);
1844 (void) WriteBlobString(image,buffer);
1845 (void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << "
1846 "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
1847 (double) image->columns,(double) image->rows);
1848 break;
1849 }
1850 default:
1851 {
1852 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
1853 "RunLengthDecode");
1854 break;
1855 }
1856 }
1857 (void) WriteBlobString(image,buffer);
1858 (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double)
1859 image->columns);
1860 (void) WriteBlobString(image,buffer);
1861 (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double)
1862 image->rows);
1863 (void) WriteBlobString(image,buffer);
1864 (void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n",
1865 (double) object+2);
1866 (void) WriteBlobString(image,buffer);
1867 (void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n",
1868 (compression == FaxCompression) || (compression == Group4Compression) ?
1869 1 : 8);
1870 (void) WriteBlobString(image,buffer);
1871 if (image->alpha_trait != UndefinedPixelTrait)
1872 {
1873 (void) FormatLocaleString(buffer,MagickPathExtent,"/SMask %.20g 0 R\n",
1874 (double) object+(has_icc_profile != MagickFalse ? 9 : 7));
1875 (void) WriteBlobString(image,buffer);
1876 }
1877 (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
1878 (double) object+1);
1879 (void) WriteBlobString(image,buffer);
1880 (void) WriteBlobString(image,">>\n");
1881 (void) WriteBlobString(image,"stream\n");
1882 offset=TellBlob(image);
1883 number_pixels=(MagickSizeType) image->columns*image->rows;
1884 if ((4*number_pixels) != (MagickSizeType) ((size_t) (4*number_pixels)))
1885 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
1886 if ((compression == FaxCompression) || (compression == Group4Compression) ||
1887 ((image_info->type != TrueColorType) &&
1888 (SetImageGray(image,exception) != MagickFalse)))
1889 {
1890 switch (compression)
1891 {
1892 case FaxCompression:
1893 case Group4Compression:
1894 {
1895 if (LocaleCompare(CCITTParam,"0") == 0)
1896 {
1897 (void) HuffmanEncodeImage(image_info,image,image,exception);
1898 break;
1899 }
1900 (void) Huffman2DEncodeImage(image_info,image,image,exception);
1901 break;
1902 }
1903 case JPEGCompression:
1904 {
1905 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
1906 if (status == MagickFalse)
1907 {
1908 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
1909 (void) CloseBlob(image);
1910 return(MagickFalse);
1911 }
1912 break;
1913 }
1914 case JPEG2000Compression:
1915 {
1916 status=InjectImageBlob(image_info,image,image,"jp2",exception);
1917 if (status == MagickFalse)
1918 {
1919 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
1920 (void) CloseBlob(image);
1921 return(MagickFalse);
1922 }
1923 break;
1924 }
1925 case RLECompression:
1926 default:
1927 {
1928 MemoryInfo
1929 *pixel_info;
1930
1931 /*
1932 Allocate pixel array.
1933 */
1934 length=(size_t) number_pixels;
1935 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1936 if (pixel_info == (MemoryInfo *) NULL)
1937 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
1938 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1939 /*
1940 Dump Runlength encoded pixels.
1941 */
1942 q=pixels;
1943 for (y=0; y < (ssize_t) image->rows; y++)
1944 {
1945 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1946 if (p == (const Quantum *) NULL)
1947 break;
1948 for (x=0; x < (ssize_t) image->columns; x++)
1949 {
1950 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p)));
1951 p+=GetPixelChannels(image);
1952 }
1953 if (image->previous == (Image *) NULL)
1954 {
1955 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1956 y,image->rows);
1957 if (status == MagickFalse)
1958 break;
1959 }
1960 }
1961 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1962 if (compression == ZipCompression)
1963 status=ZLIBEncodeImage(image,length,pixels,exception);
1964 else
1965 #endif
1966 if (compression == LZWCompression)
1967 status=LZWEncodeImage(image,length,pixels,exception);
1968 else
1969 status=PackbitsEncodeImage(image,length,pixels,exception);
1970 pixel_info=RelinquishVirtualMemory(pixel_info);
1971 if (status == MagickFalse)
1972 {
1973 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
1974 (void) CloseBlob(image);
1975 return(MagickFalse);
1976 }
1977 break;
1978 }
1979 case NoCompression:
1980 {
1981 /*
1982 Dump uncompressed PseudoColor packets.
1983 */
1984 Ascii85Initialize(image);
1985 for (y=0; y < (ssize_t) image->rows; y++)
1986 {
1987 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1988 if (p == (const Quantum *) NULL)
1989 break;
1990 for (x=0; x < (ssize_t) image->columns; x++)
1991 {
1992 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
1993 GetPixelLuma(image,p))));
1994 p+=GetPixelChannels(image);
1995 }
1996 if (image->previous == (Image *) NULL)
1997 {
1998 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1999 y,image->rows);
2000 if (status == MagickFalse)
2001 break;
2002 }
2003 }
2004 Ascii85Flush(image);
2005 break;
2006 }
2007 }
2008 }
2009 else
2010 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2011 (compression == JPEGCompression) ||
2012 (compression == JPEG2000Compression))
2013 switch (compression)
2014 {
2015 case JPEGCompression:
2016 {
2017 status=InjectImageBlob(image_info,image,image,"jpeg",exception);
2018 if (status == MagickFalse)
2019 {
2020 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2021 (void) CloseBlob(image);
2022 return(MagickFalse);
2023 }
2024 break;
2025 }
2026 case JPEG2000Compression:
2027 {
2028 status=InjectImageBlob(image_info,image,image,"jp2",exception);
2029 if (status == MagickFalse)
2030 {
2031 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2032 (void) CloseBlob(image);
2033 return(MagickFalse);
2034 }
2035 break;
2036 }
2037 case RLECompression:
2038 default:
2039 {
2040 MemoryInfo
2041 *pixel_info;
2042
2043 /*
2044 Allocate pixel array.
2045 */
2046 length=(size_t) number_pixels;
2047 length*=image->colorspace == CMYKColorspace ? 4UL : 3UL;
2048 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2049 if (pixel_info == (MemoryInfo *) NULL)
2050 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
2051 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2052 /*
2053 Dump runoffset encoded pixels.
2054 */
2055 q=pixels;
2056 for (y=0; y < (ssize_t) image->rows; y++)
2057 {
2058 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2059 if (p == (const Quantum *) NULL)
2060 break;
2061 for (x=0; x < (ssize_t) image->columns; x++)
2062 {
2063 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
2064 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
2065 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
2066 if (image->colorspace == CMYKColorspace)
2067 *q++=ScaleQuantumToChar(GetPixelBlack(image,p));
2068 p+=GetPixelChannels(image);
2069 }
2070 if (image->previous == (Image *) NULL)
2071 {
2072 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
2073 y,image->rows);
2074 if (status == MagickFalse)
2075 break;
2076 }
2077 }
2078 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2079 if (compression == ZipCompression)
2080 status=ZLIBEncodeImage(image,length,pixels,exception);
2081 else
2082 #endif
2083 if (compression == LZWCompression)
2084 status=LZWEncodeImage(image,length,pixels,exception);
2085 else
2086 status=PackbitsEncodeImage(image,length,pixels,exception);
2087 pixel_info=RelinquishVirtualMemory(pixel_info);
2088 if (status == MagickFalse)
2089 {
2090 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2091 (void) CloseBlob(image);
2092 return(MagickFalse);
2093 }
2094 break;
2095 }
2096 case NoCompression:
2097 {
2098 /*
2099 Dump uncompressed DirectColor packets.
2100 */
2101 Ascii85Initialize(image);
2102 for (y=0; y < (ssize_t) image->rows; y++)
2103 {
2104 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2105 if (p == (const Quantum *) NULL)
2106 break;
2107 for (x=0; x < (ssize_t) image->columns; x++)
2108 {
2109 Ascii85Encode(image,ScaleQuantumToChar(GetPixelRed(image,p)));
2110 Ascii85Encode(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
2111 Ascii85Encode(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
2112 if (image->colorspace == CMYKColorspace)
2113 Ascii85Encode(image,ScaleQuantumToChar(
2114 GetPixelBlack(image,p)));
2115 p+=GetPixelChannels(image);
2116 }
2117 if (image->previous == (Image *) NULL)
2118 {
2119 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
2120 y,image->rows);
2121 if (status == MagickFalse)
2122 break;
2123 }
2124 }
2125 Ascii85Flush(image);
2126 break;
2127 }
2128 }
2129 else
2130 {
2131 /*
2132 Dump number of colors and colormap.
2133 */
2134 switch (compression)
2135 {
2136 case RLECompression:
2137 default:
2138 {
2139 MemoryInfo
2140 *pixel_info;
2141
2142 /*
2143 Allocate pixel array.
2144 */
2145 length=(size_t) number_pixels;
2146 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2147 if (pixel_info == (MemoryInfo *) NULL)
2148 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
2149 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2150 /*
2151 Dump Runlength encoded pixels.
2152 */
2153 q=pixels;
2154 for (y=0; y < (ssize_t) image->rows; y++)
2155 {
2156 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2157 if (p == (const Quantum *) NULL)
2158 break;
2159 for (x=0; x < (ssize_t) image->columns; x++)
2160 {
2161 *q++=(unsigned char) GetPixelIndex(image,p);
2162 p+=GetPixelChannels(image);
2163 }
2164 if (image->previous == (Image *) NULL)
2165 {
2166 status=SetImageProgress(image,SaveImageTag,
2167 (MagickOffsetType) y,image->rows);
2168 if (status == MagickFalse)
2169 break;
2170 }
2171 }
2172 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2173 if (compression == ZipCompression)
2174 status=ZLIBEncodeImage(image,length,pixels,exception);
2175 else
2176 #endif
2177 if (compression == LZWCompression)
2178 status=LZWEncodeImage(image,length,pixels,exception);
2179 else
2180 status=PackbitsEncodeImage(image,length,pixels,exception);
2181 pixel_info=RelinquishVirtualMemory(pixel_info);
2182 if (status == MagickFalse)
2183 {
2184 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2185 (void) CloseBlob(image);
2186 return(MagickFalse);
2187 }
2188 break;
2189 }
2190 case NoCompression:
2191 {
2192 /*
2193 Dump uncompressed PseudoColor packets.
2194 */
2195 Ascii85Initialize(image);
2196 for (y=0; y < (ssize_t) image->rows; y++)
2197 {
2198 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2199 if (p == (const Quantum *) NULL)
2200 break;
2201 for (x=0; x < (ssize_t) image->columns; x++)
2202 {
2203 Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p));
2204 p+=GetPixelChannels(image);
2205 }
2206 if (image->previous == (Image *) NULL)
2207 {
2208 status=SetImageProgress(image,SaveImageTag,
2209 (MagickOffsetType) y,image->rows);
2210 if (status == MagickFalse)
2211 break;
2212 }
2213 }
2214 Ascii85Flush(image);
2215 break;
2216 }
2217 }
2218 }
2219 offset=TellBlob(image)-offset;
2220 (void) WriteBlobString(image,"\nendstream\n");
2221 (void) WriteBlobString(image,"endobj\n");
2222 /*
2223 Write Length object.
2224 */
2225 xref[object++]=TellBlob(image);
2226 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2227 object);
2228 (void) WriteBlobString(image,buffer);
2229 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2230 offset);
2231 (void) WriteBlobString(image,buffer);
2232 (void) WriteBlobString(image,"endobj\n");
2233 /*
2234 Write Colorspace object.
2235 */
2236 xref[object++]=TellBlob(image);
2237 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2238 object);
2239 (void) WriteBlobString(image,buffer);
2240 device="DeviceRGB";
2241 channels=0;
2242 if (image->colorspace == CMYKColorspace)
2243 {
2244 device="DeviceCMYK";
2245 channels=4;
2246 }
2247 else
2248 if ((compression == FaxCompression) ||
2249 (compression == Group4Compression) ||
2250 ((image_info->type != TrueColorType) &&
2251 (SetImageGray(image,exception) != MagickFalse)))
2252 {
2253 device="DeviceGray";
2254 channels=1;
2255 }
2256 else
2257 if ((image->storage_class == DirectClass) ||
2258 (image->colors > 256) || (compression == JPEGCompression) ||
2259 (compression == JPEG2000Compression))
2260 {
2261 device="DeviceRGB";
2262 channels=3;
2263 }
2264 profile=GetImageProfile(image,"icc");
2265 if ((profile == (StringInfo *) NULL) || (channels == 0))
2266 {
2267 if (channels != 0)
2268 (void) FormatLocaleString(buffer,MagickPathExtent,"/%s\n",device);
2269 else
2270 (void) FormatLocaleString(buffer,MagickPathExtent,
2271 "[ /Indexed /%s %.20g %.20g 0 R ]\n",device,(double) image->colors-
2272 1,(double) object+3);
2273 (void) WriteBlobString(image,buffer);
2274 }
2275 else
2276 {
2277 const unsigned char
2278 *p;
2279
2280 /*
2281 Write ICC profile.
2282 */
2283 (void) FormatLocaleString(buffer,MagickPathExtent,
2284 "[/ICCBased %.20g 0 R]\n",(double) object+1);
2285 (void) WriteBlobString(image,buffer);
2286 (void) WriteBlobString(image,"endobj\n");
2287 xref[object++]=TellBlob(image);
2288 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",
2289 (double) object);
2290 (void) WriteBlobString(image,buffer);
2291 (void) FormatLocaleString(buffer,MagickPathExtent,"<<\n/N %.20g\n"
2292 "/Filter /ASCII85Decode\n/Length %.20g 0 R\n/Alternate /%s\n>>\n"
2293 "stream\n",(double) channels,(double) object+1,device);
2294 (void) WriteBlobString(image,buffer);
2295 offset=TellBlob(image);
2296 Ascii85Initialize(image);
2297 p=GetStringInfoDatum(profile);
2298 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
2299 Ascii85Encode(image,(unsigned char) *p++);
2300 Ascii85Flush(image);
2301 offset=TellBlob(image)-offset;
2302 (void) WriteBlobString(image,"endstream\n");
2303 (void) WriteBlobString(image,"endobj\n");
2304 /*
2305 Write Length object.
2306 */
2307 xref[object++]=TellBlob(image);
2308 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",
2309 (double) object);
2310 (void) WriteBlobString(image,buffer);
2311 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2312 offset);
2313 (void) WriteBlobString(image,buffer);
2314 }
2315 (void) WriteBlobString(image,"endobj\n");
2316 /*
2317 Write Thumb object.
2318 */
2319 SetGeometry(image,&geometry);
2320 (void) ParseMetaGeometry("106x106+0+0>",&geometry.x,&geometry.y,
2321 &geometry.width,&geometry.height);
2322 tile_image=ThumbnailImage(image,geometry.width,geometry.height,exception);
2323 if (tile_image == (Image *) NULL)
2324 return(MagickFalse);
2325 xref[object++]=TellBlob(image);
2326 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2327 object);
2328 (void) WriteBlobString(image,buffer);
2329 (void) WriteBlobString(image,"<<\n");
2330 switch (compression)
2331 {
2332 case NoCompression:
2333 {
2334 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2335 "ASCII85Decode");
2336 break;
2337 }
2338 case JPEGCompression:
2339 {
2340 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"DCTDecode");
2341 if (image->colorspace != CMYKColorspace)
2342 break;
2343 (void) WriteBlobString(image,buffer);
2344 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2345 MagickPathExtent);
2346 break;
2347 }
2348 case JPEG2000Compression:
2349 {
2350 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"JPXDecode");
2351 if (image->colorspace != CMYKColorspace)
2352 break;
2353 (void) WriteBlobString(image,buffer);
2354 (void) CopyMagickString(buffer,"/Decode [1 0 1 0 1 0 1 0]\n",
2355 MagickPathExtent);
2356 break;
2357 }
2358 case LZWCompression:
2359 {
2360 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,"LZWDecode");
2361 break;
2362 }
2363 case ZipCompression:
2364 {
2365 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2366 "FlateDecode");
2367 break;
2368 }
2369 case FaxCompression:
2370 case Group4Compression:
2371 {
2372 (void) CopyMagickString(buffer,"/Filter [ /CCITTFaxDecode ]\n",
2373 MagickPathExtent);
2374 (void) WriteBlobString(image,buffer);
2375 (void) FormatLocaleString(buffer,MagickPathExtent,"/DecodeParms [ << "
2376 "/K %s /BlackIs1 false /Columns %.20g /Rows %.20g >> ]\n",CCITTParam,
2377 (double) tile_image->columns,(double) tile_image->rows);
2378 break;
2379 }
2380 default:
2381 {
2382 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2383 "RunLengthDecode");
2384 break;
2385 }
2386 }
2387 (void) WriteBlobString(image,buffer);
2388 (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",(double)
2389 tile_image->columns);
2390 (void) WriteBlobString(image,buffer);
2391 (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",(double)
2392 tile_image->rows);
2393 (void) WriteBlobString(image,buffer);
2394 (void) FormatLocaleString(buffer,MagickPathExtent,"/ColorSpace %.20g 0 R\n",
2395 (double) object-(has_icc_profile != MagickFalse ? 3 : 1));
2396 (void) WriteBlobString(image,buffer);
2397 (void) FormatLocaleString(buffer,MagickPathExtent,"/BitsPerComponent %d\n",
2398 (compression == FaxCompression) || (compression == Group4Compression) ?
2399 1 : 8);
2400 (void) WriteBlobString(image,buffer);
2401 (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2402 (double) object+1);
2403 (void) WriteBlobString(image,buffer);
2404 (void) WriteBlobString(image,">>\n");
2405 (void) WriteBlobString(image,"stream\n");
2406 offset=TellBlob(image);
2407 number_pixels=(MagickSizeType) tile_image->columns*tile_image->rows;
2408 if ((compression == FaxCompression) ||
2409 (compression == Group4Compression) ||
2410 ((image_info->type != TrueColorType) &&
2411 (SetImageGray(tile_image,exception) != MagickFalse)))
2412 {
2413 switch (compression)
2414 {
2415 case FaxCompression:
2416 case Group4Compression:
2417 {
2418 if (LocaleCompare(CCITTParam,"0") == 0)
2419 {
2420 (void) HuffmanEncodeImage(image_info,image,tile_image,
2421 exception);
2422 break;
2423 }
2424 (void) Huffman2DEncodeImage(image_info,image,tile_image,exception);
2425 break;
2426 }
2427 case JPEGCompression:
2428 {
2429 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2430 exception);
2431 if (status == MagickFalse)
2432 {
2433 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2434 (void) CloseBlob(image);
2435 return(MagickFalse);
2436 }
2437 break;
2438 }
2439 case JPEG2000Compression:
2440 {
2441 status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
2442 if (status == MagickFalse)
2443 {
2444 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2445 (void) CloseBlob(image);
2446 return(MagickFalse);
2447 }
2448 break;
2449 }
2450 case RLECompression:
2451 default:
2452 {
2453 MemoryInfo
2454 *pixel_info;
2455
2456 /*
2457 Allocate pixel array.
2458 */
2459 length=(size_t) number_pixels;
2460 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2461 if (pixel_info == (MemoryInfo *) NULL)
2462 {
2463 tile_image=DestroyImage(tile_image);
2464 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
2465 }
2466 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2467 /*
2468 Dump runlength encoded pixels.
2469 */
2470 q=pixels;
2471 for (y=0; y < (ssize_t) tile_image->rows; y++)
2472 {
2473 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2474 exception);
2475 if (p == (const Quantum *) NULL)
2476 break;
2477 for (x=0; x < (ssize_t) tile_image->columns; x++)
2478 {
2479 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2480 tile_image,p)));
2481 p+=GetPixelChannels(tile_image);
2482 }
2483 }
2484 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2485 if (compression == ZipCompression)
2486 status=ZLIBEncodeImage(image,length,pixels,exception);
2487 else
2488 #endif
2489 if (compression == LZWCompression)
2490 status=LZWEncodeImage(image,length,pixels,exception);
2491 else
2492 status=PackbitsEncodeImage(image,length,pixels,exception);
2493 pixel_info=RelinquishVirtualMemory(pixel_info);
2494 if (status == MagickFalse)
2495 {
2496 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2497 (void) CloseBlob(image);
2498 return(MagickFalse);
2499 }
2500 break;
2501 }
2502 case NoCompression:
2503 {
2504 /*
2505 Dump uncompressed PseudoColor packets.
2506 */
2507 Ascii85Initialize(image);
2508 for (y=0; y < (ssize_t) tile_image->rows; y++)
2509 {
2510 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2511 exception);
2512 if (p == (const Quantum *) NULL)
2513 break;
2514 for (x=0; x < (ssize_t) tile_image->columns; x++)
2515 {
2516 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2517 GetPixelLuma(tile_image,p))));
2518 p+=GetPixelChannels(tile_image);
2519 }
2520 }
2521 Ascii85Flush(image);
2522 break;
2523 }
2524 }
2525 }
2526 else
2527 if ((tile_image->storage_class == DirectClass) ||
2528 (tile_image->colors > 256) || (compression == JPEGCompression) ||
2529 (compression == JPEG2000Compression))
2530 switch (compression)
2531 {
2532 case JPEGCompression:
2533 {
2534 status=InjectImageBlob(image_info,image,tile_image,"jpeg",
2535 exception);
2536 if (status == MagickFalse)
2537 {
2538 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2539 (void) CloseBlob(image);
2540 return(MagickFalse);
2541 }
2542 break;
2543 }
2544 case JPEG2000Compression:
2545 {
2546 status=InjectImageBlob(image_info,image,tile_image,"jp2",exception);
2547 if (status == MagickFalse)
2548 {
2549 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2550 (void) CloseBlob(image);
2551 return(MagickFalse);
2552 }
2553 break;
2554 }
2555 case RLECompression:
2556 default:
2557 {
2558 MemoryInfo
2559 *pixel_info;
2560
2561 /*
2562 Allocate pixel array.
2563 */
2564 length=(size_t) number_pixels;
2565 length*=tile_image->colorspace == CMYKColorspace ? 4UL : 3UL;
2566 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2567 if (pixel_info == (MemoryInfo *) NULL)
2568 {
2569 tile_image=DestroyImage(tile_image);
2570 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
2571 }
2572 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2573 /*
2574 Dump runlength encoded pixels.
2575 */
2576 q=pixels;
2577 for (y=0; y < (ssize_t) tile_image->rows; y++)
2578 {
2579 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2580 exception);
2581 if (p == (const Quantum *) NULL)
2582 break;
2583 for (x=0; x < (ssize_t) tile_image->columns; x++)
2584 {
2585 *q++=ScaleQuantumToChar(GetPixelRed(tile_image,p));
2586 *q++=ScaleQuantumToChar(GetPixelGreen(tile_image,p));
2587 *q++=ScaleQuantumToChar(GetPixelBlue(tile_image,p));
2588 if (tile_image->colorspace == CMYKColorspace)
2589 *q++=ScaleQuantumToChar(GetPixelBlack(tile_image,p));
2590 p+=GetPixelChannels(tile_image);
2591 }
2592 }
2593 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2594 if (compression == ZipCompression)
2595 status=ZLIBEncodeImage(image,length,pixels,exception);
2596 else
2597 #endif
2598 if (compression == LZWCompression)
2599 status=LZWEncodeImage(image,length,pixels,exception);
2600 else
2601 status=PackbitsEncodeImage(image,length,pixels,exception);
2602 pixel_info=RelinquishVirtualMemory(pixel_info);
2603 if (status == MagickFalse)
2604 {
2605 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2606 (void) CloseBlob(image);
2607 return(MagickFalse);
2608 }
2609 break;
2610 }
2611 case NoCompression:
2612 {
2613 /*
2614 Dump uncompressed DirectColor packets.
2615 */
2616 Ascii85Initialize(image);
2617 for (y=0; y < (ssize_t) tile_image->rows; y++)
2618 {
2619 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2620 exception);
2621 if (p == (const Quantum *) NULL)
2622 break;
2623 for (x=0; x < (ssize_t) tile_image->columns; x++)
2624 {
2625 Ascii85Encode(image,ScaleQuantumToChar(
2626 GetPixelRed(tile_image,p)));
2627 Ascii85Encode(image,ScaleQuantumToChar(
2628 GetPixelGreen(tile_image,p)));
2629 Ascii85Encode(image,ScaleQuantumToChar(
2630 GetPixelBlue(tile_image,p)));
2631 if (image->colorspace == CMYKColorspace)
2632 Ascii85Encode(image,ScaleQuantumToChar(
2633 GetPixelBlack(tile_image,p)));
2634 p+=GetPixelChannels(tile_image);
2635 }
2636 }
2637 Ascii85Flush(image);
2638 break;
2639 }
2640 }
2641 else
2642 {
2643 /*
2644 Dump number of colors and colormap.
2645 */
2646 switch (compression)
2647 {
2648 case RLECompression:
2649 default:
2650 {
2651 MemoryInfo
2652 *pixel_info;
2653
2654 /*
2655 Allocate pixel array.
2656 */
2657 length=(size_t) number_pixels;
2658 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
2659 if (pixel_info == (MemoryInfo *) NULL)
2660 {
2661 tile_image=DestroyImage(tile_image);
2662 ThrowPDFException(ResourceLimitError,
2663 "MemoryAllocationFailed");
2664 }
2665 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2666 /*
2667 Dump runlength encoded pixels.
2668 */
2669 q=pixels;
2670 for (y=0; y < (ssize_t) tile_image->rows; y++)
2671 {
2672 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2673 exception);
2674 if (p == (const Quantum *) NULL)
2675 break;
2676 for (x=0; x < (ssize_t) tile_image->columns; x++)
2677 {
2678 *q++=(unsigned char) GetPixelIndex(tile_image,p);
2679 p+=GetPixelChannels(tile_image);
2680 }
2681 }
2682 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2683 if (compression == ZipCompression)
2684 status=ZLIBEncodeImage(image,length,pixels,exception);
2685 else
2686 #endif
2687 if (compression == LZWCompression)
2688 status=LZWEncodeImage(image,length,pixels,exception);
2689 else
2690 status=PackbitsEncodeImage(image,length,pixels,exception);
2691 pixel_info=RelinquishVirtualMemory(pixel_info);
2692 if (status == MagickFalse)
2693 {
2694 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2695 (void) CloseBlob(image);
2696 return(MagickFalse);
2697 }
2698 break;
2699 }
2700 case NoCompression:
2701 {
2702 /*
2703 Dump uncompressed PseudoColor packets.
2704 */
2705 Ascii85Initialize(image);
2706 for (y=0; y < (ssize_t) tile_image->rows; y++)
2707 {
2708 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,1,
2709 exception);
2710 if (p == (const Quantum *) NULL)
2711 break;
2712 for (x=0; x < (ssize_t) tile_image->columns; x++)
2713 {
2714 Ascii85Encode(image,(unsigned char)
2715 GetPixelIndex(tile_image,p));
2716 p+=GetPixelChannels(image);
2717 }
2718 }
2719 Ascii85Flush(image);
2720 break;
2721 }
2722 }
2723 }
2724 tile_image=DestroyImage(tile_image);
2725 offset=TellBlob(image)-offset;
2726 (void) WriteBlobString(image,"\nendstream\n");
2727 (void) WriteBlobString(image,"endobj\n");
2728 /*
2729 Write Length object.
2730 */
2731 xref[object++]=TellBlob(image);
2732 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2733 object);
2734 (void) WriteBlobString(image,buffer);
2735 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2736 offset);
2737 (void) WriteBlobString(image,buffer);
2738 (void) WriteBlobString(image,"endobj\n");
2739 xref[object++]=TellBlob(image);
2740 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2741 object);
2742 (void) WriteBlobString(image,buffer);
2743 (void) WriteBlobString(image,"<<\n");
2744 if ((image->storage_class == DirectClass) || (image->colors > 256) ||
2745 (compression == FaxCompression) || (compression == Group4Compression))
2746 (void) WriteBlobString(image,">>\n");
2747 else
2748 {
2749 /*
2750 Write Colormap object.
2751 */
2752 if (compression == NoCompression)
2753 (void) WriteBlobString(image,"/Filter [ /ASCII85Decode ]\n");
2754 (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2755 (double) object+1);
2756 (void) WriteBlobString(image,buffer);
2757 (void) WriteBlobString(image,">>\n");
2758 (void) WriteBlobString(image,"stream\n");
2759 offset=TellBlob(image);
2760 if (compression == NoCompression)
2761 Ascii85Initialize(image);
2762 for (i=0; i < (ssize_t) image->colors; i++)
2763 {
2764 if (compression == NoCompression)
2765 {
2766 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2767 image->colormap[i].red)));
2768 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2769 image->colormap[i].green)));
2770 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum(
2771 image->colormap[i].blue)));
2772 continue;
2773 }
2774 (void) WriteBlobByte(image,ScaleQuantumToChar(
2775 ClampToQuantum(image->colormap[i].red)));
2776 (void) WriteBlobByte(image,ScaleQuantumToChar(
2777 ClampToQuantum(image->colormap[i].green)));
2778 (void) WriteBlobByte(image,ScaleQuantumToChar(
2779 ClampToQuantum(image->colormap[i].blue)));
2780 }
2781 if (compression == NoCompression)
2782 Ascii85Flush(image);
2783 offset=TellBlob(image)-offset;
2784 (void) WriteBlobString(image,"\nendstream\n");
2785 }
2786 (void) WriteBlobString(image,"endobj\n");
2787 /*
2788 Write Length object.
2789 */
2790 xref[object++]=TellBlob(image);
2791 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2792 object);
2793 (void) WriteBlobString(image,buffer);
2794 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2795 offset);
2796 (void) WriteBlobString(image,buffer);
2797 (void) WriteBlobString(image,"endobj\n");
2798 /*
2799 Write softmask object.
2800 */
2801 xref[object++]=TellBlob(image);
2802 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2803 object);
2804 (void) WriteBlobString(image,buffer);
2805 (void) WriteBlobString(image,"<<\n");
2806 if (image->alpha_trait == UndefinedPixelTrait)
2807 (void) WriteBlobString(image,">>\n");
2808 else
2809 {
2810 (void) WriteBlobString(image,"/Type /XObject\n");
2811 (void) WriteBlobString(image,"/Subtype /Image\n");
2812 (void) FormatLocaleString(buffer,MagickPathExtent,"/Name /Ma%.20g\n",
2813 (double) image->scene);
2814 (void) WriteBlobString(image,buffer);
2815 switch (compression)
2816 {
2817 case NoCompression:
2818 {
2819 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2820 "ASCII85Decode");
2821 break;
2822 }
2823 case LZWCompression:
2824 {
2825 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2826 "LZWDecode");
2827 break;
2828 }
2829 case ZipCompression:
2830 {
2831 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2832 "FlateDecode");
2833 break;
2834 }
2835 default:
2836 {
2837 (void) FormatLocaleString(buffer,MagickPathExtent,CFormat,
2838 "RunLengthDecode");
2839 break;
2840 }
2841 }
2842 (void) WriteBlobString(image,buffer);
2843 (void) FormatLocaleString(buffer,MagickPathExtent,"/Width %.20g\n",
2844 (double) image->columns);
2845 (void) WriteBlobString(image,buffer);
2846 (void) FormatLocaleString(buffer,MagickPathExtent,"/Height %.20g\n",
2847 (double) image->rows);
2848 (void) WriteBlobString(image,buffer);
2849 (void) WriteBlobString(image,"/ColorSpace /DeviceGray\n");
2850 (void) FormatLocaleString(buffer,MagickPathExtent,
2851 "/BitsPerComponent %d\n",(compression == FaxCompression) ||
2852 (compression == Group4Compression) ? 1 : 8);
2853 (void) WriteBlobString(image,buffer);
2854 (void) FormatLocaleString(buffer,MagickPathExtent,"/Length %.20g 0 R\n",
2855 (double) object+1);
2856 (void) WriteBlobString(image,buffer);
2857 (void) WriteBlobString(image,">>\n");
2858 (void) WriteBlobString(image,"stream\n");
2859 offset=TellBlob(image);
2860 number_pixels=(MagickSizeType) image->columns*image->rows;
2861 switch (compression)
2862 {
2863 case RLECompression:
2864 default:
2865 {
2866 MemoryInfo
2867 *pixel_info;
2868
2869 /*
2870 Allocate pixel array.
2871 */
2872 length=(size_t) number_pixels;
2873 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels));
2874 if (pixel_info == (MemoryInfo *) NULL)
2875 {
2876 image=DestroyImage(image);
2877 ThrowPDFException(ResourceLimitError,"MemoryAllocationFailed");
2878 }
2879 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
2880 /*
2881 Dump Runlength encoded pixels.
2882 */
2883 q=pixels;
2884 for (y=0; y < (ssize_t) image->rows; y++)
2885 {
2886 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2887 if (p == (const Quantum *) NULL)
2888 break;
2889 for (x=0; x < (ssize_t) image->columns; x++)
2890 {
2891 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
2892 p+=GetPixelChannels(image);
2893 }
2894 }
2895 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2896 if (compression == ZipCompression)
2897 status=ZLIBEncodeImage(image,length,pixels,exception);
2898 else
2899 #endif
2900 if (compression == LZWCompression)
2901 status=LZWEncodeImage(image,length,pixels,exception);
2902 else
2903 status=PackbitsEncodeImage(image,length,pixels,exception);
2904 pixel_info=RelinquishVirtualMemory(pixel_info);
2905 if (status == MagickFalse)
2906 {
2907 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
2908 (void) CloseBlob(image);
2909 return(MagickFalse);
2910 }
2911 break;
2912 }
2913 case NoCompression:
2914 {
2915 /*
2916 Dump uncompressed PseudoColor packets.
2917 */
2918 Ascii85Initialize(image);
2919 for (y=0; y < (ssize_t) image->rows; y++)
2920 {
2921 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2922 if (p == (const Quantum *) NULL)
2923 break;
2924 for (x=0; x < (ssize_t) image->columns; x++)
2925 {
2926 Ascii85Encode(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
2927 p+=GetPixelChannels(image);
2928 }
2929 }
2930 Ascii85Flush(image);
2931 break;
2932 }
2933 }
2934 offset=TellBlob(image)-offset;
2935 (void) WriteBlobString(image,"\nendstream\n");
2936 }
2937 (void) WriteBlobString(image,"endobj\n");
2938 /*
2939 Write Length object.
2940 */
2941 xref[object++]=TellBlob(image);
2942 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2943 object);
2944 (void) WriteBlobString(image,buffer);
2945 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2946 offset);
2947 (void) WriteBlobString(image,buffer);
2948 (void) WriteBlobString(image,"endobj\n");
2949 if (GetNextImageInList(image) == (Image *) NULL)
2950 break;
2951 image=SyncNextImageInList(image);
2952 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
2953 if (status == MagickFalse)
2954 break;
2955 } while (image_info->adjoin != MagickFalse);
2956 /*
2957 Write Metadata object.
2958 */
2959 xref[object++]=TellBlob(image);
2960 info_id=object;
2961 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g 0 obj\n",(double)
2962 object);
2963 (void) WriteBlobString(image,buffer);
2964 (void) WriteBlobString(image,"<<\n");
2965 if (LocaleCompare(image_info->magick,"PDFA") == 0)
2966 (void) FormatLocaleString(buffer,MagickPathExtent,"/Title (%s)\n",
2967 EscapeParenthesis(basename));
2968 else
2969 {
2970 wchar_t
2971 *utf16;
2972
2973 utf16=ConvertUTF8ToUTF16((unsigned char *) basename,&length);
2974 if (utf16 != (wchar_t *) NULL)
2975 {
2976 (void) FormatLocaleString(buffer,MagickPathExtent,"/Title (\xfe\xff");
2977 (void) WriteBlobString(image,buffer);
2978 for (i=0; i < (ssize_t) length; i++)
2979 (void) WriteBlobMSBShort(image,(unsigned short) utf16[i]);
2980 (void) FormatLocaleString(buffer,MagickPathExtent,")\n");
2981 utf16=(wchar_t *) RelinquishMagickMemory(utf16);
2982 }
2983 }
2984 (void) WriteBlobString(image,buffer);
2985 seconds=time((time_t *) NULL);
2986 #if defined(MAGICKCORE_HAVE_LOCALTIME_R)
2987 (void) localtime_r(&seconds,&local_time);
2988 #else
2989 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
2990 #endif
2991 (void) FormatLocaleString(date,MagickPathExtent,"D:%04d%02d%02d%02d%02d%02d",
2992 local_time.tm_year+1900,local_time.tm_mon+1,local_time.tm_mday,
2993 local_time.tm_hour,local_time.tm_min,local_time.tm_sec);
2994 (void) FormatLocaleString(buffer,MagickPathExtent,"/CreationDate (%s)\n",
2995 date);
2996 (void) WriteBlobString(image,buffer);
2997 (void) FormatLocaleString(buffer,MagickPathExtent,"/ModDate (%s)\n",date);
2998 (void) WriteBlobString(image,buffer);
2999 url=(char *) MagickAuthoritativeURL;
3000 escape=EscapeParenthesis(url);
3001 (void) FormatLocaleString(buffer,MagickPathExtent,"/Producer (%s)\n",escape);
3002 escape=DestroyString(escape);
3003 (void) WriteBlobString(image,buffer);
3004 (void) WriteBlobString(image,">>\n");
3005 (void) WriteBlobString(image,"endobj\n");
3006 /*
3007 Write Xref object.
3008 */
3009 offset=TellBlob(image)-xref[0]+
3010 (LocaleCompare(image_info->magick,"PDFA") == 0 ? 6 : 0)+10;
3011 (void) WriteBlobString(image,"xref\n");
3012 (void) FormatLocaleString(buffer,MagickPathExtent,"0 %.20g\n",(double)
3013 object+1);
3014 (void) WriteBlobString(image,buffer);
3015 (void) WriteBlobString(image,"0000000000 65535 f \n");
3016 for (i=0; i < (ssize_t) object; i++)
3017 {
3018 (void) FormatLocaleString(buffer,MagickPathExtent,"%010lu 00000 n \n",
3019 (unsigned long) xref[i]);
3020 (void) WriteBlobString(image,buffer);
3021 }
3022 (void) WriteBlobString(image,"trailer\n");
3023 (void) WriteBlobString(image,"<<\n");
3024 (void) FormatLocaleString(buffer,MagickPathExtent,"/Size %.20g\n",(double)
3025 object+1);
3026 (void) WriteBlobString(image,buffer);
3027 (void) FormatLocaleString(buffer,MagickPathExtent,"/Info %.20g 0 R\n",(double)
3028 info_id);
3029 (void) WriteBlobString(image,buffer);
3030 (void) FormatLocaleString(buffer,MagickPathExtent,"/Root %.20g 0 R\n",(double)
3031 root_id);
3032 (void) WriteBlobString(image,buffer);
3033 (void) SignatureImage(image,exception);
3034 (void) FormatLocaleString(buffer,MagickPathExtent,"/ID [<%s> <%s>]\n",
3035 GetImageProperty(image,"signature",exception),
3036 GetImageProperty(image,"signature",exception));
3037 (void) WriteBlobString(image,buffer);
3038 (void) WriteBlobString(image,">>\n");
3039 (void) WriteBlobString(image,"startxref\n");
3040 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) offset);
3041 (void) WriteBlobString(image,buffer);
3042 (void) WriteBlobString(image,"%%EOF\n");
3043 xref=(MagickOffsetType *) RelinquishMagickMemory(xref);
3044 (void) CloseBlob(image);
3045 return(MagickTrue);
3046 }
3047