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