pcl.c revision 4dd7567a1a42170a7eb263b67a933bec7c431353
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-2014 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/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/attribute.h" 45#include "MagickCore/blob.h" 46#include "MagickCore/blob-private.h" 47#include "MagickCore/cache.h" 48#include "MagickCore/color.h" 49#include "MagickCore/color-private.h" 50#include "MagickCore/colorspace.h" 51#include "MagickCore/colorspace-private.h" 52#include "MagickCore/constitute.h" 53#include "MagickCore/delegate.h" 54#include "MagickCore/draw.h" 55#include "MagickCore/exception.h" 56#include "MagickCore/exception-private.h" 57#include "MagickCore/geometry.h" 58#include "MagickCore/image.h" 59#include "MagickCore/image-private.h" 60#include "MagickCore/list.h" 61#include "MagickCore/magick.h" 62#include "MagickCore/memory_.h" 63#include "MagickCore/monitor.h" 64#include "MagickCore/monitor-private.h" 65#include "MagickCore/option.h" 66#include "MagickCore/pixel-accessor.h" 67#include "MagickCore/profile.h" 68#include "MagickCore/property.h" 69#include "MagickCore/resource_.h" 70#include "MagickCore/quantum-private.h" 71#include "MagickCore/static.h" 72#include "MagickCore/string_.h" 73#include "MagickCore/module.h" 74#include "MagickCore/token.h" 75#include "MagickCore/transform.h" 76#include "MagickCore/utility.h" 77 78/* 79 Forward declarations. 80*/ 81static MagickBooleanType 82 WritePCLImage(const ImageInfo *,Image *,ExceptionInfo *); 83 84/* 85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 86% % 87% % 88% % 89% I s P C L % 90% % 91% % 92% % 93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94% 95% IsPCL() returns MagickTrue if the image format type, identified by the 96% magick string, is PCL. 97% 98% The format of the IsPCL method is: 99% 100% MagickBooleanType IsPCL(const unsigned char *magick,const size_t length) 101% 102% A description of each parameter follows: 103% 104% o magick: compare image format pattern against these bytes. 105% 106% o length: Specifies the length of the magick string. 107% 108*/ 109static MagickBooleanType IsPCL(const unsigned char *magick,const size_t length) 110{ 111 if (length < 4) 112 return(MagickFalse); 113 if (memcmp(magick,"\033E\033&",4) == 0) 114 return(MagickFalse); 115 if (memcmp(magick,"\033E\033",3) == 0) 116 return(MagickTrue); 117 return(MagickFalse); 118} 119 120/* 121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 122% % 123% % 124% % 125% R e a d P C L I m a g e % 126% % 127% % 128% % 129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 130% 131% ReadPCLImage() reads a Printer Control Language image file and returns it. 132% It allocates the memory necessary for the new Image structure and returns a 133% pointer to the new image. 134% 135% The format of the ReadPCLImage method is: 136% 137% Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception) 138% 139% A description of each parameter follows: 140% 141% o image_info: the image info. 142% 143% o exception: return any errors or warnings in this structure. 144% 145*/ 146static Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception) 147{ 148#define CropBox "CropBox" 149#define DeviceCMYK "DeviceCMYK" 150#define MediaBox "MediaBox" 151#define RenderPCLText " Rendering PCL... " 152 153 char 154 command[MaxTextExtent], 155 density[MaxTextExtent], 156 filename[MaxTextExtent], 157 geometry[MaxTextExtent], 158 options[MaxTextExtent], 159 input_filename[MaxTextExtent]; 160 161 const char 162 *option; 163 164 const DelegateInfo 165 *delegate_info; 166 167 Image 168 *image, 169 *next_image; 170 171 ImageInfo 172 *read_info; 173 174 MagickBooleanType 175 cmyk, 176 status; 177 178 PointInfo 179 delta; 180 181 RectangleInfo 182 bounding_box, 183 page; 184 185 register char 186 *p; 187 188 register ssize_t 189 c; 190 191 SegmentInfo 192 bounds; 193 194 size_t 195 height, 196 width; 197 198 ssize_t 199 count; 200 201 assert(image_info != (const ImageInfo *) NULL); 202 assert(image_info->signature == MagickSignature); 203 if (image_info->debug != MagickFalse) 204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 205 image_info->filename); 206 assert(exception != (ExceptionInfo *) NULL); 207 assert(exception->signature == MagickSignature); 208 /* 209 Open image file. 210 */ 211 image=AcquireImage(image_info,exception); 212 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 213 if (status == MagickFalse) 214 { 215 image=DestroyImageList(image); 216 return((Image *) NULL); 217 } 218 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename); 219 if (status == MagickFalse) 220 { 221 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", 222 image_info->filename); 223 image=DestroyImageList(image); 224 return((Image *) NULL); 225 } 226 /* 227 Set the page density. 228 */ 229 delta.x=DefaultResolution; 230 delta.y=DefaultResolution; 231 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0)) 232 { 233 GeometryInfo 234 geometry_info; 235 236 MagickStatusType 237 flags; 238 239 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 240 image->resolution.x=geometry_info.rho; 241 image->resolution.y=geometry_info.sigma; 242 if ((flags & SigmaValue) == 0) 243 image->resolution.y=image->resolution.x; 244 } 245 /* 246 Determine page geometry from the PCL media box. 247 */ 248 cmyk=image->colorspace == CMYKColorspace ? MagickTrue : MagickFalse; 249 count=0; 250 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box)); 251 (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); 252 (void) ResetMagickMemory(&page,0,sizeof(page)); 253 (void) ResetMagickMemory(command,0,sizeof(command)); 254 p=command; 255 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image)) 256 { 257 if (image_info->page != (char *) NULL) 258 continue; 259 /* 260 Note PCL elements. 261 */ 262 *p++=(char) c; 263 if ((c != (int) '/') && (c != '\n') && 264 ((size_t) (p-command) < (MaxTextExtent-1))) 265 continue; 266 *p='\0'; 267 p=command; 268 /* 269 Is this a CMYK document? 270 */ 271 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0) 272 cmyk=MagickTrue; 273 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0) 274 { 275 /* 276 Note region defined by crop box. 277 */ 278 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf", 279 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 280 if (count != 4) 281 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf", 282 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 283 } 284 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0) 285 { 286 /* 287 Note region defined by media box. 288 */ 289 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf", 290 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 291 if (count != 4) 292 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf", 293 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 294 } 295 if (count != 4) 296 continue; 297 /* 298 Set PCL render geometry. 299 */ 300 width=(size_t) floor(bounds.x2-bounds.x1+0.5); 301 height=(size_t) floor(bounds.y2-bounds.y1+0.5); 302 if (width > page.width) 303 page.width=width; 304 if (height > page.height) 305 page.height=height; 306 } 307 (void) CloseBlob(image); 308 /* 309 Render PCL with the GhostPCL delegate. 310 */ 311 if ((page.width == 0) || (page.height == 0)) 312 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 313 if (image_info->page != (char *) NULL) 314 (void) ParseAbsoluteGeometry(image_info->page,&page); 315 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g",(double) 316 page.width,(double) page.height); 317 if (image_info->monochrome != MagickFalse) 318 delegate_info=GetDelegateInfo("pcl:mono",(char *) NULL,exception); 319 else 320 if (cmyk != MagickFalse) 321 delegate_info=GetDelegateInfo("pcl:cmyk",(char *) NULL,exception); 322 else 323 delegate_info=GetDelegateInfo("pcl:color",(char *) NULL,exception); 324 if (delegate_info == (const DelegateInfo *) NULL) 325 return((Image *) NULL); 326 *options='\0'; 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 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g", 332 image->resolution.x,image->resolution.y); 333 page.width=(size_t) floor(page.width*image->resolution.x/delta.x+0.5); 334 page.height=(size_t) floor(page.height*image->resolution.y/delta.y+ 335 0.5); 336 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double) 337 page.width,(double) page.height); 338 image=DestroyImage(image); 339 read_info=CloneImageInfo(image_info); 340 *read_info->magick='\0'; 341 if (read_info->number_scenes != 0) 342 { 343 if (read_info->number_scenes != 1) 344 (void) FormatLocaleString(options,MaxTextExtent,"-dLastPage=%.20g", 345 (double) (read_info->scene+read_info->number_scenes)); 346 else 347 (void) FormatLocaleString(options,MaxTextExtent, 348 "-dFirstPage=%.20g -dLastPage=%.20g",(double) read_info->scene+1, 349 (double) (read_info->scene+read_info->number_scenes)); 350 read_info->number_scenes=0; 351 if (read_info->scenes != (char *) NULL) 352 *read_info->scenes='\0'; 353 } 354 option=GetImageOption(image_info,"authenticate"); 355 if (option != (const char *) NULL) 356 (void) FormatLocaleString(options+strlen(options),MaxTextExtent, 357 " -sPCLPassword=%s",option); 358 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); 359 (void) AcquireUniqueFilename(read_info->filename); 360 (void) FormatLocaleString(command,MaxTextExtent, 361 GetDelegateCommands(delegate_info), 362 read_info->antialias != MagickFalse ? 4 : 1, 363 read_info->antialias != MagickFalse ? 4 : 1,density,options, 364 read_info->filename,input_filename); 365 status=SystemCommand(MagickFalse,read_info->verbose,command,(char *) NULL, 366 exception) != 0 ? MagickTrue : MagickFalse; 367 image=ReadImage(read_info,exception); 368 (void) RelinquishUniqueFileResource(read_info->filename); 369 (void) RelinquishUniqueFileResource(input_filename); 370 read_info=DestroyImageInfo(read_info); 371 if (image == (Image *) NULL) 372 ThrowReaderException(DelegateError,"PCLDelegateFailed"); 373 if (LocaleCompare(image->magick,"BMP") == 0) 374 { 375 Image 376 *cmyk_image; 377 378 cmyk_image=ConsolidateCMYKImages(image,exception); 379 if (cmyk_image != (Image *) NULL) 380 { 381 image=DestroyImageList(image); 382 image=cmyk_image; 383 } 384 } 385 do 386 { 387 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 388 image->page=page; 389 next_image=SyncNextImageInList(image); 390 if (next_image != (Image *) NULL) 391 image=next_image; 392 } while (next_image != (Image *) NULL); 393 return(GetFirstImageInList(image)); 394} 395 396/* 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*/ 419ModuleExport size_t RegisterPCLImage(void) 420{ 421 MagickInfo 422 *entry; 423 424 entry=SetMagickInfo("PCL"); 425 entry->decoder=(DecodeImageHandler *) ReadPCLImage; 426 entry->encoder=(EncodeImageHandler *) WritePCLImage; 427 entry->magick=(IsImageFormatHandler *) IsPCL; 428 entry->blob_support=MagickFalse; 429 entry->seekable_stream=MagickTrue; 430 entry->thread_support=EncoderThreadSupport; 431 entry->description=ConstantString("Printer Control Language"); 432 entry->module=ConstantString("PCL"); 433 (void) RegisterMagickInfo(entry); 434 return(MagickImageCoderSignature); 435} 436 437/* 438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 439% % 440% % 441% % 442% U n r e g i s t e r P C L I m a g e % 443% % 444% % 445% % 446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 447% 448% UnregisterPCLImage() removes format registrations made by the PCL module 449% from the list of supported formats. 450% 451% The format of the UnregisterPCLImage method is: 452% 453% UnregisterPCLImage(void) 454% 455*/ 456ModuleExport void UnregisterPCLImage(void) 457{ 458 (void) UnregisterMagickInfo("PCL"); 459} 460 461/* 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 490static 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 561static 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 662static MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image, 663 ExceptionInfo *exception) 664{ 665 char 666 buffer[MaxTextExtent]; 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 == MagickSignature); 706 assert(image != (Image *) NULL); 707 assert(image->signature == MagickSignature); 708 if (image->debug != MagickFalse) 709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 710 assert(exception != (ExceptionInfo *) NULL); 711 assert(exception->signature == MagickSignature); 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,MaxTextExtent,"\033*r%.20gs%.20gT", 735 (double) image->columns,(double) image->rows); 736 (void) WriteBlobString(image,buffer); 737 (void) FormatLocaleString(buffer,MaxTextExtent,"\033*t%.20gR",(double) 738 density); 739 (void) WriteBlobString(image,buffer); 740 (void) WriteBlobString(image,"\033&l0E"); /* top margin 0 */ 741 if (IsImageMonochrome(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,MaxTextExtent, 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,MaxTextExtent,"\033*v%.20gI", 788 (double) i); 789 (void) WriteBlobString(image,buffer); 790 } 791 } 792 option=GetImageOption(image_info,"pcl:fit-to-page"); 793 if (IfMagickTrue(IsStringTrue(option))) 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,MaxTextExtent,"\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,MaxTextExtent,"\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,MaxTextExtent,"\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,MaxTextExtent,"\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,MaxTextExtent,"\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,MaxTextExtent,"\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