]> Creatis software - clitk.git/blobdiff - utilities/CxImage/ximapcx.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximapcx.cpp
index 0d7e0a862465109064c5001675549f4b75ea44ff..f32ba33bd2f8bf547f1e9250939cfd9e9a23947d 100644 (file)
-/*\r
- * File:       ximapcx.cpp\r
- * Purpose:    Platform Independent PCX Image Class Loader and Writer\r
- * 05/Jan/2002 Davide Pizzolato - www.xdp.it\r
- * CxImage version 6.0.0 02/Feb/2008\r
- *\r
- * based on ppmtopcx.c - convert a portable pixmap to PCX\r
- * Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)\r
- * based on ppmtopcx.c by Michael Davidson\r
- */\r
-\r
-#include "ximapcx.h"\r
-\r
-#if CXIMAGE_SUPPORT_PCX\r
-\r
-#include "xmemfile.h"\r
-\r
-#define PCX_MAGIC 0X0A  // PCX magic number\r
-#define PCX_256_COLORS 0X0C  // magic number for 256 colors\r
-#define PCX_HDR_SIZE 128  // size of PCX header\r
-#define PCX_MAXCOLORS 256\r
-#define PCX_MAXPLANES 4\r
-#define PCX_MAXVAL 255\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImagePCX::Decode(CxFile *hFile)\r
-{\r
-       if (hFile == NULL) return false;\r
-\r
-       PCXHEADER pcxHeader;\r
-       int i, x, y, y2, nbytes, count, Height, Width;\r
-       BYTE c, ColorMap[PCX_MAXCOLORS][3];\r
-       BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL;\r
-       BYTE *pcxplanes, *pcxpixels;\r
-\r
-  cx_try\r
-  {\r
-       if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image");\r
-\r
-       PCX_toh(&pcxHeader);\r
-\r
-    if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file");\r
-    // Check for PCX run length encoding\r
-    if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme");\r
\r
-    Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1;\r
-    Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1;\r
-       info.xDPI = pcxHeader.Hres;\r
-       info.yDPI = pcxHeader.Vres;\r
-\r
-       if (info.nEscape == -1){\r
-               head.biWidth = Width;\r
-               head.biHeight= Height;\r
-               info.dwType = CXIMAGE_FORMAT_PCX;\r
-               return true;\r
-       }\r
-\r
-    // Check that we can handle this image format\r
-    if (pcxHeader.ColorPlanes > 4)\r
-               cx_throw("Can't handle image with more than 4 planes");\r
-\r
-       // Create the image\r
-       if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){\r
-               Create (Width, Height, 24, CXIMAGE_FORMAT_PCX);\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-               if (pcxHeader.ColorPlanes==4) AlphaCreate();\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-       } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1)\r
-               Create (Width, Height, 4, CXIMAGE_FORMAT_PCX);\r
-       else\r
-               Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX);\r
-\r
-       if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
-\r
-       //Read the image and check if it's ok\r
-    nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height;\r
-    lpHead1 = pcximage = (BYTE*)malloc(nbytes);\r
-    while (nbytes > 0){\r
-               if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX");\r
-\r
-               hFile->Read(&c,1,1);\r
-               if ((c & 0XC0) != 0XC0){ // Repeated group\r
-                       *pcximage++ = c;\r
-                       --nbytes;\r
-                       continue;\r
-               }\r
-               count = c & 0X3F; // extract count\r
-               hFile->Read(&c,1,1);\r
-               if (count > nbytes) cx_throw("repeat count spans end of image");\r
-\r
-               nbytes -= count;\r
-               while (--count >=0) *pcximage++ = c;\r
-       }\r
-    pcximage = lpHead1;\r
-\r
-       //store the palette\r
-    for (i = 0; i < 16; i++){\r
-               ColorMap[i][0] = pcxHeader.ColorMap[i][0];\r
-               ColorMap[i][1] = pcxHeader.ColorMap[i][1];\r
-               ColorMap[i][2] = pcxHeader.ColorMap[i][2];\r
-       }\r
-    if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){\r
-               hFile->Read(&c,1,1);\r
-               if (c != PCX_256_COLORS) cx_throw("bad color map signature");\r
-               \r
-               for (i = 0; i < PCX_MAXCOLORS; i++){\r
-                       hFile->Read(&ColorMap[i][0],1,1);\r
-                       hFile->Read(&ColorMap[i][1],1,1);\r
-                       hFile->Read(&ColorMap[i][2],1,1);\r
-               }\r
-       }\r
-    if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){\r
-               ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0;\r
-               ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255;\r
-       }\r
-\r
-       for (DWORD idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((BYTE)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]);\r
-\r
-    lpHead2 = pcxpixels = (BYTE *)malloc(Width + pcxHeader.BytesPerLine * 8);\r
-    // Convert the image\r
-    for (y = 0; y < Height; y++){\r
-\r
-               if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
-\r
-               y2=Height-1-y;\r
-               pcxpixels = lpHead2;\r
-               pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes);\r
-\r
-               if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){\r
-                       // Deal with 24 bit color image\r
-                       for (x = 0; x < Width; x++){\r
-                               SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));\r
-                       }\r
-                       continue;\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-               } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){\r
-                       for (x = 0; x < Width; x++){\r
-                               SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));\r
-                               AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]);\r
-                       }\r
-                       continue;\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-               } else if (pcxHeader.ColorPlanes == 1) {\r
-                       if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){\r
-                               cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane");\r
-                       }\r
-               } else {\r
-                       if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){\r
-                               cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel");\r
-                       }\r
-               }\r
-               for (x = 0; x < Width; x++)     SetPixelIndex(x,y2,pcxpixels[x]);\r
-       }\r
-\r
-  } cx_catch {\r
-       if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
-       if (lpHead1){ free(lpHead1); lpHead1 = NULL; }\r
-    if (lpHead2){ free(lpHead2); lpHead2 = NULL; }\r
-       return false;\r
-  }\r
-       if (lpHead1){ free(lpHead1); lpHead1 = NULL; }\r
-    if (lpHead2){ free(lpHead2); lpHead2 = NULL; }\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif //CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_ENCODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImagePCX::Encode(CxFile * hFile)\r
-{\r
-       if (EncodeSafeCheck(hFile)) return false;\r
-\r
-  cx_try\r
-  {\r
-       PCXHEADER pcxHeader;\r
-       memset(&pcxHeader,0,sizeof(pcxHeader));\r
-       pcxHeader.Manufacturer = PCX_MAGIC;\r
-       pcxHeader.Version = 5;\r
-       pcxHeader.Encoding = 1;\r
-       pcxHeader.Xmin = 0;\r
-       pcxHeader.Ymin = 0;\r
-       pcxHeader.Xmax = (WORD)head.biWidth-1;\r
-       pcxHeader.Ymax = (WORD)head.biHeight-1;\r
-       pcxHeader.Hres = (WORD)info.xDPI;\r
-       pcxHeader.Vres = (WORD)info.yDPI;\r
-       pcxHeader.Reserved = 0;\r
-       pcxHeader.PaletteType = head.biClrUsed==0;\r
-\r
-       switch(head.biBitCount){\r
-       case 24:\r
-       case 8:\r
-               {\r
-                       pcxHeader.BitsPerPixel = 8;\r
-                       pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1;\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-                       if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4;\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-                       pcxHeader.BytesPerLine = (WORD)head.biWidth;\r
-                       break;\r
-               }\r
-       default: //(4 1)\r
-               pcxHeader.BitsPerPixel = 1;\r
-               pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1;\r
-               pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3);\r
-       }\r
-\r
-    if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){\r
-               pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0;\r
-               pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255;\r
-       }\r
-       if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){\r
-               RGBQUAD c;\r
-               for (int i = 0; i < 16; i++){\r
-                       c=GetPaletteColor(i);\r
-                       pcxHeader.ColorMap[i][0] = c.rgbRed;\r
-                       pcxHeader.ColorMap[i][1] = c.rgbGreen;\r
-                       pcxHeader.ColorMap[i][2] = c.rgbBlue;\r
-               }\r
-       }\r
-\r
-       pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1);\r
-\r
-       PCX_toh(&pcxHeader);\r
-       if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 )\r
-          cx_throw("cannot write PCX header");\r
-       PCX_toh(&pcxHeader);\r
-\r
-       CxMemFile buffer;\r
-       buffer.Open();\r
-\r
-       BYTE c,n;\r
-       long x,y;\r
-       if (head.biClrUsed==0){\r
-               for (y = head.biHeight-1; y >=0 ; y--){\r
-                       for (int p=0; p<pcxHeader.ColorPlanes; p++){\r
-                               c=n=0;\r
-                               for (x = 0; x<head.biWidth; x++){\r
-                                       if (p==0)\r
-                                               PCX_PackPixels(BlindGetPixelColor(x,y).rgbRed,c,n,buffer);\r
-                                       else if (p==1)\r
-                                               PCX_PackPixels(BlindGetPixelColor(x,y).rgbGreen,c,n,buffer);\r
-                                       else if (p==2)\r
-                                               PCX_PackPixels(BlindGetPixelColor(x,y).rgbBlue,c,n,buffer);\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-                                       else if (p==3)\r
-                                               PCX_PackPixels(BlindAlphaGet(x,y),c,n,buffer);\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-                               }\r
-                               PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);\r
-                       }\r
-               }\r
-\r
-               hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);\r
-\r
-       } else if (head.biBitCount==8) {\r
-\r
-               for (y = head.biHeight-1; y >=0 ; y--){\r
-                       c=n=0;\r
-                       for (x = 0; x<head.biWidth; x++){\r
-                               PCX_PackPixels(GetPixelIndex(x,y),c,n,buffer);\r
-                       }\r
-                       PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);\r
-               }\r
-\r
-               hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);\r
-\r
-               if (head.biBitCount == 8){\r
-                       hFile->PutC(0x0C);\r
-                       BYTE* pal = (BYTE*)malloc(768);\r
-                       RGBQUAD c;\r
-                       for (int i=0;i<256;i++){\r
-                               c=GetPaletteColor(i);\r
-                               pal[3*i+0] = c.rgbRed;\r
-                               pal[3*i+1] = c.rgbGreen;\r
-                               pal[3*i+2] = c.rgbBlue;\r
-                       }\r
-                       hFile->Write(pal,768,1);\r
-                       free(pal);\r
-               }\r
-       } else { //(head.biBitCount==4) || (head.biBitCount==1)\r
-\r
-               RGBQUAD *rgb = GetPalette();\r
-               bool binvert = false;\r
-               if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1);\r
-               \r
-               BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine);\r
-               BYTE* raw = (BYTE*)malloc(head.biWidth);\r
-\r
-               for(y = head.biHeight-1; y >=0 ; y--) {\r
-\r
-                       for( x = 0; x < head.biWidth; x++)      raw[x] = (BYTE)GetPixelIndex(x,y);\r
-\r
-                       if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x];\r
-\r
-                       for( x = 0; x < pcxHeader.ColorPlanes; x++ ) {\r
-                               PCX_PixelsToPlanes(raw, head.biWidth, plane, x);\r
-                               PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer);\r
-                       }\r
-               }\r
-\r
-               free(plane);\r
-               free(raw);\r
-\r
-               hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);\r
-\r
-       }\r
-\r
-  } cx_catch {\r
-       if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
-       return false;\r
-  }\r
-    return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif // CXIMAGE_SUPPORT_ENCODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Convert multi-plane format into 1 pixel per byte\r
-// from unpacked file data bitplanes[] into pixel row pixels[]\r
-// image Height rows, with each row having planes image planes each\r
-// bytesperline bytes\r
-bool CxImagePCX::PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)\r
-{\r
-       int i, j, npixels;\r
-       BYTE * p;\r
-       if (planes > 4) return false;\r
-       if (bitsperpixel != 1) return false;\r
-\r
-       // Clear the pixel buffer\r
-       npixels = (bytesperline * 8) / bitsperpixel;\r
-       p = pixels;\r
-       while (--npixels >= 0) *p++ = 0;\r
-\r
-       // Do the format conversion\r
-       for (i = 0; i < planes; i++){\r
-               int pixbit, bits, mask;\r
-               p = pixels;\r
-               pixbit = (1 << i);  // pixel bit for this plane\r
-               for (j = 0; j < bytesperline; j++){\r
-                       bits = *bitplanes++;\r
-                       for (mask = 0X80; mask != 0; mask >>= 1, p++)\r
-                               if (bits & mask) *p |= pixbit;\r
-               }\r
-       }\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-// convert packed pixel format into 1 pixel per byte\r
-// from unpacked file data bitplanes[] into pixel row pixels[]\r
-// image Height rows, with each row having planes image planes each\r
-// bytesperline bytes\r
-bool CxImagePCX::PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)\r
-{\r
-       register int bits;\r
-       if (planes != 1) return false;\r
-       \r
-       if (bitsperpixel == 8){  // 8 bits/pixels, no unpacking needed\r
-               while (bytesperline-- > 0) *pixels++ = *bitplanes++;\r
-       } else if (bitsperpixel == 4){  // 4 bits/pixel, two pixels per byte\r
-               while (bytesperline-- > 0){\r
-                       bits = *bitplanes++;\r
-                       *pixels++ = (BYTE)((bits >> 4) & 0X0F);\r
-                       *pixels++ = (BYTE)((bits) & 0X0F);\r
-               }\r
-       } else if (bitsperpixel == 2){  // 2 bits/pixel, four pixels per byte\r
-               while (bytesperline-- > 0){\r
-                       bits = *bitplanes++;\r
-                       *pixels++ = (BYTE)((bits >> 6) & 0X03);\r
-                       *pixels++ = (BYTE)((bits >> 4) & 0X03);\r
-                       *pixels++ = (BYTE)((bits >> 2) & 0X03);\r
-                       *pixels++ = (BYTE)((bits) & 0X03);\r
-               }\r
-       } else if (bitsperpixel == 1){  // 1 bits/pixel, 8 pixels per byte\r
-               while (bytesperline-- > 0){\r
-                       bits = *bitplanes++;\r
-                       *pixels++ = ((bits & 0X80) != 0);\r
-                       *pixels++ = ((bits & 0X40) != 0);\r
-                       *pixels++ = ((bits & 0X20) != 0);\r
-                       *pixels++ = ((bits & 0X10) != 0);\r
-                       *pixels++ = ((bits & 0X08) != 0);\r
-                       *pixels++ = ((bits & 0X04) != 0);\r
-                       *pixels++ = ((bits & 0X02) != 0);\r
-                       *pixels++ = ((bits & 0X01) != 0);\r
-               }\r
-       }\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/* PCX_PackPixels(const long p,BYTE &c, BYTE &n, long &l, CxFile &f)\r
- * p = current pixel (-1 ends the line -2 ends odd line)\r
- * c = previous pixel\r
- * n = number of consecutive pixels\r
- */\r
-void CxImagePCX::PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f)\r
-{\r
-       if (p!=c && n){\r
-               if (n==1 && c<0xC0){\r
-                       f.PutC(c);\r
-               } else {\r
-                       f.PutC(0xC0|n);\r
-                       f.PutC(c);\r
-               }\r
-               n=0;\r
-       }\r
-       if (n==0x3F) {\r
-               f.PutC(0xFF);\r
-               f.PutC(c);\r
-               n=0;\r
-       }\r
-       if (p==-2) f.PutC(0);\r
-       c=(BYTE)p;\r
-       n++;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-void CxImagePCX::PCX_PackPlanes(BYTE* buff, const long size, CxFile &f)\r
-{\r
-    BYTE *start,*end;\r
-    BYTE c, previous, count;\r
-\r
-       start = buff;\r
-    end = buff + size;\r
-    previous = *start++;\r
-    count    = 1;\r
-\r
-    while (start < end) {\r
-        c = *start++;\r
-        if (c == previous && count < 63) {\r
-            ++count;\r
-            continue;\r
-        }\r
-\r
-        if (count > 1 || (previous & 0xc0) == 0xc0) {\r
-            f.PutC( count | 0xc0 );\r
-        }\r
-        f.PutC(previous);\r
-        previous = c;\r
-        count   = 1;\r
-    }\r
-\r
-    if (count > 1 || (previous & 0xc0) == 0xc0) {\r
-        count |= 0xc0;\r
-        f.PutC(count);\r
-    }\r
-    f.PutC(previous);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-void CxImagePCX::PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane)\r
-{\r
-    int cbit, x, mask;\r
-    unsigned char *cp = buf-1;\r
-\r
-    mask = 1 << plane;\r
-    cbit = -1;\r
-    for( x = 0; x < width; x++ ) {\r
-        if( cbit < 0 ) {\r
-            cbit = 7;\r
-            *++cp = 0;\r
-        }\r
-        if( raw[x] & mask )\r
-            *cp |= (1<<cbit);\r
-        --cbit;\r
-    }\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-void CxImagePCX::PCX_toh(PCXHEADER* p)\r
-{\r
-       p->Xmin = ntohs(p->Xmin);\r
-       p->Ymin = ntohs(p->Ymin);\r
-       p->Xmax = ntohs(p->Xmax);\r
-       p->Ymax = ntohs(p->Ymax);\r
-       p->Hres = ntohs(p->Hres);\r
-       p->Vres = ntohs(p->Vres);\r
-       p->BytesPerLine = ntohs(p->BytesPerLine);\r
-       p->PaletteType = ntohs(p->PaletteType);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif // CXIMAGE_SUPPORT_PCX\r
+/*
+ * File:       ximapcx.cpp
+ * Purpose:    Platform Independent PCX Image Class Loader and Writer
+ * 05/Jan/2002 Davide Pizzolato - www.xdp.it
+ * CxImage version 6.0.0 02/Feb/2008
+ *
+ * based on ppmtopcx.c - convert a portable pixmap to PCX
+ * Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+ * based on ppmtopcx.c by Michael Davidson
+ */
+
+#include "ximapcx.h"
+
+#if CXIMAGE_SUPPORT_PCX
+
+#include "xmemfile.h"
+
+#define PCX_MAGIC 0X0A  // PCX magic number
+#define PCX_256_COLORS 0X0C  // magic number for 256 colors
+#define PCX_HDR_SIZE 128  // size of PCX header
+#define PCX_MAXCOLORS 256
+#define PCX_MAXPLANES 4
+#define PCX_MAXVAL 255
+
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+bool CxImagePCX::Decode(CxFile *hFile)
+{
+       if (hFile == NULL) return false;
+
+       PCXHEADER pcxHeader;
+       int i, x, y, y2, nbytes, count, Height, Width;
+       BYTE c, ColorMap[PCX_MAXCOLORS][3];
+       BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL;
+       BYTE *pcxplanes, *pcxpixels;
+
+  cx_try
+  {
+       if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image");
+
+       PCX_toh(&pcxHeader);
+
+    if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file");
+    // Check for PCX run length encoding
+    if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme");
+    Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1;
+    Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1;
+       info.xDPI = pcxHeader.Hres;
+       info.yDPI = pcxHeader.Vres;
+
+       if (info.nEscape == -1){
+               head.biWidth = Width;
+               head.biHeight= Height;
+               info.dwType = CXIMAGE_FORMAT_PCX;
+               return true;
+       }
+
+    // Check that we can handle this image format
+    if (pcxHeader.ColorPlanes > 4)
+               cx_throw("Can't handle image with more than 4 planes");
+
+       // Create the image
+       if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){
+               Create (Width, Height, 24, CXIMAGE_FORMAT_PCX);
+#if CXIMAGE_SUPPORT_ALPHA
+               if (pcxHeader.ColorPlanes==4) AlphaCreate();
+#endif //CXIMAGE_SUPPORT_ALPHA
+       } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1)
+               Create (Width, Height, 4, CXIMAGE_FORMAT_PCX);
+       else
+               Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX);
+
+       if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
+
+       //Read the image and check if it's ok
+    nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height;
+    lpHead1 = pcximage = (BYTE*)malloc(nbytes);
+    while (nbytes > 0){
+               if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX");
+
+               hFile->Read(&c,1,1);
+               if ((c & 0XC0) != 0XC0){ // Repeated group
+                       *pcximage++ = c;
+                       --nbytes;
+                       continue;
+               }
+               count = c & 0X3F; // extract count
+               hFile->Read(&c,1,1);
+               if (count > nbytes) cx_throw("repeat count spans end of image");
+
+               nbytes -= count;
+               while (--count >=0) *pcximage++ = c;
+       }
+    pcximage = lpHead1;
+
+       //store the palette
+    for (i = 0; i < 16; i++){
+               ColorMap[i][0] = pcxHeader.ColorMap[i][0];
+               ColorMap[i][1] = pcxHeader.ColorMap[i][1];
+               ColorMap[i][2] = pcxHeader.ColorMap[i][2];
+       }
+    if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){
+               hFile->Read(&c,1,1);
+               if (c != PCX_256_COLORS) cx_throw("bad color map signature");
+               
+               for (i = 0; i < PCX_MAXCOLORS; i++){
+                       hFile->Read(&ColorMap[i][0],1,1);
+                       hFile->Read(&ColorMap[i][1],1,1);
+                       hFile->Read(&ColorMap[i][2],1,1);
+               }
+       }
+    if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){
+               ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0;
+               ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255;
+       }
+
+       for (DWORD idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((BYTE)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]);
+
+    lpHead2 = pcxpixels = (BYTE *)malloc(Width + pcxHeader.BytesPerLine * 8);
+    // Convert the image
+    for (y = 0; y < Height; y++){
+
+               if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
+
+               y2=Height-1-y;
+               pcxpixels = lpHead2;
+               pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes);
+
+               if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){
+                       // Deal with 24 bit color image
+                       for (x = 0; x < Width; x++){
+                               SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));
+                       }
+                       continue;
+#if CXIMAGE_SUPPORT_ALPHA
+               } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){
+                       for (x = 0; x < Width; x++){
+                               SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));
+                               AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]);
+                       }
+                       continue;
+#endif //CXIMAGE_SUPPORT_ALPHA
+               } else if (pcxHeader.ColorPlanes == 1) {
+                       if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){
+                               cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane");
+                       }
+               } else {
+                       if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){
+                               cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel");
+                       }
+               }
+               for (x = 0; x < Width; x++)     SetPixelIndex(x,y2,pcxpixels[x]);
+       }
+
+  } cx_catch {
+       if (strcmp(message,"")) strncpy(info.szLastError,message,255);
+       if (lpHead1){ free(lpHead1); lpHead1 = NULL; }
+    if (lpHead2){ free(lpHead2); lpHead2 = NULL; }
+       return false;
+  }
+       if (lpHead1){ free(lpHead1); lpHead1 = NULL; }
+    if (lpHead2){ free(lpHead2); lpHead2 = NULL; }
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif //CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_ENCODE
+////////////////////////////////////////////////////////////////////////////////
+bool CxImagePCX::Encode(CxFile * hFile)
+{
+       if (EncodeSafeCheck(hFile)) return false;
+
+  cx_try
+  {
+       PCXHEADER pcxHeader;
+       memset(&pcxHeader,0,sizeof(pcxHeader));
+       pcxHeader.Manufacturer = PCX_MAGIC;
+       pcxHeader.Version = 5;
+       pcxHeader.Encoding = 1;
+       pcxHeader.Xmin = 0;
+       pcxHeader.Ymin = 0;
+       pcxHeader.Xmax = (WORD)head.biWidth-1;
+       pcxHeader.Ymax = (WORD)head.biHeight-1;
+       pcxHeader.Hres = (WORD)info.xDPI;
+       pcxHeader.Vres = (WORD)info.yDPI;
+       pcxHeader.Reserved = 0;
+       pcxHeader.PaletteType = head.biClrUsed==0;
+
+       switch(head.biBitCount){
+       case 24:
+       case 8:
+               {
+                       pcxHeader.BitsPerPixel = 8;
+                       pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1;
+#if CXIMAGE_SUPPORT_ALPHA
+                       if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4;
+#endif //CXIMAGE_SUPPORT_ALPHA
+                       pcxHeader.BytesPerLine = (WORD)head.biWidth;
+                       break;
+               }
+       default: //(4 1)
+               pcxHeader.BitsPerPixel = 1;
+               pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1;
+               pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3);
+       }
+
+    if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){
+               pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0;
+               pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255;
+       }
+       if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){
+               RGBQUAD c;
+               for (int i = 0; i < 16; i++){
+                       c=GetPaletteColor(i);
+                       pcxHeader.ColorMap[i][0] = c.rgbRed;
+                       pcxHeader.ColorMap[i][1] = c.rgbGreen;
+                       pcxHeader.ColorMap[i][2] = c.rgbBlue;
+               }
+       }
+
+       pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1);
+
+       PCX_toh(&pcxHeader);
+       if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 )
+          cx_throw("cannot write PCX header");
+       PCX_toh(&pcxHeader);
+
+       CxMemFile buffer;
+       buffer.Open();
+
+       BYTE c,n;
+       long x,y;
+       if (head.biClrUsed==0){
+               for (y = head.biHeight-1; y >=0 ; y--){
+                       for (int p=0; p<pcxHeader.ColorPlanes; p++){
+                               c=n=0;
+                               for (x = 0; x<head.biWidth; x++){
+                                       if (p==0)
+                                               PCX_PackPixels(BlindGetPixelColor(x,y).rgbRed,c,n,buffer);
+                                       else if (p==1)
+                                               PCX_PackPixels(BlindGetPixelColor(x,y).rgbGreen,c,n,buffer);
+                                       else if (p==2)
+                                               PCX_PackPixels(BlindGetPixelColor(x,y).rgbBlue,c,n,buffer);
+#if CXIMAGE_SUPPORT_ALPHA
+                                       else if (p==3)
+                                               PCX_PackPixels(BlindAlphaGet(x,y),c,n,buffer);
+#endif //CXIMAGE_SUPPORT_ALPHA
+                               }
+                               PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);
+                       }
+               }
+
+               hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
+
+       } else if (head.biBitCount==8) {
+
+               for (y = head.biHeight-1; y >=0 ; y--){
+                       c=n=0;
+                       for (x = 0; x<head.biWidth; x++){
+                               PCX_PackPixels(GetPixelIndex(x,y),c,n,buffer);
+                       }
+                       PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);
+               }
+
+               hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
+
+               if (head.biBitCount == 8){
+                       hFile->PutC(0x0C);
+                       BYTE* pal = (BYTE*)malloc(768);
+                       RGBQUAD c;
+                       for (int i=0;i<256;i++){
+                               c=GetPaletteColor(i);
+                               pal[3*i+0] = c.rgbRed;
+                               pal[3*i+1] = c.rgbGreen;
+                               pal[3*i+2] = c.rgbBlue;
+                       }
+                       hFile->Write(pal,768,1);
+                       free(pal);
+               }
+       } else { //(head.biBitCount==4) || (head.biBitCount==1)
+
+               RGBQUAD *rgb = GetPalette();
+               bool binvert = false;
+               if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1);
+               
+               BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine);
+               BYTE* raw = (BYTE*)malloc(head.biWidth);
+
+               for(y = head.biHeight-1; y >=0 ; y--) {
+
+                       for( x = 0; x < head.biWidth; x++)      raw[x] = (BYTE)GetPixelIndex(x,y);
+
+                       if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x];
+
+                       for( x = 0; x < pcxHeader.ColorPlanes; x++ ) {
+                               PCX_PixelsToPlanes(raw, head.biWidth, plane, x);
+                               PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer);
+                       }
+               }
+
+               free(plane);
+               free(raw);
+
+               hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
+
+       }
+
+  } cx_catch {
+       if (strcmp(message,"")) strncpy(info.szLastError,message,255);
+       return false;
+  }
+    return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif // CXIMAGE_SUPPORT_ENCODE
+////////////////////////////////////////////////////////////////////////////////
+// Convert multi-plane format into 1 pixel per byte
+// from unpacked file data bitplanes[] into pixel row pixels[]
+// image Height rows, with each row having planes image planes each
+// bytesperline bytes
+bool CxImagePCX::PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)
+{
+       int i, j, npixels;
+       BYTE * p;
+       if (planes > 4) return false;
+       if (bitsperpixel != 1) return false;
+
+       // Clear the pixel buffer
+       npixels = (bytesperline * 8) / bitsperpixel;
+       p = pixels;
+       while (--npixels >= 0) *p++ = 0;
+
+       // Do the format conversion
+       for (i = 0; i < planes; i++){
+               int pixbit, bits, mask;
+               p = pixels;
+               pixbit = (1 << i);  // pixel bit for this plane
+               for (j = 0; j < bytesperline; j++){
+                       bits = *bitplanes++;
+                       for (mask = 0X80; mask != 0; mask >>= 1, p++)
+                               if (bits & mask) *p |= pixbit;
+               }
+       }
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+// convert packed pixel format into 1 pixel per byte
+// from unpacked file data bitplanes[] into pixel row pixels[]
+// image Height rows, with each row having planes image planes each
+// bytesperline bytes
+bool CxImagePCX::PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)
+{
+       register int bits;
+       if (planes != 1) return false;
+       
+       if (bitsperpixel == 8){  // 8 bits/pixels, no unpacking needed
+               while (bytesperline-- > 0) *pixels++ = *bitplanes++;
+       } else if (bitsperpixel == 4){  // 4 bits/pixel, two pixels per byte
+               while (bytesperline-- > 0){
+                       bits = *bitplanes++;
+                       *pixels++ = (BYTE)((bits >> 4) & 0X0F);
+                       *pixels++ = (BYTE)((bits) & 0X0F);
+               }
+       } else if (bitsperpixel == 2){  // 2 bits/pixel, four pixels per byte
+               while (bytesperline-- > 0){
+                       bits = *bitplanes++;
+                       *pixels++ = (BYTE)((bits >> 6) & 0X03);
+                       *pixels++ = (BYTE)((bits >> 4) & 0X03);
+                       *pixels++ = (BYTE)((bits >> 2) & 0X03);
+                       *pixels++ = (BYTE)((bits) & 0X03);
+               }
+       } else if (bitsperpixel == 1){  // 1 bits/pixel, 8 pixels per byte
+               while (bytesperline-- > 0){
+                       bits = *bitplanes++;
+                       *pixels++ = ((bits & 0X80) != 0);
+                       *pixels++ = ((bits & 0X40) != 0);
+                       *pixels++ = ((bits & 0X20) != 0);
+                       *pixels++ = ((bits & 0X10) != 0);
+                       *pixels++ = ((bits & 0X08) != 0);
+                       *pixels++ = ((bits & 0X04) != 0);
+                       *pixels++ = ((bits & 0X02) != 0);
+                       *pixels++ = ((bits & 0X01) != 0);
+               }
+       }
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+/* PCX_PackPixels(const long p,BYTE &c, BYTE &n, long &l, CxFile &f)
+ * p = current pixel (-1 ends the line -2 ends odd line)
+ * c = previous pixel
+ * n = number of consecutive pixels
+ */
+void CxImagePCX::PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f)
+{
+       if (p!=c && n){
+               if (n==1 && c<0xC0){
+                       f.PutC(c);
+               } else {
+                       f.PutC(0xC0|n);
+                       f.PutC(c);
+               }
+               n=0;
+       }
+       if (n==0x3F) {
+               f.PutC(0xFF);
+               f.PutC(c);
+               n=0;
+       }
+       if (p==-2) f.PutC(0);
+       c=(BYTE)p;
+       n++;
+}
+////////////////////////////////////////////////////////////////////////////////
+void CxImagePCX::PCX_PackPlanes(BYTE* buff, const long size, CxFile &f)
+{
+    BYTE *start,*end;
+    BYTE c, previous, count;
+
+       start = buff;
+    end = buff + size;
+    previous = *start++;
+    count    = 1;
+
+    while (start < end) {
+        c = *start++;
+        if (c == previous && count < 63) {
+            ++count;
+            continue;
+        }
+
+        if (count > 1 || (previous & 0xc0) == 0xc0) {
+            f.PutC( count | 0xc0 );
+        }
+        f.PutC(previous);
+        previous = c;
+        count   = 1;
+    }
+
+    if (count > 1 || (previous & 0xc0) == 0xc0) {
+        count |= 0xc0;
+        f.PutC(count);
+    }
+    f.PutC(previous);
+}
+////////////////////////////////////////////////////////////////////////////////
+void CxImagePCX::PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane)
+{
+    int cbit, x, mask;
+    unsigned char *cp = buf-1;
+
+    mask = 1 << plane;
+    cbit = -1;
+    for( x = 0; x < width; x++ ) {
+        if( cbit < 0 ) {
+            cbit = 7;
+            *++cp = 0;
+        }
+        if( raw[x] & mask )
+            *cp |= (1<<cbit);
+        --cbit;
+    }
+}
+////////////////////////////////////////////////////////////////////////////////
+void CxImagePCX::PCX_toh(PCXHEADER* p)
+{
+       p->Xmin = ntohs(p->Xmin);
+       p->Ymin = ntohs(p->Ymin);
+       p->Xmax = ntohs(p->Xmax);
+       p->Ymax = ntohs(p->Ymax);
+       p->Hres = ntohs(p->Hres);
+       p->Vres = ntohs(p->Vres);
+       p->BytesPerLine = ntohs(p->BytesPerLine);
+       p->PaletteType = ntohs(p->PaletteType);
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif // CXIMAGE_SUPPORT_PCX