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