1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP SSSSS % 7 % P P SS % 8 % PPPP SSS % 9 % P SS % 10 % P SSSSS % 11 % % 12 % % 13 % Read/Write Postscript Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2016 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 % http://www.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/artifact.h" 45 #include "MagickCore/attribute.h" 46 #include "MagickCore/blob.h" 47 #include "MagickCore/blob-private.h" 48 #include "MagickCore/cache.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/constitute.h" 54 #include "MagickCore/delegate.h" 55 #include "MagickCore/delegate-private.h" 56 #include "MagickCore/draw.h" 57 #include "MagickCore/exception.h" 58 #include "MagickCore/exception-private.h" 59 #include "MagickCore/geometry.h" 60 #include "MagickCore/image.h" 61 #include "MagickCore/image-private.h" 62 #include "MagickCore/list.h" 63 #include "MagickCore/magick.h" 64 #include "MagickCore/memory_.h" 65 #include "MagickCore/monitor.h" 66 #include "MagickCore/monitor-private.h" 67 #include "MagickCore/nt-base-private.h" 68 #include "MagickCore/option.h" 69 #include "MagickCore/profile.h" 70 #include "MagickCore/resource_.h" 71 #include "MagickCore/pixel-accessor.h" 72 #include "MagickCore/property.h" 73 #include "MagickCore/quantum-private.h" 74 #include "MagickCore/static.h" 75 #include "MagickCore/string_.h" 76 #include "MagickCore/module.h" 77 #include "MagickCore/token.h" 78 #include "MagickCore/transform.h" 79 #include "MagickCore/utility.h" 80 81 /* 83 Forward declarations. 84 */ 85 static MagickBooleanType 86 WritePSImage(const ImageInfo *,Image *,ExceptionInfo *); 87 88 /* 90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 91 % % 92 % % 93 % % 94 % I n v o k e P o s t s r i p t D e l e g a t e % 95 % % 96 % % 97 % % 98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 99 % 100 % InvokePostscriptDelegate() executes the Postscript interpreter with the 101 % specified command. 102 % 103 % The format of the InvokePostscriptDelegate method is: 104 % 105 % MagickBooleanType InvokePostscriptDelegate( 106 % const MagickBooleanType verbose,const char *command, 107 % ExceptionInfo *exception) 108 % 109 % A description of each parameter follows: 110 % 111 % o verbose: A value other than zero displays the command prior to 112 % executing it. 113 % 114 % o command: the address of a character string containing the command to 115 % execute. 116 % 117 % o exception: return any errors or warnings in this structure. 118 % 119 */ 120 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT) 121 static int MagickDLLCall PostscriptDelegateMessage(void *handle, 122 const char *message,int length) 123 { 124 char 125 **messages; 126 127 ssize_t 128 offset; 129 130 offset=0; 131 messages=(char **) handle; 132 if (*messages == (char *) NULL) 133 *messages=(char *) AcquireQuantumMemory(length+1,sizeof(char *)); 134 else 135 { 136 offset=strlen(*messages); 137 *messages=(char *) ResizeQuantumMemory(*messages,offset+length+1, 138 sizeof(char *)); 139 } 140 (void) memcpy(*messages+offset,message,length); 141 (*messages)[length+offset] ='\0'; 142 return(length); 143 } 144 #endif 145 146 static MagickBooleanType InvokePostscriptDelegate( 147 const MagickBooleanType verbose,const char *command,char *message, 148 ExceptionInfo *exception) 149 { 150 int 151 status; 152 153 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT) 154 #define SetArgsStart(command,args_start) \ 155 if (args_start == (const char *) NULL) \ 156 { \ 157 if (*command != '"') \ 158 args_start=strchr(command,' '); \ 159 else \ 160 { \ 161 args_start=strchr(command+1,'"'); \ 162 if (args_start != (const char *) NULL) \ 163 args_start++; \ 164 } \ 165 } 166 167 #define ExecuteGhostscriptCommand(command,status) \ 168 { \ 169 status=ExternalDelegateCommand(MagickFalse,verbose,command,message, \ 170 exception); \ 171 if (status == 0) \ 172 return(MagickTrue); \ 173 if (status < 0) \ 174 return(MagickFalse); \ 175 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, \ 176 "FailedToExecuteCommand","`%s' (%d)",command,status); \ 177 return(MagickFalse); \ 178 } 179 180 char 181 **argv, 182 *errors; 183 184 const char 185 *args_start = (const char *) NULL; 186 187 const GhostInfo 188 *ghost_info; 189 190 gs_main_instance 191 *interpreter; 192 193 gsapi_revision_t 194 revision; 195 196 int 197 argc, 198 code; 199 200 register ssize_t 201 i; 202 203 #if defined(MAGICKCORE_WINDOWS_SUPPORT) 204 ghost_info=NTGhostscriptDLLVectors(); 205 #else 206 GhostInfo 207 ghost_info_struct; 208 209 ghost_info=(&ghost_info_struct); 210 (void) ResetMagickMemory(&ghost_info_struct,0,sizeof(ghost_info_struct)); 211 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *)) 212 gsapi_delete_instance; 213 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit; 214 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *)) 215 gsapi_new_instance; 216 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **)) 217 gsapi_init_with_args; 218 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int, 219 int *)) gsapi_run_string; 220 ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int(*)(void *,char *, 221 int),int(*)(void *,const char *,int),int(*)(void *, const char *, int))) 222 gsapi_set_stdio; 223 ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision; 224 #endif 225 if (ghost_info == (GhostInfo *) NULL) 226 ExecuteGhostscriptCommand(command,status); 227 if ((ghost_info->revision)(&revision,sizeof(revision)) != 0) 228 revision.revision=0; 229 if (verbose != MagickFalse) 230 { 231 (void) fprintf(stdout,"[ghostscript library %.2f]",(double) 232 revision.revision/100.0); 233 SetArgsStart(command,args_start); 234 (void) fputs(args_start,stdout); 235 } 236 errors=(char *) NULL; 237 status=(ghost_info->new_instance)(&interpreter,(void *) &errors); 238 if (status < 0) 239 ExecuteGhostscriptCommand(command,status); 240 code=0; 241 argv=StringToArgv(command,&argc); 242 if (argv == (char **) NULL) 243 { 244 (ghost_info->delete_instance)(interpreter); 245 return(MagickFalse); 246 } 247 (void) (ghost_info->set_stdio)(interpreter,(int(MagickDLLCall *)(void *, 248 char *,int)) NULL,PostscriptDelegateMessage,PostscriptDelegateMessage); 249 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1); 250 if (status == 0) 251 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n", 252 0,&code); 253 (ghost_info->exit)(interpreter); 254 (ghost_info->delete_instance)(interpreter); 255 for (i=0; i < (ssize_t) argc; i++) 256 argv[i]=DestroyString(argv[i]); 257 argv=(char **) RelinquishMagickMemory(argv); 258 if (status != 0) 259 { 260 SetArgsStart(command,args_start); 261 if (status == -101) /* quit */ 262 (void) FormatLocaleString(message,MagickPathExtent, 263 "[ghostscript library %.2f]%s: %s",(double)revision.revision / 100, 264 args_start,errors); 265 else 266 { 267 (void) ThrowMagickException(exception,GetMagickModule(), 268 DelegateError,"PostscriptDelegateFailed", 269 "`[ghostscript library %.2f]%s': %s", 270 (double)revision.revision / 100,args_start,errors); 271 if (errors != (char *) NULL) 272 errors=DestroyString(errors); 273 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 274 "Ghostscript returns status %d, exit code %d",status,code); 275 return(MagickFalse); 276 } 277 } 278 if (errors != (char *) NULL) 279 errors=DestroyString(errors); 280 return(MagickTrue); 281 #else 282 status=ExternalDelegateCommand(MagickFalse,verbose,command,message,exception); 283 return(status == 0 ? MagickTrue : MagickFalse); 284 #endif 285 } 286 287 /* 289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 290 % % 291 % % 292 % % 293 % I s P S % 294 % % 295 % % 296 % % 297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 298 % 299 % IsPS() returns MagickTrue if the image format type, identified by the 300 % magick string, is PS. 301 % 302 % The format of the IsPS method is: 303 % 304 % MagickBooleanType IsPS(const unsigned char *magick,const size_t length) 305 % 306 % A description of each parameter follows: 307 % 308 % o magick: compare image format pattern against these bytes. 309 % 310 % o length: Specifies the length of the magick string. 311 % 312 */ 313 static MagickBooleanType IsPS(const unsigned char *magick,const size_t length) 314 { 315 if (length < 4) 316 return(MagickFalse); 317 if (memcmp(magick,"%!",2) == 0) 318 return(MagickTrue); 319 if (memcmp(magick,"\004%!",3) == 0) 320 return(MagickTrue); 321 return(MagickFalse); 322 } 323 324 /* 326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 327 % % 328 % % 329 % % 330 % R e a d P S I m a g e % 331 % % 332 % % 333 % % 334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 335 % 336 % ReadPSImage() reads a Postscript image file and returns it. It allocates 337 % the memory necessary for the new Image structure and returns a pointer 338 % to the new image. 339 % 340 % The format of the ReadPSImage method is: 341 % 342 % Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception) 343 % 344 % A description of each parameter follows: 345 % 346 % o image_info: the image info. 347 % 348 % o exception: return any errors or warnings in this structure. 349 % 350 */ 351 352 static MagickBooleanType IsPostscriptRendered(const char *path) 353 { 354 MagickBooleanType 355 status; 356 357 struct stat 358 attributes; 359 360 if ((path == (const char *) NULL) || (*path == '\0')) 361 return(MagickFalse); 362 status=GetPathAttributes(path,&attributes); 363 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) && 364 (attributes.st_size > 0)) 365 return(MagickTrue); 366 return(MagickFalse); 367 } 368 369 static inline int ProfileInteger(Image *image,short int *hex_digits) 370 { 371 int 372 c, 373 l, 374 value; 375 376 register ssize_t 377 i; 378 379 l=0; 380 value=0; 381 for (i=0; i < 2; ) 382 { 383 c=ReadBlobByte(image); 384 if ((c == EOF) || ((c == '%') && (l == '%'))) 385 { 386 value=(-1); 387 break; 388 } 389 l=c; 390 c&=0xff; 391 if (isxdigit(c) == MagickFalse) 392 continue; 393 value=(int) ((size_t) value << 4)+hex_digits[c]; 394 i++; 395 } 396 return(value); 397 } 398 399 static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception) 400 { 401 #define BoundingBox "BoundingBox:" 402 #define BeginDocument "BeginDocument:" 403 #define BeginXMPPacket "<?xpacket begin=" 404 #define EndXMPPacket "<?xpacket end=" 405 #define ICCProfile "BeginICCProfile:" 406 #define CMYKCustomColor "CMYKCustomColor:" 407 #define CMYKProcessColor "CMYKProcessColor:" 408 #define DocumentMedia "DocumentMedia:" 409 #define DocumentCustomColors "DocumentCustomColors:" 410 #define DocumentProcessColors "DocumentProcessColors:" 411 #define EndDocument "EndDocument:" 412 #define HiResBoundingBox "HiResBoundingBox:" 413 #define ImageData "ImageData:" 414 #define PageBoundingBox "PageBoundingBox:" 415 #define LanguageLevel "LanguageLevel:" 416 #define PageMedia "PageMedia:" 417 #define Pages "Pages:" 418 #define PhotoshopProfile "BeginPhotoshop:" 419 #define PostscriptLevel "!PS-" 420 #define RenderPostscriptText " Rendering Postscript... " 421 #define SpotColor "+ " 422 423 char 424 command[MagickPathExtent], 425 *density, 426 filename[MagickPathExtent], 427 geometry[MagickPathExtent], 428 input_filename[MagickPathExtent], 429 message[MagickPathExtent], 430 *options, 431 postscript_filename[MagickPathExtent]; 432 433 const char 434 *option; 435 436 const DelegateInfo 437 *delegate_info; 438 439 GeometryInfo 440 geometry_info; 441 442 Image 443 *image, 444 *next, 445 *postscript_image; 446 447 ImageInfo 448 *read_info; 449 450 int 451 c, 452 file; 453 454 MagickBooleanType 455 cmyk, 456 fitPage, 457 skip, 458 status; 459 460 MagickStatusType 461 flags; 462 463 PointInfo 464 delta, 465 resolution; 466 467 RectangleInfo 468 page; 469 470 register char 471 *p; 472 473 register ssize_t 474 i; 475 476 SegmentInfo 477 bounds, 478 hires_bounds; 479 480 short int 481 hex_digits[256]; 482 483 size_t 484 length; 485 486 ssize_t 487 count, 488 priority; 489 490 StringInfo 491 *profile; 492 493 unsigned long 494 columns, 495 extent, 496 language_level, 497 pages, 498 rows, 499 scene, 500 spotcolor; 501 502 /* 503 Open image file. 504 */ 505 assert(image_info != (const ImageInfo *) NULL); 506 assert(image_info->signature == MagickCoreSignature); 507 if (image_info->debug != MagickFalse) 508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 509 image_info->filename); 510 assert(exception != (ExceptionInfo *) NULL); 511 assert(exception->signature == MagickCoreSignature); 512 image=AcquireImage(image_info,exception); 513 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 514 if (status == MagickFalse) 515 { 516 image=DestroyImageList(image); 517 return((Image *) NULL); 518 } 519 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename); 520 if (status == MagickFalse) 521 { 522 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", 523 image_info->filename); 524 image=DestroyImageList(image); 525 return((Image *) NULL); 526 } 527 /* 528 Initialize hex values. 529 */ 530 (void) ResetMagickMemory(hex_digits,0,sizeof(hex_digits)); 531 hex_digits[(int) '0']=0; 532 hex_digits[(int) '1']=1; 533 hex_digits[(int) '2']=2; 534 hex_digits[(int) '3']=3; 535 hex_digits[(int) '4']=4; 536 hex_digits[(int) '5']=5; 537 hex_digits[(int) '6']=6; 538 hex_digits[(int) '7']=7; 539 hex_digits[(int) '8']=8; 540 hex_digits[(int) '9']=9; 541 hex_digits[(int) 'a']=10; 542 hex_digits[(int) 'b']=11; 543 hex_digits[(int) 'c']=12; 544 hex_digits[(int) 'd']=13; 545 hex_digits[(int) 'e']=14; 546 hex_digits[(int) 'f']=15; 547 hex_digits[(int) 'A']=10; 548 hex_digits[(int) 'B']=11; 549 hex_digits[(int) 'C']=12; 550 hex_digits[(int) 'D']=13; 551 hex_digits[(int) 'E']=14; 552 hex_digits[(int) 'F']=15; 553 /* 554 Set the page density. 555 */ 556 delta.x=DefaultResolution; 557 delta.y=DefaultResolution; 558 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0)) 559 { 560 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 561 image->resolution.x=geometry_info.rho; 562 image->resolution.y=geometry_info.sigma; 563 if ((flags & SigmaValue) == 0) 564 image->resolution.y=image->resolution.x; 565 } 566 if (image_info->density != (char *) NULL) 567 { 568 flags=ParseGeometry(image_info->density,&geometry_info); 569 image->resolution.x=geometry_info.rho; 570 image->resolution.y=geometry_info.sigma; 571 if ((flags & SigmaValue) == 0) 572 image->resolution.y=image->resolution.x; 573 } 574 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 575 if (image_info->page != (char *) NULL) 576 (void) ParseAbsoluteGeometry(image_info->page,&page); 577 resolution=image->resolution; 578 page.width=(size_t) ceil((double) (page.width*resolution.x/delta.x)-0.5); 579 page.height=(size_t) ceil((double) (page.height*resolution.y/delta.y)-0.5); 580 /* 581 Determine page geometry from the Postscript bounding box. 582 */ 583 (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); 584 (void) ResetMagickMemory(command,0,sizeof(command)); 585 cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse; 586 (void) ResetMagickMemory(&hires_bounds,0,sizeof(hires_bounds)); 587 columns=0; 588 rows=0; 589 priority=0; 590 rows=0; 591 extent=0; 592 spotcolor=0; 593 language_level=1; 594 pages=(~0UL); 595 skip=MagickFalse; 596 p=command; 597 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image)) 598 { 599 /* 600 Note document structuring comments. 601 */ 602 *p++=(char) c; 603 if ((strchr("\n\r%",c) == (char *) NULL) && 604 ((size_t) (p-command) < (MagickPathExtent-1))) 605 continue; 606 *p='\0'; 607 p=command; 608 /* 609 Skip %%BeginDocument thru %%EndDocument. 610 */ 611 if (LocaleNCompare(BeginDocument,command,strlen(BeginDocument)) == 0) 612 skip=MagickTrue; 613 if (LocaleNCompare(EndDocument,command,strlen(EndDocument)) == 0) 614 skip=MagickFalse; 615 if (skip != MagickFalse) 616 continue; 617 if (LocaleNCompare(PostscriptLevel,command,strlen(PostscriptLevel)) == 0) 618 { 619 (void) SetImageProperty(image,"ps:Level",command+4,exception); 620 if (GlobExpression(command,"*EPSF-*",MagickTrue) != MagickFalse) 621 pages=1; 622 } 623 if (LocaleNCompare(LanguageLevel,command,strlen(LanguageLevel)) == 0) 624 (void) sscanf(command,LanguageLevel " %lu",&language_level); 625 if (LocaleNCompare(Pages,command,strlen(Pages)) == 0) 626 (void) sscanf(command,Pages " %lu",&pages); 627 if (LocaleNCompare(ImageData,command,strlen(ImageData)) == 0) 628 (void) sscanf(command,ImageData " %lu %lu",&columns,&rows); 629 if (LocaleNCompare(ICCProfile,command,strlen(ICCProfile)) == 0) 630 { 631 unsigned char 632 *datum; 633 634 /* 635 Read ICC profile. 636 */ 637 profile=AcquireStringInfo(65536); 638 for (i=0; (c=ProfileInteger(image,hex_digits)) != EOF; i++) 639 { 640 SetStringInfoLength(profile,(size_t) i+1); 641 datum=GetStringInfoDatum(profile); 642 datum[i]=(unsigned char) c; 643 } 644 (void) SetImageProfile(image,"icc",profile,exception); 645 profile=DestroyStringInfo(profile); 646 continue; 647 } 648 if (LocaleNCompare(PhotoshopProfile,command,strlen(PhotoshopProfile)) == 0) 649 { 650 unsigned char 651 *q; 652 653 /* 654 Read Photoshop profile. 655 */ 656 count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent); 657 if (count != 1) 658 continue; 659 length=extent; 660 profile=BlobToStringInfo((const void *) NULL,length); 661 if (profile != (StringInfo *) NULL) 662 { 663 q=GetStringInfoDatum(profile); 664 for (i=0; i < (ssize_t) length; i++) 665 *q++=(unsigned char) ProfileInteger(image,hex_digits); 666 (void) SetImageProfile(image,"8bim",profile,exception); 667 profile=DestroyStringInfo(profile); 668 } 669 continue; 670 } 671 if (LocaleNCompare(BeginXMPPacket,command,strlen(BeginXMPPacket)) == 0) 672 { 673 /* 674 Read XMP profile. 675 */ 676 p=command; 677 profile=StringToStringInfo(command); 678 for (i=GetStringInfoLength(profile)-1; c != EOF; i++) 679 { 680 SetStringInfoLength(profile,i+1); 681 c=ReadBlobByte(image); 682 GetStringInfoDatum(profile)[i]=(unsigned char) c; 683 *p++=(char) c; 684 if ((strchr("\n\r%",c) == (char *) NULL) && 685 ((size_t) (p-command) < (MagickPathExtent-1))) 686 continue; 687 *p='\0'; 688 p=command; 689 if (LocaleNCompare(EndXMPPacket,command,strlen(EndXMPPacket)) == 0) 690 break; 691 } 692 SetStringInfoLength(profile,i); 693 (void) SetImageProfile(image,"xmp",profile,exception); 694 profile=DestroyStringInfo(profile); 695 continue; 696 } 697 /* 698 Is this a CMYK document? 699 */ 700 length=strlen(DocumentProcessColors); 701 if (LocaleNCompare(DocumentProcessColors,command,length) == 0) 702 { 703 if ((GlobExpression(command,"*Cyan*",MagickTrue) != MagickFalse) || 704 (GlobExpression(command,"*Magenta*",MagickTrue) != MagickFalse) || 705 (GlobExpression(command,"*Yellow*",MagickTrue) != MagickFalse)) 706 cmyk=MagickTrue; 707 } 708 if (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) 709 cmyk=MagickTrue; 710 if (LocaleNCompare(CMYKProcessColor,command,strlen(CMYKProcessColor)) == 0) 711 cmyk=MagickTrue; 712 length=strlen(DocumentCustomColors); 713 if ((LocaleNCompare(DocumentCustomColors,command,length) == 0) || 714 (LocaleNCompare(CMYKCustomColor,command,strlen(CMYKCustomColor)) == 0) || 715 (LocaleNCompare(SpotColor,command,strlen(SpotColor)) == 0)) 716 { 717 char 718 property[MagickPathExtent], 719 *value; 720 721 register char 722 *q; 723 724 /* 725 Note spot names. 726 */ 727 (void) FormatLocaleString(property,MagickPathExtent,"ps:SpotColor-%.20g", 728 (double) (spotcolor++)); 729 for (q=command; *q != '\0'; q++) 730 if (isspace((int) (unsigned char) *q) != 0) 731 break; 732 value=AcquireString(q); 733 (void) SubstituteString(&value,"(",""); 734 (void) SubstituteString(&value,")",""); 735 (void) StripString(value); 736 (void) SetImageProperty(image,property,value,exception); 737 value=DestroyString(value); 738 continue; 739 } 740 if (image_info->page != (char *) NULL) 741 continue; 742 /* 743 Note region defined by bounding box. 744 */ 745 count=0; 746 i=0; 747 if (LocaleNCompare(BoundingBox,command,strlen(BoundingBox)) == 0) 748 { 749 count=(ssize_t) sscanf(command,BoundingBox " %lf %lf %lf %lf", 750 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 751 i=2; 752 } 753 if (LocaleNCompare(DocumentMedia,command,strlen(DocumentMedia)) == 0) 754 { 755 count=(ssize_t) sscanf(command,DocumentMedia " %lf %lf %lf %lf", 756 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 757 i=1; 758 } 759 if (LocaleNCompare(HiResBoundingBox,command,strlen(HiResBoundingBox)) == 0) 760 { 761 count=(ssize_t) sscanf(command,HiResBoundingBox " %lf %lf %lf %lf", 762 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 763 i=3; 764 } 765 if (LocaleNCompare(PageBoundingBox,command,strlen(PageBoundingBox)) == 0) 766 { 767 count=(ssize_t) sscanf(command,PageBoundingBox " %lf %lf %lf %lf", 768 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 769 i=1; 770 } 771 if (LocaleNCompare(PageMedia,command,strlen(PageMedia)) == 0) 772 { 773 count=(ssize_t) sscanf(command,PageMedia " %lf %lf %lf %lf", 774 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 775 i=1; 776 } 777 if ((count != 4) || (i < (ssize_t) priority)) 778 continue; 779 if ((fabs(bounds.x2-bounds.x1) <= fabs(hires_bounds.x2-hires_bounds.x1)) || 780 (fabs(bounds.y2-bounds.y1) <= fabs(hires_bounds.y2-hires_bounds.y1))) 781 if (i == (ssize_t) priority) 782 continue; 783 hires_bounds=bounds; 784 priority=i; 785 } 786 if ((fabs(hires_bounds.x2-hires_bounds.x1) >= MagickEpsilon) && 787 (fabs(hires_bounds.y2-hires_bounds.y1) >= MagickEpsilon)) 788 { 789 /* 790 Set Postscript render geometry. 791 */ 792 (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+.15g%+.15g", 793 hires_bounds.x2-hires_bounds.x1,hires_bounds.y2-hires_bounds.y1, 794 hires_bounds.x1,hires_bounds.y1); 795 (void) SetImageProperty(image,"ps:HiResBoundingBox",geometry,exception); 796 page.width=(size_t) ceil((double) ((hires_bounds.x2-hires_bounds.x1)* 797 resolution.x/delta.x)-0.5); 798 page.height=(size_t) ceil((double) ((hires_bounds.y2-hires_bounds.y1)* 799 resolution.y/delta.y)-0.5); 800 } 801 fitPage=MagickFalse; 802 option=GetImageOption(image_info,"eps:fit-page"); 803 if (option != (char *) NULL) 804 { 805 char 806 *page_geometry; 807 808 page_geometry=GetPageGeometry(option); 809 flags=ParseMetaGeometry(page_geometry,&page.x,&page.y,&page.width, 810 &page.height); 811 if (flags == NoValue) 812 { 813 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 814 "InvalidGeometry","`%s'",option); 815 image=DestroyImage(image); 816 return((Image *) NULL); 817 } 818 page.width=(size_t) ceil((double) (page.width*image->resolution.x/delta.x) 819 -0.5); 820 page.height=(size_t) ceil((double) (page.height*image->resolution.y/ 821 delta.y) -0.5); 822 page_geometry=DestroyString(page_geometry); 823 fitPage=MagickTrue; 824 } 825 (void) CloseBlob(image); 826 if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse) 827 cmyk=MagickFalse; 828 /* 829 Create Ghostscript control file. 830 */ 831 file=AcquireUniqueFileResource(postscript_filename); 832 if (file == -1) 833 { 834 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 835 image_info->filename); 836 image=DestroyImageList(image); 837 return((Image *) NULL); 838 } 839 (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {" 840 "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n" 841 "<</UseCIEColor true>>setpagedevice\n",MagickPathExtent); 842 count=write(file,command,(unsigned int) strlen(command)); 843 if (image_info->page == (char *) NULL) 844 { 845 char 846 translate_geometry[MagickPathExtent]; 847 848 (void) FormatLocaleString(translate_geometry,MagickPathExtent, 849 "%g %g translate\n",-bounds.x1,-bounds.y1); 850 count=write(file,translate_geometry,(unsigned int) 851 strlen(translate_geometry)); 852 } 853 file=close(file)-1; 854 /* 855 Render Postscript with the Ghostscript delegate. 856 */ 857 if (image_info->monochrome != MagickFalse) 858 delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception); 859 else 860 if (cmyk != MagickFalse) 861 delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception); 862 else 863 delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception); 864 if (delegate_info == (const DelegateInfo *) NULL) 865 { 866 (void) RelinquishUniqueFileResource(postscript_filename); 867 image=DestroyImageList(image); 868 return((Image *) NULL); 869 } 870 density=AcquireString(""); 871 options=AcquireString(""); 872 (void) FormatLocaleString(density,MagickPathExtent,"%gx%g",resolution.x, 873 resolution.y); 874 (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double) 875 page.width,(double) page.height); 876 read_info=CloneImageInfo(image_info); 877 *read_info->magick='\0'; 878 if (read_info->number_scenes != 0) 879 { 880 char 881 pages[MagickPathExtent]; 882 883 (void) FormatLocaleString(pages,MagickPathExtent,"-dFirstPage=%.20g " 884 "-dLastPage=%.20g ",(double) read_info->scene+1,(double) 885 (read_info->scene+read_info->number_scenes)); 886 (void) ConcatenateMagickString(options,pages,MagickPathExtent); 887 read_info->number_scenes=0; 888 if (read_info->scenes != (char *) NULL) 889 *read_info->scenes='\0'; 890 } 891 if (*image_info->magick == 'E') 892 { 893 option=GetImageOption(image_info,"eps:use-cropbox"); 894 if ((option == (const char *) NULL) || 895 (IsStringTrue(option) != MagickFalse)) 896 (void) ConcatenateMagickString(options,"-dEPSCrop ",MagickPathExtent); 897 if (fitPage != MagickFalse) 898 (void) ConcatenateMagickString(options,"-dEPSFitPage ",MagickPathExtent); 899 } 900 (void) CopyMagickString(filename,read_info->filename,MagickPathExtent); 901 (void) AcquireUniqueFilename(filename); 902 (void) RelinquishUniqueFileResource(filename); 903 (void) ConcatenateMagickString(filename,"%d",MagickPathExtent); 904 (void) FormatLocaleString(command,MagickPathExtent, 905 GetDelegateCommands(delegate_info), 906 read_info->antialias != MagickFalse ? 4 : 1, 907 read_info->antialias != MagickFalse ? 4 : 1,density,options,filename, 908 postscript_filename,input_filename); 909 options=DestroyString(options); 910 density=DestroyString(density); 911 *message='\0'; 912 status=InvokePostscriptDelegate(read_info->verbose,command,message,exception); 913 (void) InterpretImageFilename(image_info,image,filename,1, 914 read_info->filename,exception); 915 if ((status == MagickFalse) || 916 (IsPostscriptRendered(read_info->filename) == MagickFalse)) 917 { 918 (void) ConcatenateMagickString(command," -c showpage",MagickPathExtent); 919 status=InvokePostscriptDelegate(read_info->verbose,command,message, 920 exception); 921 } 922 (void) RelinquishUniqueFileResource(postscript_filename); 923 (void) RelinquishUniqueFileResource(input_filename); 924 postscript_image=(Image *) NULL; 925 if (status == MagickFalse) 926 for (i=1; ; i++) 927 { 928 (void) InterpretImageFilename(image_info,image,filename,(int) i, 929 read_info->filename,exception); 930 if (IsPostscriptRendered(read_info->filename) == MagickFalse) 931 break; 932 (void) RelinquishUniqueFileResource(read_info->filename); 933 } 934 else 935 for (i=1; ; i++) 936 { 937 (void) InterpretImageFilename(image_info,image,filename,(int) i, 938 read_info->filename,exception); 939 if (IsPostscriptRendered(read_info->filename) == MagickFalse) 940 break; 941 read_info->blob=NULL; 942 read_info->length=0; 943 next=ReadImage(read_info,exception); 944 (void) RelinquishUniqueFileResource(read_info->filename); 945 if (next == (Image *) NULL) 946 break; 947 AppendImageToList(&postscript_image,next); 948 } 949 (void) RelinquishUniqueFileResource(read_info->filename); 950 read_info=DestroyImageInfo(read_info); 951 if (postscript_image == (Image *) NULL) 952 { 953 if (*message != '\0') 954 (void) ThrowMagickException(exception,GetMagickModule(), 955 DelegateError,"PostscriptDelegateFailed","`%s'",message); 956 image=DestroyImageList(image); 957 return((Image *) NULL); 958 } 959 if (LocaleCompare(postscript_image->magick,"BMP") == 0) 960 { 961 Image 962 *cmyk_image; 963 964 cmyk_image=ConsolidateCMYKImages(postscript_image,exception); 965 if (cmyk_image != (Image *) NULL) 966 { 967 postscript_image=DestroyImageList(postscript_image); 968 postscript_image=cmyk_image; 969 } 970 } 971 if (image_info->number_scenes != 0) 972 { 973 Image 974 *clone_image; 975 976 /* 977 Add place holder images to meet the subimage specification requirement. 978 */ 979 for (i=0; i < (ssize_t) image_info->scene; i++) 980 { 981 clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception); 982 if (clone_image != (Image *) NULL) 983 PrependImageToList(&postscript_image,clone_image); 984 } 985 } 986 do 987 { 988 (void) CopyMagickString(postscript_image->filename,filename,MagickPathExtent); 989 (void) CopyMagickString(postscript_image->magick,image->magick, 990 MagickPathExtent); 991 if (columns != 0) 992 postscript_image->magick_columns=columns; 993 if (rows != 0) 994 postscript_image->magick_rows=rows; 995 postscript_image->page=page; 996 (void) CloneImageProfiles(postscript_image,image); 997 (void) CloneImageProperties(postscript_image,image); 998 next=SyncNextImageInList(postscript_image); 999 if (next != (Image *) NULL) 1000 postscript_image=next; 1001 } while (next != (Image *) NULL); 1002 image=DestroyImageList(image); 1003 scene=0; 1004 for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; ) 1005 { 1006 next->scene=scene++; 1007 next=GetNextImageInList(next); 1008 } 1009 return(GetFirstImageInList(postscript_image)); 1010 } 1011 1012 /* 1014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1015 % % 1016 % % 1017 % % 1018 % R e g i s t e r P S I m a g e % 1019 % % 1020 % % 1021 % % 1022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1023 % 1024 % RegisterPSImage() adds properties for the PS image format to 1025 % the list of supported formats. The properties include the image format 1026 % tag, a method to read and/or write the format, whether the format 1027 % supports the saving of more than one frame to the same file or blob, 1028 % whether the format supports native in-memory I/O, and a brief 1029 % description of the format. 1030 % 1031 % The format of the RegisterPSImage method is: 1032 % 1033 % size_t RegisterPSImage(void) 1034 % 1035 */ 1036 ModuleExport size_t RegisterPSImage(void) 1037 { 1038 MagickInfo 1039 *entry; 1040 1041 entry=AcquireMagickInfo("PS","EPI", 1042 "Encapsulated PostScript Interchange format"); 1043 entry->decoder=(DecodeImageHandler *) ReadPSImage; 1044 entry->encoder=(EncodeImageHandler *) WritePSImage; 1045 entry->magick=(IsImageFormatHandler *) IsPS; 1046 entry->flags^=CoderAdjoinFlag; 1047 entry->flags^=CoderBlobSupportFlag; 1048 entry->flags|=CoderSeekableStreamFlag; 1049 entry->mime_type=ConstantString("application/postscript"); 1050 (void) RegisterMagickInfo(entry); 1051 entry=AcquireMagickInfo("PS","EPS","Encapsulated PostScript"); 1052 entry->decoder=(DecodeImageHandler *) ReadPSImage; 1053 entry->encoder=(EncodeImageHandler *) WritePSImage; 1054 entry->magick=(IsImageFormatHandler *) IsPS; 1055 entry->flags^=CoderAdjoinFlag; 1056 entry->flags^=CoderBlobSupportFlag; 1057 entry->flags|=CoderSeekableStreamFlag; 1058 entry->mime_type=ConstantString("application/postscript"); 1059 (void) RegisterMagickInfo(entry); 1060 entry=AcquireMagickInfo("PS","EPSF","Encapsulated PostScript"); 1061 entry->decoder=(DecodeImageHandler *) ReadPSImage; 1062 entry->encoder=(EncodeImageHandler *) WritePSImage; 1063 entry->magick=(IsImageFormatHandler *) IsPS; 1064 entry->flags^=CoderAdjoinFlag; 1065 entry->flags^=CoderBlobSupportFlag; 1066 entry->flags|=CoderSeekableStreamFlag; 1067 entry->mime_type=ConstantString("application/postscript"); 1068 (void) RegisterMagickInfo(entry); 1069 entry=AcquireMagickInfo("PS","EPSI", 1070 "Encapsulated PostScript Interchange format"); 1071 entry->decoder=(DecodeImageHandler *) ReadPSImage; 1072 entry->encoder=(EncodeImageHandler *) WritePSImage; 1073 entry->magick=(IsImageFormatHandler *) IsPS; 1074 entry->flags^=CoderAdjoinFlag; 1075 entry->flags^=CoderBlobSupportFlag; 1076 entry->flags|=CoderSeekableStreamFlag; 1077 entry->mime_type=ConstantString("application/postscript"); 1078 (void) RegisterMagickInfo(entry); 1079 entry=AcquireMagickInfo("PS","PS","PostScript"); 1080 entry->decoder=(DecodeImageHandler *) ReadPSImage; 1081 entry->encoder=(EncodeImageHandler *) WritePSImage; 1082 entry->magick=(IsImageFormatHandler *) IsPS; 1083 entry->mime_type=ConstantString("application/postscript"); 1084 entry->flags^=CoderBlobSupportFlag; 1085 entry->flags|=CoderSeekableStreamFlag; 1086 (void) RegisterMagickInfo(entry); 1087 return(MagickImageCoderSignature); 1088 } 1089 1090 /* 1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1093 % % 1094 % % 1095 % % 1096 % U n r e g i s t e r P S I m a g e % 1097 % % 1098 % % 1099 % % 1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1101 % 1102 % UnregisterPSImage() removes format registrations made by the 1103 % PS module from the list of supported formats. 1104 % 1105 % The format of the UnregisterPSImage method is: 1106 % 1107 % UnregisterPSImage(void) 1108 % 1109 */ 1110 ModuleExport void UnregisterPSImage(void) 1111 { 1112 (void) UnregisterMagickInfo("EPI"); 1113 (void) UnregisterMagickInfo("EPS"); 1114 (void) UnregisterMagickInfo("EPSF"); 1115 (void) UnregisterMagickInfo("EPSI"); 1116 (void) UnregisterMagickInfo("PS"); 1117 } 1118 1119 /* 1121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1122 % % 1123 % % 1124 % % 1125 % W r i t e P S I m a g e % 1126 % % 1127 % % 1128 % % 1129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1130 % 1131 % WritePSImage translates an image to encapsulated Postscript 1132 % Level I for printing. If the supplied geometry is null, the image is 1133 % centered on the Postscript page. Otherwise, the image is positioned as 1134 % specified by the geometry. 1135 % 1136 % The format of the WritePSImage method is: 1137 % 1138 % MagickBooleanType WritePSImage(const ImageInfo *image_info, 1139 % Image *image,ExceptionInfo *exception) 1140 % 1141 % A description of each parameter follows: 1142 % 1143 % o image_info: the image info. 1144 % 1145 % o image: the image. 1146 % 1147 % o exception: return any errors or warnings in this structure. 1148 % 1149 */ 1150 1151 static inline unsigned char *PopHexPixel(const char *const *hex_digits, 1152 const size_t pixel,unsigned char *pixels) 1153 { 1154 register const char 1155 *hex; 1156 1157 hex=hex_digits[pixel]; 1158 *pixels++=(unsigned char) (*hex++); 1159 *pixels++=(unsigned char) (*hex); 1160 return(pixels); 1161 } 1162 1163 static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image, 1164 ExceptionInfo *exception) 1165 { 1166 #define WriteRunlengthPacket(image,pixel,length,p) \ 1167 { \ 1168 if ((image->alpha_trait != UndefinedPixelTrait) && \ 1169 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) \ 1170 { \ 1171 q=PopHexPixel(hex_digits,0xff,q); \ 1172 q=PopHexPixel(hex_digits,0xff,q); \ 1173 q=PopHexPixel(hex_digits,0xff,q); \ 1174 } \ 1175 else \ 1176 { \ 1177 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.red)),q); \ 1178 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.green)),q); \ 1179 q=PopHexPixel(hex_digits,ScaleQuantumToChar(ClampToQuantum(pixel.blue)),q); \ 1180 } \ 1181 q=PopHexPixel(hex_digits,(size_t) MagickMin(length,0xff),q); \ 1182 } 1183 1184 static const char 1185 *const hex_digits[] = 1186 { 1187 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", 1188 "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", 1189 "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", 1190 "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", 1191 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", 1192 "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", 1193 "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", 1194 "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", 1195 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", 1196 "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", 1197 "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", 1198 "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", 1199 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", 1200 "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", 1201 "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", 1202 "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", 1203 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", 1204 "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", 1205 "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", 1206 "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", 1207 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", 1208 "FC", "FD", "FE", "FF", (const char *) NULL 1209 }, 1210 *const PostscriptProlog[]= 1211 { 1212 "%%BeginProlog", 1213 "%", 1214 "% Display a color image. The image is displayed in color on", 1215 "% Postscript viewers or printers that support color, otherwise", 1216 "% it is displayed as grayscale.", 1217 "%", 1218 "/DirectClassPacket", 1219 "{", 1220 " %", 1221 " % Get a DirectClass packet.", 1222 " %", 1223 " % Parameters:", 1224 " % red.", 1225 " % green.", 1226 " % blue.", 1227 " % length: number of pixels minus one of this color (optional).", 1228 " %", 1229 " currentfile color_packet readhexstring pop pop", 1230 " compression 0 eq", 1231 " {", 1232 " /number_pixels 3 def", 1233 " }", 1234 " {", 1235 " currentfile byte readhexstring pop 0 get", 1236 " /number_pixels exch 1 add 3 mul def", 1237 " } ifelse", 1238 " 0 3 number_pixels 1 sub", 1239 " {", 1240 " pixels exch color_packet putinterval", 1241 " } for", 1242 " pixels 0 number_pixels getinterval", 1243 "} bind def", 1244 "", 1245 "/DirectClassImage", 1246 "{", 1247 " %", 1248 " % Display a DirectClass image.", 1249 " %", 1250 " systemdict /colorimage known", 1251 " {", 1252 " columns rows 8", 1253 " [", 1254 " columns 0 0", 1255 " rows neg 0 rows", 1256 " ]", 1257 " { DirectClassPacket } false 3 colorimage", 1258 " }", 1259 " {", 1260 " %", 1261 " % No colorimage operator; convert to grayscale.", 1262 " %", 1263 " columns rows 8", 1264 " [", 1265 " columns 0 0", 1266 " rows neg 0 rows", 1267 " ]", 1268 " { GrayDirectClassPacket } image", 1269 " } ifelse", 1270 "} bind def", 1271 "", 1272 "/GrayDirectClassPacket", 1273 "{", 1274 " %", 1275 " % Get a DirectClass packet; convert to grayscale.", 1276 " %", 1277 " % Parameters:", 1278 " % red", 1279 " % green", 1280 " % blue", 1281 " % length: number of pixels minus one of this color (optional).", 1282 " %", 1283 " currentfile color_packet readhexstring pop pop", 1284 " color_packet 0 get 0.299 mul", 1285 " color_packet 1 get 0.587 mul add", 1286 " color_packet 2 get 0.114 mul add", 1287 " cvi", 1288 " /gray_packet exch def", 1289 " compression 0 eq", 1290 " {", 1291 " /number_pixels 1 def", 1292 " }", 1293 " {", 1294 " currentfile byte readhexstring pop 0 get", 1295 " /number_pixels exch 1 add def", 1296 " } ifelse", 1297 " 0 1 number_pixels 1 sub", 1298 " {", 1299 " pixels exch gray_packet put", 1300 " } for", 1301 " pixels 0 number_pixels getinterval", 1302 "} bind def", 1303 "", 1304 "/GrayPseudoClassPacket", 1305 "{", 1306 " %", 1307 " % Get a PseudoClass packet; convert to grayscale.", 1308 " %", 1309 " % Parameters:", 1310 " % index: index into the colormap.", 1311 " % length: number of pixels minus one of this color (optional).", 1312 " %", 1313 " currentfile byte readhexstring pop 0 get", 1314 " /offset exch 3 mul def", 1315 " /color_packet colormap offset 3 getinterval def", 1316 " color_packet 0 get 0.299 mul", 1317 " color_packet 1 get 0.587 mul add", 1318 " color_packet 2 get 0.114 mul add", 1319 " cvi", 1320 " /gray_packet exch def", 1321 " compression 0 eq", 1322 " {", 1323 " /number_pixels 1 def", 1324 " }", 1325 " {", 1326 " currentfile byte readhexstring pop 0 get", 1327 " /number_pixels exch 1 add def", 1328 " } ifelse", 1329 " 0 1 number_pixels 1 sub", 1330 " {", 1331 " pixels exch gray_packet put", 1332 " } for", 1333 " pixels 0 number_pixels getinterval", 1334 "} bind def", 1335 "", 1336 "/PseudoClassPacket", 1337 "{", 1338 " %", 1339 " % Get a PseudoClass packet.", 1340 " %", 1341 " % Parameters:", 1342 " % index: index into the colormap.", 1343 " % length: number of pixels minus one of this color (optional).", 1344 " %", 1345 " currentfile byte readhexstring pop 0 get", 1346 " /offset exch 3 mul def", 1347 " /color_packet colormap offset 3 getinterval def", 1348 " compression 0 eq", 1349 " {", 1350 " /number_pixels 3 def", 1351 " }", 1352 " {", 1353 " currentfile byte readhexstring pop 0 get", 1354 " /number_pixels exch 1 add 3 mul def", 1355 " } ifelse", 1356 " 0 3 number_pixels 1 sub", 1357 " {", 1358 " pixels exch color_packet putinterval", 1359 " } for", 1360 " pixels 0 number_pixels getinterval", 1361 "} bind def", 1362 "", 1363 "/PseudoClassImage", 1364 "{", 1365 " %", 1366 " % Display a PseudoClass image.", 1367 " %", 1368 " % Parameters:", 1369 " % class: 0-PseudoClass or 1-Grayscale.", 1370 " %", 1371 " currentfile buffer readline pop", 1372 " token pop /class exch def pop", 1373 " class 0 gt", 1374 " {", 1375 " currentfile buffer readline pop", 1376 " token pop /depth exch def pop", 1377 " /grays columns 8 add depth sub depth mul 8 idiv string def", 1378 " columns rows depth", 1379 " [", 1380 " columns 0 0", 1381 " rows neg 0 rows", 1382 " ]", 1383 " { currentfile grays readhexstring pop } image", 1384 " }", 1385 " {", 1386 " %", 1387 " % Parameters:", 1388 " % colors: number of colors in the colormap.", 1389 " % colormap: red, green, blue color packets.", 1390 " %", 1391 " currentfile buffer readline pop", 1392 " token pop /colors exch def pop", 1393 " /colors colors 3 mul def", 1394 " /colormap colors string def", 1395 " currentfile colormap readhexstring pop pop", 1396 " systemdict /colorimage known", 1397 " {", 1398 " columns rows 8", 1399 " [", 1400 " columns 0 0", 1401 " rows neg 0 rows", 1402 " ]", 1403 " { PseudoClassPacket } false 3 colorimage", 1404 " }", 1405 " {", 1406 " %", 1407 " % No colorimage operator; convert to grayscale.", 1408 " %", 1409 " columns rows 8", 1410 " [", 1411 " columns 0 0", 1412 " rows neg 0 rows", 1413 " ]", 1414 " { GrayPseudoClassPacket } image", 1415 " } ifelse", 1416 " } ifelse", 1417 "} bind def", 1418 "", 1419 "/DisplayImage", 1420 "{", 1421 " %", 1422 " % Display a DirectClass or PseudoClass image.", 1423 " %", 1424 " % Parameters:", 1425 " % x & y translation.", 1426 " % x & y scale.", 1427 " % label pointsize.", 1428 " % image label.", 1429 " % image columns & rows.", 1430 " % class: 0-DirectClass or 1-PseudoClass.", 1431 " % compression: 0-none or 1-RunlengthEncoded.", 1432 " % hex color packets.", 1433 " %", 1434 " gsave", 1435 " /buffer 512 string def", 1436 " /byte 1 string def", 1437 " /color_packet 3 string def", 1438 " /pixels 768 string def", 1439 "", 1440 " currentfile buffer readline pop", 1441 " token pop /x exch def", 1442 " token pop /y exch def pop", 1443 " x y translate", 1444 " currentfile buffer readline pop", 1445 " token pop /x exch def", 1446 " token pop /y exch def pop", 1447 " currentfile buffer readline pop", 1448 " token pop /pointsize exch def pop", 1449 " /Times-Roman findfont pointsize scalefont setfont", 1450 (const char *) NULL 1451 }, 1452 *const PostscriptEpilog[]= 1453 { 1454 " x y scale", 1455 " currentfile buffer readline pop", 1456 " token pop /columns exch def", 1457 " token pop /rows exch def pop", 1458 " currentfile buffer readline pop", 1459 " token pop /class exch def pop", 1460 " currentfile buffer readline pop", 1461 " token pop /compression exch def pop", 1462 " class 0 gt { PseudoClassImage } { DirectClassImage } ifelse", 1463 " grestore", 1464 (const char *) NULL 1465 }; 1466 1467 char 1468 buffer[MagickPathExtent], 1469 date[MagickPathExtent], 1470 **labels, 1471 page_geometry[MagickPathExtent]; 1472 1473 CompressionType 1474 compression; 1475 1476 const char 1477 *const *s, 1478 *value; 1479 1480 const StringInfo 1481 *profile; 1482 1483 double 1484 pointsize; 1485 1486 GeometryInfo 1487 geometry_info; 1488 1489 MagickBooleanType 1490 status; 1491 1492 MagickOffsetType 1493 scene; 1494 1495 MagickStatusType 1496 flags; 1497 1498 PixelInfo 1499 pixel; 1500 1501 PointInfo 1502 delta, 1503 resolution, 1504 scale; 1505 1506 Quantum 1507 index; 1508 1509 RectangleInfo 1510 geometry, 1511 media_info, 1512 page_info; 1513 1514 register const Quantum 1515 *p; 1516 1517 register ssize_t 1518 i, 1519 x; 1520 1521 register unsigned char 1522 *q; 1523 1524 SegmentInfo 1525 bounds; 1526 1527 size_t 1528 bit, 1529 byte, 1530 length, 1531 page, 1532 text_size; 1533 1534 ssize_t 1535 j, 1536 y; 1537 1538 time_t 1539 timer; 1540 1541 unsigned char 1542 pixels[2048]; 1543 1544 /* 1545 Open output image file. 1546 */ 1547 assert(image_info != (const ImageInfo *) NULL); 1548 assert(image_info->signature == MagickCoreSignature); 1549 assert(image != (Image *) NULL); 1550 assert(image->signature == MagickCoreSignature); 1551 if (image->debug != MagickFalse) 1552 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1553 assert(exception != (ExceptionInfo *) NULL); 1554 assert(exception->signature == MagickCoreSignature); 1555 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 1556 if (status == MagickFalse) 1557 return(status); 1558 (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); 1559 compression=image->compression; 1560 if (image_info->compression != UndefinedCompression) 1561 compression=image_info->compression; 1562 page=1; 1563 scene=0; 1564 do 1565 { 1566 /* 1567 Scale relative to dots-per-inch. 1568 */ 1569 (void) TransformImageColorspace(image,sRGBColorspace,exception); 1570 delta.x=DefaultResolution; 1571 delta.y=DefaultResolution; 1572 resolution.x=image->resolution.x; 1573 resolution.y=image->resolution.y; 1574 if ((resolution.x == 0.0) || (resolution.y == 0.0)) 1575 { 1576 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 1577 resolution.x=geometry_info.rho; 1578 resolution.y=geometry_info.sigma; 1579 if ((flags & SigmaValue) == 0) 1580 resolution.y=resolution.x; 1581 } 1582 if (image_info->density != (char *) NULL) 1583 { 1584 flags=ParseGeometry(image_info->density,&geometry_info); 1585 resolution.x=geometry_info.rho; 1586 resolution.y=geometry_info.sigma; 1587 if ((flags & SigmaValue) == 0) 1588 resolution.y=resolution.x; 1589 } 1590 if (image->units == PixelsPerCentimeterResolution) 1591 { 1592 resolution.x=(double) ((size_t) (100.0*2.54*resolution.x+0.5)/100.0); 1593 resolution.y=(double) ((size_t) (100.0*2.54*resolution.y+0.5)/100.0); 1594 } 1595 SetGeometry(image,&geometry); 1596 (void) FormatLocaleString(page_geometry,MagickPathExtent,"%.20gx%.20g", 1597 (double) image->columns,(double) image->rows); 1598 if (image_info->page != (char *) NULL) 1599 (void) CopyMagickString(page_geometry,image_info->page,MagickPathExtent); 1600 else 1601 if ((image->page.width != 0) && (image->page.height != 0)) 1602 (void) FormatLocaleString(page_geometry,MagickPathExtent, 1603 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double) 1604 image->page.height,(double) image->page.x,(double) image->page.y); 1605 else 1606 if ((image->gravity != UndefinedGravity) && 1607 (LocaleCompare(image_info->magick,"PS") == 0)) 1608 (void) CopyMagickString(page_geometry,PSPageGeometry,MagickPathExtent); 1609 (void) ConcatenateMagickString(page_geometry,">",MagickPathExtent); 1610 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y, 1611 &geometry.width,&geometry.height); 1612 scale.x=(double) (geometry.width*delta.x)/resolution.x; 1613 geometry.width=(size_t) floor(scale.x+0.5); 1614 scale.y=(double) (geometry.height*delta.y)/resolution.y; 1615 geometry.height=(size_t) floor(scale.y+0.5); 1616 (void) ParseAbsoluteGeometry(page_geometry,&media_info); 1617 (void) ParseGravityGeometry(image,page_geometry,&page_info,exception); 1618 if (image->gravity != UndefinedGravity) 1619 { 1620 geometry.x=(-page_info.x); 1621 geometry.y=(ssize_t) (media_info.height+page_info.y-image->rows); 1622 } 1623 pointsize=12.0; 1624 if (image_info->pointsize != 0.0) 1625 pointsize=image_info->pointsize; 1626 text_size=0; 1627 value=GetImageProperty(image,"label",exception); 1628 if (value != (const char *) NULL) 1629 text_size=(size_t) (MultilineCensus(value)*pointsize+12); 1630 if (page == 1) 1631 { 1632 /* 1633 Output Postscript header. 1634 */ 1635 if (LocaleCompare(image_info->magick,"PS") == 0) 1636 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0\n",MagickPathExtent); 1637 else 1638 (void) CopyMagickString(buffer,"%!PS-Adobe-3.0 EPSF-3.0\n", 1639 MagickPathExtent); 1640 (void) WriteBlobString(image,buffer); 1641 (void) WriteBlobString(image,"%%Creator: (ImageMagick)\n"); 1642 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n", 1643 image->filename); 1644 (void) WriteBlobString(image,buffer); 1645 timer=time((time_t *) NULL); 1646 (void) FormatMagickTime(timer,MagickPathExtent,date); 1647 (void) FormatLocaleString(buffer,MagickPathExtent, 1648 "%%%%CreationDate: (%s)\n",date); 1649 (void) WriteBlobString(image,buffer); 1650 bounds.x1=(double) geometry.x; 1651 bounds.y1=(double) geometry.y; 1652 bounds.x2=(double) geometry.x+scale.x; 1653 bounds.y2=(double) geometry.y+(geometry.height+text_size); 1654 if ((image_info->adjoin != MagickFalse) && 1655 (GetNextImageInList(image) != (Image *) NULL)) 1656 (void) CopyMagickString(buffer,"%%%%BoundingBox: (atend)\n", 1657 MagickPathExtent); 1658 else 1659 { 1660 (void) FormatLocaleString(buffer,MagickPathExtent, 1661 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5), 1662 ceil(bounds.y1-0.5),floor(bounds.x2+0.5),floor(bounds.y2+0.5)); 1663 (void) WriteBlobString(image,buffer); 1664 (void) FormatLocaleString(buffer,MagickPathExtent, 1665 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1, 1666 bounds.y1,bounds.x2,bounds.y2); 1667 } 1668 (void) WriteBlobString(image,buffer); 1669 profile=GetImageProfile(image,"8bim"); 1670 if (profile != (StringInfo *) NULL) 1671 { 1672 /* 1673 Embed Photoshop profile. 1674 */ 1675 (void) FormatLocaleString(buffer,MagickPathExtent, 1676 "%%BeginPhotoshop: %.20g",(double) GetStringInfoLength(profile)); 1677 (void) WriteBlobString(image,buffer); 1678 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++) 1679 { 1680 if ((i % 32) == 0) 1681 (void) WriteBlobString(image,"\n% "); 1682 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X", 1683 (unsigned int) (GetStringInfoDatum(profile)[i] & 0xff)); 1684 (void) WriteBlobString(image,buffer); 1685 } 1686 (void) WriteBlobString(image,"\n%EndPhotoshop\n"); 1687 } 1688 profile=GetImageProfile(image,"xmp"); 1689 DisableMSCWarning(4127) 1690 if (0 && (profile != (StringInfo *) NULL)) 1691 RestoreMSCWarning 1692 { 1693 /* 1694 Embed XML profile. 1695 */ 1696 (void) WriteBlobString(image,"\n%begin_xml_code\n"); 1697 (void) FormatLocaleString(buffer,MagickPathExtent, 1698 "\n%%begin_xml_packet: %.20g\n",(double) 1699 GetStringInfoLength(profile)); 1700 (void) WriteBlobString(image,buffer); 1701 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++) 1702 (void) WriteBlobByte(image,GetStringInfoDatum(profile)[i]); 1703 (void) WriteBlobString(image,"\n%end_xml_packet\n%end_xml_code\n"); 1704 } 1705 value=GetImageProperty(image,"label",exception); 1706 if (value != (const char *) NULL) 1707 (void) WriteBlobString(image, 1708 "%%DocumentNeededResources: font Times-Roman\n"); 1709 (void) WriteBlobString(image,"%%DocumentData: Clean7Bit\n"); 1710 (void) WriteBlobString(image,"%%LanguageLevel: 1\n"); 1711 if (LocaleCompare(image_info->magick,"PS") != 0) 1712 (void) WriteBlobString(image,"%%Pages: 1\n"); 1713 else 1714 { 1715 /* 1716 Compute the number of pages. 1717 */ 1718 (void) WriteBlobString(image,"%%Orientation: Portrait\n"); 1719 (void) WriteBlobString(image,"%%PageOrder: Ascend\n"); 1720 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Pages: %.20g\n", 1721 image_info->adjoin != MagickFalse ? (double) 1722 GetImageListLength(image) : 1.0); 1723 (void) WriteBlobString(image,buffer); 1724 } 1725 (void) WriteBlobString(image,"%%EndComments\n"); 1726 (void) WriteBlobString(image,"\n%%BeginDefaults\n"); 1727 (void) WriteBlobString(image,"%%EndDefaults\n\n"); 1728 if ((LocaleCompare(image_info->magick,"EPI") == 0) || 1729 (LocaleCompare(image_info->magick,"EPSI") == 0) || 1730 (LocaleCompare(image_info->magick,"EPT") == 0)) 1731 { 1732 Image 1733 *preview_image; 1734 1735 Quantum 1736 pixel; 1737 1738 register ssize_t 1739 x; 1740 1741 ssize_t 1742 y; 1743 1744 /* 1745 Create preview image. 1746 */ 1747 preview_image=CloneImage(image,0,0,MagickTrue,exception); 1748 if (preview_image == (Image *) NULL) 1749 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1750 /* 1751 Dump image as bitmap. 1752 */ 1753 (void) FormatLocaleString(buffer,MagickPathExtent, 1754 "%%%%BeginPreview: %.20g %.20g %.20g %.20g\n%% ",(double) 1755 preview_image->columns,(double) preview_image->rows,1.0, 1756 (double) ((((preview_image->columns+7) >> 3)*preview_image->rows+ 1757 35)/36)); 1758 (void) WriteBlobString(image,buffer); 1759 q=pixels; 1760 for (y=0; y < (ssize_t) image->rows; y++) 1761 { 1762 p=GetVirtualPixels(preview_image,0,y,preview_image->columns,1, 1763 exception); 1764 if (p == (const Quantum *) NULL) 1765 break; 1766 bit=0; 1767 byte=0; 1768 for (x=0; x < (ssize_t) preview_image->columns; x++) 1769 { 1770 byte<<=1; 1771 pixel=ClampToQuantum(GetPixelLuma(preview_image,p)); 1772 if (pixel >= (Quantum) (QuantumRange/2)) 1773 byte|=0x01; 1774 bit++; 1775 if (bit == 8) 1776 { 1777 q=PopHexPixel(hex_digits,byte,q); 1778 if ((q-pixels+8) >= 80) 1779 { 1780 *q++='\n'; 1781 (void) WriteBlob(image,q-pixels,pixels); 1782 q=pixels; 1783 (void) WriteBlobString(image,"% "); 1784 }; 1785 bit=0; 1786 byte=0; 1787 } 1788 } 1789 if (bit != 0) 1790 { 1791 byte<<=(8-bit); 1792 q=PopHexPixel(hex_digits,byte,q); 1793 if ((q-pixels+8) >= 80) 1794 { 1795 *q++='\n'; 1796 (void) WriteBlob(image,q-pixels,pixels); 1797 q=pixels; 1798 (void) WriteBlobString(image,"% "); 1799 }; 1800 }; 1801 } 1802 if (q != pixels) 1803 { 1804 *q++='\n'; 1805 (void) WriteBlob(image,q-pixels,pixels); 1806 } 1807 (void) WriteBlobString(image,"\n%%EndPreview\n"); 1808 preview_image=DestroyImage(preview_image); 1809 } 1810 /* 1811 Output Postscript commands. 1812 */ 1813 for (s=PostscriptProlog; *s != (char *) NULL; s++) 1814 { 1815 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*s); 1816 (void) WriteBlobString(image,buffer); 1817 } 1818 value=GetImageProperty(image,"label",exception); 1819 if (value != (const char *) NULL) 1820 for (j=(ssize_t) MultilineCensus(value)-1; j >= 0; j--) 1821 { 1822 (void) WriteBlobString(image," /label 512 string def\n"); 1823 (void) WriteBlobString(image," currentfile label readline pop\n"); 1824 (void) FormatLocaleString(buffer,MagickPathExtent, 1825 " 0 y %g add moveto label show pop\n",j*pointsize+12); 1826 (void) WriteBlobString(image,buffer); 1827 } 1828 for (s=PostscriptEpilog; *s != (char *) NULL; s++) 1829 { 1830 (void) FormatLocaleString(buffer,MagickPathExtent,"%s\n",*s); 1831 (void) WriteBlobString(image,buffer); 1832 } 1833 if (LocaleCompare(image_info->magick,"PS") == 0) 1834 (void) WriteBlobString(image," showpage\n"); 1835 (void) WriteBlobString(image,"} bind def\n"); 1836 (void) WriteBlobString(image,"%%EndProlog\n"); 1837 } 1838 (void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Page: 1 %.20g\n", 1839 (double) (page++)); 1840 (void) WriteBlobString(image,buffer); 1841 (void) FormatLocaleString(buffer,MagickPathExtent, 1842 "%%%%PageBoundingBox: %.20g %.20g %.20g %.20g\n",(double) geometry.x, 1843 (double) geometry.y,geometry.x+(double) geometry.width,geometry.y+(double) 1844 (geometry.height+text_size)); 1845 (void) WriteBlobString(image,buffer); 1846 if ((double) geometry.x < bounds.x1) 1847 bounds.x1=(double) geometry.x; 1848 if ((double) geometry.y < bounds.y1) 1849 bounds.y1=(double) geometry.y; 1850 if ((double) (geometry.x+geometry.width-1) > bounds.x2) 1851 bounds.x2=(double) geometry.x+geometry.width-1; 1852 if ((double) (geometry.y+(geometry.height+text_size)-1) > bounds.y2) 1853 bounds.y2=(double) geometry.y+(geometry.height+text_size)-1; 1854 value=GetImageProperty(image,"label",exception); 1855 if (value != (const char *) NULL) 1856 (void) WriteBlobString(image,"%%%%PageResources: font Times-Roman\n"); 1857 if (LocaleCompare(image_info->magick,"PS") != 0) 1858 (void) WriteBlobString(image,"userdict begin\n"); 1859 (void) WriteBlobString(image,"DisplayImage\n"); 1860 /* 1861 Output image data. 1862 */ 1863 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n%g %g\n%g\n", 1864 (double) geometry.x,(double) geometry.y,scale.x,scale.y,pointsize); 1865 (void) WriteBlobString(image,buffer); 1866 labels=(char **) NULL; 1867 value=GetImageProperty(image,"label",exception); 1868 if (value != (const char *) NULL) 1869 labels=StringToList(value); 1870 if (labels != (char **) NULL) 1871 { 1872 for (i=0; labels[i] != (char *) NULL; i++) 1873 { 1874 (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n", 1875 labels[i]); 1876 (void) WriteBlobString(image,buffer); 1877 labels[i]=DestroyString(labels[i]); 1878 } 1879 labels=(char **) RelinquishMagickMemory(labels); 1880 } 1881 (void) ResetMagickMemory(&pixel,0,sizeof(pixel)); 1882 pixel.alpha=(MagickRealType) TransparentAlpha; 1883 index=0; 1884 x=0; 1885 if ((image_info->type != TrueColorType) && 1886 (SetImageGray(image,exception) != MagickFalse)) 1887 { 1888 if (SetImageMonochrome(image,exception) == MagickFalse) 1889 { 1890 Quantum 1891 pixel; 1892 1893 /* 1894 Dump image as grayscale. 1895 */ 1896 (void) FormatLocaleString(buffer,MagickPathExtent, 1897 "%.20g %.20g\n1\n1\n1\n8\n",(double) image->columns,(double) 1898 image->rows); 1899 (void) WriteBlobString(image,buffer); 1900 q=pixels; 1901 for (y=0; y < (ssize_t) image->rows; y++) 1902 { 1903 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1904 if (p == (const Quantum *) NULL) 1905 break; 1906 for (x=0; x < (ssize_t) image->columns; x++) 1907 { 1908 pixel=(Quantum) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma( 1909 image,p))); 1910 q=PopHexPixel(hex_digits,(size_t) pixel,q); 1911 if ((q-pixels+8) >= 80) 1912 { 1913 *q++='\n'; 1914 (void) WriteBlob(image,q-pixels,pixels); 1915 q=pixels; 1916 } 1917 p+=GetPixelChannels(image); 1918 } 1919 if (image->previous == (Image *) NULL) 1920 { 1921 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 1922 y,image->rows); 1923 if (status == MagickFalse) 1924 break; 1925 } 1926 } 1927 if (q != pixels) 1928 { 1929 *q++='\n'; 1930 (void) WriteBlob(image,q-pixels,pixels); 1931 } 1932 } 1933 else 1934 { 1935 ssize_t 1936 y; 1937 1938 Quantum 1939 pixel; 1940 1941 /* 1942 Dump image as bitmap. 1943 */ 1944 (void) FormatLocaleString(buffer,MagickPathExtent, 1945 "%.20g %.20g\n1\n1\n1\n1\n",(double) image->columns,(double) 1946 image->rows); 1947 (void) WriteBlobString(image,buffer); 1948 q=pixels; 1949 for (y=0; y < (ssize_t) image->rows; y++) 1950 { 1951 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1952 if (p == (const Quantum *) NULL) 1953 break; 1954 bit=0; 1955 byte=0; 1956 for (x=0; x < (ssize_t) image->columns; x++) 1957 { 1958 byte<<=1; 1959 pixel=ClampToQuantum(GetPixelLuma(image,p)); 1960 if (pixel >= (Quantum) (QuantumRange/2)) 1961 byte|=0x01; 1962 bit++; 1963 if (bit == 8) 1964 { 1965 q=PopHexPixel(hex_digits,byte,q); 1966 if ((q-pixels+2) >= 80) 1967 { 1968 *q++='\n'; 1969 (void) WriteBlob(image,q-pixels,pixels); 1970 q=pixels; 1971 }; 1972 bit=0; 1973 byte=0; 1974 } 1975 p+=GetPixelChannels(image); 1976 } 1977 if (bit != 0) 1978 { 1979 byte<<=(8-bit); 1980 q=PopHexPixel(hex_digits,byte,q); 1981 if ((q-pixels+2) >= 80) 1982 { 1983 *q++='\n'; 1984 (void) WriteBlob(image,q-pixels,pixels); 1985 q=pixels; 1986 } 1987 }; 1988 if (image->previous == (Image *) NULL) 1989 { 1990 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) 1991 y,image->rows); 1992 if (status == MagickFalse) 1993 break; 1994 } 1995 } 1996 if (q != pixels) 1997 { 1998 *q++='\n'; 1999 (void) WriteBlob(image,q-pixels,pixels); 2000 } 2001 } 2002 } 2003 else 2004 if ((image->storage_class == DirectClass) || 2005 (image->colors > 256) || (image->alpha_trait != UndefinedPixelTrait)) 2006 { 2007 /* 2008 Dump DirectClass image. 2009 */ 2010 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n0\n%d\n", 2011 (double) image->columns,(double) image->rows, 2012 compression == RLECompression ? 1 : 0); 2013 (void) WriteBlobString(image,buffer); 2014 switch (compression) 2015 { 2016 case RLECompression: 2017 { 2018 /* 2019 Dump runlength-encoded DirectColor packets. 2020 */ 2021 q=pixels; 2022 for (y=0; y < (ssize_t) image->rows; y++) 2023 { 2024 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2025 if (p == (const Quantum *) NULL) 2026 break; 2027 GetPixelInfoPixel(image,p,&pixel); 2028 length=255; 2029 for (x=0; x < (ssize_t) image->columns; x++) 2030 { 2031 if ((GetPixelRed(image,p) == ClampToQuantum(pixel.red)) && 2032 (GetPixelGreen(image,p) == ClampToQuantum(pixel.green)) && 2033 (GetPixelBlue(image,p) == ClampToQuantum(pixel.blue)) && 2034 (GetPixelAlpha(image,p) == ClampToQuantum(pixel.alpha)) && 2035 (length < 255) && (x < (ssize_t) (image->columns-1))) 2036 length++; 2037 else 2038 { 2039 if (x > 0) 2040 { 2041 WriteRunlengthPacket(image,pixel,length,p); 2042 if ((q-pixels+10) >= 80) 2043 { 2044 *q++='\n'; 2045 (void) WriteBlob(image,q-pixels,pixels); 2046 q=pixels; 2047 } 2048 } 2049 length=0; 2050 } 2051 GetPixelInfoPixel(image,p,&pixel); 2052 p+=GetPixelChannels(image); 2053 } 2054 WriteRunlengthPacket(image,pixel,length,p); 2055 if ((q-pixels+10) >= 80) 2056 { 2057 *q++='\n'; 2058 (void) WriteBlob(image,q-pixels,pixels); 2059 q=pixels; 2060 } 2061 if (image->previous == (Image *) NULL) 2062 { 2063 status=SetImageProgress(image,SaveImageTag, 2064 (MagickOffsetType) y,image->rows); 2065 if (status == MagickFalse) 2066 break; 2067 } 2068 } 2069 if (q != pixels) 2070 { 2071 *q++='\n'; 2072 (void) WriteBlob(image,q-pixels,pixels); 2073 } 2074 break; 2075 } 2076 case NoCompression: 2077 default: 2078 { 2079 /* 2080 Dump uncompressed DirectColor packets. 2081 */ 2082 q=pixels; 2083 for (y=0; y < (ssize_t) image->rows; y++) 2084 { 2085 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2086 if (p == (const Quantum *) NULL) 2087 break; 2088 for (x=0; x < (ssize_t) image->columns; x++) 2089 { 2090 if ((image->alpha_trait != UndefinedPixelTrait) && 2091 (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)) 2092 { 2093 q=PopHexPixel(hex_digits,0xff,q); 2094 q=PopHexPixel(hex_digits,0xff,q); 2095 q=PopHexPixel(hex_digits,0xff,q); 2096 } 2097 else 2098 { 2099 q=PopHexPixel(hex_digits,ScaleQuantumToChar( 2100 GetPixelRed(image,p)),q); 2101 q=PopHexPixel(hex_digits,ScaleQuantumToChar( 2102 GetPixelGreen(image,p)),q); 2103 q=PopHexPixel(hex_digits,ScaleQuantumToChar( 2104 GetPixelBlue(image,p)),q); 2105 } 2106 if ((q-pixels+6) >= 80) 2107 { 2108 *q++='\n'; 2109 (void) WriteBlob(image,q-pixels,pixels); 2110 q=pixels; 2111 } 2112 p+=GetPixelChannels(image); 2113 } 2114 if (image->previous == (Image *) NULL) 2115 { 2116 status=SetImageProgress(image,SaveImageTag, 2117 (MagickOffsetType) y,image->rows); 2118 if (status == MagickFalse) 2119 break; 2120 } 2121 } 2122 if (q != pixels) 2123 { 2124 *q++='\n'; 2125 (void) WriteBlob(image,q-pixels,pixels); 2126 } 2127 break; 2128 } 2129 } 2130 (void) WriteBlobByte(image,'\n'); 2131 } 2132 else 2133 { 2134 /* 2135 Dump PseudoClass image. 2136 */ 2137 (void) FormatLocaleString(buffer,MagickPathExtent, 2138 "%.20g %.20g\n%d\n%d\n0\n",(double) image->columns,(double) 2139 image->rows,image->storage_class == PseudoClass ? 1 : 0, 2140 compression == RLECompression ? 1 : 0); 2141 (void) WriteBlobString(image,buffer); 2142 /* 2143 Dump number of colors and colormap. 2144 */ 2145 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double) 2146 image->colors); 2147 (void) WriteBlobString(image,buffer); 2148 for (i=0; i < (ssize_t) image->colors; i++) 2149 { 2150 (void) FormatLocaleString(buffer,MagickPathExtent,"%02X%02X%02X\n", 2151 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red)), 2152 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green)), 2153 ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue))); 2154 (void) WriteBlobString(image,buffer); 2155 } 2156 switch (compression) 2157 { 2158 case RLECompression: 2159 { 2160 /* 2161 Dump runlength-encoded PseudoColor packets. 2162 */ 2163 q=pixels; 2164 for (y=0; y < (ssize_t) image->rows; y++) 2165 { 2166 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2167 if (p == (const Quantum *) NULL) 2168 break; 2169 index=GetPixelIndex(image,p); 2170 length=255; 2171 for (x=0; x < (ssize_t) image->columns; x++) 2172 { 2173 if ((index == GetPixelIndex(image,p)) && 2174 (length < 255) && (x < ((ssize_t) image->columns-1))) 2175 length++; 2176 else 2177 { 2178 if (x > 0) 2179 { 2180 q=PopHexPixel(hex_digits,(size_t) index,q); 2181 q=PopHexPixel(hex_digits,(size_t) 2182 MagickMin(length,0xff),q); 2183 i++; 2184 if ((q-pixels+6) >= 80) 2185 { 2186 *q++='\n'; 2187 (void) WriteBlob(image,q-pixels,pixels); 2188 q=pixels; 2189 } 2190 } 2191 length=0; 2192 } 2193 index=GetPixelIndex(image,p); 2194 pixel.red=(MagickRealType) GetPixelRed(image,p); 2195 pixel.green=(MagickRealType) GetPixelGreen(image,p); 2196 pixel.blue=(MagickRealType) GetPixelBlue(image,p); 2197 pixel.alpha=(MagickRealType) GetPixelAlpha(image,p); 2198 p+=GetPixelChannels(image); 2199 } 2200 q=PopHexPixel(hex_digits,(size_t) index,q); 2201 q=PopHexPixel(hex_digits,(size_t) 2202 MagickMin(length,0xff),q); 2203 if (image->previous == (Image *) NULL) 2204 { 2205 status=SetImageProgress(image,SaveImageTag, 2206 (MagickOffsetType) y,image->rows); 2207 if (status == MagickFalse) 2208 break; 2209 } 2210 } 2211 if (q != pixels) 2212 { 2213 *q++='\n'; 2214 (void) WriteBlob(image,q-pixels,pixels); 2215 } 2216 break; 2217 } 2218 case NoCompression: 2219 default: 2220 { 2221 /* 2222 Dump uncompressed PseudoColor packets. 2223 */ 2224 q=pixels; 2225 for (y=0; y < (ssize_t) image->rows; y++) 2226 { 2227 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2228 if (p == (const Quantum *) NULL) 2229 break; 2230 for (x=0; x < (ssize_t) image->columns; x++) 2231 { 2232 q=PopHexPixel(hex_digits,(size_t) GetPixelIndex(image,p),q); 2233 if ((q-pixels+4) >= 80) 2234 { 2235 *q++='\n'; 2236 (void) WriteBlob(image,q-pixels,pixels); 2237 q=pixels; 2238 } 2239 p+=GetPixelChannels(image); 2240 } 2241 if (image->previous == (Image *) NULL) 2242 { 2243 status=SetImageProgress(image,SaveImageTag, 2244 (MagickOffsetType) y,image->rows); 2245 if (status == MagickFalse) 2246 break; 2247 } 2248 } 2249 if (q != pixels) 2250 { 2251 *q++='\n'; 2252 (void) WriteBlob(image,q-pixels,pixels); 2253 } 2254 break; 2255 } 2256 } 2257 (void) WriteBlobByte(image,'\n'); 2258 } 2259 if (LocaleCompare(image_info->magick,"PS") != 0) 2260 (void) WriteBlobString(image,"end\n"); 2261 (void) WriteBlobString(image,"%%PageTrailer\n"); 2262 if (GetNextImageInList(image) == (Image *) NULL) 2263 break; 2264 image=SyncNextImageInList(image); 2265 status=SetImageProgress(image,SaveImagesTag,scene++, 2266 GetImageListLength(image)); 2267 if (status == MagickFalse) 2268 break; 2269 } while (image_info->adjoin != MagickFalse); 2270 (void) WriteBlobString(image,"%%Trailer\n"); 2271 if (page > 2) 2272 { 2273 (void) FormatLocaleString(buffer,MagickPathExtent, 2274 "%%%%BoundingBox: %.20g %.20g %.20g %.20g\n",ceil(bounds.x1-0.5), 2275 ceil(bounds.y1-0.5),floor(bounds.x2-0.5),floor(bounds.y2-0.5)); 2276 (void) WriteBlobString(image,buffer); 2277 (void) FormatLocaleString(buffer,MagickPathExtent, 2278 "%%%%HiResBoundingBox: %g %g %g %g\n",bounds.x1,bounds.y1,bounds.x2, 2279 bounds.y2); 2280 (void) WriteBlobString(image,buffer); 2281 } 2282 (void) WriteBlobString(image,"%%EOF\n"); 2283 (void) CloseBlob(image); 2284 return(MagickTrue); 2285 } 2286