Exemple #1
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e I N F O I m a g e                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  WriteINFOImage() writes image descriptive info to stdout.
%
%  The format of the WriteINFOImage method is:
%
%      MagickPassFail WriteINFOImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: The image info.
%
%    o image:  The image.
%
%
*/
static MagickPassFail
WriteINFOImage(const ImageInfo *image_info,Image *image)
{
  MagickPassFail
    status;

  FILE
    *file;

  Image
    *list_entry;

  char
    temporary_filename[MaxTextExtent];

  const char
    *format;

  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);

  /*
    Obtain optional 'identify' style output specification.
  */
  format=AccessDefinition(image_info,"info","format");
  if (format != (char *) NULL)
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
			  "info:format=\"%s\"",format);

  /*
    Open blob.
  */
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
  if (status == MagickFail)
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);

  /*
    Allocate and open a temporary file to write output to.
  */
  temporary_filename[0]='\0';
  if ((file=GetBlobFileHandle(image)) == (FILE *) NULL)
    {
      if(!AcquireTemporaryFileName(temporary_filename))
	ThrowWriterException(FileOpenError,UnableToCreateTemporaryFile,image);
      if ((file=fopen(temporary_filename,"w")) == (FILE *) NULL)
	{
	  (void) LiberateTemporaryFile(temporary_filename);
	  ThrowWriterException(FileOpenError,UnableToCreateTemporaryFile,image);
	}
      
    }
  list_entry=image;
  
  while (list_entry != (Image *) NULL)
    {
      /*
	Avoid convert style output syntax by restoring original filename.
      */
      (void) strlcpy(list_entry->filename,list_entry->magick_filename,
		     sizeof(list_entry->filename));

      /*
	Describe image.
      */
      if (format != (char *) NULL)
	{
	  char
	    *text;

	  text=TranslateText(image_info,list_entry,format);
	  if (text != (char *) NULL)
	    {
	      (void) fputs(text,file);
	      (void) fputs("\n",file);
	      MagickFreeMemory(text);
	    }
	}
      else
	{
	  if ((status=DescribeImage(list_entry,file,image_info->verbose))
	      == MagickFail)
	    break;
	}
      
      list_entry=GetNextImageInList(list_entry);
    }

  if ('\0' != temporary_filename[0])
    {
      /*
	Close temporary file.
      */
      (void) fclose(file);

      /*
	Send content of temporary file to blob stream.
      */
      if (WriteBlobFile(image,temporary_filename) == MagickFail)
	status=MagickFail;
      (void) LiberateTemporaryFile(temporary_filename);
    }

  CloseBlob(image);

  return status;
}
Exemple #2
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e J P 2 I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method WriteJP2Image writes an image in the JPEG 2000 image format.
%
%  JP2 support originally written by Nathan Brown, [email protected]
%
%  The format of the WriteJP2Image method is:
%
%      MagickPassFail WriteJP2Image(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o status: Method WriteJP2Image return MagickTrue if the image is written.
%      MagickFalse is returned is there is a memory shortage or if the image file
%      fails to write.
%
%    o image_info: Specifies a pointer to a ImageInfo structure.
%
%    o image:  A pointer to an Image structure.
%
%
*/
static MagickPassFail
WriteJP2Image(const ImageInfo *image_info,Image *image)
{
  char
    magick[MaxTextExtent],
    option_keyval[MaxTextExtent],
    *options = NULL;

  int
    format;

  long
    y;

  jas_image_cmptparm_t
    component_info;

  jas_image_t
    *jp2_image;

  jas_matrix_t
    *jp2_pixels;

  jas_stream_t
    *jp2_stream;

  register const PixelPacket
    *p;

  register int
    x;

  unsigned int
    rate_specified=False,
    status;

  int
    component,
    number_components;

  unsigned short
    *lut;

  ImageCharacteristics
    characteristics;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
  if (status == False)
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);

  /*
    Ensure that image is in RGB space.
  */
  (void) TransformColorspace(image,RGBColorspace);

  /*
    Analyze image to be written.
  */
  if (!GetImageCharacteristics(image,&characteristics,
                               (OptimizeType == image_info->type),
                               &image->exception))
    {
      CloseBlob(image);
      return MagickFail;
    }

  /*
    Obtain a JP2 stream.
  */
  jp2_stream=JP2StreamManager(image);
  if (jp2_stream == (jas_stream_t *) NULL)
    ThrowWriterException(DelegateError,UnableToManageJP2Stream,image);
  number_components=image->matte ? 4 : 3;
  if ((image_info->type != TrueColorType) &&
      (characteristics.grayscale))
    number_components=1;

  jp2_image=jas_image_create0();
  if (jp2_image == (jas_image_t *) NULL)
    ThrowWriterException(DelegateError,UnableToCreateImage,image);

  for (component=0; component < number_components; component++)
  {
    (void) memset((void *)&component_info,0,sizeof(jas_image_cmptparm_t));
    component_info.tlx=0; /* top left x ordinate */
    component_info.tly=0; /* top left y ordinate */
    component_info.hstep=1; /* horizontal pixels per step */
    component_info.vstep=1; /* vertical pixels per step */
    component_info.width=(unsigned int) image->columns;
    component_info.height=(unsigned int) image->rows;
    component_info.prec=(unsigned int) Max(2,Min(image->depth,16)); /* bits in range */
    component_info.sgnd = false;  /* range is signed value? */

    if (jas_image_addcmpt(jp2_image, component,&component_info)) {
      jas_image_destroy(jp2_image);
      ThrowWriterException(DelegateError,UnableToCreateImageComponent,image);
    }
  }

  /*
    Allocate and compute LUT.
  */
  {
    unsigned long
      i,
      max_value;

    double
      scale_to_component;

    lut=MagickAllocateArray(unsigned short *,MaxMap+1,sizeof(*lut));
    if (lut == (unsigned short *) NULL)
      {
	jas_image_destroy(jp2_image);
	ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
      }

    max_value=MaxValueGivenBits(component_info.prec);
    scale_to_component=max_value/MaxRGBDouble;
    for(i=0; i <= MaxMap; i++)
	lut[i]=scale_to_component*i+0.5;
  }

  if (number_components == 1)
    {
      /* FIXME: If image has an attached ICC profile, then the profile
         should be transferred and the image colorspace set to
         JAS_CLRSPC_GENGRAY */
      /* sRGB Grayscale */
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Setting SGRAY colorspace");
      jas_image_setclrspc(jp2_image, JAS_CLRSPC_SGRAY);
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Setting GRAY channel to channel 0");
      jas_image_setcmpttype(jp2_image,0,
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
    }
  else
    {
      /* FIXME: If image has an attached ICC profile, then the profile
         should be transferred and the image colorspace set to
         JAS_CLRSPC_GENRGB */

      /* sRGB */
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Setting SRGB colorspace");
      jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB);
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Setting RED channel to channel 0");
      jas_image_setcmpttype(jp2_image,0,
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Setting GREEN channel to channel 1");
      jas_image_setcmpttype(jp2_image,1,
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Setting BLUE channel to channel 2");
      jas_image_setcmpttype(jp2_image,2,
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
      if (number_components == 4 )
        {
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
            "Setting OPACITY channel to channel 3");
          jas_image_setcmpttype(jp2_image,3,
            JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
        }
    }
  /*
    Convert to JPEG 2000 pixels.
  */
  jp2_pixels=jas_matrix_create(1,(unsigned int) image->columns);
  if (jp2_pixels == (jas_matrix_t *) NULL)
    {
      MagickFreeMemory(lut);
      jas_image_destroy(jp2_image);
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
    }

  for (y=0; y < (long) image->rows; y++)
  {
    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
    if (p == (const PixelPacket *) NULL)
      break;
    if (number_components == 1)
      {
	for (x=0; x < (long) image->columns; x++)
	  jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(PixelIntensityToQuantum(&p[x]))]);
	(void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y,
				   (unsigned int) image->columns,1,jp2_pixels);
      }
    else
      {
	for (x=0; x < (long) image->columns; x++)
	  jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].red)]);
	(void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y,
				   (unsigned int) image->columns,1,jp2_pixels);

	for (x=0; x < (long) image->columns; x++)
	  jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].green)]);
	(void) jas_image_writecmpt(jp2_image,1,0,(unsigned int) y,
				   (unsigned int) image->columns,1,jp2_pixels);

	for (x=0; x < (long) image->columns; x++)
	  jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].blue)]);
	(void) jas_image_writecmpt(jp2_image,2,0,(unsigned int) y,
				   (unsigned int) image->columns,1,jp2_pixels);

	if (number_components > 3)
	  for (x=0; x < (long) image->columns; x++)
	    jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(MaxRGB-p[x].opacity)]);
	(void) jas_image_writecmpt(jp2_image,3,0,(unsigned int) y,
				   (unsigned int) image->columns,1,jp2_pixels);
      }
    if (image->previous == (Image *) NULL)
      if (QuantumTick(y,image->rows))
        if (!MagickMonitorFormatted(y,image->rows,&image->exception,
                                    SaveImageText,image->filename,
				    image->columns,image->rows))
          break;
  }
  (void) strlcpy(magick,image_info->magick,MaxTextExtent);
  /*
    J2C is an alias for JPC but Jasper only supports "JPC".
  */
  if (LocaleCompare(magick,"j2c") == 0)
    (void) strlcpy(magick,"jpc",sizeof(magick));
  LocaleLower(magick);
  format=jas_image_strtofmt(magick);

  /*
    Support passing Jasper options.
  */
  {
    const char
      **option_name;

    static const char *jasper_options[] =
      {
        "imgareatlx",
        "imgareatly",
        "tilegrdtlx",
        "tilegrdtly",
        "tilewidth",
        "tileheight",
        "prcwidth",
        "prcheight",
        "cblkwidth",
        "cblkheight",
        "mode",
        "ilyrrates",
        "prg",
        "nomct",
        "numrlvls",
        "sop",
        "eph",
        "lazy",
        "rate",
        "termall",
        "segsym",
        "vcausal",
        "pterm",
        "resetprob",
        "numgbits",
        NULL
      };
    for (option_name = jasper_options; *option_name != NULL; option_name++)
      {
        const char
          *value;

        if ((value=AccessDefinition(image_info,"jp2",*option_name)) != NULL)
          {
            if(LocaleCompare(*option_name,"rate") == 0)
              rate_specified=True;
            FormatString(option_keyval,"%s=%.1024s ",*option_name,value);
            ConcatenateString(&options,option_keyval);
          }
      }
  }
  /*
    Provide an emulation of IJG JPEG "quality" by default.
  */
  if (rate_specified == False)
    {
      double
        rate=1.0;
      
      /*
        A rough approximation to JPEG v1 quality using JPEG-2000.
        Default "quality" 75 results in a request for 16:1 compression, which
        results in image sizes approximating that of JPEG v1.
      */
      if ((image_info->quality < 99.5) && (image->rows*image->columns > 2500))
        {
          double
            header_size,
            current_size,
            target_size,
            d;
          
          d=115-image_info->quality;  /* Best number is 110-115 */
          rate=100.0/(d*d);
          header_size=550.0; /* Base file size. */
          header_size+=(number_components-1)*142; /* Additional components */
          /* FIXME: Need to account for any ICC profiles here */
          
          current_size=(double)((image->rows*image->columns*image->depth)/8)*
            number_components;
          target_size=(current_size*rate)+header_size;
          rate=target_size/current_size;
        }
      FormatString(option_keyval,"%s=%g ","rate",rate);
      ConcatenateString(&options,option_keyval);
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "Compression rate: %g (%3.2f:1)",rate,1.0/rate);
    }
  if (options)
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "Jasper options: \"%s\"", options);

  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Encoding image");
  status=jas_image_encode(jp2_image,jp2_stream,format,options);
  (void) jas_stream_close(jp2_stream);
  MagickFreeMemory(options);
  MagickFreeMemory(lut);
  jas_matrix_destroy(jp2_pixels);
  jas_image_destroy(jp2_image);
  if (status)
    ThrowWriterException(DelegateError,UnableToEncodeImageFile,image);
  return(True);
}
Exemple #3
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e P C L I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method WritePCLImage writes an image in the Page Control Language encoded
%  image format.
%
%  The format of the WritePCLImage method is:
%
%      unsigned int WritePCLImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o status: Method WritePCLImage return True if the image is written.
%      False is returned is there is a memory shortage or if the image file
%      fails to write.
%
%    o image_info: Specifies a pointer to a ImageInfo structure.
%
%    o image:  A pointer to an Image structure.
%
%
%
*/
static unsigned int WritePCLImage(const ImageInfo *image_info,Image *image)
{
  char
    buffer[MaxTextExtent];

  long
    sans,
    y;

  register const PixelPacket
    *p;

  register const IndexPacket
    *indexes;

  register long
    i,
    x;

  register unsigned char
    *q;

  unsigned char
    *pixels,
    *last_row_pixels,
    *output_row;

  unsigned int
    status;

  long
    zero_rows;

  unsigned long
    bytes_to_write,
    scene,
    density,
    bytes_per_line;

  unsigned char
    bits_per_pixel;

  ImageCharacteristics
    characteristics;

  PCL_CompressionType
    compression,
    last_row_compression;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
  if (status == False)
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);

  (void) GetGeometry("75x75",&sans,&sans,&density,&density);
  if (image_info->density != (char *) NULL)
    (void) GetGeometry(image_info->density,&sans,&sans,&density,&density);

  scene = 0;
  output_row = (unsigned char *) NULL;
  last_row_pixels = (unsigned char *) NULL;
  do
    {
      /*
        Ensure that image is in an RGB space.
      */
      (void) TransformColorspace(image,RGBColorspace);

      /*
        Analyze image to be written.
      */
      if (!GetImageCharacteristics(image,&characteristics,
                                   (OptimizeType == image_info->type),
                                   &image->exception))
        {
          CloseBlob(image);
          return MagickFail;
        }

      /*
        Initialize the printer
      */
      (void) WriteBlobString(image,"\033E");  /* printer reset */
      (void) WriteBlobString(image,"\033*r3F");  /* set presentation mode */
      /* define columns and rows in image */
      FormatString(buffer,"\033*r%lus%luT",image->columns,image->rows);
      (void) WriteBlobString(image,buffer);
      FormatString(buffer,"\033*t%luR",density);  /* set resolution */
      (void) WriteBlobString(image,buffer);
      (void) WriteBlobString(image,"\033&l0E");  /* top margin 0 */

      /*
        Determine output type and initialize further accordingly
      */
      if (image->storage_class == DirectClass)
        {
          /*
            Full color
          */
          bits_per_pixel=24;
          (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */
          (void) WriteBlobByte(image,0); /* RGB */
          (void) WriteBlobByte(image,3); /* direct by pixel */
          (void) WriteBlobByte(image,0); /* bits per index (ignored) */
          (void) WriteBlobByte(image,8); /* bits per red component */
          (void) WriteBlobByte(image,8); /* bits per green component */
          (void) WriteBlobByte(image,8); /* bits per blue component */
        }
      else
      if (characteristics.monochrome)
        {
          /*
            Use default printer monochrome setup - NB white = 0, black = 1
          */
          bits_per_pixel=1;
        }
      else
        {
          /*
            PseudoClass
          */
          bits_per_pixel=8;
          (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */
          (void) WriteBlobByte(image,0); /* RGB */
          (void) WriteBlobByte(image,1); /* indexed by pixel */
          (void) WriteBlobByte(image,bits_per_pixel); /* bits per index */
          (void) WriteBlobByte(image,8); /* bits per red component (implicit) */
          (void) WriteBlobByte(image,8); /* bits per green component (implicit) */
          (void) WriteBlobByte(image,8); /* bits per blue component (implicit) */

          /*
            Write colormap to file.
          */
          for (i=0; i < (long)(image->colors); i++)
            {
              FormatString(buffer,"\033*v%da%db%dc%ldI",
                           ScaleQuantumToChar(image->colormap[i].red),
                           ScaleQuantumToChar(image->colormap[i].green),
                           ScaleQuantumToChar(image->colormap[i].blue),
                           i);
              WriteBlobString(image,buffer);
            }
          /*
            Initialize rest of palette with empty entries
          */
          for ( ; i < (1L << bits_per_pixel); i++)
            {
              FormatString(buffer,"\033*v%luI",i);
              /* set index to current component values */
              (void) WriteBlobString(image,buffer);
            }
        }

      /*
        Start raster image
      */
      if  ((AccessDefinition(image_info,"pcl","fit-to-page") != NULL) ||
	   (AccessDefinition(image_info,"pcl","fit_to_page") != NULL))
        (void) WriteBlobString(image,"\033*r3A");  /* start raster graphics with scaling */
      else
        (void) WriteBlobString(image,"\033*r1A");  /* start raster graphics */
      (void) WriteBlobString(image,"\033*b0Y");  /* set y offset */

      /*
        Assign row buffer
      */
      bytes_per_line=(image->columns*bits_per_pixel+7)/8;
      pixels=MagickAllocateMemory(unsigned char *,bytes_per_line);
      if (pixels == (unsigned char *) NULL)
        ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);

      /*
        Set up for compression if desired
      */
      last_row_compression = PCL_UndefinedCompression;
      if (image_info->compression != NoCompression)
        {
          MagickFreeMemory(last_row_pixels);
          last_row_pixels=MagickAllocateMemory(unsigned char *,bytes_per_line);
          if (last_row_pixels == (unsigned char *) NULL)
            {
              MagickFreeMemory(pixels);
              ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
            }
          MagickFreeMemory(output_row);
          output_row=MagickAllocateMemory(unsigned char *,bytes_per_line);
          if (output_row == (unsigned char *) NULL)
            {
              MagickFreeMemory(pixels);
              MagickFreeMemory(last_row_pixels);
              ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
            }
            memset(last_row_pixels,0,bytes_per_line);
        }

      /*
        Convert MIFF to PCL raster pixels.
      */
      zero_rows=0;
      for (y=0; y < (long) image->rows; y++)
        {
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
          if (p == (const PixelPacket *) NULL)
            break;
          q=pixels;

          if (characteristics.monochrome)
            {
              register unsigned char
                bit,
                byte;
              int
                blk_ind;
              /*
                Monochrome row
              */
              blk_ind = ((image->colormap == NULL) || (image->colormap[0].red == 0)) ? 0 : 1;
              indexes=AccessImmutableIndexes(image);
              bit=0;
              byte=0;
              for (x=0; x < (long) image->columns; x++)
                {
                  byte<<=1;
                  if (indexes[x] == blk_ind) byte |= 1;
                  bit++;
                  if (bit == 8)
                    {
                      *q++=byte;
                      bit=0;
                      byte=0;
                    }
                }
              if (bit != 0)
                *q++=byte << (8-bit);
            }
          else
          if (bits_per_pixel == 8)
            {
              /*
                8 bit PseudoClass row
              */
              indexes=AccessImmutableIndexes(image);
              for (x=0; x < (long) image->columns; x++)
                {
                  *q++=indexes[x];
                }
            }
          else
          if ((bits_per_pixel == 24) || (bits_per_pixel == 32))
            {
              /*
                DirectClass/RGB row
              */
              for (x=0; x < (long) image->columns; x++)
                {
                  *q++=ScaleQuantumToChar(p->red);
                  *q++=ScaleQuantumToChar(p->green);
                  *q++=ScaleQuantumToChar(p->blue);
                  p++;
                }
            }

          if (image_info->compression == NoCompression)
            {
              FormatString(buffer,"\033*b%luW",bytes_per_line);  /* send row */
              (void) WriteBlobString(image,buffer);
              (void) WriteBlob(image,bytes_per_line,pixels);
            }
          else
            {
              compression=PCL_ChooseCompression(bytes_per_line,pixels,last_row_pixels);
              if (compression == PCL_ZeroRowCompression)
                {
                  zero_rows++;
                }
              else
                {
                  /*
                    Skip any omitted zero rows now
                  */
                  if (zero_rows > 0)
                    {
                      i = 32767;
                      do
                        {
                          if (zero_rows < i)
                            i=zero_rows;
                          FormatString(buffer,"\033*b%ldY",i); /* Y Offset */
                          (void) WriteBlobString(image,buffer);
                          zero_rows -= i;
                        } while (zero_rows > 0);
                    }

                  switch (compression)
                    {
                      case PCL_DeltaCompression:
                        {
                          if (compression != last_row_compression)
                            {
                              FormatString(buffer,"\033*b3M");  /* delta compression */
                              (void) WriteBlobString(image,buffer);
                              last_row_compression=compression;
                            }
                          bytes_to_write=PCL_DeltaCompress(bytes_per_line,pixels,
                                                           last_row_pixels,output_row);
                          FormatString(buffer,"\033*b%luW",bytes_to_write);
                          (void) WriteBlobString(image,buffer);
                          WriteBlob(image,bytes_to_write,output_row);
                          break;
                        } 
                      case PCL_TiffRLECompression:
                        {
                          if (compression != last_row_compression)
                            {
                              FormatString(buffer,"\033*b2M");  /* Tiff RLE compression */
                              (void) WriteBlobString(image,buffer);
                              last_row_compression=compression;
                            }
                          bytes_to_write=PCL_TiffRLECompress(bytes_per_line,pixels,output_row);
                          FormatString(buffer,"\033*b%luW",bytes_to_write);
                          (void) WriteBlobString(image,buffer);
                          WriteBlob(image,bytes_to_write,output_row);         
                          break;
                        }
                      case PCL_RLECompression:
                        {
                          if (compression != last_row_compression)
                            {
                              FormatString(buffer,"\033*b1M");  /* RLE compression */
                              (void) WriteBlobString(image,buffer);
                              last_row_compression=compression;
                            }
                          bytes_to_write=PCL_RLECompress(bytes_per_line,pixels,output_row);
                          FormatString(buffer,"\033*b%luW",bytes_to_write);
                          (void) WriteBlobString(image,buffer);
                          WriteBlob(image,bytes_to_write,output_row);         
                          break;
                        }
                      case PCL_RepeatedRowCompression:
                        {
                          compression=PCL_DeltaCompression;
                          if (compression != last_row_compression)
                            {
                              FormatString(buffer,"\033*b3M");  /* delta row compression */
                              (void) WriteBlobString(image,buffer);
                              last_row_compression=compression;
                            }
                          FormatString(buffer,"\033*b0W");  /* no data -> replicate row */
                          (void) WriteBlobString(image,buffer);
                          break;
                        } 
                      case PCL_NoCompression:
                        {
                          if (compression != last_row_compression)
                            {
                              FormatString(buffer,"\033*b0M");  /* no compression */
                              (void) WriteBlobString(image,buffer);
                              last_row_compression=compression;
                            }
                          FormatString(buffer,"\033*b%luW",bytes_per_line);  /* send row */
                          (void) WriteBlobString(image,buffer);
                          (void) WriteBlob(image,bytes_per_line,pixels);
                          break;
                        }
                      case PCL_ZeroRowCompression:
                        {
                          break;
                        }
                      case PCL_UndefinedCompression:
                        {
                          break;
                        }
                    }
                }

            /*
              Swap row with last row
            */
            q=last_row_pixels;
            last_row_pixels=pixels;
            pixels=q;
          }

          if (image->previous == (Image *) NULL)
            if (QuantumTick(y,image->rows))
              if (!MagickMonitorFormatted(y,image->rows,&image->exception,
                                          SaveImageText,image->filename,
                                          image->columns,image->rows))
                break;
        }

      (void) WriteBlobString(image,"\033*rB");  /* end graphics */
      MagickFreeMemory(pixels);
      MagickFreeMemory(last_row_pixels);
      MagickFreeMemory(output_row);
      if (image->next == (Image *) NULL)
        break;
      image=SyncNextImageInList(image);
      if ((status &= MagickMonitorFormatted(scene++,
                                            GetImageListLength(image),
                                            &image->exception,
                                            SaveImagesText,
                                            image->filename)) == MagickFail)
        break;
    } while (image_info->adjoin);