]> 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-2011 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/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/draw.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/geometry.h"
57 #include "MagickCore/image.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/monitor.h"
63 #include "MagickCore/monitor-private.h"
64 #include "MagickCore/option.h"
65 #include "MagickCore/pixel-accessor.h"
66 #include "MagickCore/profile.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/quantum-private.h"
70 #include "MagickCore/static.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/module.h"
73 #include "MagickCore/token.h"
74 #include "MagickCore/transform.h"
75 #include "MagickCore/utility.h"
76 \f
77 /*
78   Forward declarations.
79 */
80 static MagickBooleanType
81   WritePCLImage(const ImageInfo *,Image *);
82 \f
83 /*
84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 %                                                                             %
86 %                                                                             %
87 %                                                                             %
88 %   I s P C L                                                                 %
89 %                                                                             %
90 %                                                                             %
91 %                                                                             %
92 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 %
94 %  IsPCL() returns MagickTrue if the image format type, identified by the
95 %  magick string, is PCL.
96 %
97 %  The format of the IsPCL method is:
98 %
99 %      MagickBooleanType IsPCL(const unsigned char *magick,const size_t length)
100 %
101 %  A description of each parameter follows:
102 %
103 %    o magick: compare image format pattern against these bytes.
104 %
105 %    o length: Specifies the length of the magick string.
106 %
107 */
108 static MagickBooleanType IsPCL(const unsigned char *magick,const size_t length)
109 {
110   if (length < 4)
111     return(MagickFalse);
112   if (memcmp(magick,"\033E\033&",4) == 0)
113     return(MagickFalse);
114   if (memcmp(magick,"\033E\033",3) == 0)
115     return(MagickTrue);
116   return(MagickFalse);
117 }
118 \f
119 /*
120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 %                                                                             %
122 %                                                                             %
123 %                                                                             %
124 %   R e a d P C L I m a g e                                                   %
125 %                                                                             %
126 %                                                                             %
127 %                                                                             %
128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129 %
130 %  ReadPCLImage() reads a Printer Control Language image file and returns it.
131 %  It allocates the memory necessary for the new Image structure and returns a
132 %  pointer to the new image.
133 %
134 %  The format of the ReadPCLImage method is:
135 %
136 %      Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception)
137 %
138 %  A description of each parameter follows:
139 %
140 %    o image_info: the image info.
141 %
142 %    o exception: return any errors or warnings in this structure.
143 %
144 */
145 static Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception)
146 {
147 #define CropBox  "CropBox"
148 #define DeviceCMYK  "DeviceCMYK"
149 #define MediaBox  "MediaBox"
150 #define RenderPCLText  "  Rendering PCL...  "
151
152   char
153     command[MaxTextExtent],
154     density[MaxTextExtent],
155     filename[MaxTextExtent],
156     geometry[MaxTextExtent],
157     options[MaxTextExtent],
158     input_filename[MaxTextExtent];
159
160   const DelegateInfo
161     *delegate_info;
162
163   Image
164     *image,
165     *next_image;
166
167   ImageInfo
168     *read_info;
169
170   MagickBooleanType
171     cmyk,
172     status;
173
174   PointInfo
175     delta;
176
177   RectangleInfo
178     bounding_box,
179     page;
180
181   register char
182     *p;
183
184   register ssize_t
185     c;
186
187   SegmentInfo
188     bounds;
189
190   size_t
191     height,
192     width;
193
194   ssize_t
195     count;
196
197   assert(image_info != (const ImageInfo *) NULL);
198   assert(image_info->signature == MagickSignature);
199   if (image_info->debug != MagickFalse)
200     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
201       image_info->filename);
202   assert(exception != (ExceptionInfo *) NULL);
203   assert(exception->signature == MagickSignature);
204   /*
205     Open image file.
206   */
207   image=AcquireImage(image_info);
208   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
209   if (status == MagickFalse)
210     {
211       image=DestroyImageList(image);
212       return((Image *) NULL);
213     }
214   status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
215   if (status == MagickFalse)
216     {
217       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
218         image_info->filename);
219       image=DestroyImageList(image);
220       return((Image *) NULL);
221     }
222   /*
223     Set the page density.
224   */
225   delta.x=DefaultResolution;
226   delta.y=DefaultResolution;
227   if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
228     {
229       GeometryInfo
230         geometry_info;
231
232       MagickStatusType
233         flags;
234
235       flags=ParseGeometry(PSDensityGeometry,&geometry_info);
236       image->x_resolution=geometry_info.rho;
237       image->y_resolution=geometry_info.sigma;
238       if ((flags & SigmaValue) == 0)
239         image->y_resolution=image->x_resolution;
240     }
241   /*
242     Determine page geometry from the PCL media box.
243   */
244   cmyk=image->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
245   count=0;
246   (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
247   (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
248   (void) ResetMagickMemory(&page,0,sizeof(page));
249   (void) ResetMagickMemory(command,0,sizeof(command));
250   p=command;
251   for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
252   {
253     if (image_info->page != (char *) NULL)
254       continue;
255     /*
256       Note PCL elements.
257     */
258     *p++=(char) c;
259     if ((c != (int) '/') && (c != '\n') &&
260         ((size_t) (p-command) < (MaxTextExtent-1)))
261       continue;
262     *p='\0';
263     p=command;
264     /*
265       Is this a CMYK document?
266     */
267     if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
268       cmyk=MagickTrue;
269     if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
270       {
271         /*
272           Note region defined by crop box.
273         */
274         count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
275           &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
276         if (count != 4)
277           count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
278             &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
279       }
280     if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
281       {
282         /*
283           Note region defined by media box.
284         */
285         count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
286           &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
287         if (count != 4)
288           count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
289             &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
290       }
291     if (count != 4)
292       continue;
293     /*
294       Set PCL render geometry.
295     */
296     width=(size_t) floor(bounds.x2-bounds.x1+0.5);
297     height=(size_t) floor(bounds.y2-bounds.y1+0.5);
298     if (width > page.width)
299       page.width=width;
300     if (height > page.height)
301       page.height=height;
302   }
303   (void) CloseBlob(image);
304   /*
305     Render PCL with the GhostPCL delegate.
306   */
307   if ((page.width == 0) || (page.height == 0))
308     (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
309   if (image_info->page != (char *) NULL)
310     (void) ParseAbsoluteGeometry(image_info->page,&page);
311   (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g",(double)
312     page.width,(double) page.height);
313   if (image_info->monochrome != MagickFalse)
314     delegate_info=GetDelegateInfo("pcl:mono",(char *) NULL,exception);
315   else
316      if (cmyk != MagickFalse)
317        delegate_info=GetDelegateInfo("pcl:cmyk",(char *) NULL,exception);
318      else
319        delegate_info=GetDelegateInfo("pcl:color",(char *) NULL,exception);
320   if (delegate_info == (const DelegateInfo *) NULL)
321     return((Image *) NULL);
322   *options='\0';
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   (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",
328     image->x_resolution,image->y_resolution);
329   page.width=(size_t) floor(page.width*image->x_resolution/delta.x+0.5);
330   page.height=(size_t) floor(page.height*image->y_resolution/delta.y+
331     0.5);
332   (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
333      page.width,(double) page.height);
334   image=DestroyImage(image);
335   read_info=CloneImageInfo(image_info);
336   *read_info->magick='\0';
337   if (read_info->number_scenes != 0)
338     {
339       if (read_info->number_scenes != 1)
340         (void) FormatLocaleString(options,MaxTextExtent,"-dLastPage=%.20g",
341           (double) (read_info->scene+read_info->number_scenes));
342       else
343         (void) FormatLocaleString(options,MaxTextExtent,
344           "-dFirstPage=%.20g -dLastPage=%.20g",(double) read_info->scene+1,
345           (double) (read_info->scene+read_info->number_scenes));
346       read_info->number_scenes=0;
347       if (read_info->scenes != (char *) NULL)
348         *read_info->scenes='\0';
349     }
350   if (read_info->authenticate != (char *) NULL)
351     (void) FormatLocaleString(options+strlen(options),MaxTextExtent,
352       " -sPCLPassword=%s",read_info->authenticate);
353   (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
354   (void) AcquireUniqueFilename(read_info->filename);
355   (void) FormatLocaleString(command,MaxTextExtent,
356     GetDelegateCommands(delegate_info),
357     read_info->antialias != MagickFalse ? 4 : 1,
358     read_info->antialias != MagickFalse ? 4 : 1,density,options,
359     read_info->filename,input_filename);
360   status=SystemCommand(MagickFalse,read_info->verbose,command,exception) != 0 ?
361     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,&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,MaxTextExtent);
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 \f
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 */
414 ModuleExport size_t RegisterPCLImage(void)
415 {
416   MagickInfo
417     *entry;
418
419   entry=SetMagickInfo("PCL");
420   entry->decoder=(DecodeImageHandler *) ReadPCLImage;
421   entry->encoder=(EncodeImageHandler *) WritePCLImage;
422   entry->magick=(IsImageFormatHandler *) IsPCL;
423   entry->blob_support=MagickFalse;
424   entry->seekable_stream=MagickTrue;
425   entry->thread_support=EncoderThreadSupport;
426   entry->description=ConstantString("Printer Control Language");
427   entry->module=ConstantString("PCL");
428   (void) RegisterMagickInfo(entry);
429   return(MagickImageCoderSignature);
430 }
431 \f
432 /*
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434 %                                                                             %
435 %                                                                             %
436 %                                                                             %
437 %   U n r e g i s t e r P C L I m a g e                                       %
438 %                                                                             %
439 %                                                                             %
440 %                                                                             %
441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442 %
443 %  UnregisterPCLImage() removes format registrations made by the PCL module
444 %  from the list of supported formats.
445 %
446 %  The format of the UnregisterPCLImage method is:
447 %
448 %      UnregisterPCLImage(void)
449 %
450 */
451 ModuleExport void UnregisterPCLImage(void)
452 {
453   (void) UnregisterMagickInfo("PCL");
454 }
455 \f
456 /*
457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458 %                                                                             %
459 %                                                                             %
460 %                                                                             %
461 %   W r i t e P C L I m a g e                                                 %
462 %                                                                             %
463 %                                                                             %
464 %                                                                             %
465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466 %
467 %  WritePCLImage() writes an image in the Page Control Language encoded
468 %  image format.
469 %
470 %  The format of the WritePCLImage method is:
471 %
472 %      MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image)
473 %
474 %  A description of each parameter follows.
475 %
476 %    o image_info: the image info.
477 %
478 %    o image:  The image.
479 %
480 */
481
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
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
654 static MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image)
655 {
656   char
657     buffer[MaxTextExtent];
658
659   const char
660     *option;
661
662   MagickBooleanType
663     status;
664
665   MagickOffsetType
666     scene;
667
668   register const Quantum *p;
669
670   register ssize_t i, x;
671
672   register unsigned char *q;
673
674   size_t
675     density,
676     length,
677     one,
678     packets;
679
680   ssize_t
681     y;
682
683   unsigned char
684     bits_per_pixel,
685     *compress_pixels,
686     *pixels,
687     *previous_pixels;
688
689   /*
690     Open output image file.
691   */
692   assert(image_info != (const ImageInfo *) NULL);
693   assert(image_info->signature == MagickSignature);
694   assert(image != (Image *) NULL);
695   assert(image->signature == MagickSignature);
696   if (image->debug != MagickFalse)
697     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
698   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
699   if (status == MagickFalse)
700     return(status);
701   density=75;
702   if (image_info->density != (char *) NULL)
703     {
704       GeometryInfo
705         geometry;
706
707       (void) ParseGeometry(image_info->density,&geometry);
708       density=(size_t) geometry.rho;
709     }
710   scene=0;
711   one=1;
712   do
713   {
714     if (IsRGBColorspace(image->colorspace) == MagickFalse)
715       (void) TransformImageColorspace(image,RGBColorspace);
716     /*
717       Initialize the printer.
718     */
719     (void) WriteBlobString(image,"\033E");  /* printer reset */
720     (void) WriteBlobString(image,"\033*r3F");  /* set presentation mode */
721     (void) FormatLocaleString(buffer,MaxTextExtent,"\033*r%.20gs%.20gT",
722       (double) image->columns,(double) image->rows);
723     (void) WriteBlobString(image,buffer);
724     (void) FormatLocaleString(buffer,MaxTextExtent,"\033*t%.20gR",(double)
725       density);
726     (void) WriteBlobString(image,buffer);
727     (void) WriteBlobString(image,"\033&l0E");  /* top margin 0 */
728     if (IsImageMonochrome(image,&image->exception) != MagickFalse)
729       {
730         /*
731           Monochrome image: use default printer monochrome setup.
732         */
733         bits_per_pixel=1;
734       }
735     else
736       if (image->storage_class == DirectClass)
737         {
738           /*
739             DirectClass image.
740           */
741           bits_per_pixel=24;
742           (void) WriteBlobString(image,"\033*v6W"); /* set color mode */
743           (void) WriteBlobByte(image,0); /* RGB */
744           (void) WriteBlobByte(image,3); /* direct by pixel */
745           (void) WriteBlobByte(image,0); /* bits per index (ignored) */
746           (void) WriteBlobByte(image,8); /* bits per red component */
747           (void) WriteBlobByte(image,8); /* bits per green component */
748           (void) WriteBlobByte(image,8); /* bits per blue component */
749         }
750       else
751         {
752           /*
753             Colormapped image.
754           */
755           bits_per_pixel=8;
756           (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */
757           (void) WriteBlobByte(image,0); /* RGB */
758           (void) WriteBlobByte(image,1); /* indexed by pixel */
759           (void) WriteBlobByte(image,bits_per_pixel); /* bits per index */
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           for (i=0; i < (ssize_t) image->colors; i++)
764           {
765             (void) FormatLocaleString(buffer,MaxTextExtent,
766               "\033*v%da%db%dc%.20gI",
767               ScaleQuantumToChar(image->colormap[i].red),
768               ScaleQuantumToChar(image->colormap[i].green),
769               ScaleQuantumToChar(image->colormap[i].blue),(double) i);
770             (void) WriteBlobString(image,buffer);
771           }
772           for (one=1; i < (ssize_t) (one << bits_per_pixel); i++)
773           {
774             (void) FormatLocaleString(buffer,MaxTextExtent,"\033*v%.20gI",
775               (double) i);
776             (void) WriteBlobString(image,buffer);
777           }
778         }
779     option=GetImageOption(image_info,"pcl:fit-to-page");
780     if ((option != (const char *) NULL) &&
781         (IsMagickTrue(option) != MagickFalse))
782       (void) WriteBlobString(image,"\033*r3A");
783     else
784       (void) WriteBlobString(image,"\033*r1A");  /* start raster graphics */
785     (void) WriteBlobString(image,"\033*b0Y");  /* set y offset */
786     length=(image->columns*bits_per_pixel+7)/8;
787     pixels=(unsigned char *) AcquireQuantumMemory(length+1,sizeof(*pixels));
788     if (pixels == (unsigned char *) NULL)
789       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
790     (void) ResetMagickMemory(pixels,0,(length+1)*sizeof(*pixels));
791     compress_pixels=(unsigned char *) NULL;
792     previous_pixels=(unsigned char *) NULL;
793     switch (image->compression)
794     {
795       case NoCompression:
796       {
797         (void) FormatLocaleString(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) ResetMagickMemory(compress_pixels,0,(length+256)*
811           sizeof(*compress_pixels));
812         (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b2M");
813         (void) WriteBlobString(image,buffer);
814         break;
815       }
816       default:
817       {
818         compress_pixels=(unsigned char *) AcquireQuantumMemory(3*length+256,
819           sizeof(*compress_pixels));
820         if (compress_pixels == (unsigned char *) NULL)
821           {
822             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
823             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
824           }
825         (void) ResetMagickMemory(compress_pixels,0,(3*length+256)*
826           sizeof(*compress_pixels));
827         previous_pixels=(unsigned char *) AcquireQuantumMemory(length+1,
828           sizeof(*previous_pixels));
829         if (previous_pixels == (unsigned char *) NULL)
830           {
831             compress_pixels=(unsigned char *) RelinquishMagickMemory(
832               compress_pixels);
833             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
834             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
835           }
836         (void) ResetMagickMemory(previous_pixels,0,(length+1)*
837           sizeof(*previous_pixels));
838         (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b3M");
839         (void) WriteBlobString(image,buffer);
840         break;
841       }
842     }
843     for (y=0; y < (ssize_t) image->rows; y++)
844     {
845       p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
846       if (p == (const Quantum *) NULL)
847         break;
848       q=pixels;
849       switch (bits_per_pixel)
850       {
851         case 1:
852         {
853           register unsigned char
854             bit,
855             byte;
856
857           /*
858             Monochrome image.
859           */
860           bit=0;
861           byte=0;
862           for (x=0; x < (ssize_t) image->columns; x++)
863           {
864             byte<<=1;
865             if (GetPixelIntensity(image,p) < ((MagickRealType) QuantumRange/2.0))
866               byte|=0x01;
867             bit++;
868             if (bit == 8)
869               {
870                 *q++=byte;
871                 bit=0;
872                 byte=0;
873               }
874             p+=GetPixelChannels(image);
875           }
876           if (bit != 0)
877             *q++=byte << (8-bit);
878           break;
879         }
880         case 8:
881         {
882           /*
883             Colormapped image.
884           */
885           for (x=0; x < (ssize_t) image->columns; x++)
886           {
887             *q++=(unsigned char) GetPixelIndex(image,p);
888             p+=GetPixelChannels(image);
889           }
890           break;
891         }
892         case 24:
893         case 32:
894         {
895           /*
896             Truecolor image.
897           */
898           for (x=0; x < (ssize_t) image->columns; x++)
899           {
900             *q++=ScaleQuantumToChar(GetPixelRed(image,p));
901             *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
902             *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
903             p+=GetPixelChannels(image);
904           }
905           break;
906         }
907       }
908       switch (image->compression)
909       {
910         case NoCompression:
911         {
912           (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b%.20gW",
913             (double) length);
914           (void) WriteBlobString(image,buffer);
915           (void) WriteBlob(image,length,pixels);
916           break;
917         }
918         case RLECompression:
919         {
920           packets=PCLPackbitsCompressImage(length,pixels,compress_pixels);
921           (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b%.20gW",
922             (double) packets);
923           (void) WriteBlobString(image,buffer);
924           (void) WriteBlob(image,packets,compress_pixels);
925           break;
926         }
927         default:
928         {
929           if (y == 0)
930             for (i=0; i < (ssize_t) length; i++)
931               previous_pixels[i]=(~pixels[i]);
932           packets=PCLDeltaCompressImage(length,previous_pixels,pixels,
933             compress_pixels);
934           (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b%.20gW",
935             (double) packets);
936           (void) WriteBlobString(image,buffer);
937           (void) WriteBlob(image,packets,compress_pixels);
938           (void) CopyMagickMemory(previous_pixels,pixels,length*
939             sizeof(*pixels));
940           break;
941         }
942       }
943     }
944     (void) WriteBlobString(image,"\033*rB");  /* end graphics */
945     switch (image->compression)
946     {
947       case NoCompression:
948         break;
949       case RLECompression:
950       {
951         compress_pixels=(unsigned char *) RelinquishMagickMemory(
952           compress_pixels);
953         break;
954       }
955       default:
956       {
957         previous_pixels=(unsigned char *) RelinquishMagickMemory(
958           previous_pixels);
959         compress_pixels=(unsigned char *) RelinquishMagickMemory(
960           compress_pixels);
961         break;
962       }
963     }
964     pixels=(unsigned char *) RelinquishMagickMemory(pixels);
965     if (GetNextImageInList(image) == (Image *) NULL)
966       break;
967     image=SyncNextImageInList(image);
968     status=SetImageProgress(image,SaveImagesTag,scene++,
969       GetImageListLength(image));
970     if (status == MagickFalse)
971       break;
972   } while (image_info->adjoin != MagickFalse);
973   (void) WriteBlobString(image,"\033E");
974   (void) CloseBlob(image);
975   return(MagickTrue);
976 }