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