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