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