From c91847d549cc1c30eb15504a15ea9a6d5aa48165 Mon Sep 17 00:00:00 2001 From: "chirs241097@gmail.com" Date: Sun, 12 Jan 2014 14:43:14 +0000 Subject: --- hge/CxImage/ximapal.cpp | 834 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 834 insertions(+) create mode 100644 hge/CxImage/ximapal.cpp (limited to 'hge/CxImage/ximapal.cpp') diff --git a/hge/CxImage/ximapal.cpp b/hge/CxImage/ximapal.cpp new file mode 100644 index 0000000..fe0615b --- /dev/null +++ b/hge/CxImage/ximapal.cpp @@ -0,0 +1,834 @@ +// xImaPal.cpp : Palette and Pixel functions +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 7.0.0 31/Dec/2010 + */ + +#include "ximage.h" + +//////////////////////////////////////////////////////////////////////////////// +/** + * returns the palette dimension in byte + */ +uint32_t CxImage::GetPaletteSize() +{ + return (head.biClrUsed * sizeof(RGBQUAD)); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::SetPaletteColor(uint8_t idx, uint8_t r, uint8_t g, uint8_t b, uint8_t alpha) +{ + if ((pDib)&&(head.biClrUsed)){ + uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER); + if (idx=head.biWidth)||(y>=head.biHeight)) { + if (info.nBkgndIndex >= 0) return (uint8_t)info.nBkgndIndex; + else return *info.pImage; + } + if (head.biBitCount==8){ + return info.pImage[y*info.dwEffWidth + x]; + } else { + uint8_t pos; + uint8_t iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)]; + if (head.biBitCount==4){ + pos = (uint8_t)(4*(1-x%2)); + iDst &= (0x0F<> pos); + } else if (head.biBitCount==1){ + pos = (uint8_t)(7-x%8); + iDst &= (0x01<> pos); + } + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +uint8_t CxImage::BlindGetPixelIndex(const int32_t x,const int32_t y) +{ +#ifdef _DEBUG + if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return 0; + #endif +#endif + + if (head.biBitCount==8){ + return info.pImage[y*info.dwEffWidth + x]; + } else { + uint8_t pos; + uint8_t iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)]; + if (head.biBitCount==4){ + pos = (uint8_t)(4*(1-x%2)); + iDst &= (0x0F<> pos); + } else if (head.biBitCount==1){ + pos = (uint8_t)(7-x%8); + iDst &= (0x01<> pos); + } + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::GetPixelColor(int32_t x,int32_t y, bool bGetAlpha) +{ +// RGBQUAD rgb={0,0,0,0}; + RGBQUAD rgb=info.nBkgndColor; // + if ((pDib==NULL)||(x<0)||(y<0)|| + (x>=head.biWidth)||(y>=head.biHeight)){ + if (info.nBkgndIndex >= 0){ + if (head.biBitCount<24) return GetPaletteColor((uint8_t)info.nBkgndIndex); + else return info.nBkgndColor; + } else if (pDib) return GetPixelColor(0,0); + return rgb; + } + + if (head.biClrUsed){ + rgb = GetPaletteColor(BlindGetPixelIndex(x,y)); + } else { + uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3; + rgb.rgbBlue = *iDst++; + rgb.rgbGreen= *iDst++; + rgb.rgbRed = *iDst; + } +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y); +#else + rgb.rgbReserved = 0; +#endif //CXIMAGE_SUPPORT_ALPHA + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * This is (a bit) faster version of GetPixelColor. + * It tests bounds only in debug mode (_DEBUG defined). + * + * It is an error to request out-of-borders pixel with this method. + * In DEBUG mode an exception will be thrown, and data will be violated in non-DEBUG mode. + * \author ***bd*** 2.2004 + */ +RGBQUAD CxImage::BlindGetPixelColor(const int32_t x,const int32_t y, bool bGetAlpha) +{ + RGBQUAD rgb; +#ifdef _DEBUG + if ((pDib==NULL) || !IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + {rgb.rgbReserved = 0; return rgb;} + #endif +#endif + + if (head.biClrUsed){ + rgb = GetPaletteColor(BlindGetPixelIndex(x,y)); + } else { + uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3; + rgb.rgbBlue = *iDst++; + rgb.rgbGreen= *iDst++; + rgb.rgbRed = *iDst; + rgb.rgbReserved = 0; //needed for images without alpha layer + } +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y); +#else + rgb.rgbReserved = 0; +#endif //CXIMAGE_SUPPORT_ALPHA + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +uint8_t CxImage::GetPixelGray(int32_t x, int32_t y) +{ + RGBQUAD color = GetPixelColor(x,y); + return (uint8_t)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::BlindSetPixelIndex(int32_t x,int32_t y,uint8_t i) +{ +#ifdef _DEBUG + if ((pDib==NULL)||(head.biClrUsed==0)|| + (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return; + #endif +#endif + + if (head.biBitCount==8){ + info.pImage[y*info.dwEffWidth + x]=i; + return; + } else { + uint8_t pos; + uint8_t* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3); + if (head.biBitCount==4){ + pos = (uint8_t)(4*(1-x%2)); + *iDst &= ~(0x0F<=head.biWidth)||(y>=head.biHeight)) return ; + + if (head.biBitCount==8){ + info.pImage[y*info.dwEffWidth + x]=i; + return; + } else { + uint8_t pos; + uint8_t* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3); + if (head.biBitCount==4){ + pos = (uint8_t)(4*(1-x%2)); + *iDst &= ~(0x0F<=head.biWidth)||(y>=head.biHeight)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return; + #endif +#endif + if (head.biClrUsed) + BlindSetPixelIndex(x,y,GetNearestIndex(c)); + else { + uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3; + *iDst++ = c.rgbBlue; + *iDst++ = c.rgbGreen; + *iDst = c.rgbRed; + } +#if CXIMAGE_SUPPORT_ALPHA + if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::SetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha) +{ + if ((pDib==NULL)||(x<0)||(y<0)|| + (x>=head.biWidth)||(y>=head.biHeight)) return; + if (head.biClrUsed) + BlindSetPixelIndex(x,y,GetNearestIndex(c)); + else { + uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3; + *iDst++ = c.rgbBlue; + *iDst++ = c.rgbGreen; + *iDst = c.rgbRed; + } +#if CXIMAGE_SUPPORT_ALPHA + if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Blends the current pixel color with a new color. + * \param x,y = pixel + * \param c = new color + * \param blend = can be from 0 (no effect) to 1 (full effect). + * \param bSetAlpha = if true, blends also the alpha component stored in c.rgbReserved + */ +void CxImage::BlendPixelColor(int32_t x,int32_t y,RGBQUAD c, float blend, bool bSetAlpha) +{ + if ((pDib==NULL)||(x<0)||(y<0)|| + (x>=head.biWidth)||(y>=head.biHeight)) return; + + int32_t a0 = (int32_t)(256*blend); + int32_t a1 = 256 - a0; + + RGBQUAD c0 = BlindGetPixelColor(x,y); + c.rgbRed = (uint8_t)((c.rgbRed * a0 + c0.rgbRed * a1)>>8); + c.rgbBlue = (uint8_t)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8); + c.rgbGreen = (uint8_t)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8); + + if (head.biClrUsed) + BlindSetPixelIndex(x,y,GetNearestIndex(c)); + else { + uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3; + *iDst++ = c.rgbBlue; + *iDst++ = c.rgbGreen; + *iDst = c.rgbRed; +#if CXIMAGE_SUPPORT_ALPHA + if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns the best palette index that matches a specified color. + */ +uint8_t CxImage::GetNearestIndex(RGBQUAD c) +{ + if ((pDib==NULL)||(head.biClrUsed==0)) return 0; + + // check matching with the previous result + if (info.last_c_isvalid && (*(int32_t*)&info.last_c == *(int32_t*)&c)) return info.last_c_index; + info.last_c = c; + info.last_c_isvalid = true; + + uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER); + int32_t distance=200000; + int32_t i,j = 0; + int32_t k,l; + int32_t m = (int32_t)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant); + for(i=0,l=0;i100) perc=100; + for(i=0;i=0){ + if (head.biClrUsed){ + if (GetPixelIndex(x,y) == info.nBkgndIndex) return true; + } else { + RGBQUAD ct = info.nBkgndColor; + RGBQUAD c = GetPixelColor(x,y,false); + if (*(int32_t*)&c==*(int32_t*)&ct) return true; + } + } + +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha) return AlphaGet(x,y)==0; +#endif + + return false; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::GetTransparentMask(CxImage* iDst) +{ + if (!pDib) return false; + + CxImage tmp; + tmp.Create(head.biWidth, head.biHeight, 1, GetType()); + tmp.SetStdPalette(); + tmp.Clear(0); + + for(int32_t y=0; yTransfer(tmp); + else Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if image has the same palette, if any. + * \param img = image to compare. + * \param bCheckAlpha = check also the rgbReserved field. + */ +bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha) +{ + if (head.biClrUsed != img.head.biClrUsed) + return false; + if (head.biClrUsed == 0) + return false; + + RGBQUAD c1,c2; + for (uint32_t n=0; n256) { + head.biClrImportant = 0; + return; + } + + switch(head.biBitCount){ + case 1: + head.biClrImportant = min(ncolors,2); + break; + case 4: + head.biClrImportant = min(ncolors,16); + break; + case 8: + head.biClrImportant = ncolors; + break; + } + return; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns pointer to pixel. Currently implemented only for truecolor images. + * + * \param x,y - coordinates + * + * \return pointer to first byte of pixel data + * + * \author ***bd*** 2.2004 + */ +void* CxImage::BlindGetPixelPointer(const int32_t x, const int32_t y) +{ +#ifdef _DEBUG + if ((pDib==NULL) || !IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return 0; + #endif +#endif + if (!IsIndexed()) + return info.pImage + y*info.dwEffWidth + x*3; + else + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, COLORREF cr) +{ + DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr)); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, RGBQUAD color, bool bSetAlpha) +{ + if (!pDib) return; + ////////////////////////////////////////////////////// + // Draws a line using the Bresenham line algorithm + // Thanks to Jordan DeLozier + ////////////////////////////////////////////////////// + int32_t x1 = StartX; + int32_t y1 = StartY; + int32_t x = x1; // Start x off at the first pixel + int32_t y = y1; // Start y off at the first pixel + int32_t x2 = EndX; + int32_t y2 = EndY; + + int32_t xinc1,xinc2,yinc1,yinc2; // Increasing values + int32_t den, num, numadd,numpixels; + int32_t deltax = abs(x2 - x1); // The difference between the x's + int32_t deltay = abs(y2 - y1); // The difference between the y's + + // Get Increasing Values + if (x2 >= x1) { // The x-values are increasing + xinc1 = 1; + xinc2 = 1; + } else { // The x-values are decreasing + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) { // The y-values are increasing + yinc1 = 1; + yinc2 = 1; + } else { // The y-values are decreasing + yinc1 = -1; + yinc2 = -1; + } + + // Actually draw the line + if (deltax >= deltay) // There is at least one x-value for every y-value + { + xinc1 = 0; // Don't change the x when numerator >= denominator + yinc2 = 0; // Don't change the y for every iteration + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; // There are more x-values than y-values + } + else // There is at least one y-value for every x-value + { + xinc2 = 0; // Don't change the x for every iteration + yinc1 = 0; // Don't change the y when numerator >= denominator + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; // There are more y-values than x-values + } + + for (int32_t curpixel = 0; curpixel <= numpixels; curpixel++) + { + // Draw the current pixel + SetPixelColor(x,y,color,bSetAlpha); + + num += numadd; // Increase the numerator by the top of the fraction + if (num >= den) // Check if numerator >= denominator + { + num -= den; // Calculate the new numerator value + x += xinc1; // Change the x as appropriate + y += yinc1; // Change the y as appropriate + } + x += xinc2; // Change the x as appropriate + y += yinc2; // Change the y as appropriate + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets a palette with standard colors for 1, 4 and 8 bpp images. + */ +void CxImage::SetStdPalette() +{ + if (!pDib) return; + switch (head.biBitCount){ + case 8: + { + const uint8_t pal256[1024] = {0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0, + 192,220,192,0,240,202,166,0,212,240,255,0,177,226,255,0,142,212,255,0,107,198,255,0, + 72,184,255,0,37,170,255,0,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0, + 50,80,0,212,227,255,0,177,199,255,0,142,171,255,0,107,143,255,0,72,115,255,0,37,87,255,0,0, + 85,255,0,0,73,220,0,0,61,185,0,0,49,150,0,0,37,115,0,0,25,80,0,212,212,255,0,177,177,255,0, + 142,142,255,0,107,107,255,0,72,72,255,0,37,37,255,0,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0, + 0,0,115,0,0,0,80,0,227,212,255,0,199,177,255,0,171,142,255,0,143,107,255,0,115,72,255,0, + 87,37,255,0,85,0,255,0,73,0,220,0,61,0,185,0,49,0,150,0,37,0,115,0,25,0,80,0,240,212,255,0, + 226,177,255,0,212,142,255,0,198,107,255,0,184,72,255,0,170,37,255,0,170,0,255,0,146,0,220,0, + 122,0,185,0,98,0,150,0,74,0,115,0,50,0,80,0,255,212,255,0,255,177,255,0,255,142,255,0,255,107,255,0, + 255,72,255,0,255,37,255,0,254,0,254,0,220,0,220,0,185,0,185,0,150,0,150,0,115,0,115,0,80,0,80,0, + 255,212,240,0,255,177,226,0,255,142,212,0,255,107,198,0,255,72,184,0,255,37,170,0,255,0,170,0, + 220,0,146,0,185,0,122,0,150,0,98,0,115,0,74,0,80,0,50,0,255,212,227,0,255,177,199,0,255,142,171,0, + 255,107,143,0,255,72,115,0,255,37,87,0,255,0,85,0,220,0,73,0,185,0,61,0,150,0,49,0,115,0,37,0, + 80,0,25,0,255,212,212,0,255,177,177,0,255,142,142,0,255,107,107,0,255,72,72,0,255,37,37,0,254,0, + 0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,0,255,227,212,0,255,199,177,0,255,171,142,0, + 255,143,107,0,255,115,72,0,255,87,37,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,115,37,0, + 0,80,25,0,0,255,240,212,0,255,226,177,0,255,212,142,0,255,198,107,0,255,184,72,0,255,170,37,0, + 255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,0,255,255,212,0,255,255,177,0, + 255,255,142,0,255,255,107,0,255,255,72,0,255,255,37,0,254,254,0,0,220,220,0,0,185,185,0,0,150,150,0, + 0,115,115,0,0,80,80,0,0,240,255,212,0,226,255,177,0,212,255,142,0,198,255,107,0,184,255,72,0, + 170,255,37,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,50,80,0,0,227,255,212,0, + 199,255,177,0,171,255,142,0,143,255,107,0,115,255,72,0,87,255,37,0,85,255,0,0,73,220,0,0,61,185,0, + 0,49,150,0,0,37,115,0,0,25,80,0,0,212,255,212,0,177,255,177,0,142,255,142,0,107,255,107,0,72,255,72,0, + 37,255,37,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,212,255,227,0,177,255,199,0, + 142,255,171,0,107,255,143,0,72,255,115,0,37,255,87,0,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0, + 115,37,0,0,80,25,0,212,255,240,0,177,255,226,0,142,255,212,0,107,255,198,0,72,255,184,0,37,255,170,0, + 0,255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,212,255,255,0,177,255,255,0, + 142,255,255,0,107,255,255,0,72,255,255,0,37,255,255,0,0,254,254,0,0,220,220,0,0,185,185,0,0, + 150,150,0,0,115,115,0,0,80,80,0,242,242,242,0,230,230,230,0,218,218,218,0,206,206,206,0,194,194,194,0, + 182,182,182,0,170,170,170,0,158,158,158,0,146,146,146,0,134,134,134,0,122,122,122,0,110,110,110,0, + 98,98,98,0,86,86,86,0,74,74,74,0,62,62,62,0,50,50,50,0,38,38,38,0,26,26,26,0,14,14,14,0,240,251,255,0, + 164,160,160,0,128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0}; + memcpy(GetPalette(),pal256,1024); + break; + } + case 4: + { + const uint8_t pal16[64]={0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0, + 128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0}; + memcpy(GetPalette(),pal16,64); + break; + } + case 1: + { + const uint8_t pal2[8]={0,0,0,0,255,255,255,0}; + memcpy(GetPalette(),pal2,8); + break; + } + } + info.last_c_isvalid = false; + return; +} +//////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3