]> granicus.if.org Git - imagemagick/blob - coders/pcl.c
(no commit message)
[imagemagick] / coders / pcl.c
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 %                                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 \f
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 \f
73 /*
74   Forward declarations.
75 */
76 static MagickBooleanType
77   WritePCLImage(const ImageInfo *,Image *);
78 \f
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 */
104 static 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 \f
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 */
141 static 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);
355   status=SystemCommand(read_info->verbose,command) != 0 ? MagickTrue :
356     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 \f
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 */
409 ModuleExport 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 \f
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 */
446 ModuleExport void UnregisterPCLImage(void)
447 {
448   (void) UnregisterMagickInfo("PCL");
449 }
450 \f
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
477 static 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
547 static 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
648 static 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     }
937     (void) WriteBlobString(image,"\033*r0B");  /* end graphics */
938     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 }