1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP SSSSS 22222 % 7 % P P SS 22 % 8 % PPPP SSS 222 % 9 % P SS 22 % 10 % P SSSSS 22222 % 11 % % 12 % % 13 % Write Postscript Level II Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization % 21 % dedicated to making software imaging solutions freely available. % 22 % % 23 % You may not use this file except in compliance with the License. You may % 24 % obtain a copy of the License at % 25 % % 26 % https://imagemagick.org/script/license.php % 27 % % 28 % Unless required by applicable law or agreed to in writing, software % 29 % distributed under the License is distributed on an "AS IS" BASIS, % 30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31 % See the License for the specific language governing permissions and % 32 % limitations under the License. % 33 % % 34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 % 36 % 37 */ 38 39 /* 41 Include declarations. 42 */ 43 #include "MagickCore/studio.h" 44 #include "MagickCore/attribute.h" 45 #include "MagickCore/blob.h" 46 #include "MagickCore/blob-private.h" 47 #include "MagickCore/cache.h" 48 #include "MagickCore/color.h" 49 #include "MagickCore/color-private.h" 50 #include "MagickCore/compress.h" 51 #include "MagickCore/constitute.h" 52 #include "MagickCore/draw.h" 53 #include "MagickCore/exception.h" 54 #include "MagickCore/exception-private.h" 55 #include "MagickCore/geometry.h" 56 #include "MagickCore/image.h" 57 #include "MagickCore/image-private.h" 58 #include "MagickCore/list.h" 59 #include "MagickCore/magick.h" 60 #include "MagickCore/memory_.h" 61 #include "MagickCore/monitor.h" 62 #include "MagickCore/monitor-private.h" 63 #include "MagickCore/monitor-private.h" 64 #include "MagickCore/option.h" 65 #include "MagickCore/pixel-accessor.h" 66 #include "MagickCore/property.h" 67 #include "MagickCore/quantum-private.h" 68 #include "MagickCore/resource_.h" 69 #include "MagickCore/static.h" 70 #include "MagickCore/string_.h" 71 #include "MagickCore/module.h" 72 #include "MagickCore/utility.h" 73 74 /* 76 Define declarations. 77 */ 78 #if defined(MAGICKCORE_TIFF_DELEGATE) 79 #define CCITTParam "-1" 80 #else 81 #define CCITTParam "0" 82 #endif 83 84 /* 86 Forward declarations. 87 */ 88 static MagickBooleanType 89 WritePS2Image(const ImageInfo *,Image *,ExceptionInfo *); 90 91 /* 93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94 % % 95 % % 96 % % 97 % R e g i s t e r P S 2 I m a g e % 98 % % 99 % % 100 % % 101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 102 % 103 % RegisterPS2Image() adds properties for the PS2 image format to 104 % the list of supported formats. The properties include the image format 105 % tag, a method to read and/or write the format, whether the format 106 % supports the saving of more than one frame to the same file or blob, 107 % whether the format supports native in-memory I/O, and a brief 108 % description of the format. 109 % 110 % The format of the RegisterPS2Image method is: 111 % 112 % size_t RegisterPS2Image(void) 113 % 114 */ 115 ModuleExport size_t RegisterPS2Image(void) 116 { 117 MagickInfo 118 *entry; 119 120 entry=AcquireMagickInfo("PS2","EPS2","Level II Encapsulated PostScript"); 121 entry->encoder=(EncodeImageHandler *) WritePS2Image; 122 entry->flags^=CoderAdjoinFlag; 123 entry->flags|=CoderEncoderSeekableStreamFlag; 124 entry->flags^=CoderBlobSupportFlag; 125 entry->mime_type=ConstantString("application/postscript"); 126 (void) RegisterMagickInfo(entry); 127 entry=AcquireMagickInfo("PS2","PS2","Level II PostScript"); 128 entry->encoder=(EncodeImageHandler *) WritePS2Image; 129 entry->flags|=CoderEncoderSeekableStreamFlag; 130 entry->flags^=CoderBlobSupportFlag; 131 entry->mime_type=ConstantString("application/postscript"); 132 (void) RegisterMagickInfo(entry); 133 return(MagickImageCoderSignature); 134 } 135 136 /* 138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 139 % % 140 % % 141 % % 142 % U n r e g i s t e r P S 2 I m a g e % 143 % % 144 % % 145 % % 146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 147 % 148 % UnregisterPS2Image() removes format registrations made by the 149 % PS2 module from the list of supported formats. 150 % 151 % The format of the UnregisterPS2Image method is: 152 % 153 % UnregisterPS2Image(void) 154 % 155 */ 156 ModuleExport void UnregisterPS2Image(void) 157 { 158 (void) UnregisterMagickInfo("EPS2"); 159 (void) UnregisterMagickInfo("PS2"); 160 } 161 162 /* 164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 165 % % 166 % % 167 % % 168 % W r i t e P S 2 I m a g e % 169 % % 170 % % 171 % % 172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 173 % 174 % WritePS2Image translates an image to encapsulated Postscript 175 % Level II for printing. If the supplied geometry is null, the image is 176 % centered on the Postscript page. Otherwise, the image is positioned as 177 % specified by the geometry. 178 % 179 % The format of the WritePS2Image method is: 180 % 181 % MagickBooleanType WritePS2Image(const ImageInfo *image_info, 182 % Image *image,ExceptionInfo *exception) 183 % 184 % A description of each parameter follows: 185 % 186 % o image_info: the image info. 187 % 188 % o image: the image. 189 % 190 % o exception: return any errors or warnings in this structure. 191 % 192 */ 193 194 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info, 195 Image *image,Image *inject_image,ExceptionInfo *exception) 196 { 197 Image 198 *group4_image; 199 200 ImageInfo 201 *write_info; 202 203 MagickBooleanType 204 status; 205 206 size_t 207 length; 208 209 unsigned char 210 *group4; 211 212 status=MagickTrue; 213 write_info=CloneImageInfo(image_info); 214 (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent); 215 (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent); 216 group4_image=CloneImage(inject_image,0,0,MagickTrue,exception); 217 if (group4_image == (Image *) NULL) 218 return(MagickFalse); 219 group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length, 220 exception); 221 group4_image=DestroyImage(group4_image); 222 if (group4 == (unsigned char *) NULL) 223 return(MagickFalse); 224 write_info=DestroyImageInfo(write_info); 225 if (WriteBlob(image,length,group4) != (ssize_t) length) 226 status=MagickFalse; 227 group4=(unsigned char *) RelinquishMagickMemory(group4); 228 return(status); 229 } 230 231 static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image, 232 ExceptionInfo *exception) 233 { 234 static const char 235 *const PostscriptProlog[]= 236 { 237 "%%%%BeginProlog", 238 "%%", 239 "%% Display a color image. The image is displayed in color on", 240 "%% Postscript viewers or printers that support color, otherwise", 241 "%% it is displayed as grayscale.", 242 "%%", 243 "/DirectClassImage", 244 "{", 245 " %%", 246 " %% Display a DirectClass image.", 247 " %%", 248 " colorspace 0 eq", 249 " {", 250 " /DeviceRGB setcolorspace", 251 " <<", 252 " /ImageType 1", 253 " /Width columns", 254 " /Height rows", 255 " /BitsPerComponent 8", 256 " /Decode [0 1 0 1 0 1]", 257 " /ImageMatrix [columns 0 0 rows neg 0 rows]", 258 " compression 0 gt", 259 " { /DataSource pixel_stream %s }", 260 " { /DataSource pixel_stream %s } ifelse", 261 " >> image", 262 " }", 263 " {", 264 " /DeviceCMYK setcolorspace", 265 " <<", 266 " /ImageType 1", 267 " /Width columns", 268 " /Height rows", 269 " /BitsPerComponent 8", 270 " /Decode [1 0 1 0 1 0 1 0]", 271 " /ImageMatrix [columns 0 0 rows neg 0 rows]", 272 " compression 0 gt", 273 " { /DataSource pixel_stream %s }", 274 " { /DataSource pixel_stream %s } ifelse", 275 " >> image", 276 " } ifelse", 277 "} bind def", 278 "", 279 "/PseudoClassImage", 280 "{", 281 " %%", 282 " %% Display a PseudoClass image.", 283 " %%", 284 " %% Parameters:", 285 " %% colors: number of colors in the colormap.", 286 " %%", 287 " currentfile buffer readline pop", 288 " token pop /colors exch def pop", 289 " colors 0 eq", 290 " {", 291 " %%", 292 " %% Image is grayscale.", 293 " %%", 294 " currentfile buffer readline pop", 295 " token pop /bits exch def pop", 296 " /DeviceGray setcolorspace", 297 " <<", 298 " /ImageType 1", 299 " /Width columns", 300 " /Height rows", 301 " /BitsPerComponent bits", 302 " /Decode [0 1]", 303 " /ImageMatrix [columns 0 0 rows neg 0 rows]", 304 " compression 0 gt", 305 " { /DataSource pixel_stream %s }", 306 " {", 307 " /DataSource pixel_stream %s", 308 " <<", 309 " /K " CCITTParam, 310 " /Columns columns", 311 " /Rows rows", 312 " >> /CCITTFaxDecode filter", 313 " } ifelse", 314 " >> image", 315 " }", 316 " {", 317 " %%", 318 " %% Parameters:", 319 " %% colormap: red, green, blue color packets.", 320 " %%", 321 " /colormap colors 3 mul string def", 322 " currentfile colormap readhexstring pop pop", 323 " currentfile buffer readline pop", 324 " [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace", 325 " <<", 326 " /ImageType 1", 327 " /Width columns", 328 " /Height rows", 329 " /BitsPerComponent 8", 330 " /Decode [0 255]", 331 " /ImageMatrix [columns 0 0 rows neg 0 rows]", 332 " compression 0 gt", 333 " { /DataSource pixel_stream %s }", 334 " { /DataSource pixel_stream %s } ifelse", 335 " >> image", 336 " } ifelse", 337 "} bind def", 338 "", 339 "/DisplayImage", 340 "{", 341 " %%", 342 " %% Display a DirectClass or PseudoClass image.", 343 " %%", 344 " %% Parameters:", 345 " %% x & y translation.", 346 " %% x & y scale.", 347 " %% label pointsize.", 348 " %% image label.", 349 " %% image columns & rows.", 350 " %% class: 0-DirectClass or 1-PseudoClass.", 351 " %% colorspace: 0-RGB or 1-CMYK.", 352 " %% compression: 0-RLECompression or 1-NoCompression.", 353 " %% hex color packets.", 354 " %%", 355 " gsave", 356 " /buffer 512 string def", 357 " /pixel_stream currentfile def", 358 "", 359 " currentfile buffer readline pop", 360 " token pop /x exch def", 361 " token pop /y exch def pop", 362 " x y translate", 363 " currentfile buffer readline pop", 364 " token pop /x exch def", 365 " token pop /y exch def pop", 366 " currentfile buffer readline pop", 367 " token pop /pointsize exch def pop", 368 (const char *) NULL 369 }, 370 *const PostscriptEpilog[]= 371 { 372 " x y scale", 373 " currentfile buffer readline pop", 374 " token pop /columns exch def", 375 " token pop /rows exch def pop", 376 " currentfile buffer readline pop", 377 " token pop /class exch def pop", 378 " currentfile buffer readline pop", 379 " token pop /colorspace exch def pop", 380 " currentfile buffer readline pop", 381 " token pop /compression exch def pop", 382 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse", 383 " grestore", 384 (const char *) NULL 385 }; 386 387 char 388 buffer[MagickPathExtent], 389 date[MagickPathExtent], 390 page_geometry[MagickPathExtent], 391 **labels; 392 393 CompressionType 394 compression; 395 396 const char 397 *const *q, 398 *value; 399 400 double 401 pointsize; 402 403 GeometryInfo 404 geometry_info; 405 406 MagickOffsetType 407 scene, 408 start, 409 stop; 410 411 MagickBooleanType 412 progress, 413 status; 414 415 MagickOffsetType 416 offset; 417 418 MagickSizeType 419 number_pixels; 420 421 MagickStatusType 422 flags; 423 424 PointInfo 425 delta, 426 resolution, 427 scale; 428 429 RectangleInfo 430 geometry, 431 media_info, 432 page_info; 433 434 register const Quantum 435 *p; 436 437 register ssize_t 438 x; 439 440 register ssize_t 441 i; 442 443 SegmentInfo 444 bounds; 445 446 size_t 447 imageListLength, 448 length, 449 page, 450 text_size; 451 452 ssize_t 453 j, 454 y; 455 456 time_t 457 timer; 458 459 unsigned char 460 *pixels; 461 462 /* 463 Open output image file. 464 */ 465 assert(image_info != (const ImageInfo *) NULL); 466 assert(image_info->signature == MagickCoreSignature); 467 assert(image != (Image *) NULL); 468 assert(image->signature == MagickCoreSignature); 469 if (image->debug != MagickFalse) 470 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 471 assert(exception != (ExceptionInfo *) NULL); 472 assert(exception->signature == MagickCoreSignature); 473 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 474 if (status == MagickFalse) 475 return(status); 476 compression=image->compression; 477 if (image_info->compression != UndefinedCompression) 478 compression=image_info->compression; 479 switch (compression) 480 { 481 #if !defined(MAGICKCORE_JPEG_DELEGATE) 482 case JPEGCompression: 483 { 484 compression=RLECompression; 485 (void) ThrowMagickException(exception,GetMagickModule(), 486 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (JPEG)", 487 image->filename); 488 break; 489 } 490 #endif 491 default: 492 break; 493 } 494 (void) memset(&bounds,0,sizeof(bounds)); 495 page=1; 496 scene=0; 497 imageListLength=GetImageListLength(image); 498 do 499 { 500 /* 501 Scale relative to dots-per-inch. 502 */ 503 delta.x=DefaultResolution; 504 delta.y=DefaultResolution; 505 resolution.x=image->resolution.x; 506 resolution.y=image->resolution.y; 507 if ((resolution.x == 0.0) || (resolution.y == 0.0)) 508 { 509 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 510 resolution.x=geometry_info.rho; 511 resolution.y=geometry_info.sigma; 512 if ((flags & SigmaValue) == 0) 513 resolution.y=resolution.x; 514 } 515 if (image_info->density != (char *) NULL) 516 { 517 flags=ParseGeometry(image_info->density,&geometry_info); 518 resolution.x=geometry_info.rho; 519 resolution.y=geometry_info.sigma; 520 if ((flags & SigmaValue) == 0) 521 resolution.y=resolution.x; 522 } 523 if (image->units == PixelsPerCentimeterResolution) 524 { 525 resolution.x=(size_t) (100.0*2.54*resolution.x+0.5)/100.0; 526 resolution.y=(size_t) (100.0*2.54*resolution.y+0.5)/100.0; 527 } 528 SetGeometry(image,&geometry); 529 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g", 530 (double) image->columns,(double) image->rows); 531 if (image_info->page != (char *) NULL) 532 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent); 533 else 534 if ((image->page.width != 0) && (image->page.height != 0)) 535 (void) FormatLocaleString(page_geometry,MagickPathExtent, 536 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double) 537 image->page.height,(double) image->page.x,(double) image->page.y); 538 else 539 if ((image->gravity != UndefinedGravity) && 540 (LocaleCompare(image_info->magick,"PS") == 0)) 541 (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent); 542 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent); 543 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y, 544 &geometry.width,&geometry.height); 545 scale.x=(double) (geometry.width*delta.x)/resolution.x; 546 geometry.width=(size_t) floor(scale.x+0.5); 547 scale.y=(double) (geometry.height*delta.y)/resolution.y; 548 geometry.height=(size_t) floor(scale.y+0.5); 549 (void) ParseAbsoluteGeometry(page_geometry,&media_info); 550 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception); 551 if (image->gravity != UndefinedGravity) 552 { 553 geometry.x=(-page_info.x); 554 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows); 555 } 556 pointsize=12.0; 557 if (image_info->pointsize != 0.0) 558 pointsize=image_info->pointsize; 559 text_size=0; 560 value=GetImageProperty(image,"label",exception); 561 if (value != (const char *) NULL) 562 text_size=(size_t) (MultilineCensus(value)*pointsize+12); 563 if (page == 1) 564 { 565 /* 566 Output Postscript header. 567 */ 568 if (LocaleCompare(image_info->magick,"PS2") == 0) 569 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent); 570 else 571 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n", 572 MagickPathExtent); 573 (void) WriteBlobString(image,buffer); 574 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n"); 575 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n", 576 image->filename); 577 (void) WriteBlobString(image,buffer); 578 timer=time((time_t *) NULL); 579 (void) FormatMagickTime(timer,MagickPathExtent,date); 580 (void) FormatLocaleString(buffer,MagickPathExtent, 581 "%%%%CreationDate: (%s)\n",date); 582 (void) WriteBlobString(image,buffer); 583 bounds.x1=(double) geometry.x; 584 bounds.y1=(double) geometry.y; 585 bounds.x2=(double) geometry.x+geometry.width; 586 bounds.y2=(double) geometry.y+geometry.height+text_size; 587 if ((image_info->adjoin != MagickFalse) && 588 (GetNextImageInList(image) != (Image *) NULL)) 589 (void) CopyMagickString(buffer,"%%BoundingBox: (atend)\n", 590 MagickPathExtent); 591 else 592 { 593 (void) FormatLocaleString(buffer,MagickPathExtent, 594 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5), 595 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5)); 596 (void) WriteBlobString(image,buffer); 597 (void) FormatLocaleString(buffer,MagickPathExtent, 598 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1, 599 bounds.y1,bounds.x2,bounds.y2); 600 } 601 (void) WriteBlobString(image,buffer); 602 value=GetImageProperty(image,"label",exception); 603 if (value != (const char *) NULL) 604 (void) WriteBlobString(image, 605 "%%DocumentNeededResources: font Helvetica\n"); 606 (void) WriteBlobString(image,"%%LanguageLevel: 2\n"); 607 if (LocaleCompare(image_info->magick,"PS2") != 0) 608 (void) WriteBlobString(image,"%%Pages: 1\n"); 609 else 610 { 611 (void) WriteBlobString(image,"%%Orientation: Portrait\n"); 612 (void) WriteBlobString(image,"%%PageOrder: Ascend\n"); 613 if (image_info->adjoin == MagickFalse) 614 (void) CopyMagickString(buffer,"%%Pages: 1\n",MagickPathExtent); 615 else 616 (void) FormatLocaleString(buffer,MagickPathExtent, 617 "%%%%Pages: %.20g\n",(double) imageListLength); 618 (void) WriteBlobString(image,buffer); 619 } 620 if (image->colorspace == CMYKColorspace) 621 (void) WriteBlobString(image, 622 "%%DocumentProcessColors: Cyan Magenta Yellow Black\n"); 623 (void) WriteBlobString(image,"%%EndComments\n"); 624 (void) WriteBlobString(image,"\n%%BeginDefaults\n"); 625 (void) WriteBlobString(image,"%%EndDefaults\n\n"); 626 /* 627 Output Postscript commands. 628 */ 629 for (q=PostscriptProlog; *q; q++) 630 { 631 switch (compression) 632 { 633 case NoCompression: 634 { 635 (void) FormatLocaleString(buffer,MagickPathExtent,*q, 636 "/ASCII85Decode filter"); 637 break; 638 } 639 case JPEGCompression: 640 { 641 (void) FormatLocaleString(buffer,MagickPathExtent,*q, 642 "/DCTDecode filter"); 643 break; 644 } 645 case LZWCompression: 646 { 647 (void) FormatLocaleString(buffer,MagickPathExtent,*q, 648 "/LZWDecode filter"); 649 break; 650 } 651 case FaxCompression: 652 case Group4Compression: 653 { 654 (void) FormatLocaleString(buffer,MagickPathExtent,*q," "); 655 break; 656 } 657 default: 658 { 659 (void) FormatLocaleString(buffer,MagickPathExtent,*q, 660 "/RunLengthDecode filter"); 661 break; 662 } 663 } 664 (void) WriteBlobString(image,buffer); 665 (void) WriteBlobByte(image,'\n'); 666 } 667 value=GetImageProperty(image,"label",exception); 668 if (value != (const char *) NULL) 669 { 670 (void) WriteBlobString(image, 671 " /Helvetica findfont pointsize scalefont setfont\n"); 672 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--) 673 { 674 (void) WriteBlobString(image," /label 512 string def\n"); 675 (void) WriteBlobString(image, 676 " currentfile label readline pop\n"); 677 (void) FormatLocaleString(buffer,MagickPathExtent, 678 " 0 y %g add moveto label show pop\n",j*pointsize+12); 679 (void) WriteBlobString(image,buffer); 680 } 681 } 682 for (q=PostscriptEpilog; *q; q++) 683 { 684 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*q); 685 (void) WriteBlobString(image,buffer); 686 } 687 if (LocaleCompare(image_info->magick,"PS2") == 0) 688 (void) WriteBlobString(image," showpage\n"); 689 (void) WriteBlobString(image,"} bind def\n"); 690 (void) WriteBlobString(image,"%%EndProlog\n"); 691 } 692 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n", 693 (double) page++); 694 (void) WriteBlobString(image,buffer); 695 (void) FormatLocaleString(buffer,MagickPathExtent, 696 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x, 697 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double) 698 (geometry.height+text_size)); 699 (void) WriteBlobString(image,buffer); 700 if ((double) geometry.x < bounds.x1) 701 bounds.x1=(double) geometry.x; 702 if ((double) geometry.y < bounds.y1) 703 bounds.y1=(double) geometry.y; 704 if ((double) (geometry.x+geometry.width-1) > bounds.x2) 705 bounds.x2=(double) geometry.x+geometry.width-1; 706 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2) 707 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1; 708 value=GetImageProperty(image,"label",exception); 709 if (value != (const char *) NULL) 710 (void) WriteBlobString(image,"%%PageResources: font Helvetica\n"); 711 if (LocaleCompare(image_info->magick,"PS2") != 0) 712 (void) WriteBlobString(image,"userdict begin\n"); 713 start=TellBlob(image); 714 (void) FormatLocaleString(buffer,MagickPathExtent, 715 "%%%%BeginData:%13ld %s Bytes\n",0L, 716 compression == NoCompression ? "ASCII" : "Binary"); 717 (void) WriteBlobString(image,buffer); 718 stop=TellBlob(image); 719 (void) WriteBlobString(image,"DisplayImage\n"); 720 /* 721 Output image data. 722 */ 723 (void) FormatLocaleString(buffer,MagickPathExtent, 724 "%.20g %.20g\n%g %g\n%g\n",(double) geometry.x,(double) geometry.y, 725 scale.x,scale.y,pointsize); 726 (void) WriteBlobString(image,buffer); 727 labels=(char **) NULL; 728 value=GetImageProperty(image,"label",exception); 729 if (value != (const char *) NULL) 730 labels=StringToList(value); 731 if (labels != (char **) NULL) 732 { 733 for (i=0; labels[i] != (char *) NULL; i++) 734 { 735 (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n", 736 labels[i]); 737 (void) WriteBlobString(image,buffer); 738 labels[i]=DestroyString(labels[i]); 739 } 740 labels=(char **) RelinquishMagickMemory(labels); 741 } 742 number_pixels=(MagickSizeType) image->columns*image->rows; 743 if (number_pixels != (MagickSizeType) ((size_t) number_pixels)) 744 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 745 if ((compression == FaxCompression) || (compression == Group4Compression) || 746 ((image_info->type != TrueColorType) && 747 (SetImageGray(image,exception) != MagickFalse))) 748 { 749 (void) FormatLocaleString(buffer,MagickPathExtent, 750 "%.20g %.20g\n1\n%d\n",(double) image->columns,(double) image->rows, 751 (int) (image->colorspace == CMYKColorspace)); 752 (void) WriteBlobString(image,buffer); 753 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n",(int) 754 ((compression != FaxCompression) && 755 (compression != Group4Compression))); 756 (void) WriteBlobString(image,buffer); 757 (void) WriteBlobString(image,"0\n"); 758 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n", 759 (compression == FaxCompression) || 760 (compression == Group4Compression) ? 1 : 8); 761 (void) WriteBlobString(image,buffer); 762 switch (compression) 763 { 764 case FaxCompression: 765 case Group4Compression: 766 { 767 if (LocaleCompare(CCITTParam,"0") == 0) 768 { 769 (void) HuffmanEncodeImage(image_info,image,image,exception); 770 break; 771 } 772 (void) Huffman2DEncodeImage(image_info,image,image,exception); 773 break; 774 } 775 case JPEGCompression: 776 { 777 status=InjectImageBlob(image_info,image,image,"jpeg",exception); 778 if (status == MagickFalse) 779 { 780 (void) CloseBlob(image); 781 return(MagickFalse); 782 } 783 break; 784 } 785 case RLECompression: 786 default: 787 { 788 MemoryInfo 789 *pixel_info; 790 791 register unsigned char 792 *q; 793 794 /* 795 Allocate pixel array. 796 */ 797 length=(size_t) number_pixels; 798 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); 799 if (pixel_info == (MemoryInfo *) NULL) 800 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 801 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 802 /* 803 Dump runlength encoded pixels. 804 */ 805 q=pixels; 806 for (y=0; y < (ssize_t) image->rows; y++) 807 { 808 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 809 if (p == (const Quantum *) NULL) 810 break; 811 for (x=0; x < (ssize_t) image->columns; x++) 812 { 813 *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(image,p))); 814 p+=GetPixelChannels(image); 815 } 816 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 817 image->rows); 818 if (progress == MagickFalse) 819 break; 820 } 821 length=(size_t) (q-pixels); 822 if (compression == LZWCompression) 823 status=LZWEncodeImage(image,length,pixels,exception); 824 else 825 status=PackbitsEncodeImage(image,length,pixels,exception); 826 pixel_info=RelinquishVirtualMemory(pixel_info); 827 if (status == MagickFalse) 828 { 829 (void) CloseBlob(image); 830 return(MagickFalse); 831 } 832 break; 833 } 834 case NoCompression: 835 { 836 /* 837 Dump uncompressed PseudoColor packets. 838 */ 839 Ascii85Initialize(image); 840 for (y=0; y < (ssize_t) image->rows; y++) 841 { 842 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 843 if (p == (const Quantum *) NULL) 844 break; 845 for (x=0; x < (ssize_t) image->columns; x++) 846 { 847 Ascii85Encode(image,ScaleQuantumToChar(ClampToQuantum( 848 GetPixelLuma(image,p)))); 849 p+=GetPixelChannels(image); 850 } 851 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 852 y,image->rows); 853 if (progress == MagickFalse) 854 break; 855 } 856 Ascii85Flush(image); 857 break; 858 } 859 } 860 } 861 else 862 if ((image->storage_class == DirectClass) || (image->colors > 256) || 863 (compression == JPEGCompression) || (image->alpha_trait != UndefinedPixelTrait)) 864 { 865 (void) FormatLocaleString(buffer,MagickPathExtent, 866 "%.20g %.20g\n0\n%d\n",(double) image->columns,(double) image->rows, 867 (int) (image->colorspace == CMYKColorspace)); 868 (void) WriteBlobString(image,buffer); 869 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n", 870 (int) (compression == NoCompression)); 871 (void) WriteBlobString(image,buffer); 872 switch (compression) 873 { 874 case JPEGCompression: 875 { 876 status=InjectImageBlob(image_info,image,image,"jpeg",exception); 877 if (status == MagickFalse) 878 { 879 (void) CloseBlob(image); 880 return(MagickFalse); 881 } 882 break; 883 } 884 case RLECompression: 885 default: 886 { 887 MemoryInfo 888 *pixel_info; 889 890 register unsigned char 891 *q; 892 893 /* 894 Allocate pixel array. 895 */ 896 length=(size_t) number_pixels; 897 pixel_info=AcquireVirtualMemory(length,4*sizeof(*pixels)); 898 if (pixel_info == (MemoryInfo *) NULL) 899 ThrowWriterException(ResourceLimitError, 900 "MemoryAllocationFailed"); 901 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 902 /* 903 Dump runlength encoded pixels. 904 */ 905 q=pixels; 906 for (y=0; y < (ssize_t) image->rows; y++) 907 { 908 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 909 if (p == (const Quantum *) NULL) 910 break; 911 for (x=0; x < (ssize_t) image->columns; x++) 912 { 913 if ((image->alpha_trait != UndefinedPixelTrait) && 914 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) 915 { 916 *q++=ScaleQuantumToChar(QuantumRange); 917 *q++=ScaleQuantumToChar(QuantumRange); 918 *q++=ScaleQuantumToChar(QuantumRange); 919 } 920 else 921 if (image->colorspace != CMYKColorspace) 922 { 923 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 924 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 925 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 926 } 927 else 928 { 929 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 930 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 931 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 932 *q++=ScaleQuantumToChar(GetPixelBlack(image,p)); 933 } 934 p+=GetPixelChannels(image); 935 } 936 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 937 y,image->rows); 938 if (progress == MagickFalse) 939 break; 940 } 941 length=(size_t) (q-pixels); 942 if (compression == LZWCompression) 943 status=LZWEncodeImage(image,length,pixels,exception); 944 else 945 status=PackbitsEncodeImage(image,length,pixels,exception); 946 if (status == MagickFalse) 947 { 948 (void) CloseBlob(image); 949 return(MagickFalse); 950 } 951 pixel_info=RelinquishVirtualMemory(pixel_info); 952 break; 953 } 954 case NoCompression: 955 { 956 /* 957 Dump uncompressed DirectColor packets. 958 */ 959 Ascii85Initialize(image); 960 for (y=0; y < (ssize_t) image->rows; y++) 961 { 962 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 963 if (p == (const Quantum *) NULL) 964 break; 965 for (x=0; x < (ssize_t) image->columns; x++) 966 { 967 if ((image->alpha_trait != UndefinedPixelTrait) && 968 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) 969 { 970 Ascii85Encode(image,ScaleQuantumToChar((Quantum) 971 QuantumRange)); 972 Ascii85Encode(image,ScaleQuantumToChar((Quantum) 973 QuantumRange)); 974 Ascii85Encode(image,ScaleQuantumToChar((Quantum) 975 QuantumRange)); 976 } 977 else 978 if (image->colorspace != CMYKColorspace) 979 { 980 Ascii85Encode(image,ScaleQuantumToChar( 981 GetPixelRed(image,p))); 982 Ascii85Encode(image,ScaleQuantumToChar( 983 GetPixelGreen(image,p))); 984 Ascii85Encode(image,ScaleQuantumToChar( 985 GetPixelBlue(image,p))); 986 } 987 else 988 { 989 Ascii85Encode(image,ScaleQuantumToChar( 990 GetPixelRed(image,p))); 991 Ascii85Encode(image,ScaleQuantumToChar( 992 GetPixelGreen(image,p))); 993 Ascii85Encode(image,ScaleQuantumToChar( 994 GetPixelBlue(image,p))); 995 Ascii85Encode(image,ScaleQuantumToChar( 996 GetPixelBlack(image,p))); 997 } 998 p+=GetPixelChannels(image); 999 } 1000 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 1001 y,image->rows); 1002 if (progress == MagickFalse) 1003 break; 1004 } 1005 Ascii85Flush(image); 1006 break; 1007 } 1008 } 1009 } 1010 else 1011 { 1012 /* 1013 Dump number of colors and colormap. 1014 */ 1015 (void) FormatLocaleString(buffer,MagickPathExtent, 1016 "%.20g %.20g\n1\n%d\n",(double) image->columns,(double) image->rows, 1017 (int) (image->colorspace == CMYKColorspace)); 1018 (void) WriteBlobString(image,buffer); 1019 (void) FormatLocaleString(buffer,MagickPathExtent,"%d\n", 1020 (int) (compression == NoCompression)); 1021 (void) WriteBlobString(image,buffer); 1022 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) 1023 image->colors); 1024 (void) WriteBlobString(image,buffer); 1025 for (i=0; i < (ssize_t) image->colors; i++) 1026 { 1027 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n", 1028 ScaleQuantumToChar(image->colormap[i].red), 1029 ScaleQuantumToChar(image->colormap[i].green), 1030 ScaleQuantumToChar(image->colormap[i].blue)); 1031 (void) WriteBlobString(image,buffer); 1032 } 1033 switch (compression) 1034 { 1035 case RLECompression: 1036 default: 1037 { 1038 MemoryInfo 1039 *pixel_info; 1040 1041 register unsigned char 1042 *q; 1043 1044 /* 1045 Allocate pixel array. 1046 */ 1047 length=(size_t) number_pixels; 1048 pixel_info=AcquireVirtualMemory(length,sizeof(*pixels)); 1049 if (pixel_info == (MemoryInfo *) NULL) 1050 ThrowWriterException(ResourceLimitError, 1051 "MemoryAllocationFailed"); 1052 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 1053 /* 1054 Dump runlength encoded pixels. 1055 */ 1056 q=pixels; 1057 for (y=0; y < (ssize_t) image->rows; y++) 1058 { 1059 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1060 if (p == (const Quantum *) NULL) 1061 break; 1062 for (x=0; x < (ssize_t) image->columns; x++) 1063 { 1064 *q++=(unsigned char) GetPixelIndex(image,p); 1065 p+=GetPixelChannels(image); 1066 } 1067 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 1068 y,image->rows); 1069 if (progress == MagickFalse) 1070 break; 1071 } 1072 length=(size_t) (q-pixels); 1073 if (compression == LZWCompression) 1074 status=LZWEncodeImage(image,length,pixels,exception); 1075 else 1076 status=PackbitsEncodeImage(image,length,pixels,exception); 1077 pixel_info=RelinquishVirtualMemory(pixel_info); 1078 if (status == MagickFalse) 1079 { 1080 (void) CloseBlob(image); 1081 return(MagickFalse); 1082 } 1083 break; 1084 } 1085 case NoCompression: 1086 { 1087 /* 1088 Dump uncompressed PseudoColor packets. 1089 */ 1090 Ascii85Initialize(image); 1091 for (y=0; y < (ssize_t) image->rows; y++) 1092 { 1093 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1094 if (p == (const Quantum *) NULL) 1095 break; 1096 for (x=0; x < (ssize_t) image->columns; x++) 1097 { 1098 Ascii85Encode(image,(unsigned char) GetPixelIndex(image,p)); 1099 p+=GetPixelChannels(image); 1100 } 1101 progress=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 1102 y,image->rows); 1103 if (progress == MagickFalse) 1104 break; 1105 } 1106 Ascii85Flush(image); 1107 break; 1108 } 1109 } 1110 } 1111 (void) WriteBlobByte(image,'\n'); 1112 length=(size_t) (TellBlob(image)-stop); 1113 stop=TellBlob(image); 1114 offset=SeekBlob(image,start,SEEK_SET); 1115 if (offset < 0) 1116 ThrowWriterException(CorruptImageError,"ImproperImageHeader"); 1117 (void) FormatLocaleString(buffer,MagickPathExtent, 1118 "%%%%BeginData:%13ld %s Bytes\n",(long) length, 1119 compression == NoCompression ? "ASCII" : "Binary"); 1120 (void) WriteBlobString(image,buffer); 1121 offset=SeekBlob(image,stop,SEEK_SET); 1122 (void) WriteBlobString(image,"%%EndData\n"); 1123 if (LocaleCompare(image_info->magick,"PS2") != 0) 1124 (void) WriteBlobString(image,"end\n"); 1125 (void) WriteBlobString(image,"%%PageTrailer\n"); 1126 if (GetNextImageInList(image) == (Image *) NULL) 1127 break; 1128 image=SyncNextImageInList(image); 1129 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength); 1130 if (status == MagickFalse) 1131 break; 1132 } while (image_info->adjoin != MagickFalse); 1133 (void) WriteBlobString(image,"%%Trailer\n"); 1134 if (page > 1) 1135 { 1136 (void) FormatLocaleString(buffer,MagickPathExtent, 1137 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5), 1138 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5)); 1139 (void) WriteBlobString(image,buffer); 1140 (void) FormatLocaleString(buffer,MagickPathExtent, 1141 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1, 1142 bounds.x2,bounds.y2); 1143 (void) WriteBlobString(image,buffer); 1144 } 1145 (void) WriteBlobString(image,"%%EOF\n"); 1146 (void) CloseBlob(image); 1147 return(MagickTrue); 1148 } 1149