1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP CCCC L % 7 % P P C L % 8 % PPPP C L % 9 % P C L % 10 % P CCCC LLLLL % 11 % % 12 % % 13 % Read/Write HP PCL Printer 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/draw.h" 56 #include "MagickCore/exception.h" 57 #include "MagickCore/exception-private.h" 58 #include "MagickCore/geometry.h" 59 #include "MagickCore/image.h" 60 #include "MagickCore/image-private.h" 61 #include "MagickCore/list.h" 62 #include "MagickCore/magick.h" 63 #include "MagickCore/memory_.h" 64 #include "MagickCore/monitor.h" 65 #include "MagickCore/monitor-private.h" 66 #include "MagickCore/option.h" 67 #include "MagickCore/pixel-accessor.h" 68 #include "MagickCore/profile.h" 69 #include "MagickCore/property.h" 70 #include "MagickCore/resource_.h" 71 #include "MagickCore/quantum-private.h" 72 #include "MagickCore/static.h" 73 #include "MagickCore/string_.h" 74 #include "MagickCore/module.h" 75 #include "MagickCore/token.h" 76 #include "MagickCore/transform.h" 77 #include "MagickCore/utility.h" 78 79 /* 81 Forward declarations. 82 */ 83 static MagickBooleanType 84 WritePCLImage(const ImageInfo *,Image *,ExceptionInfo *); 85 86 /* 88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 89 % % 90 % % 91 % % 92 % I s P C L % 93 % % 94 % % 95 % % 96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97 % 98 % IsPCL() returns MagickTrue if the image format type, identified by the 99 % magick string, is PCL. 100 % 101 % The format of the IsPCL method is: 102 % 103 % MagickBooleanType IsPCL(const unsigned char *magick,const size_t length) 104 % 105 % A description of each parameter follows: 106 % 107 % o magick: compare image format pattern against these bytes. 108 % 109 % o length: Specifies the length of the magick string. 110 % 111 */ 112 static MagickBooleanType IsPCL(const unsigned char *magick,const size_t length) 113 { 114 if (length < 4) 115 return(MagickFalse); 116 if (memcmp(magick,"\033E\033&",4) == 0) 117 return(MagickFalse); 118 if (memcmp(magick,"\033E\033",3) == 0) 119 return(MagickTrue); 120 return(MagickFalse); 121 } 122 123 /* 125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126 % % 127 % % 128 % % 129 % R e a d P C L I m a g e % 130 % % 131 % % 132 % % 133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 134 % 135 % ReadPCLImage() reads a Printer Control Language image file and returns it. 136 % It allocates the memory necessary for the new Image structure and returns a 137 % pointer to the new image. 138 % 139 % The format of the ReadPCLImage method is: 140 % 141 % Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception) 142 % 143 % A description of each parameter follows: 144 % 145 % o image_info: the image info. 146 % 147 % o exception: return any errors or warnings in this structure. 148 % 149 */ 150 static Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception) 151 { 152 #define CropBox "CropBox" 153 #define DeviceCMYK "DeviceCMYK" 154 #define MediaBox "MediaBox" 155 #define RenderPCLText " Rendering PCL... " 156 157 char 158 command[MagickPathExtent], 159 *density, 160 filename[MagickPathExtent], 161 geometry[MagickPathExtent], 162 *options, 163 input_filename[MagickPathExtent]; 164 165 const DelegateInfo 166 *delegate_info; 167 168 Image 169 *image, 170 *next_image; 171 172 ImageInfo 173 *read_info; 174 175 MagickBooleanType 176 cmyk, 177 status; 178 179 PointInfo 180 delta; 181 182 RectangleInfo 183 bounding_box, 184 page; 185 186 register char 187 *p; 188 189 register ssize_t 190 c; 191 192 SegmentInfo 193 bounds; 194 195 size_t 196 height, 197 width; 198 199 ssize_t 200 count; 201 202 assert(image_info != (const ImageInfo *) NULL); 203 assert(image_info->signature == MagickCoreSignature); 204 if (image_info->debug != MagickFalse) 205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 206 image_info->filename); 207 assert(exception != (ExceptionInfo *) NULL); 208 assert(exception->signature == MagickCoreSignature); 209 /* 210 Open image file. 211 */ 212 image=AcquireImage(image_info,exception); 213 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 214 if (status == MagickFalse) 215 { 216 image=DestroyImageList(image); 217 return((Image *) NULL); 218 } 219 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename); 220 if (status == MagickFalse) 221 { 222 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", 223 image_info->filename); 224 image=DestroyImageList(image); 225 return((Image *) NULL); 226 } 227 /* 228 Set the page density. 229 */ 230 delta.x=DefaultResolution; 231 delta.y=DefaultResolution; 232 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0)) 233 { 234 GeometryInfo 235 geometry_info; 236 237 MagickStatusType 238 flags; 239 240 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 241 image->resolution.x=geometry_info.rho; 242 image->resolution.y=geometry_info.sigma; 243 if ((flags & SigmaValue) == 0) 244 image->resolution.y=image->resolution.x; 245 } 246 /* 247 Determine page geometry from the PCL media box. 248 */ 249 cmyk=image->colorspace == CMYKColorspace ? MagickTrue : MagickFalse; 250 count=0; 251 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box)); 252 (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); 253 (void) ResetMagickMemory(&page,0,sizeof(page)); 254 (void) ResetMagickMemory(command,0,sizeof(command)); 255 p=command; 256 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image)) 257 { 258 if (image_info->page != (char *) NULL) 259 continue; 260 /* 261 Note PCL elements. 262 */ 263 *p++=(char) c; 264 if ((c != (int) '/') && (c != '\n') && 265 ((size_t) (p-command) < (MagickPathExtent-1))) 266 continue; 267 *p='\0'; 268 p=command; 269 /* 270 Is this a CMYK document? 271 */ 272 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0) 273 cmyk=MagickTrue; 274 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0) 275 { 276 /* 277 Note region defined by crop box. 278 */ 279 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf", 280 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 281 if (count != 4) 282 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf", 283 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 284 } 285 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0) 286 { 287 /* 288 Note region defined by media box. 289 */ 290 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf", 291 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 292 if (count != 4) 293 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf", 294 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 295 } 296 if (count != 4) 297 continue; 298 /* 299 Set PCL render geometry. 300 */ 301 width=(size_t) floor(bounds.x2-bounds.x1+0.5); 302 height=(size_t) floor(bounds.y2-bounds.y1+0.5); 303 if (width > page.width) 304 page.width=width; 305 if (height > page.height) 306 page.height=height; 307 } 308 (void) CloseBlob(image); 309 /* 310 Render PCL with the GhostPCL delegate. 311 */ 312 if ((page.width == 0) || (page.height == 0)) 313 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 314 if (image_info->page != (char *) NULL) 315 (void) ParseAbsoluteGeometry(image_info->page,&page); 316 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g",(double) 317 page.width,(double) page.height); 318 if (image_info->monochrome != MagickFalse) 319 delegate_info=GetDelegateInfo("pcl:mono",(char *) NULL,exception); 320 else 321 if (cmyk != MagickFalse) 322 delegate_info=GetDelegateInfo("pcl:cmyk",(char *) NULL,exception); 323 else 324 delegate_info=GetDelegateInfo("pcl:color",(char *) NULL,exception); 325 if (delegate_info == (const DelegateInfo *) NULL) 326 return((Image *) NULL); 327 if ((page.width == 0) || (page.height == 0)) 328 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 329 if (image_info->page != (char *) NULL) 330 (void) ParseAbsoluteGeometry(image_info->page,&page); 331 density=AcquireString(""); 332 options=AcquireString(""); 333 (void) FormatLocaleString(density,MagickPathExtent,"%gx%g",image->resolution.x, 334 image->resolution.y); 335 page.width=(size_t) floor(page.width*image->resolution.x/delta.x+0.5); 336 page.height=(size_t) floor(page.height*image->resolution.y/delta.y+0.5); 337 (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double) 338 page.width,(double) page.height); 339 image=DestroyImage(image); 340 read_info=CloneImageInfo(image_info); 341 *read_info->magick='\0'; 342 if (read_info->number_scenes != 0) 343 { 344 if (read_info->number_scenes != 1) 345 (void) FormatLocaleString(options,MagickPathExtent,"-dLastPage=%.20g", 346 (double) (read_info->scene+read_info->number_scenes)); 347 else 348 (void) FormatLocaleString(options,MagickPathExtent, 349 "-dFirstPage=%.20g -dLastPage=%.20g",(double) read_info->scene+1, 350 (double) (read_info->scene+read_info->number_scenes)); 351 read_info->number_scenes=0; 352 if (read_info->scenes != (char *) NULL) 353 *read_info->scenes='\0'; 354 } 355 (void) CopyMagickString(filename,read_info->filename,MagickPathExtent); 356 (void) AcquireUniqueFilename(read_info->filename); 357 (void) FormatLocaleString(command,MagickPathExtent, 358 GetDelegateCommands(delegate_info), 359 read_info->antialias != MagickFalse ? 4 : 1, 360 read_info->antialias != MagickFalse ? 4 : 1,density,options, 361 read_info->filename,input_filename); 362 options=DestroyString(options); 363 density=DestroyString(density); 364 status=ExternalDelegateCommand(MagickFalse,read_info->verbose,command, 365 (char *) NULL,exception) != 0 ? MagickTrue : MagickFalse; 366 image=ReadImage(read_info,exception); 367 (void) RelinquishUniqueFileResource(read_info->filename); 368 (void) RelinquishUniqueFileResource(input_filename); 369 read_info=DestroyImageInfo(read_info); 370 if (image == (Image *) NULL) 371 ThrowReaderException(DelegateError,"PCLDelegateFailed"); 372 if (LocaleCompare(image->magick,"BMP") == 0) 373 { 374 Image 375 *cmyk_image; 376 377 cmyk_image=ConsolidateCMYKImages(image,exception); 378 if (cmyk_image != (Image *) NULL) 379 { 380 image=DestroyImageList(image); 381 image=cmyk_image; 382 } 383 } 384 do 385 { 386 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 387 image->page=page; 388 next_image=SyncNextImageInList(image); 389 if (next_image != (Image *) NULL) 390 image=next_image; 391 } while (next_image != (Image *) NULL); 392 return(GetFirstImageInList(image)); 393 } 394 395 /* 397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 398 % % 399 % % 400 % % 401 % R e g i s t e r P C L I m a g e % 402 % % 403 % % 404 % % 405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 406 % 407 % RegisterPCLImage() adds attributes for the PCL image format to 408 % the list of supported formats. The attributes include the image format 409 % tag, a method to read and/or write the format, whether the format 410 % supports the saving of more than one frame to the i file or blob, 411 % whether the format supports native in-memory I/O, and a brief 412 % description of the format. 413 % 414 % The format of the RegisterPCLImage method is: 415 % 416 % size_t RegisterPCLImage(void) 417 % 418 */ 419 ModuleExport size_t RegisterPCLImage(void) 420 { 421 MagickInfo 422 *entry; 423 424 entry=AcquireMagickInfo("PCL","PCL","Printer Control Language"); 425 entry->decoder=(DecodeImageHandler *) ReadPCLImage; 426 entry->encoder=(EncodeImageHandler *) WritePCLImage; 427 entry->magick=(IsImageFormatHandler *) IsPCL; 428 entry->flags^=CoderBlobSupportFlag; 429 entry->flags^=CoderDecoderThreadSupportFlag; 430 entry->flags|=CoderSeekableStreamFlag; 431 (void) RegisterMagickInfo(entry); 432 return(MagickImageCoderSignature); 433 } 434 435 /* 437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 438 % % 439 % % 440 % % 441 % U n r e g i s t e r P C L I m a g e % 442 % % 443 % % 444 % % 445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 446 % 447 % UnregisterPCLImage() removes format registrations made by the PCL module 448 % from the list of supported formats. 449 % 450 % The format of the UnregisterPCLImage method is: 451 % 452 % UnregisterPCLImage(void) 453 % 454 */ 455 ModuleExport void UnregisterPCLImage(void) 456 { 457 (void) UnregisterMagickInfo("PCL"); 458 } 459 460 /* 462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 463 % % 464 % % 465 % % 466 % W r i t e P C L I m a g e % 467 % % 468 % % 469 % % 470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 471 % 472 % WritePCLImage() writes an image in the Page Control Language encoded 473 % image format. 474 % 475 % The format of the WritePCLImage method is: 476 % 477 % MagickBooleanType WritePCLImage(const ImageInfo *image_info, 478 % Image *image,ExceptionInfo *exception) 479 % 480 % A description of each parameter follows. 481 % 482 % o image_info: the image info. 483 % 484 % o image: The image. 485 % 486 % o exception: return any errors or warnings in this structure. 487 % 488 */ 489 490 static size_t PCLDeltaCompressImage(const size_t length, 491 const unsigned char *previous_pixels,const unsigned char *pixels, 492 unsigned char *compress_pixels) 493 { 494 int 495 delta, 496 j, 497 replacement; 498 499 register ssize_t 500 i, 501 x; 502 503 register unsigned char 504 *q; 505 506 q=compress_pixels; 507 for (x=0; x < (ssize_t) length; ) 508 { 509 j=0; 510 for (i=0; x < (ssize_t) length; x++) 511 { 512 if (*pixels++ != *previous_pixels++) 513 { 514 i=1; 515 break; 516 } 517 j++; 518 } 519 while (x < (ssize_t) length) 520 { 521 x++; 522 if (*pixels == *previous_pixels) 523 break; 524 i++; 525 previous_pixels++; 526 pixels++; 527 } 528 if (i == 0) 529 break; 530 replacement=j >= 31 ? 31 : j; 531 j-=replacement; 532 delta=i >= 8 ? 8 : i; 533 *q++=(unsigned char) (((delta-1) << 5) | replacement); 534 if (replacement == 31) 535 { 536 for (replacement=255; j != 0; ) 537 { 538 if (replacement > j) 539 replacement=j; 540 *q++=(unsigned char) replacement; 541 j-=replacement; 542 } 543 if (replacement == 255) 544 *q++='\0'; 545 } 546 for (pixels-=i; i != 0; ) 547 { 548 for (i-=delta; delta != 0; delta--) 549 *q++=(*pixels++); 550 if (i == 0) 551 break; 552 delta=i; 553 if (i >= 8) 554 delta=8; 555 *q++=(unsigned char) ((delta-1) << 5); 556 } 557 } 558 return((size_t) (q-compress_pixels)); 559 } 560 561 static size_t PCLPackbitsCompressImage(const size_t length, 562 const unsigned char *pixels,unsigned char *compress_pixels) 563 { 564 int 565 count; 566 567 register ssize_t 568 x; 569 570 register unsigned char 571 *q; 572 573 ssize_t 574 j; 575 576 unsigned char 577 packbits[128]; 578 579 /* 580 Compress pixels with Packbits encoding. 581 */ 582 q=compress_pixels; 583 for (x=(ssize_t) length; x != 0; ) 584 { 585 switch (x) 586 { 587 case 1: 588 { 589 x--; 590 *q++=0; 591 *q++=(*pixels); 592 break; 593 } 594 case 2: 595 { 596 x-=2; 597 *q++=1; 598 *q++=(*pixels); 599 *q++=pixels[1]; 600 break; 601 } 602 case 3: 603 { 604 x-=3; 605 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) 606 { 607 *q++=(unsigned char) ((256-3)+1); 608 *q++=(*pixels); 609 break; 610 } 611 *q++=2; 612 *q++=(*pixels); 613 *q++=pixels[1]; 614 *q++=pixels[2]; 615 break; 616 } 617 default: 618 { 619 if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) 620 { 621 /* 622 Packed run. 623 */ 624 count=3; 625 while (((ssize_t) count < x) && (*pixels == *(pixels+count))) 626 { 627 count++; 628 if (count >= 127) 629 break; 630 } 631 x-=count; 632 *q++=(unsigned char) ((256-count)+1); 633 *q++=(*pixels); 634 pixels+=count; 635 break; 636 } 637 /* 638 Literal run. 639 */ 640 count=0; 641 while ((*(pixels+count) != *(pixels+count+1)) || 642 (*(pixels+count+1) != *(pixels+count+2))) 643 { 644 packbits[count+1]=pixels[count]; 645 count++; 646 if (((ssize_t) count >= (x-3)) || (count >= 127)) 647 break; 648 } 649 x-=count; 650 *packbits=(unsigned char) (count-1); 651 for (j=0; j <= (ssize_t) count; j++) 652 *q++=packbits[j]; 653 pixels+=count; 654 break; 655 } 656 } 657 } 658 *q++=128; /* EOD marker */ 659 return((size_t) (q-compress_pixels)); 660 } 661 662 static MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image, 663 ExceptionInfo *exception) 664 { 665 char 666 buffer[MagickPathExtent]; 667 668 CompressionType 669 compression; 670 671 const char 672 *option; 673 674 MagickBooleanType 675 status; 676 677 MagickOffsetType 678 scene; 679 680 register const Quantum *p; 681 682 register ssize_t i, x; 683 684 register unsigned char *q; 685 686 size_t 687 density, 688 length, 689 one, 690 packets; 691 692 ssize_t 693 y; 694 695 unsigned char 696 bits_per_pixel, 697 *compress_pixels, 698 *pixels, 699 *previous_pixels; 700 701 /* 702 Open output image file. 703 */ 704 assert(image_info != (const ImageInfo *) NULL); 705 assert(image_info->signature == MagickCoreSignature); 706 assert(image != (Image *) NULL); 707 assert(image->signature == MagickCoreSignature); 708 if (image->debug != MagickFalse) 709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 710 assert(exception != (ExceptionInfo *) NULL); 711 assert(exception->signature == MagickCoreSignature); 712 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 713 if (status == MagickFalse) 714 return(status); 715 density=75; 716 if (image_info->density != (char *) NULL) 717 { 718 GeometryInfo 719 geometry; 720 721 (void) ParseGeometry(image_info->density,&geometry); 722 density=(size_t) geometry.rho; 723 } 724 scene=0; 725 one=1; 726 do 727 { 728 /* 729 Initialize the printer. 730 */ 731 (void) TransformImageColorspace(image,sRGBColorspace,exception); 732 (void) WriteBlobString(image,"\033E"); /* printer reset */ 733 (void) WriteBlobString(image,"\033*r3F"); /* set presentation mode */ 734 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*r%.20gs%.20gT", 735 (double) image->columns,(double) image->rows); 736 (void) WriteBlobString(image,buffer); 737 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*t%.20gR",(double) 738 density); 739 (void) WriteBlobString(image,buffer); 740 (void) WriteBlobString(image,"\033&l0E"); /* top margin 0 */ 741 if (SetImageMonochrome(image,exception) != MagickFalse) 742 { 743 /* 744 Monochrome image: use default printer monochrome setup. 745 */ 746 bits_per_pixel=1; 747 } 748 else 749 if (image->storage_class == DirectClass) 750 { 751 /* 752 DirectClass image. 753 */ 754 bits_per_pixel=24; 755 (void) WriteBlobString(image,"\033*v6W"); /* set color mode */ 756 (void) WriteBlobByte(image,0); /* RGB */ 757 (void) WriteBlobByte(image,3); /* direct by pixel */ 758 (void) WriteBlobByte(image,0); /* bits per index (ignored) */ 759 (void) WriteBlobByte(image,8); /* bits per red component */ 760 (void) WriteBlobByte(image,8); /* bits per green component */ 761 (void) WriteBlobByte(image,8); /* bits per blue component */ 762 } 763 else 764 { 765 /* 766 Colormapped image. 767 */ 768 bits_per_pixel=8; 769 (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */ 770 (void) WriteBlobByte(image,0); /* RGB */ 771 (void) WriteBlobByte(image,1); /* indexed by pixel */ 772 (void) WriteBlobByte(image,bits_per_pixel); /* bits per index */ 773 (void) WriteBlobByte(image,8); /* bits per red component */ 774 (void) WriteBlobByte(image,8); /* bits per green component */ 775 (void) WriteBlobByte(image,8); /* bits per blue component */ 776 for (i=0; i < (ssize_t) image->colors; i++) 777 { 778 (void) FormatLocaleString(buffer,MagickPathExtent, 779 "\033*v%da%db%dc%.20gI", 780 ScaleQuantumToChar(image->colormap[i].red), 781 ScaleQuantumToChar(image->colormap[i].green), 782 ScaleQuantumToChar(image->colormap[i].blue),(double) i); 783 (void) WriteBlobString(image,buffer); 784 } 785 for (one=1; i < (ssize_t) (one << bits_per_pixel); i++) 786 { 787 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*v%.20gI", 788 (double) i); 789 (void) WriteBlobString(image,buffer); 790 } 791 } 792 option=GetImageOption(image_info,"pcl:fit-to-page"); 793 if (IsStringTrue(option) != MagickFalse) 794 (void) WriteBlobString(image,"\033*r3A"); 795 else 796 (void) WriteBlobString(image,"\033*r1A"); /* start raster graphics */ 797 (void) WriteBlobString(image,"\033*b0Y"); /* set y offset */ 798 length=(image->columns*bits_per_pixel+7)/8; 799 pixels=(unsigned char *) AcquireQuantumMemory(length+1,sizeof(*pixels)); 800 if (pixels == (unsigned char *) NULL) 801 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 802 (void) ResetMagickMemory(pixels,0,(length+1)*sizeof(*pixels)); 803 compress_pixels=(unsigned char *) NULL; 804 previous_pixels=(unsigned char *) NULL; 805 806 compression=UndefinedCompression; 807 if (image_info->compression != UndefinedCompression) 808 compression=image_info->compression; 809 switch (compression) 810 { 811 case NoCompression: 812 { 813 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b0M"); 814 (void) WriteBlobString(image,buffer); 815 break; 816 } 817 case RLECompression: 818 { 819 compress_pixels=(unsigned char *) AcquireQuantumMemory(length+256, 820 sizeof(*compress_pixels)); 821 if (compress_pixels == (unsigned char *) NULL) 822 { 823 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 824 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 825 } 826 (void) ResetMagickMemory(compress_pixels,0,(length+256)* 827 sizeof(*compress_pixels)); 828 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b2M"); 829 (void) WriteBlobString(image,buffer); 830 break; 831 } 832 default: 833 { 834 compress_pixels=(unsigned char *) AcquireQuantumMemory(3*length+256, 835 sizeof(*compress_pixels)); 836 if (compress_pixels == (unsigned char *) NULL) 837 { 838 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 839 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 840 } 841 (void) ResetMagickMemory(compress_pixels,0,(3*length+256)* 842 sizeof(*compress_pixels)); 843 previous_pixels=(unsigned char *) AcquireQuantumMemory(length+1, 844 sizeof(*previous_pixels)); 845 if (previous_pixels == (unsigned char *) NULL) 846 { 847 compress_pixels=(unsigned char *) RelinquishMagickMemory( 848 compress_pixels); 849 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 850 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 851 } 852 (void) ResetMagickMemory(previous_pixels,0,(length+1)* 853 sizeof(*previous_pixels)); 854 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b3M"); 855 (void) WriteBlobString(image,buffer); 856 break; 857 } 858 } 859 for (y=0; y < (ssize_t) image->rows; y++) 860 { 861 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 862 if (p == (const Quantum *) NULL) 863 break; 864 q=pixels; 865 switch (bits_per_pixel) 866 { 867 case 1: 868 { 869 register unsigned char 870 bit, 871 byte; 872 873 /* 874 Monochrome image. 875 */ 876 bit=0; 877 byte=0; 878 for (x=0; x < (ssize_t) image->columns; x++) 879 { 880 byte<<=1; 881 if (GetPixelLuma(image,p) < (QuantumRange/2.0)) 882 byte|=0x01; 883 bit++; 884 if (bit == 8) 885 { 886 *q++=byte; 887 bit=0; 888 byte=0; 889 } 890 p+=GetPixelChannels(image); 891 } 892 if (bit != 0) 893 *q++=byte << (8-bit); 894 break; 895 } 896 case 8: 897 { 898 /* 899 Colormapped image. 900 */ 901 for (x=0; x < (ssize_t) image->columns; x++) 902 { 903 *q++=(unsigned char) GetPixelIndex(image,p); 904 p+=GetPixelChannels(image); 905 } 906 break; 907 } 908 case 24: 909 case 32: 910 { 911 /* 912 Truecolor image. 913 */ 914 for (x=0; x < (ssize_t) image->columns; x++) 915 { 916 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 917 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 918 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 919 p+=GetPixelChannels(image); 920 } 921 break; 922 } 923 } 924 switch (compression) 925 { 926 case NoCompression: 927 { 928 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b%.20gW", 929 (double) length); 930 (void) WriteBlobString(image,buffer); 931 (void) WriteBlob(image,length,pixels); 932 break; 933 } 934 case RLECompression: 935 { 936 packets=PCLPackbitsCompressImage(length,pixels,compress_pixels); 937 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b%.20gW", 938 (double) packets); 939 (void) WriteBlobString(image,buffer); 940 (void) WriteBlob(image,packets,compress_pixels); 941 break; 942 } 943 default: 944 { 945 if (y == 0) 946 for (i=0; i < (ssize_t) length; i++) 947 previous_pixels[i]=(~pixels[i]); 948 packets=PCLDeltaCompressImage(length,previous_pixels,pixels, 949 compress_pixels); 950 (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b%.20gW", 951 (double) packets); 952 (void) WriteBlobString(image,buffer); 953 (void) WriteBlob(image,packets,compress_pixels); 954 (void) CopyMagickMemory(previous_pixels,pixels,length* 955 sizeof(*pixels)); 956 break; 957 } 958 } 959 } 960 (void) WriteBlobString(image,"\033*rB"); /* end graphics */ 961 switch (compression) 962 { 963 case NoCompression: 964 break; 965 case RLECompression: 966 { 967 compress_pixels=(unsigned char *) RelinquishMagickMemory( 968 compress_pixels); 969 break; 970 } 971 default: 972 { 973 previous_pixels=(unsigned char *) RelinquishMagickMemory( 974 previous_pixels); 975 compress_pixels=(unsigned char *) RelinquishMagickMemory( 976 compress_pixels); 977 break; 978 } 979 } 980 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 981 if (GetNextImageInList(image) == (Image *) NULL) 982 break; 983 image=SyncNextImageInList(image); 984 status=SetImageProgress(image,SaveImagesTag,scene++, 985 GetImageListLength(image)); 986 if (status == MagickFalse) 987 break; 988 } while (image_info->adjoin != MagickFalse); 989 (void) WriteBlobString(image,"\033E"); 990 (void) CloseBlob(image); 991 return(MagickTrue); 992 } 993