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