📄 ximapal.cpp
字号:
// xImaPal.cpp : Palette and Pixel functions
/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
* CxImage version 5.99c 17/Oct/2004
*/
#include "ximage.h"
////////////////////////////////////////////////////////////////////////////////
/**
* returns the palette dimension in byte
*/
DWORD CxImage::GetPaletteSize()
{
return (head.biClrUsed * sizeof(RGBQUAD));
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha)
{
if ((pDib)&&(head.biClrUsed)){
BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
if (idx<head.biClrUsed){
long ldx=idx*sizeof(RGBQUAD);
iDst[ldx++] = (BYTE) b;
iDst[ldx++] = (BYTE) g;
iDst[ldx++] = (BYTE) r;
iDst[ldx] = (BYTE) alpha;
info.last_c_isvalid = false;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::SetPaletteColor(BYTE idx, RGBQUAD c)
{
if ((pDib)&&(head.biClrUsed)){
BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
if (idx<head.biClrUsed){
long ldx=idx*sizeof(RGBQUAD);
iDst[ldx++] = (BYTE) c.rgbBlue;
iDst[ldx++] = (BYTE) c.rgbGreen;
iDst[ldx++] = (BYTE) c.rgbRed;
iDst[ldx] = (BYTE) c.rgbReserved;
info.last_c_isvalid = false;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::SetPaletteColor(BYTE idx, COLORREF cr)
{
if ((pDib)&&(head.biClrUsed)){
BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
if (idx<head.biClrUsed){
long ldx=idx*sizeof(RGBQUAD);
iDst[ldx++] = (BYTE) GetBValue(cr);
iDst[ldx++] = (BYTE) GetGValue(cr);
iDst[ldx++] = (BYTE) GetRValue(cr);
iDst[ldx] = (BYTE) 0;
info.last_c_isvalid = false;
}
}
}
////////////////////////////////////////////////////////////////////////////////
/**
* returns the pointer to the first palette index
*/
RGBQUAD* CxImage::GetPalette() const
{
if ((pDib)&&(head.biClrUsed))
return (RGBQUAD*)((BYTE*)pDib + sizeof(BITMAPINFOHEADER));
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Returns the color of the specified index.
*/
RGBQUAD CxImage::GetPaletteColor(BYTE idx)
{
RGBQUAD rgb = {0,0,0,0};
if ((pDib)&&(head.biClrUsed)){
BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
if (idx<head.biClrUsed){
long ldx=idx*sizeof(RGBQUAD);
rgb.rgbBlue = iDst[ldx++];
rgb.rgbGreen=iDst[ldx++];
rgb.rgbRed =iDst[ldx++];
rgb.rgbReserved = iDst[ldx];
}
}
return rgb;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Returns the palette index of the specified pixel.
*/
BYTE CxImage::GetPixelIndex(long x,long y)
{
if ((pDib==NULL)||(head.biClrUsed==0)) return 0;
if ((x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) {
if (info.nBkgndIndex != -1) return (BYTE)info.nBkgndIndex;
else return *info.pImage;
}
if (head.biBitCount==8){
return info.pImage[y*info.dwEffWidth + x];
} else {
BYTE pos;
BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];
if (head.biBitCount==4){
pos = (BYTE)(4*(1-x%2));
iDst &= (0x0F<<pos);
return (BYTE)(iDst >> pos);
} else if (head.biBitCount==1){
pos = (BYTE)(7-x%8);
iDst &= (0x01<<pos);
return (BYTE)(iDst >> pos);
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
BYTE CxImage::BlindGetPixelIndex(const long x,const long y)
{
#ifdef _DEBUG
if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y)) throw 0;
#endif
if (head.biBitCount==8){
return info.pImage[y*info.dwEffWidth + x];
} else {
BYTE pos;
BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];
if (head.biBitCount==4){
pos = (BYTE)(4*(1-x%2));
iDst &= (0x0F<<pos);
return (BYTE)(iDst >> pos);
} else if (head.biBitCount==1){
pos = (BYTE)(7-x%8);
iDst &= (0x01<<pos);
return (BYTE)(iDst >> pos);
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::GetPixelColor(long x,long y, bool bGetAlpha)
{
// RGBQUAD rgb={0,0,0,0};
RGBQUAD rgb=info.nBkgndColor; //<mpwolski>
if ((pDib==NULL)||(x<0)||(y<0)||
(x>=head.biWidth)||(y>=head.biHeight)){
if (info.nBkgndIndex != -1){
if (head.biBitCount<24) return GetPaletteColor((BYTE)info.nBkgndIndex);
else return info.nBkgndColor;
} else if (pDib) return GetPixelColor(0,0);
return rgb;
}
if (head.biClrUsed){
rgb = GetPaletteColor(GetPixelIndex(x,y));
} else {
BYTE* 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 = AlphaGet(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 long x,const long y)
{
RGBQUAD rgb;
#ifdef _DEBUG
if ((pDib==NULL) || !IsInside(x,y)) throw 0;
#endif
if (head.biClrUsed){
return GetPaletteColor(BlindGetPixelIndex(x,y));
}
BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;
rgb.rgbBlue = *iDst++;
rgb.rgbGreen= *iDst++;
rgb.rgbRed = *iDst;
#if CXIMAGE_SUPPORT_ALPHA
if (pAlpha) rgb.rgbReserved = pAlpha[x+y*head.biWidth];
#else
rgb.rgbReserved = 0;
#endif //CXIMAGE_SUPPORT_ALPHA
return rgb;
}
////////////////////////////////////////////////////////////////////////////////
BYTE CxImage::GetPixelGray(long x, long y)
{
RGBQUAD color = GetPixelColor(x,y);
return (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::SetPixelIndex(long x,long y,BYTE i)
{
if ((pDib==NULL)||(head.biClrUsed==0)||
(x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) return ;
if (head.biBitCount==8){
info.pImage[y*info.dwEffWidth + x]=i;
return;
} else {
BYTE pos;
BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);
if (head.biBitCount==4){
pos = (BYTE)(4*(1-x%2));
*iDst &= ~(0x0F<<pos);
*iDst |= ((i & 0x0F)<<pos);
return;
} else if (head.biBitCount==1){
pos = (BYTE)(7-x%8);
*iDst &= ~(0x01<<pos);
*iDst |= ((i & 0x01)<<pos);
return;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::SetPixelColor(long x,long y,COLORREF cr)
{
SetPixelColor(x,y,RGBtoRGBQUAD(cr));
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)
{
if ((pDib==NULL)||(x<0)||(y<0)||
(x>=head.biWidth)||(y>=head.biHeight)) return;
if (head.biClrUsed)
SetPixelIndex(x,y,GetNearestIndex(c));
else {
BYTE* 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(long x,long y,RGBQUAD c, float blend, bool bSetAlpha)
{
if ((pDib==NULL)||(x<0)||(y<0)||
(x>=head.biWidth)||(y>=head.biHeight)) return;
int a0 = (int)(256*blend);
int a1 = 256 - a0;
RGBQUAD c0 = BlindGetPixelColor(x,y);
c.rgbRed = (BYTE)((c.rgbRed * a0 + c0.rgbRed * a1)>>8);
c.rgbBlue = (BYTE)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8);
c.rgbGreen = (BYTE)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8);
if (head.biClrUsed)
SetPixelIndex(x,y,GetNearestIndex(c));
else {
BYTE* 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.
*/
BYTE CxImage::GetNearestIndex(RGBQUAD c)
{
if ((pDib==NULL)||(head.biClrUsed==0)) return 0;
// <RJ> check matching with the previous result
if (info.last_c_isvalid && (*(long*)&info.last_c == *(long*)&c)) return info.last_c_index;
info.last_c = c;
info.last_c_isvalid = true;
BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);
long distance=200000;
int i,j = 0;
long k,l;
int m = (int)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant);
for(i=0,l=0;i<m;i++,l+=sizeof(RGBQUAD)){
k = (iDst[l]-c.rgbBlue)*(iDst[l]-c.rgbBlue)+
(iDst[l+1]-c.rgbGreen)*(iDst[l+1]-c.rgbGreen)+
(iDst[l+2]-c.rgbRed)*(iDst[l+2]-c.rgbRed);
// k = abs(iDst[l]-c.rgbBlue)+abs(iDst[l+1]-c.rgbGreen)+abs(iDst[l+2]-c.rgbRed);
if (k==0){
j=i;
break;
}
if (k<distance){
distance=k;
j=i;
}
}
info.last_c_index = j;
return (BYTE)j;
}
////////////////////////////////////////////////////////////////////////////////
/**
* swaps the blue and red components (for RGB images)
* \param buffer : pointer to the pixels
* \param length : number of bytes to swap. lenght may not exceed the scan line.
*/
void CxImage::RGBtoBGR(BYTE *buffer, int length)
{
if (buffer && (head.biClrUsed==0)){
BYTE temp;
length = min(length,(int)info.dwEffWidth);
for (int i=0;i<length;i+=3){
temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp;
}
}
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::RGBtoRGBQUAD(COLORREF cr)
{
RGBQUAD c;
c.rgbRed = GetRValue(cr); /* get R, G, and B out of DWORD */
c.rgbGreen = GetGValue(cr);
c.rgbBlue = GetBValue(cr);
c.rgbReserved=0;
return c;
}
////////////////////////////////////////////////////////////////////////////////
COLORREF CxImage::RGBQUADtoRGB (RGBQUAD c)
{
return RGB(c.rgbRed,c.rgbGreen,c.rgbBlue);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -