]> Creatis software - clitk.git/blobdiff - utilities/CxImage/ximage.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximage.cpp
index f4e185675a5e3fa5c6543f08ef1b2a024b52cc38..e81d3c6c8e2487d85c9a310c10aec0dfc2927339 100644 (file)
-// ximage.cpp : main implementation file\r
-/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
- * CxImage version 6.0.0 02/Feb/2008\r
- */\r
-\r
-#include "ximage.h"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// CxImage \r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Initialize the internal structures\r
- */\r
-void CxImage::Startup(DWORD imagetype)\r
-{\r
-       //init pointers\r
-       pDib = pSelection = pAlpha = NULL;\r
-       ppLayers = ppFrames = NULL;\r
-       //init structures\r
-       memset(&head,0,sizeof(BITMAPINFOHEADER));\r
-       memset(&info,0,sizeof(CXIMAGEINFO));\r
-       //init default attributes\r
-    info.dwType = imagetype;\r
-       info.fQuality = 90.0f;\r
-       info.nAlphaMax = 255;\r
-       info.nBkgndIndex = -1;\r
-       info.bEnabled = true;\r
-       SetXDPI(CXIMAGE_DEFAULT_DPI);\r
-       SetYDPI(CXIMAGE_DEFAULT_DPI);\r
-\r
-       short test = 1;\r
-       info.bLittleEndianHost = (*((char *) &test) == 1);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Empty image constructor\r
- * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS\r
- */\r
-CxImage::CxImage(DWORD imagetype)\r
-{\r
-       Startup(imagetype);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Call this function to destroy image pixels, alpha channel, selection and sub layers.\r
- * - Attributes are not erased, but IsValid returns false.\r
- *\r
- * \return true if everything is freed, false if the image is a Ghost\r
- */\r
-bool CxImage::Destroy()\r
-{\r
-       //free this only if it's valid and it's not a ghost\r
-       if (info.pGhost==NULL){\r
-               if (ppLayers) { \r
-                       for(long n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }\r
-                       delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;\r
-               }\r
-               if (pSelection) {free(pSelection); pSelection=0;}\r
-               if (pAlpha) {free(pAlpha); pAlpha=0;}\r
-               if (pDib) {free(pDib); pDib=0;}\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImage::DestroyFrames()\r
-{\r
-       if (info.pGhost==NULL) {\r
-               if (ppFrames) {\r
-                       for (long n=0; n<info.nNumFrames; n++) { delete ppFrames[n]; }\r
-                       delete [] ppFrames; ppFrames = NULL; info.nNumFrames = 0;\r
-               }\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Sized image constructor\r
- * \param dwWidth: width\r
- * \param dwHeight: height\r
- * \param wBpp: bit per pixel, can be 1, 4, 8, 24\r
- * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS\r
- */\r
-CxImage::CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)\r
-{\r
-       Startup(imagetype);\r
-       Create(dwWidth,dwHeight,wBpp,imagetype);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * image constructor from existing source\r
- * \param src: source image.\r
- * \param copypixels: copy the pixels from the source image into the new image.\r
- * \param copyselection: copy the selection from source\r
- * \param copyalpha: copy the alpha channel from source\r
- * \sa Copy\r
- */\r
-CxImage::CxImage(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)\r
-{\r
-       Startup(src.GetType());\r
-       Copy(src,copypixels,copyselection,copyalpha);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Copies the image from an exsisting source\r
- * \param src: source image.\r
- * \param copypixels: copy the pixels from the source image into the new image.\r
- * \param copyselection: copy the selection from source\r
- * \param copyalpha: copy the alpha channel from source\r
- */\r
-void CxImage::Copy(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)\r
-{\r
-       // if the source is a ghost, the copy is still a ghost\r
-       if (src.info.pGhost){\r
-               Ghost(&src);\r
-               return;\r
-       }\r
-       //copy the attributes\r
-       memcpy(&info,&src.info,sizeof(CXIMAGEINFO));\r
-       memcpy(&head,&src.head,sizeof(BITMAPINFOHEADER)); // [andy] - fix for bitmap header DPI\r
-       //rebuild the image\r
-       Create(src.GetWidth(),src.GetHeight(),src.GetBpp(),src.GetType());\r
-       //copy the pixels and the palette, or at least copy the palette only.\r
-       if (copypixels && pDib && src.pDib) memcpy(pDib,src.pDib,GetSize());\r
-       else SetPalette(src.GetPalette());\r
-       long nSize = head.biWidth * head.biHeight;\r
-       //copy the selection\r
-       if (copyselection && src.pSelection){\r
-               if (pSelection) free(pSelection);\r
-               pSelection = (BYTE*)malloc(nSize);\r
-               memcpy(pSelection,src.pSelection,nSize);\r
-       }\r
-       //copy the alpha channel\r
-       if (copyalpha && src.pAlpha){\r
-               if (pAlpha) free(pAlpha);\r
-               pAlpha = (BYTE*)malloc(nSize);\r
-               memcpy(pAlpha,src.pAlpha,nSize);\r
-       }\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Copies the image attributes from an existing image.\r
- * - Works only on an empty image, and the image will be still empty.\r
- * - <b> Use it before Create() </b>\r
- */\r
-void CxImage::CopyInfo(const CxImage &src)\r
-{\r
-       if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO));\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * \sa Copy\r
- */\r
-CxImage& CxImage::operator = (const CxImage& isrc)\r
-{\r
-       if (this != &isrc) Copy(isrc);\r
-       return *this;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Initializes or rebuilds the image.\r
- * \param dwWidth: width\r
- * \param dwHeight: height\r
- * \param wBpp: bit per pixel, can be 1, 4, 8, 24\r
- * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS\r
- * \return pointer to the internal pDib object; NULL if an error occurs.\r
- */\r
-void* CxImage::Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)\r
-{\r
-       // destroy the existing image (if any)\r
-       if (!Destroy())\r
-               return NULL;\r
-\r
-       // prevent further actions if width or height are not vaild <Balabasnia>\r
-       if ((dwWidth == 0) || (dwHeight == 0)){\r
-               strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero");\r
-               return NULL;\r
-       }\r
-\r
-    // Make sure bits per pixel is valid\r
-    if         (wBpp <= 1)     wBpp = 1;\r
-    else if (wBpp <= 4)        wBpp = 4;\r
-    else if (wBpp <= 8)        wBpp = 8;\r
-    else                               wBpp = 24;\r
-\r
-       // limit memory requirements (and also a check for bad parameters)\r
-       if (((dwWidth*dwHeight*wBpp)>>3) > CXIMAGE_MAX_MEMORY ||\r
-               ((dwWidth*dwHeight*wBpp)/wBpp) != (dwWidth*dwHeight))\r
-       {\r
-               strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded");\r
-               return NULL;\r
-       }\r
-\r
-       // set the correct bpp value\r
-    switch (wBpp){\r
-        case 1:\r
-            head.biClrUsed = 2;        break;\r
-        case 4:\r
-            head.biClrUsed = 16; break;\r
-        case 8:\r
-            head.biClrUsed = 256; break;\r
-        default:\r
-            head.biClrUsed = 0;\r
-    }\r
-\r
-       //set the common image informations\r
-    info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4);\r
-    info.dwType = imagetype;\r
-\r
-    // initialize BITMAPINFOHEADER\r
-       head.biSize = sizeof(BITMAPINFOHEADER); //<ralphw>\r
-    head.biWidth = dwWidth;            // fill in width from parameter\r
-    head.biHeight = dwHeight;  // fill in height from parameter\r
-    head.biPlanes = 1;                 // must be 1\r
-    head.biBitCount = (WORD)wBpp;              // from parameter\r
-    head.biCompression = BI_RGB;    \r
-    head.biSizeImage = info.dwEffWidth * dwHeight;\r
-//    head.biXPelsPerMeter = 0; See SetXDPI\r
-//    head.biYPelsPerMeter = 0; See SetYDPI\r
-//    head.biClrImportant = 0;  See SetClrImportant\r
-\r
-       pDib = malloc(GetSize()); // alloc memory block to store our bitmap\r
-    if (!pDib){\r
-               strcpy(info.szLastError,"CxImage::Create can't allocate memory");\r
-               return NULL;\r
-       }\r
-\r
-       //clear the palette\r
-       RGBQUAD* pal=GetPalette();\r
-       if (pal) memset(pal,0,GetPaletteSize());\r
-       //Destroy the existing selection\r
-#if CXIMAGE_SUPPORT_SELECTION\r
-       if (pSelection) SelectionDelete();\r
-#endif //CXIMAGE_SUPPORT_SELECTION\r
-       //Destroy the existing alpha channel\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-       if (pAlpha) AlphaDelete();\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-\r
-    // use our bitmap info structure to fill in first part of\r
-    // our DIB with the BITMAPINFOHEADER\r
-    BITMAPINFOHEADER*  lpbi;\r
-       lpbi = (BITMAPINFOHEADER*)(pDib);\r
-    *lpbi = head;\r
-\r
-       info.pImage=GetBits();\r
-\r
-    return pDib; //return handle to the DIB\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * \return pointer to the image pixels. <b> USE CAREFULLY </b>\r
- */\r
-BYTE* CxImage::GetBits(DWORD row)\r
-{ \r
-       if (pDib){\r
-               if (row) {\r
-                       if (row<(DWORD)head.biHeight){\r
-                               return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (info.dwEffWidth * row));\r
-                       } else {\r
-                               return NULL;\r
-                       }\r
-               } else {\r
-                       return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize());\r
-               }\r
-       }\r
-       return NULL;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * \return the size in bytes of the internal pDib object\r
- */\r
-long CxImage::GetSize()\r
-{\r
-       return head.biSize + head.biSizeImage + GetPaletteSize();\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Checks if the coordinates are inside the image\r
- * \return true if x and y are both inside the image\r
- */\r
-bool CxImage::IsInside(long x, long y)\r
-{\r
-  return (0<=y && y<head.biHeight && 0<=x && x<head.biWidth);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Sets the image bits to the specified value\r
- * - for indexed images, the output color is set by the palette entries.\r
- * - for RGB images, the output color is a shade of gray.\r
- */\r
-void CxImage::Clear(BYTE bval)\r
-{\r
-       if (pDib == 0) return;\r
-\r
-       if (GetBpp() == 1){\r
-               if (bval > 0) bval = 255;\r
-       }\r
-       if (GetBpp() == 4){\r
-               bval = (BYTE)(17*(0x0F & bval));\r
-       }\r
-\r
-       memset(info.pImage,bval,head.biSizeImage);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Transfers the image from an existing source image. The source becomes empty.\r
- * \return true if everything is ok\r
- */\r
-bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/)\r
-{\r
-       if (!Destroy())\r
-               return false;\r
-\r
-       memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER));\r
-       memcpy(&info,&from.info,sizeof(CXIMAGEINFO));\r
-\r
-       pDib = from.pDib;\r
-       pSelection = from.pSelection;\r
-       pAlpha = from.pAlpha;\r
-       ppLayers = from.ppLayers;\r
-\r
-       memset(&from.head,0,sizeof(BITMAPINFOHEADER));\r
-       memset(&from.info,0,sizeof(CXIMAGEINFO));\r
-       from.pDib = from.pSelection = from.pAlpha = NULL;\r
-       from.ppLayers = NULL;\r
-\r
-       if (bTransferFrames){\r
-               DestroyFrames();\r
-               ppFrames = from.ppFrames;\r
-               from.ppFrames = NULL;\r
-       }\r
-\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * (this) points to the same pDib owned by (*from), the image remains in (*from)\r
- * but (this) has the access to the pixels. <b>Use carefully !!!</b>\r
- */\r
-void CxImage::Ghost(const CxImage *from)\r
-{\r
-       if (from){\r
-               memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER));\r
-               memcpy(&info,&from->info,sizeof(CXIMAGEINFO));\r
-               pDib = from->pDib;\r
-               pSelection = from->pSelection;\r
-               pAlpha = from->pAlpha;\r
-               ppLayers = from->ppLayers;\r
-               ppFrames = from->ppFrames;\r
-               info.pGhost=(CxImage *)from;\r
-       }\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * turns a 16 or 32 bit bitfield image into a RGB image\r
- */\r
-void CxImage::Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp)\r
-{\r
-       switch (bpp){\r
-       case 16:\r
-       {\r
-               DWORD ns[3]={0,0,0};\r
-               // compute the number of shift for each mask\r
-               for (int i=0;i<16;i++){\r
-                       if ((redmask>>i)&0x01) ns[0]++;\r
-                       if ((greenmask>>i)&0x01) ns[1]++;\r
-                       if ((bluemask>>i)&0x01) ns[2]++;\r
-               }\r
-               ns[1]+=ns[0]; ns[2]+=ns[1];     ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8;\r
-               // dword aligned width for 16 bit image\r
-               long effwidth2=(((head.biWidth + 1) / 2) * 4);\r
-               WORD w;\r
-               long y2,y3,x2,x3;\r
-               BYTE *p=info.pImage;\r
-               // scan the buffer in reverse direction to avoid reallocations\r
-               for (long y=head.biHeight-1; y>=0; y--){\r
-                       y2=effwidth2*y;\r
-                       y3=info.dwEffWidth*y;\r
-                       for (long x=head.biWidth-1; x>=0; x--){\r
-                               x2 = 2*x+y2;\r
-                               x3 = 3*x+y3;\r
-                               w = (WORD)(src[x2]+256*src[1+x2]);\r
-                               p[  x3]=(BYTE)((w & bluemask)<<ns[0]);\r
-                               p[1+x3]=(BYTE)((w & greenmask)>>ns[1]);\r
-                               p[2+x3]=(BYTE)((w & redmask)>>ns[2]);\r
-                       }\r
-               }\r
-               break;\r
-       }\r
-       case 32:\r
-       {\r
-               DWORD ns[3]={0,0,0};\r
-               // compute the number of shift for each mask\r
-               for (int i=8;i<32;i+=8){\r
-                       if (redmask>>i) ns[0]++;\r
-                       if (greenmask>>i) ns[1]++;\r
-                       if (bluemask>>i) ns[2]++;\r
-               }\r
-               // dword aligned width for 32 bit image\r
-               long effwidth4 = head.biWidth * 4;\r
-               long y4,y3,x4,x3;\r
-               BYTE *p=info.pImage;\r
-               // scan the buffer in reverse direction to avoid reallocations\r
-               for (long y=head.biHeight-1; y>=0; y--){\r
-                       y4=effwidth4*y;\r
-                       y3=info.dwEffWidth*y;\r
-                       for (long x=head.biWidth-1; x>=0; x--){\r
-                               x4 = 4*x+y4;\r
-                               x3 = 3*x+y3;\r
-                               p[  x3]=src[ns[2]+x4];\r
-                               p[1+x3]=src[ns[1]+x4];\r
-                               p[2+x3]=src[ns[0]+x4];\r
-                       }\r
-               }\r
-       }\r
-\r
-       }\r
-       return;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * Creates an image from a generic buffer\r
- * \param pArray: source memory buffer\r
- * \param dwWidth: image width\r
- * \param dwHeight: image height\r
- * \param dwBitsperpixel: can be 1,4,8,24,32\r
- * \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray\r
- * \param bFlipImage: tune this parameter if the image is upsidedown\r
- * \return true if everything is ok\r
- */\r
-bool CxImage::CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)\r
-{\r
-       if (pArray==NULL) return false;\r
-       if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||\r
-               (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;\r
-\r
-       if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;\r
-\r
-       if (dwBitsperpixel<24) SetGrayPalette();\r
-\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-       if (dwBitsperpixel==32) AlphaCreate();\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-\r
-       BYTE *dst,*src;\r
-\r
-       for (DWORD y = 0; y<dwHeight; y++) {\r
-               dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;\r
-               src = pArray + y * dwBytesperline;\r
-               if (dwBitsperpixel==32){\r
-                       for(DWORD x=0;x<dwWidth;x++){\r
-                               *dst++=src[0];\r
-                               *dst++=src[1];\r
-                               *dst++=src[2];\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-                               AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-                               src+=4;\r
-                       }\r
-               } else {\r
-                       memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));\r
-               }\r
-       }\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * \sa CreateFromArray\r
- */\r
-bool CxImage::CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)\r
-{\r
-       if (ppMatrix==NULL) return false;\r
-       if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||\r
-               (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;\r
-\r
-       if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;\r
-\r
-       if (dwBitsperpixel<24) SetGrayPalette();\r
-\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-       if (dwBitsperpixel==32) AlphaCreate();\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-\r
-       BYTE *dst,*src;\r
-\r
-       for (DWORD y = 0; y<dwHeight; y++) {\r
-               dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;\r
-               src = ppMatrix[y];\r
-               if (src){\r
-                       if (dwBitsperpixel==32){\r
-                               for(DWORD x=0;x<dwWidth;x++){\r
-                                       *dst++=src[0];\r
-                                       *dst++=src[1];\r
-                                       *dst++=src[2];\r
-#if CXIMAGE_SUPPORT_ALPHA\r
-                                       AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);\r
-#endif //CXIMAGE_SUPPORT_ALPHA\r
-                                       src+=4;\r
-                               }\r
-                       } else {\r
-                               memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));\r
-                       }\r
-               }\r
-       }\r
-       return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * \return lightness difference between elem1 and elem2\r
- */\r
-int CxImage::CompareColors(const void *elem1, const void *elem2)\r
-{\r
-       RGBQUAD* c1 = (RGBQUAD*)elem1;\r
-       RGBQUAD* c2 = (RGBQUAD*)elem2;\r
-\r
-       int g1 = (int)RGB2GRAY(c1->rgbRed,c1->rgbGreen,c1->rgbBlue);\r
-       int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue);\r
-       \r
-       return (g1-g2);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * simply calls "if (memblock) free(memblock);".\r
- * Useful when calling Encode for a memory buffer,\r
- * from a DLL compiled with different memory management options.\r
- * CxImage::FreeMemory will use the same memory environment used by Encode. \r
- * \author [livecn]\r
- */\r
-void CxImage::FreeMemory(void* memblock)\r
-{\r
-       if (memblock)\r
-               free(memblock);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-//EOF\r
+// ximage.cpp : main implementation file
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
+ * CxImage version 6.0.0 02/Feb/2008
+ */
+
+#include "ximage.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// CxImage 
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Initialize the internal structures
+ */
+void CxImage::Startup(DWORD imagetype)
+{
+       //init pointers
+       pDib = pSelection = pAlpha = NULL;
+       ppLayers = ppFrames = NULL;
+       //init structures
+       memset(&head,0,sizeof(BITMAPINFOHEADER));
+       memset(&info,0,sizeof(CXIMAGEINFO));
+       //init default attributes
+    info.dwType = imagetype;
+       info.fQuality = 90.0f;
+       info.nAlphaMax = 255;
+       info.nBkgndIndex = -1;
+       info.bEnabled = true;
+       SetXDPI(CXIMAGE_DEFAULT_DPI);
+       SetYDPI(CXIMAGE_DEFAULT_DPI);
+
+       short test = 1;
+       info.bLittleEndianHost = (*((char *) &test) == 1);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Empty image constructor
+ * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
+ */
+CxImage::CxImage(DWORD imagetype)
+{
+       Startup(imagetype);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Call this function to destroy image pixels, alpha channel, selection and sub layers.
+ * - Attributes are not erased, but IsValid returns false.
+ *
+ * \return true if everything is freed, false if the image is a Ghost
+ */
+bool CxImage::Destroy()
+{
+       //free this only if it's valid and it's not a ghost
+       if (info.pGhost==NULL){
+               if (ppLayers) { 
+                       for(long n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }
+                       delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;
+               }
+               if (pSelection) {free(pSelection); pSelection=0;}
+               if (pAlpha) {free(pAlpha); pAlpha=0;}
+               if (pDib) {free(pDib); pDib=0;}
+               return true;
+       }
+       return false;
+}
+////////////////////////////////////////////////////////////////////////////////
+bool CxImage::DestroyFrames()
+{
+       if (info.pGhost==NULL) {
+               if (ppFrames) {
+                       for (long n=0; n<info.nNumFrames; n++) { delete ppFrames[n]; }
+                       delete [] ppFrames; ppFrames = NULL; info.nNumFrames = 0;
+               }
+               return true;
+       }
+       return false;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sized image constructor
+ * \param dwWidth: width
+ * \param dwHeight: height
+ * \param wBpp: bit per pixel, can be 1, 4, 8, 24
+ * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
+ */
+CxImage::CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)
+{
+       Startup(imagetype);
+       Create(dwWidth,dwHeight,wBpp,imagetype);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * image constructor from existing source
+ * \param src: source image.
+ * \param copypixels: copy the pixels from the source image into the new image.
+ * \param copyselection: copy the selection from source
+ * \param copyalpha: copy the alpha channel from source
+ * \sa Copy
+ */
+CxImage::CxImage(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)
+{
+       Startup(src.GetType());
+       Copy(src,copypixels,copyselection,copyalpha);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Copies the image from an exsisting source
+ * \param src: source image.
+ * \param copypixels: copy the pixels from the source image into the new image.
+ * \param copyselection: copy the selection from source
+ * \param copyalpha: copy the alpha channel from source
+ */
+void CxImage::Copy(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)
+{
+       // if the source is a ghost, the copy is still a ghost
+       if (src.info.pGhost){
+               Ghost(&src);
+               return;
+       }
+       //copy the attributes
+       memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
+       memcpy(&head,&src.head,sizeof(BITMAPINFOHEADER)); // [andy] - fix for bitmap header DPI
+       //rebuild the image
+       Create(src.GetWidth(),src.GetHeight(),src.GetBpp(),src.GetType());
+       //copy the pixels and the palette, or at least copy the palette only.
+       if (copypixels && pDib && src.pDib) memcpy(pDib,src.pDib,GetSize());
+       else SetPalette(src.GetPalette());
+       long nSize = head.biWidth * head.biHeight;
+       //copy the selection
+       if (copyselection && src.pSelection){
+               if (pSelection) free(pSelection);
+               pSelection = (BYTE*)malloc(nSize);
+               memcpy(pSelection,src.pSelection,nSize);
+       }
+       //copy the alpha channel
+       if (copyalpha && src.pAlpha){
+               if (pAlpha) free(pAlpha);
+               pAlpha = (BYTE*)malloc(nSize);
+               memcpy(pAlpha,src.pAlpha,nSize);
+       }
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Copies the image attributes from an existing image.
+ * - Works only on an empty image, and the image will be still empty.
+ * - <b> Use it before Create() </b>
+ */
+void CxImage::CopyInfo(const CxImage &src)
+{
+       if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * \sa Copy
+ */
+CxImage& CxImage::operator = (const CxImage& isrc)
+{
+       if (this != &isrc) Copy(isrc);
+       return *this;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Initializes or rebuilds the image.
+ * \param dwWidth: width
+ * \param dwHeight: height
+ * \param wBpp: bit per pixel, can be 1, 4, 8, 24
+ * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
+ * \return pointer to the internal pDib object; NULL if an error occurs.
+ */
+void* CxImage::Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)
+{
+       // destroy the existing image (if any)
+       if (!Destroy())
+               return NULL;
+
+       // prevent further actions if width or height are not vaild <Balabasnia>
+       if ((dwWidth == 0) || (dwHeight == 0)){
+               strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero");
+               return NULL;
+       }
+
+    // Make sure bits per pixel is valid
+    if         (wBpp <= 1)     wBpp = 1;
+    else if (wBpp <= 4)        wBpp = 4;
+    else if (wBpp <= 8)        wBpp = 8;
+    else                               wBpp = 24;
+
+       // limit memory requirements (and also a check for bad parameters)
+       if (((dwWidth*dwHeight*wBpp)>>3) > CXIMAGE_MAX_MEMORY ||
+               ((dwWidth*dwHeight*wBpp)/wBpp) != (dwWidth*dwHeight))
+       {
+               strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded");
+               return NULL;
+       }
+
+       // set the correct bpp value
+    switch (wBpp){
+        case 1:
+            head.biClrUsed = 2;        break;
+        case 4:
+            head.biClrUsed = 16; break;
+        case 8:
+            head.biClrUsed = 256; break;
+        default:
+            head.biClrUsed = 0;
+    }
+
+       //set the common image informations
+    info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4);
+    info.dwType = imagetype;
+
+    // initialize BITMAPINFOHEADER
+       head.biSize = sizeof(BITMAPINFOHEADER); //<ralphw>
+    head.biWidth = dwWidth;            // fill in width from parameter
+    head.biHeight = dwHeight;  // fill in height from parameter
+    head.biPlanes = 1;                 // must be 1
+    head.biBitCount = (WORD)wBpp;              // from parameter
+    head.biCompression = BI_RGB;    
+    head.biSizeImage = info.dwEffWidth * dwHeight;
+//    head.biXPelsPerMeter = 0; See SetXDPI
+//    head.biYPelsPerMeter = 0; See SetYDPI
+//    head.biClrImportant = 0;  See SetClrImportant
+
+       pDib = malloc(GetSize()); // alloc memory block to store our bitmap
+    if (!pDib){
+               strcpy(info.szLastError,"CxImage::Create can't allocate memory");
+               return NULL;
+       }
+
+       //clear the palette
+       RGBQUAD* pal=GetPalette();
+       if (pal) memset(pal,0,GetPaletteSize());
+       //Destroy the existing selection
+#if CXIMAGE_SUPPORT_SELECTION
+       if (pSelection) SelectionDelete();
+#endif //CXIMAGE_SUPPORT_SELECTION
+       //Destroy the existing alpha channel
+#if CXIMAGE_SUPPORT_ALPHA
+       if (pAlpha) AlphaDelete();
+#endif //CXIMAGE_SUPPORT_ALPHA
+
+    // use our bitmap info structure to fill in first part of
+    // our DIB with the BITMAPINFOHEADER
+    BITMAPINFOHEADER*  lpbi;
+       lpbi = (BITMAPINFOHEADER*)(pDib);
+    *lpbi = head;
+
+       info.pImage=GetBits();
+
+    return pDib; //return handle to the DIB
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * \return pointer to the image pixels. <b> USE CAREFULLY </b>
+ */
+BYTE* CxImage::GetBits(DWORD row)
+{ 
+       if (pDib){
+               if (row) {
+                       if (row<(DWORD)head.biHeight){
+                               return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (info.dwEffWidth * row));
+                       } else {
+                               return NULL;
+                       }
+               } else {
+                       return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize());
+               }
+       }
+       return NULL;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * \return the size in bytes of the internal pDib object
+ */
+long CxImage::GetSize()
+{
+       return head.biSize + head.biSizeImage + GetPaletteSize();
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Checks if the coordinates are inside the image
+ * \return true if x and y are both inside the image
+ */
+bool CxImage::IsInside(long x, long y)
+{
+  return (0<=y && y<head.biHeight && 0<=x && x<head.biWidth);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sets the image bits to the specified value
+ * - for indexed images, the output color is set by the palette entries.
+ * - for RGB images, the output color is a shade of gray.
+ */
+void CxImage::Clear(BYTE bval)
+{
+       if (pDib == 0) return;
+
+       if (GetBpp() == 1){
+               if (bval > 0) bval = 255;
+       }
+       if (GetBpp() == 4){
+               bval = (BYTE)(17*(0x0F & bval));
+       }
+
+       memset(info.pImage,bval,head.biSizeImage);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Transfers the image from an existing source image. The source becomes empty.
+ * \return true if everything is ok
+ */
+bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/)
+{
+       if (!Destroy())
+               return false;
+
+       memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER));
+       memcpy(&info,&from.info,sizeof(CXIMAGEINFO));
+
+       pDib = from.pDib;
+       pSelection = from.pSelection;
+       pAlpha = from.pAlpha;
+       ppLayers = from.ppLayers;
+
+       memset(&from.head,0,sizeof(BITMAPINFOHEADER));
+       memset(&from.info,0,sizeof(CXIMAGEINFO));
+       from.pDib = from.pSelection = from.pAlpha = NULL;
+       from.ppLayers = NULL;
+
+       if (bTransferFrames){
+               DestroyFrames();
+               ppFrames = from.ppFrames;
+               from.ppFrames = NULL;
+       }
+
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * (this) points to the same pDib owned by (*from), the image remains in (*from)
+ * but (this) has the access to the pixels. <b>Use carefully !!!</b>
+ */
+void CxImage::Ghost(const CxImage *from)
+{
+       if (from){
+               memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER));
+               memcpy(&info,&from->info,sizeof(CXIMAGEINFO));
+               pDib = from->pDib;
+               pSelection = from->pSelection;
+               pAlpha = from->pAlpha;
+               ppLayers = from->ppLayers;
+               ppFrames = from->ppFrames;
+               info.pGhost=(CxImage *)from;
+       }
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * turns a 16 or 32 bit bitfield image into a RGB image
+ */
+void CxImage::Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp)
+{
+       switch (bpp){
+       case 16:
+       {
+               DWORD ns[3]={0,0,0};
+               // compute the number of shift for each mask
+               for (int i=0;i<16;i++){
+                       if ((redmask>>i)&0x01) ns[0]++;
+                       if ((greenmask>>i)&0x01) ns[1]++;
+                       if ((bluemask>>i)&0x01) ns[2]++;
+               }
+               ns[1]+=ns[0]; ns[2]+=ns[1];     ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8;
+               // dword aligned width for 16 bit image
+               long effwidth2=(((head.biWidth + 1) / 2) * 4);
+               WORD w;
+               long y2,y3,x2,x3;
+               BYTE *p=info.pImage;
+               // scan the buffer in reverse direction to avoid reallocations
+               for (long y=head.biHeight-1; y>=0; y--){
+                       y2=effwidth2*y;
+                       y3=info.dwEffWidth*y;
+                       for (long x=head.biWidth-1; x>=0; x--){
+                               x2 = 2*x+y2;
+                               x3 = 3*x+y3;
+                               w = (WORD)(src[x2]+256*src[1+x2]);
+                               p[  x3]=(BYTE)((w & bluemask)<<ns[0]);
+                               p[1+x3]=(BYTE)((w & greenmask)>>ns[1]);
+                               p[2+x3]=(BYTE)((w & redmask)>>ns[2]);
+                       }
+               }
+               break;
+       }
+       case 32:
+       {
+               DWORD ns[3]={0,0,0};
+               // compute the number of shift for each mask
+               for (int i=8;i<32;i+=8){
+                       if (redmask>>i) ns[0]++;
+                       if (greenmask>>i) ns[1]++;
+                       if (bluemask>>i) ns[2]++;
+               }
+               // dword aligned width for 32 bit image
+               long effwidth4 = head.biWidth * 4;
+               long y4,y3,x4,x3;
+               BYTE *p=info.pImage;
+               // scan the buffer in reverse direction to avoid reallocations
+               for (long y=head.biHeight-1; y>=0; y--){
+                       y4=effwidth4*y;
+                       y3=info.dwEffWidth*y;
+                       for (long x=head.biWidth-1; x>=0; x--){
+                               x4 = 4*x+y4;
+                               x3 = 3*x+y3;
+                               p[  x3]=src[ns[2]+x4];
+                               p[1+x3]=src[ns[1]+x4];
+                               p[2+x3]=src[ns[0]+x4];
+                       }
+               }
+       }
+
+       }
+       return;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Creates an image from a generic buffer
+ * \param pArray: source memory buffer
+ * \param dwWidth: image width
+ * \param dwHeight: image height
+ * \param dwBitsperpixel: can be 1,4,8,24,32
+ * \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray
+ * \param bFlipImage: tune this parameter if the image is upsidedown
+ * \return true if everything is ok
+ */
+bool CxImage::CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)
+{
+       if (pArray==NULL) return false;
+       if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||
+               (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;
+
+       if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;
+
+       if (dwBitsperpixel<24) SetGrayPalette();
+
+#if CXIMAGE_SUPPORT_ALPHA
+       if (dwBitsperpixel==32) AlphaCreate();
+#endif //CXIMAGE_SUPPORT_ALPHA
+
+       BYTE *dst,*src;
+
+       for (DWORD y = 0; y<dwHeight; y++) {
+               dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;
+               src = pArray + y * dwBytesperline;
+               if (dwBitsperpixel==32){
+                       for(DWORD x=0;x<dwWidth;x++){
+                               *dst++=src[0];
+                               *dst++=src[1];
+                               *dst++=src[2];
+#if CXIMAGE_SUPPORT_ALPHA
+                               AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);
+#endif //CXIMAGE_SUPPORT_ALPHA
+                               src+=4;
+                       }
+               } else {
+                       memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));
+               }
+       }
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * \sa CreateFromArray
+ */
+bool CxImage::CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)
+{
+       if (ppMatrix==NULL) return false;
+       if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||
+               (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;
+
+       if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;
+
+       if (dwBitsperpixel<24) SetGrayPalette();
+
+#if CXIMAGE_SUPPORT_ALPHA
+       if (dwBitsperpixel==32) AlphaCreate();
+#endif //CXIMAGE_SUPPORT_ALPHA
+
+       BYTE *dst,*src;
+
+       for (DWORD y = 0; y<dwHeight; y++) {
+               dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;
+               src = ppMatrix[y];
+               if (src){
+                       if (dwBitsperpixel==32){
+                               for(DWORD x=0;x<dwWidth;x++){
+                                       *dst++=src[0];
+                                       *dst++=src[1];
+                                       *dst++=src[2];
+#if CXIMAGE_SUPPORT_ALPHA
+                                       AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);
+#endif //CXIMAGE_SUPPORT_ALPHA
+                                       src+=4;
+                               }
+                       } else {
+                               memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));
+                       }
+               }
+       }
+       return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * \return lightness difference between elem1 and elem2
+ */
+int CxImage::CompareColors(const void *elem1, const void *elem2)
+{
+       RGBQUAD* c1 = (RGBQUAD*)elem1;
+       RGBQUAD* c2 = (RGBQUAD*)elem2;
+
+       int g1 = (int)RGB2GRAY(c1->rgbRed,c1->rgbGreen,c1->rgbBlue);
+       int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue);
+       
+       return (g1-g2);
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * simply calls "if (memblock) free(memblock);".
+ * Useful when calling Encode for a memory buffer,
+ * from a DLL compiled with different memory management options.
+ * CxImage::FreeMemory will use the same memory environment used by Encode. 
+ * \author [livecn]
+ */
+void CxImage::FreeMemory(void* memblock)
+{
+       if (memblock)
+               free(memblock);
+}
+////////////////////////////////////////////////////////////////////////////////
+//EOF