]> 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 *,ExceptionInfo *);
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,exception);
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,
473 %        Image *image,ExceptionInfo *exception)
474 %
475 %  A description of each parameter follows.
476 %
477 %    o image_info: the image info.
478 %
479 %    o image:  The image.
480 %
481 %    o exception: return any errors or warnings in this structure.
482 %
483 */
484
485 static size_t PCLDeltaCompressImage(const size_t length,
486   const unsigned char *previous_pixels,const unsigned char *pixels,
487   unsigned char *compress_pixels)
488 {
489   int
490     delta,
491     j,
492     replacement;
493
494   register ssize_t
495     i,
496     x;
497
498   register unsigned char
499     *q;
500
501   q=compress_pixels;
502   for (x=0; x < (ssize_t) length; )
503   {
504     j=0;
505     for (i=0; x < (ssize_t) length; x++)
506     {
507       if (*pixels++ != *previous_pixels++)
508         {
509           i=1;
510           break;
511         }
512       j++;
513     }
514     while (x < (ssize_t) length)
515     {
516       x++;
517       if (*pixels == *previous_pixels)
518         break;
519       i++;
520       previous_pixels++;
521       pixels++;
522     }
523     if (i == 0)
524       break;
525     replacement=j >= 31 ? 31 : j;
526     j-=replacement;
527     delta=i >= 8 ? 8 : i;
528     *q++=(unsigned char) (((delta-1) << 5) | replacement);
529     if (replacement == 31)
530       {
531         for (replacement=255; j != 0; )
532         {
533           if (replacement > j)
534             replacement=j;
535           *q++=(unsigned char) replacement;
536           j-=replacement;
537         }
538         if (replacement == 255)
539           *q++='\0';
540       }
541     for (pixels-=i; i != 0; )
542     {
543       for (i-=delta; delta != 0; delta--)
544         *q++=(*pixels++);
545       if (i == 0)
546         break;
547       delta=i;
548       if (i >= 8)
549         delta=8;
550       *q++=(unsigned char) ((delta-1) << 5);
551     }
552   }
553   return((size_t) (q-compress_pixels));
554 }
555
556 static size_t PCLPackbitsCompressImage(const size_t length,
557   const unsigned char *pixels,unsigned char *compress_pixels)
558 {
559   int
560     count;
561
562   register ssize_t
563     x;
564
565   register unsigned char
566     *q;
567
568   ssize_t
569     j;
570
571   unsigned char
572     packbits[128];
573
574   /*
575     Compress pixels with Packbits encoding.
576   */
577   q=compress_pixels;
578   for (x=(ssize_t) length; x != 0; )
579   {
580     switch (x)
581     {
582       case 1:
583       {
584         x--;
585         *q++=0;
586         *q++=(*pixels);
587         break;
588       }
589       case 2:
590       {
591         x-=2;
592         *q++=1;
593         *q++=(*pixels);
594         *q++=pixels[1];
595         break;
596       }
597       case 3:
598       {
599         x-=3;
600         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
601           {
602             *q++=(unsigned char) ((256-3)+1);
603             *q++=(*pixels);
604             break;
605           }
606         *q++=2;
607         *q++=(*pixels);
608         *q++=pixels[1];
609         *q++=pixels[2];
610         break;
611       }
612       default:
613       {
614         if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
615           {
616             /*
617               Packed run.
618             */
619             count=3;
620             while (((ssize_t) count < x) && (*pixels == *(pixels+count)))
621             {
622               count++;
623               if (count >= 127)
624                 break;
625             }
626             x-=count;
627             *q++=(unsigned char) ((256-count)+1);
628             *q++=(*pixels);
629             pixels+=count;
630             break;
631           }
632         /*
633           Literal run.
634         */
635         count=0;
636         while ((*(pixels+count) != *(pixels+count+1)) ||
637                (*(pixels+count+1) != *(pixels+count+2)))
638         {
639           packbits[count+1]=pixels[count];
640           count++;
641           if (((ssize_t) count >= (x-3)) || (count >= 127))
642             break;
643         }
644         x-=count;
645         *packbits=(unsigned char) (count-1);
646         for (j=0; j <= (ssize_t) count; j++)
647           *q++=packbits[j];
648         pixels+=count;
649         break;
650       }
651     }
652   }
653   *q++=128; /* EOD marker */
654   return((size_t) (q-compress_pixels));
655 }
656
657 static MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image,
658   ExceptionInfo *exception)
659 {
660   char
661     buffer[MaxTextExtent];
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     length,
681     one,
682     packets;
683
684   ssize_t
685     y;
686
687   unsigned char
688     bits_per_pixel,
689     *compress_pixels,
690     *pixels,
691     *previous_pixels;
692
693   /*
694     Open output image file.
695   */
696   assert(image_info != (const ImageInfo *) NULL);
697   assert(image_info->signature == MagickSignature);
698   assert(image != (Image *) NULL);
699   assert(image->signature == MagickSignature);
700   if (image->debug != MagickFalse)
701     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
702   assert(exception != (ExceptionInfo *) NULL);
703   assert(exception->signature == MagickSignature);
704   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
705   if (status == MagickFalse)
706     return(status);
707   density=75;
708   if (image_info->density != (char *) NULL)
709     {
710       GeometryInfo
711         geometry;
712
713       (void) ParseGeometry(image_info->density,&geometry);
714       density=(size_t) geometry.rho;
715     }
716   scene=0;
717   one=1;
718   do
719   {
720     if (IsRGBColorspace(image->colorspace) == MagickFalse)
721       (void) TransformImageColorspace(image,RGBColorspace);
722     /*
723       Initialize the printer.
724     */
725     (void) WriteBlobString(image,"\033E");  /* printer reset */
726     (void) WriteBlobString(image,"\033*r3F");  /* set presentation mode */
727     (void) FormatLocaleString(buffer,MaxTextExtent,"\033*r%.20gs%.20gT",
728       (double) image->columns,(double) image->rows);
729     (void) WriteBlobString(image,buffer);
730     (void) FormatLocaleString(buffer,MaxTextExtent,"\033*t%.20gR",(double)
731       density);
732     (void) WriteBlobString(image,buffer);
733     (void) WriteBlobString(image,"\033&l0E");  /* top margin 0 */
734     if (IsImageMonochrome(image,exception) != MagickFalse)
735       {
736         /*
737           Monochrome image: use default printer monochrome setup.
738         */
739         bits_per_pixel=1;
740       }
741     else
742       if (image->storage_class == DirectClass)
743         {
744           /*
745             DirectClass image.
746           */
747           bits_per_pixel=24;
748           (void) WriteBlobString(image,"\033*v6W"); /* set color mode */
749           (void) WriteBlobByte(image,0); /* RGB */
750           (void) WriteBlobByte(image,3); /* direct by pixel */
751           (void) WriteBlobByte(image,0); /* bits per index (ignored) */
752           (void) WriteBlobByte(image,8); /* bits per red component */
753           (void) WriteBlobByte(image,8); /* bits per green component */
754           (void) WriteBlobByte(image,8); /* bits per blue component */
755         }
756       else
757         {
758           /*
759             Colormapped image.
760           */
761           bits_per_pixel=8;
762           (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */
763           (void) WriteBlobByte(image,0); /* RGB */
764           (void) WriteBlobByte(image,1); /* indexed by pixel */
765           (void) WriteBlobByte(image,bits_per_pixel); /* bits per index */
766           (void) WriteBlobByte(image,8); /* bits per red component */
767           (void) WriteBlobByte(image,8); /* bits per green component */
768           (void) WriteBlobByte(image,8); /* bits per blue component */
769           for (i=0; i < (ssize_t) image->colors; i++)
770           {
771             (void) FormatLocaleString(buffer,MaxTextExtent,
772               "\033*v%da%db%dc%.20gI",
773               ScaleQuantumToChar(image->colormap[i].red),
774               ScaleQuantumToChar(image->colormap[i].green),
775               ScaleQuantumToChar(image->colormap[i].blue),(double) i);
776             (void) WriteBlobString(image,buffer);
777           }
778           for (one=1; i < (ssize_t) (one << bits_per_pixel); i++)
779           {
780             (void) FormatLocaleString(buffer,MaxTextExtent,"\033*v%.20gI",
781               (double) i);
782             (void) WriteBlobString(image,buffer);
783           }
784         }
785     option=GetImageOption(image_info,"pcl:fit-to-page");
786     if ((option != (const char *) NULL) &&
787         (IsMagickTrue(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) ResetMagickMemory(pixels,0,(length+1)*sizeof(*pixels));
797     compress_pixels=(unsigned char *) NULL;
798     previous_pixels=(unsigned char *) NULL;
799     switch (image->compression)
800     {
801       case NoCompression:
802       {
803         (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b0M");
804         (void) WriteBlobString(image,buffer);
805         break;
806       }
807       case RLECompression:
808       {
809         compress_pixels=(unsigned char *) AcquireQuantumMemory(length+256,
810           sizeof(*compress_pixels));
811         if (compress_pixels == (unsigned char *) NULL)
812           {
813             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
814             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
815           }
816         (void) ResetMagickMemory(compress_pixels,0,(length+256)*
817           sizeof(*compress_pixels));
818         (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b2M");
819         (void) WriteBlobString(image,buffer);
820         break;
821       }
822       default:
823       {
824         compress_pixels=(unsigned char *) AcquireQuantumMemory(3*length+256,
825           sizeof(*compress_pixels));
826         if (compress_pixels == (unsigned char *) NULL)
827           {
828             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
829             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
830           }
831         (void) ResetMagickMemory(compress_pixels,0,(3*length+256)*
832           sizeof(*compress_pixels));
833         previous_pixels=(unsigned char *) AcquireQuantumMemory(length+1,
834           sizeof(*previous_pixels));
835         if (previous_pixels == (unsigned char *) NULL)
836           {
837             compress_pixels=(unsigned char *) RelinquishMagickMemory(
838               compress_pixels);
839             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
840             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
841           }
842         (void) ResetMagickMemory(previous_pixels,0,(length+1)*
843           sizeof(*previous_pixels));
844         (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b3M");
845         (void) WriteBlobString(image,buffer);
846         break;
847       }
848     }
849     for (y=0; y < (ssize_t) image->rows; y++)
850     {
851       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
852       if (p == (const Quantum *) NULL)
853         break;
854       q=pixels;
855       switch (bits_per_pixel)
856       {
857         case 1:
858         {
859           register unsigned char
860             bit,
861             byte;
862
863           /*
864             Monochrome image.
865           */
866           bit=0;
867           byte=0;
868           for (x=0; x < (ssize_t) image->columns; x++)
869           {
870             byte<<=1;
871             if (GetPixelIntensity(image,p) < ((MagickRealType) QuantumRange/2.0))
872               byte|=0x01;
873             bit++;
874             if (bit == 8)
875               {
876                 *q++=byte;
877                 bit=0;
878                 byte=0;
879               }
880             p+=GetPixelChannels(image);
881           }
882           if (bit != 0)
883             *q++=byte << (8-bit);
884           break;
885         }
886         case 8:
887         {
888           /*
889             Colormapped image.
890           */
891           for (x=0; x < (ssize_t) image->columns; x++)
892           {
893             *q++=(unsigned char) GetPixelIndex(image,p);
894             p+=GetPixelChannels(image);
895           }
896           break;
897         }
898         case 24:
899         case 32:
900         {
901           /*
902             Truecolor image.
903           */
904           for (x=0; x < (ssize_t) image->columns; x++)
905           {
906             *q++=ScaleQuantumToChar(GetPixelRed(image,p));
907             *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
908             *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
909             p+=GetPixelChannels(image);
910           }
911           break;
912         }
913       }
914       switch (image->compression)
915       {
916         case NoCompression:
917         {
918           (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b%.20gW",
919             (double) length);
920           (void) WriteBlobString(image,buffer);
921           (void) WriteBlob(image,length,pixels);
922           break;
923         }
924         case RLECompression:
925         {
926           packets=PCLPackbitsCompressImage(length,pixels,compress_pixels);
927           (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b%.20gW",
928             (double) packets);
929           (void) WriteBlobString(image,buffer);
930           (void) WriteBlob(image,packets,compress_pixels);
931           break;
932         }
933         default:
934         {
935           if (y == 0)
936             for (i=0; i < (ssize_t) length; i++)
937               previous_pixels[i]=(~pixels[i]);
938           packets=PCLDeltaCompressImage(length,previous_pixels,pixels,
939             compress_pixels);
940           (void) FormatLocaleString(buffer,MaxTextExtent,"\033*b%.20gW",
941             (double) packets);
942           (void) WriteBlobString(image,buffer);
943           (void) WriteBlob(image,packets,compress_pixels);
944           (void) CopyMagickMemory(previous_pixels,pixels,length*
945             sizeof(*pixels));
946           break;
947         }
948       }
949     }
950     (void) WriteBlobString(image,"\033*rB");  /* end graphics */
951     switch (image->compression)
952     {
953       case NoCompression:
954         break;
955       case RLECompression:
956       {
957         compress_pixels=(unsigned char *) RelinquishMagickMemory(
958           compress_pixels);
959         break;
960       }
961       default:
962       {
963         previous_pixels=(unsigned char *) RelinquishMagickMemory(
964           previous_pixels);
965         compress_pixels=(unsigned char *) RelinquishMagickMemory(
966           compress_pixels);
967         break;
968       }
969     }
970     pixels=(unsigned char *) RelinquishMagickMemory(pixels);
971     if (GetNextImageInList(image) == (Image *) NULL)
972       break;
973     image=SyncNextImageInList(image);
974     status=SetImageProgress(image,SaveImagesTag,scene++,
975       GetImageListLength(image));
976     if (status == MagickFalse)
977       break;
978   } while (image_info->adjoin != MagickFalse);
979   (void) WriteBlobString(image,"\033E");
980   (void) CloseBlob(image);
981   return(MagickTrue);
982 }