root / ImageMagick / trunk / coders / pcl.c

Revision 12546, 22.1 kB (checked in by cristy, 12 days ago)
Line 
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-2008 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
39/*
40  Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/property.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/color.h"
47#include "magick/color-private.h"
48#include "magick/colorspace.h"
49#include "magick/constitute.h"
50#include "magick/delegate.h"
51#include "magick/draw.h"
52#include "magick/exception.h"
53#include "magick/exception-private.h"
54#include "magick/geometry.h"
55#include "magick/image.h"
56#include "magick/image-private.h"
57#include "magick/list.h"
58#include "magick/magick.h"
59#include "magick/memory_.h"
60#include "magick/monitor.h"
61#include "magick/monitor-private.h"
62#include "magick/profile.h"
63#include "magick/resource_.h"
64#include "magick/quantum-private.h"
65#include "magick/static.h"
66#include "magick/string_.h"
67#include "magick/module.h"
68#include "magick/token.h"
69#include "magick/transform.h"
70#include "magick/utility.h"
71
72/*
73  Forward declarations.
74*/
75static MagickBooleanType
76  WritePCLImage(const ImageInfo *,Image *);
77
78/*
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%                                                                             %
81%                                                                             %
82%                                                                             %
83%   I s P C L                                                                 %
84%                                                                             %
85%                                                                             %
86%                                                                             %
87%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88%
89%  IsPCL() returns MagickTrue if the image format type, identified by the
90%  magick string, is PCL.
91%
92%  The format of the IsPCL method is:
93%
94%      MagickBooleanType IsPCL(const unsigned char *magick,const size_t length)
95%
96%  A description of each parameter follows:
97%
98%    o magick: This string is generally the first few bytes of an image file
99%      or blob.
100%
101%    o length: Specifies the length of the magick string.
102%
103%
104*/
105static MagickBooleanType IsPCL(const unsigned char *magick,const size_t length)
106{
107  if (length < 4)
108    return(MagickFalse);
109  if (memcmp(magick,"\033E\033",3) == 0)
110    return(MagickTrue);
111  if (memcmp(magick,"\033E\033&",4) == 0)
112    return(MagickFalse);
113  return(MagickFalse);
114}
115
116/*
117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118%                                                                             %
119%                                                                             %
120%                                                                             %
121%   R e a d P C L I m a g e                                                   %
122%                                                                             %
123%                                                                             %
124%                                                                             %
125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126%
127%  ReadPCLImage() reads a Printer Control Language image file and returns it.
128%  It allocates the memory necessary for the new Image structure and returns a
129%  pointer to the new image.
130%
131%  The format of the ReadPCLImage method is:
132%
133%      Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception)
134%
135%  A description of each parameter follows:
136%
137%    o image_info: the image info.
138%
139%    o exception: return any errors or warnings in this structure.
140%
141*/
142static Image *ReadPCLImage(const ImageInfo *image_info,ExceptionInfo *exception)
143{
144#define CropBox  "CropBox"
145#define DeviceCMYK  "DeviceCMYK"
146#define MediaBox  "MediaBox"
147#define RenderPCLText  "  Rendering PCL...  "
148
149  char
150    command[MaxTextExtent],
151    density[MaxTextExtent],
152    filename[MaxTextExtent],
153    geometry[MaxTextExtent],
154    options[MaxTextExtent],
155    input_filename[MaxTextExtent];
156
157  const DelegateInfo
158    *delegate_info;
159
160  Image
161    *image,
162    *next_image;
163
164  ImageInfo
165    *read_info;
166
167  MagickBooleanType
168    cmyk,
169    status;
170
171  PointInfo
172    delta;
173
174  RectangleInfo
175    bounding_box,
176    page;
177
178  register char
179    *p;
180
181  register long
182    c;
183
184  SegmentInfo
185    bounds;
186
187  ssize_t
188    count;
189
190  unsigned long
191    height,
192    width;
193
194  assert(image_info != (const ImageInfo *) NULL);
195  assert(image_info->signature == MagickSignature);
196  if (image_info->debug != MagickFalse)
197    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
198      image_info->filename);
199  assert(exception != (ExceptionInfo *) NULL);
200  assert(exception->signature == MagickSignature);
201  /*
202    Open image file.
203  */
204  image=AcquireImage(image_info);
205  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
206  if (status == MagickFalse)
207    {
208      image=DestroyImageList(image);
209      return((Image *) NULL);
210    }
211  status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
212  if (status == MagickFalse)
213    {
214      ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
215        image_info->filename);
216      image=DestroyImageList(image);
217      return((Image *) NULL);
218    }
219  /*
220    Set the page density.
221  */
222  delta.x=DefaultResolution;
223  delta.y=DefaultResolution;
224  if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
225    {
226      GeometryInfo
227        geometry_info;
228
229      MagickStatusType
230        flags;
231
232      flags=ParseGeometry(PSDensityGeometry,&geometry_info);
233      image->x_resolution=geometry_info.rho;
234      image->y_resolution=geometry_info.sigma;
235      if ((flags & SigmaValue) == 0)
236        image->y_resolution=image->x_resolution;
237    }
238  /*
239    Determine page geometry from the PCL media box.
240  */
241  cmyk=image->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
242  count=0;
243  (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
244  (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
245  (void) ResetMagickMemory(&page,0,sizeof(page));
246  (void) ResetMagickMemory(command,0,sizeof(command));
247  p=command;
248  for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
249  {
250    if (image_info->page != (char *) NULL)
251      continue;
252    /*
253      Note PCL elements.
254    */
255    *p++=(char) c;
256    if ((c != (int) '/') && (c != '\n') &&
257        ((size_t) (p-command) < MaxTextExtent))
258      continue;
259    *p='\0';
260    p=command;
261    /*
262      Is this a CMYK document?
263    */
264    if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
265      cmyk=MagickTrue;
266    if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
267      {
268        /*
269          Note region defined by crop box.
270        */
271        count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
272          &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
273        if (count != 4)
274          count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
275            &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
276      }
277    if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
278      {
279        /*
280          Note region defined by media box.
281        */
282        count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
283          &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
284        if (count != 4)
285          count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
286            &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
287      }
288    if (count != 4)
289      continue;
290    /*
291      Set PCL render geometry.
292    */
293    width=(unsigned long) (bounds.x2-bounds.x1+0.5);
294    height=(unsigned long) (bounds.y2-bounds.y1+0.5);
295    if (width > page.width)
296      page.width=width;
297    if (height > page.height)
298      page.height=height;
299  }
300  (void) CloseBlob(image);
301  /*
302    Render PCL with the GhostPCL delegate.
303  */
304  if ((page.width == 0) || (page.height == 0))
305    (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
306  if (image_info->page != (char *) NULL)
307    (void) ParseAbsoluteGeometry(image_info->page,&page);
308  (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu",
309    page.width,page.height);
310  if (image_info->monochrome != MagickFalse)
311    delegate_info=GetDelegateInfo("pcl:mono",(char *) NULL,exception);
312  else
313     if (cmyk != MagickFalse)
314       delegate_info=GetDelegateInfo("pcl:cmyk",(char *) NULL,exception);
315     else
316       delegate_info=GetDelegateInfo("pcl:color",(char *) NULL,exception);
317  if (delegate_info == (const DelegateInfo *) NULL)
318    return((Image *) NULL);
319  *options='\0';
320  if ((page.width == 0) || (page.height == 0))
321    (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
322  if (image_info->page != (char *) NULL)
323    (void) ParseAbsoluteGeometry(image_info->page,&page);
324  (void) FormatMagickString(density,MaxTextExtent,"%gx%g",
325    image->x_resolution,image->y_resolution);
326  page.width=(unsigned long) (page.width*image->x_resolution/delta.x+0.5);
327  page.height=(unsigned long) (page.height*image->y_resolution/delta.y+0.5);
328  (void) FormatMagickString(options,MaxTextExtent,"-g%lux%lu ",
329    page.width,page.height);
330  image=DestroyImage(image);
331  read_info=CloneImageInfo(image_info);
332  *read_info->magick='\0';
333  if (read_info->number_scenes != 0)
334    {
335      if (read_info->number_scenes != 1)
336        (void) FormatMagickString(options,MaxTextExtent,"-dLastPage=%lu",
337          read_info->scene+read_info->number_scenes);
338      else
339        (void) FormatMagickString(options,MaxTextExtent,
340          "-dFirstPage=%lu -dLastPage=%lu",read_info->scene+1,read_info->scene+
341          read_info->number_scenes);
342      read_info->number_scenes=0;
343      if (read_info->scenes != (char *) NULL)
344        *read_info->scenes='\0';
345    }
346  if (read_info->authenticate != (char *) NULL)
347    (void) FormatMagickString(options+strlen(options),MaxTextExtent,
348      " -sPCLPassword=%s",read_info->authenticate);
349  (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
350  (void) AcquireUniqueFilename(read_info->filename);
351  (void) FormatMagickString(command,MaxTextExtent,
352    GetDelegateCommands(delegate_info),
353    read_info->antialias != MagickFalse ? 4 : 1,
354    read_info->antialias != MagickFalse ? 4 : 1,density,options,
355    read_info->filename,input_filename);
356  status=SystemCommand(read_info->verbose,command) != 0 ? MagickTrue :
357    MagickFalse;
358  image=ReadImage(read_info,exception);
359  (void) RelinquishUniqueFileResource(read_info->filename);
360  (void) RelinquishUniqueFileResource(input_filename);
361  read_info=DestroyImageInfo(read_info);
362  if (image == (Image *) NULL)
363    ThrowReaderException(DelegateError,"PCLDelegateFailed");
364  if (LocaleCompare(image->magick,"BMP") == 0)
365    {
366      Image
367        *cmyk_image;
368
369      cmyk_image=ConsolidateCMYKImages(image,&image->exception);
370      if (cmyk_image != (Image *) NULL)
371        {
372          image=DestroyImageList(image);
373          image=cmyk_image;
374        }
375    }
376  do
377  {
378    (void) CopyMagickString(image->filename,filename,MaxTextExtent);
379    image->page=page;
380    next_image=SyncNextImageInList(image);
381    if (next_image != (Image *) NULL)
382      image=next_image;
383  } while (next_image != (Image *) NULL);
384  return(GetFirstImageInList(image));
385}
386
387/*
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389%                                                                             %
390%                                                                             %
391%                                                                             %
392%   R e g i s t e r P C L I m a g e                                           %
393%                                                                             %
394%                                                                             %
395%                                                                             %
396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397%
398%  RegisterPCLImage() adds attributes for the PCL image format to
399%  the list of supported formats.  The attributes include the image format
400%  tag, a method to read and/or write the format, whether the format
401%  supports the saving of more than one frame to the same file or blob,
402%  whether the format supports native in-memory I/O, and a brief
403%  description of the format.
404%
405%  The format of the RegisterPCLImage method is:
406%
407%      unsigned long RegisterPCLImage(void)
408%
409*/
410ModuleExport unsigned long RegisterPCLImage(void)
411{
412  MagickInfo
413    *entry;
414
415  entry=SetMagickInfo("PCL");
416  entry->decoder=(DecodeImageHandler *) ReadPCLImage;
417  entry->encoder=(EncodeImageHandler *) WritePCLImage;
418  entry->magick=(IsImageFormatHandler *) IsPCL;
419  entry->adjoin=MagickFalse;
420  entry->blob_support=MagickFalse;
421  entry->seekable_stream=MagickTrue;
422  entry->thread_support=EncoderThreadSupport;
423  entry->description=ConstantString("Printer Control Language");
424  entry->module=ConstantString("PCL");
425  (void) RegisterMagickInfo(entry);
426  return(MagickImageCoderSignature);
427}
428
429/*
430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431%                                                                             %
432%                                                                             %
433%                                                                             %
434%   U n r e g i s t e r P C L I m a g e                                       %
435%                                                                             %
436%                                                                             %
437%                                                                             %
438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439%
440%  UnregisterPCLImage() removes format registrations made by the
441%  PCL module from the list of supported formats.
442%
443%  The format of the UnregisterPCLImage method is:
444%
445%      UnregisterPCLImage(void)
446%
447*/
448ModuleExport void UnregisterPCLImage(void)
449{
450  (void) UnregisterMagickInfo("PCL");
451}
452
453/*
454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455%                                                                             %
456%                                                                             %
457%                                                                             %
458%   W r i t e P C L I m a g e                                                 %
459%                                                                             %
460%                                                                             %
461%                                                                             %
462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
463%
464%  WritePCLImage() writes an image in the Page Control Language encoded
465%  image format.
466%
467%  The format of the WritePCLImage method is:
468%
469%      MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image)
470%
471%  A description of each parameter follows.
472%
473%    o image_info: the image info.
474%
475%    o image:  The image.
476%
477*/
478static MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image)
479{
480  char
481    buffer[MaxTextExtent];
482
483  long
484    y;
485
486  MagickBooleanType
487    status;
488
489  register const PixelPacket
490    *p;
491
492  register long
493    x;
494
495  register unsigned char
496    *q;
497
498  unsigned long
499    density;
500
501  /*
502    Open output image file.
503  */
504  assert(image_info != (const ImageInfo *) NULL);
505  assert(image_info->signature == MagickSignature);
506  assert(image != (Image *) NULL);
507  assert(image->signature == MagickSignature);
508  if (image->debug != MagickFalse)
509    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
510  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
511  if (status == MagickFalse)
512    return(status);
513  if (image->colorspace != RGBColorspace)
514    (void) SetImageColorspace(image,RGBColorspace);
515  /*
516    Initialize the printer.
517  */
518  (void) WriteBlobString(image,"\033E");  /* printer reset */
519  (void) WriteBlobString(image,"\033&l0E");  /* top margin 0 */
520  density=75;
521  if (image_info->density != (char *) NULL)
522    {
523      GeometryInfo
524        geometry;
525
526      (void) ParseGeometry(image_info->density,&geometry);
527      density=(unsigned long) geometry.rho;
528    }
529  if (IsMonochromeImage(image,&image->exception) != MagickFalse)
530    {
531      register unsigned char
532        bit,
533        byte;
534
535      /*
536        Write PCL monochrome image.
537      */
538      (void) FormatMagickString(buffer,MaxTextExtent,"\033*t%ldR",density);
539      (void) WriteBlobString(image,buffer);
540      (void) WriteBlobString(image,"\033*r1A");  /* start graphics */
541      (void) WriteBlobString(image,"\033*b0M");  /* no compression */
542      for (y=0; y < (long) image->rows; y++)
543      {
544        p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
545        if (p == (const PixelPacket *) NULL)
546          break;
547        bit=0;
548        byte=0;
549        (void) FormatMagickString(buffer,MaxTextExtent,"\033*b%luW",
550          (image->columns+7)/8);
551        (void) WriteBlobString(image,buffer);
552        for (x=0; x < (long) image->columns; x++)
553        {
554          byte<<=1;
555          if (PixelIntensity(p) < ((MagickRealType) QuantumRange/2.0))
556            byte|=0x01;
557          bit++;
558          if (bit == 8)
559            {
560              (void) WriteBlobByte(image,byte);
561              bit=0;
562              byte=0;
563            }
564          p++;
565        }
566        if (bit != 0)
567          (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
568        status=SetImageProgress(image,SaveImageTag,y,image->rows);
569        if (status == MagickFalse)
570          break;
571      }
572      (void) WriteBlobString(image,"\033*rB");  /* end graphics */
573    }
574  else
575    {
576      static char
577        color_mode[6] = { 0, 3, 0, 8, 8, 8 };
578
579      unsigned char
580        *pixels;
581
582      /*
583        Allocate pixel buffers.
584      */
585      pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
586        3UL*sizeof(*pixels));
587      if (pixels == (unsigned char *) NULL)
588        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
589      /*
590        Write PCL color image.
591      */
592      (void) WriteBlobString(image,"\033*r3F");  /* set presentation mode */
593      (void) FormatMagickString(buffer,MaxTextExtent,"\033*t%luR",density);  /* set resolution */
594      (void) WriteBlobString(image,buffer);
595      (void) FormatMagickString(buffer,MaxTextExtent,"\033*r%luT",image->rows);
596      (void) WriteBlobString(image,buffer);
597      (void) FormatMagickString(buffer,MaxTextExtent,"\033*r%luS",
598        image->columns);
599      (void) WriteBlobString(image,buffer);
600      (void) WriteBlobString(image,"\033*v6W");  /* set color mode */
601      (void) WriteBlob(image,6,(unsigned char *) color_mode);
602      (void) WriteBlobString(image,"\033*r1A");  /* start raster graphics */
603      (void) WriteBlobString(image,"\033*b0Y");  /* set y offset */
604      (void) WriteBlobString(image,"\033*b0M");  /* no compression */
605      for (y=0; y < (long) image->rows; y++)
606      {
607        p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
608        if (p == (const PixelPacket *) NULL)
609          break;
610        q=pixels;
611        for (x=0; x < (long) image->columns; x++)
612        {
613          *q++=ScaleQuantumToChar(p->red);
614          *q++=ScaleQuantumToChar(p->green);
615          *q++=ScaleQuantumToChar(p->blue);
616          p++;
617        }
618        (void) FormatMagickString(buffer,MaxTextExtent,"\033*b%luW",
619          3*image->columns);  /* send row */
620        (void) WriteBlobString(image,buffer);
621        (void) WriteBlob(image,3*image->columns,pixels);
622        status=SetImageProgress(image,SaveImageTag,y,image->rows);
623        if (status == MagickFalse)
624          break;
625      }
626      (void) WriteBlobString(image,"\033*r0C");  /* end graphics */
627      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
628    }
629  (void) WriteBlobString(image,"\033E");
630  (void) CloseBlob(image);
631  return(MagickTrue);
632}
Note: See TracBrowser for help on using the browser.