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