GraphicsMagick: coders/wpg.c Added WPG writer ... cross your fin...

GraphicsMagick Commits <[email protected]>
Newsgroups gmane.comp.video.graphicsmagick.cvs
Message-ID <mailman.2077.1673777587.1727.graphicsmagick-commit@lists.sourceforge.net>
changeset 6c85091fcce6 in /hg/GraphicsMagick
details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=6c85091fcce6
summary: coders/wpg.c Added WPG writer ... cross your fingers.

diffstat:

 ChangeLog                      |    5 +
 VisualMagick/tests/runtest.bat |    2 +
 coders/wpg.c                   |  275 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+), 0 deletions(-)

diffs (323 lines):

diff -r 1f23c0fa61f4 -r 6c85091fcce6 ChangeLog
--- a/ChangeLog	Sat Jan 14 12:33:16 2023 -0600
+++ b/ChangeLog	Sun Jan 15 11:12:20 2023 +0100
@@ -1,3 +1,8 @@
+2023-01-15  Fojtik Jaroslav  <[email protected]>
+
+	* VisualMagick/tests/runtest.bat
+	* coders/wpg.c Added WPG writer ... cross your fingers.
+
 2023-01-14  Bob Friesenhahn  <[email protected]>
 
 	* PerlMagick/MANIFEST: Update PerlMagick manifest.
diff -r 1f23c0fa61f4 -r 6c85091fcce6 VisualMagick/tests/runtest.bat
--- a/VisualMagick/tests/runtest.bat	Sat Jan 14 12:33:16 2023 -0600
+++ b/VisualMagick/tests/runtest.bat	Sun Jan 15 11:12:20 2023 +0100
@@ -152,6 +152,8 @@
 if not %COUNT% EQU 6 goto :_failed
 call :_dorwtest both WEBP
 if not %COUNT% EQU 6 goto :_failed
+call :_dorwtest both WPG
+if not %COUNT% EQU 6 goto :_failed
 call :_dorwtest both XBM
 if not %COUNT% EQU 6 goto :_failed
 call :_dorwtest both XPM
diff -r 1f23c0fa61f4 -r 6c85091fcce6 coders/wpg.c
--- a/coders/wpg.c	Sat Jan 14 12:33:16 2023 -0600
+++ b/coders/wpg.c	Sun Jan 15 11:12:20 2023 +0100
@@ -46,6 +46,7 @@
 #include "magick/shear.h"
 #include "magick/tempfile.h"
 #include "magick/transform.h"
+#include "magick/quantize.h"
 #include "magick/utility.h"
 
 
@@ -1787,6 +1788,279 @@
     ThrowReaderException(CorruptImageError,ImageFileDoesNotContainAnyImageData,image);
   return(image);
 }
+
+
+typedef struct
+{
+	unsigned char count;
+	unsigned char pos;
+	unsigned char buf[254];
+} WPG_RLE_packer;
+
+
+static void WPG_RLE_Flush(WPG_RLE_packer *WPG_RLE, Image *image, unsigned char n)
+{
+  if(n>WPG_RLE->pos) n=WPG_RLE->pos;
+  if(n>0x7F) n=0x7F;
+  if(n>0)
+  {
+    WriteBlobByte(image,n);
+    WriteBlob(image, n, WPG_RLE->buf);
+    WPG_RLE->pos -= n;
+    if(WPG_RLE->pos>0)
+      memcpy(WPG_RLE->buf, WPG_RLE->buf+n, n);
+    else
+     WPG_RLE->count = 0;
+  }
+}
+
+
+static void WPG_RLE_AddCharacter(WPG_RLE_packer *WPG_RLE, unsigned char b, Image *image)
+{
+  WPG_RLE->buf[WPG_RLE->pos++] = b;
+
+  if(WPG_RLE->pos>1)
+  {
+    if(WPG_RLE->count==0x7E || WPG_RLE->buf[WPG_RLE->pos-2]!=b)
+    {
+      if(WPG_RLE->count>=1)
+      {
+        WPG_RLE->count++;		// True number of repeated BYTEs.
+        WPG_RLE_Flush(WPG_RLE, image, WPG_RLE->pos-1-WPG_RLE->count);
+        WriteBlobByte(image, WPG_RLE->count|0x80);
+        WriteBlobByte(image, WPG_RLE->buf[0]);
+        WPG_RLE->pos = 1;
+        WPG_RLE->buf[0] = b;
+      }
+      WPG_RLE->count = 0;
+    }
+    else
+      WPG_RLE->count++;
+  }
+
+  if(WPG_RLE->pos>=254)
+  {
+    WPG_RLE_Flush(WPG_RLE, image, 0x7F);
+    return;
+  }
+}
+
+
+static void WPG_RLE_FinalFlush(WPG_RLE_packer *WPG_RLE, Image *image)
+{
+  if(WPG_RLE->count>1)
+  {
+    WPG_RLE_AddCharacter(WPG_RLE, WPG_RLE->buf[WPG_RLE->pos-1]^0xFF, image); // Add a fake BYTE.
+    WPG_RLE->pos = 0;			// Take a last fake BYTE away.
+  }
+  else
+  {
+    WPG_RLE_Flush(WPG_RLE,image,0x7F);
+    WPG_RLE_Flush(WPG_RLE,image,0x7F);
+    WPG_RLE->count = 0;
+  }
+}
+
+
+static void WPG_RLE_AddBlock(WPG_RLE_packer *WPG_RLE, Image *image, const BYTE *blk, magick_uint16_t size)
+{
+  while(size-- > 0)
+  {
+    WPG_RLE_AddCharacter(WPG_RLE, *blk, image);
+    blk++;
+  }
+}
+
+
+static void WPG_RLE_Init(WPG_RLE_packer *WPG_RLE)
+{
+  WPG_RLE->pos = WPG_RLE->count = 0;
+}
+
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   W r i t e W P G I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Function WriteWPGImage writes an WPG image to a file.
+%
+%  The format of the WriteWPGImage method is:
+%
+%      unsigned int WriteWPGImage(const ImageInfo *image_info,Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o status: Function WriteWPGImage 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 MagickPassFail WriteWPGImage(const ImageInfo *image_info, Image *image)
+{
+  long y;
+  unsigned dummy = 0;
+  unsigned int status;
+  int logging;
+  unsigned char StoredPlanes;
+  unsigned ldblk;
+  magick_off_t NumericOffs, CurrOffs;
+  QuantizeInfo quantize_info;
+  WPG_RLE_packer PackRLE;
+  unsigned char *pixels;
+
+  /*
+    Open output image file.
+  */
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter WPG");
+  status = OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
+  if(status == MagickFail)
+    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
+  WPG_RLE_Init(&PackRLE);
+
+  (void)TransformColorspace(image,RGBColorspace);
+
+  if(image->colors <= 2)
+  {
+    StoredPlanes=1;
+    ldblk = (image->columns+7)/8;
+  } else if(image->colors <= 16)
+  {
+    StoredPlanes=4;
+    ldblk = (image->columns+1)/2;
+  } else if(image->colors <= 256)
+  {
+    StoredPlanes = 8;
+    ldblk = image->columns;
+  } else
+  {
+    GetQuantizeInfo(&quantize_info);
+    quantize_info.dither = image_info->dither;
+    quantize_info.number_colors = 256;
+    (void)QuantizeImage(&quantize_info,image);
+    StoredPlanes = 8;
+    ldblk = image->columns;
+  }
+  pixels = MagickAllocateResourceLimitedMemory(unsigned char *,(size_t)(ldblk));
+  if(pixels == (unsigned char *) NULL)
+    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
+
+	/* Write WPG hader. */
+  WriteBlobLSBLong(image,0x435057FF);		//DWORD FileId
+  WriteBlobLSBLong(image,16);			//DWORD DataOffset;
+  WriteBlobByte(image,1);			//BYTE Product Type
+  WriteBlobByte(image,0x16);			//BYTE FileType;
+  WriteBlobByte(image,1);			//BYTE MajorVersion;
+  WriteBlobByte(image,0);			//BYTE MinorVersion;
+  WriteBlobLSBShort(image,0);			//WORD EncryptKey;
+  WriteBlobLSBShort(image,0);			//WORD Reserved;
+
+	/* Start WPG l1 */
+  WriteBlobByte(image,0xF);
+  WriteBlobByte(image,0x6);
+  WriteBlobByte(image,1);			//BYTE Version number
+  WriteBlobByte(image,0);			//BYTE Flags (bit 0 PostScript, maybe bitmap, bit 1 PostScript, no bitmap
+  WriteBlobLSBShort(image,image->columns);	//WORD Width of image (arbitrary units)
+  WriteBlobLSBShort(image,image->rows);		//WORD Height of image (arbitrary units)
+
+	/* Palette */
+  if(StoredPlanes>1)
+  {
+    int i;
+    WriteBlobByte(image,0xE);
+    i = 4+3*(1<<StoredPlanes);
+    if(i<0xFF)
+        WriteBlobByte(image,i);
+    else
+    {
+      WriteBlobByte(image,0xFF);
+      WriteBlobLSBShort(image,i);
+    }
+    WriteBlobLSBShort(image,0);				// Start index
+    WriteBlobLSBShort(image,1<<StoredPlanes);		// Num entries
+
+    for(i=0; i<(1<<StoredPlanes); i++)
+    {
+      if(i>=image->colors || image->colormap==NULL)
+      {
+        WriteBlobByte(image,i);
+        WriteBlobByte(image,i);
+        WriteBlobByte(image,i);
+      }
+      else
+      {
+        WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
+        WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].green));
+        WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
+      }
+    }
+  }
+
+	/* Bitmap 1 header */
+  WriteBlobByte(image,0xB);
+  WriteBlobByte(image,0xFF);
+  NumericOffs = TellBlob(image);
+  WriteBlobLSBShort(image,0x8000);
+  WriteBlobLSBShort(image,0);
+
+  WriteBlobLSBShort(image,image->columns);	//WORD Width
+  WriteBlobLSBShort(image,image->rows);		//WORD Height
+  WriteBlobLSBShort(image,StoredPlanes);	//WORD Depth;
+  WriteBlobLSBShort(image,75);			//WORD HorzRes;
+  WriteBlobLSBShort(image,75);			//WORD VertRes;
+
+  /*
+    Store image data.
+  */
+  for(y=0; y<(long)image->rows; y++)
+  {
+    if(AcquireImagePixels(image,0,y,image->columns,1,&image->exception) == (const PixelPacket *)NULL)
+    {
+      status = MagickFail;
+      break;
+    }
+    if(ExportImagePixelArea(image, (StoredPlanes==1)?GrayQuantum:IndexQuantum, StoredPlanes,pixels,0,0) != MagickPass)
+    {
+      status = MagickFail;
+      break;
+    }
+    WPG_RLE_AddBlock(&PackRLE,image,pixels,ldblk);
+    WPG_RLE_FinalFlush(&PackRLE,image);
+  }
+
+  CurrOffs = TellBlob(image);
+  SeekBlob(image,NumericOffs,SEEK_SET);
+  NumericOffs = CurrOffs - NumericOffs - 4;
+  WriteBlobLSBShort(image, 0x8000|(NumericOffs>>16));
+  WriteBlobLSBShort(image, NumericOffs&0xFFFF);
+  SeekBlob(image,CurrOffs,SEEK_SET);
+
+	/* End of WPG data */
+  WriteBlobByte(image,0x10);
+  WriteBlobByte(image,0);
+
+  CloseBlob(image);
+  MagickFreeResourceLimitedMemory(pixels);
+
+  if (logging)
+    (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return WPG");
+
+  return(status);
+}
+
 
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1818,6 +2092,7 @@
 
   entry=SetMagickInfo("WPG");
   entry->decoder=(DecoderHandler) ReadWPGImage;
+  entry->encoder = (EncoderHandler)WriteWPGImage;
   entry->magick=(MagickHandler) IsWPG;
   entry->description="Word Perfect Graphics";
   entry->module="WPG";
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.