📄 ximadsp.cpp
字号:
long kmax= Ksize-k2;
BYTE r,g,b;
RGBQUAD c;
CxImage tmp(*this);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=255;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
if (!IsInside(x+j,y+k)) continue;
c = BlindGetPixelColor(x+j,y+k);
if (c.rgbRed < r) r=c.rgbRed;
if (c.rgbGreen < g) g=c.rgbGreen;
if (c.rgbBlue < b) b=c.rgbBlue;
}
}
c.rgbRed = r;
c.rgbGreen = g;
c.rgbBlue = b;
tmp.BlindSetPixelColor(x,y,c);
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Enhance the light areas of the image
* \param Ksize: size of the kernel.
* \return true if everything is ok
*/
bool CxImage::Dilate(long Ksize)
{
if (!pDib) return false;
long k2 = Ksize/2;
long kmax= Ksize-k2;
BYTE r,g,b;
RGBQUAD c;
CxImage tmp(*this);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=0;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
if (!IsInside(x+j,y+k)) continue;
c = BlindGetPixelColor(x+j,y+k);
if (c.rgbRed > r) r=c.rgbRed;
if (c.rgbGreen > g) g=c.rgbGreen;
if (c.rgbBlue > b) b=c.rgbBlue;
}
}
c.rgbRed = r;
c.rgbGreen = g;
c.rgbBlue = b;
tmp.BlindSetPixelColor(x,y,c);
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Enhance the variations between adjacent pixels.
* Similar results can be achieved using Filter(),
* but the algorithms are different both in Edge() and in Contour().
* \param Ksize: size of the kernel.
* \return true if everything is ok
*/
bool CxImage::Edge(long Ksize)
{
if (!pDib) return false;
long k2 = Ksize/2;
long kmax= Ksize-k2;
BYTE r,g,b,rr,gg,bb;
RGBQUAD c;
CxImage tmp(*this);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=0;
rr=bb=gg=255;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
if (!IsInside(x+j,y+k)) continue;
c = BlindGetPixelColor(x+j,y+k);
if (c.rgbRed > r) r=c.rgbRed;
if (c.rgbGreen > g) g=c.rgbGreen;
if (c.rgbBlue > b) b=c.rgbBlue;
if (c.rgbRed < rr) rr=c.rgbRed;
if (c.rgbGreen < gg) gg=c.rgbGreen;
if (c.rgbBlue < bb) bb=c.rgbBlue;
}
}
c.rgbRed = (BYTE)(255-abs(r-rr));
c.rgbGreen = (BYTE)(255-abs(g-gg));
c.rgbBlue = (BYTE)(255-abs(b-bb));
tmp.BlindSetPixelColor(x,y,c);
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Blends two images
* \param imgsrc2: image to be mixed with this
* \param op: blending method; see ImageOpType
* \param lXOffset, lYOffset: image displacement
* \param bMixAlpha: if true and imgsrc2 has a valid alpha layer, it will be mixed in the destination image.
* \return true if everything is ok
*
* thanks to Mwolski
*/
//
void CxImage::Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset, long lYOffset, bool bMixAlpha)
{
long lWide = min(GetWidth(),imgsrc2.GetWidth()-lXOffset);
long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lYOffset);
bool bEditAlpha = imgsrc2.AlphaIsValid() & bMixAlpha;
if (bEditAlpha && AlphaIsValid()==false){
AlphaCreate();
}
RGBQUAD rgbBackgrnd1 = GetTransColor();
RGBQUAD rgb1, rgb2, rgbDest;
for(long lY=0;lY<lHeight;lY++)
{
info.nProgress = (long)(100*lY/head.biHeight);
if (info.nEscape) break;
for(long lX=0;lX<lWide;lX++)
{
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(lX,lY) && imgsrc2.SelectionIsInside(lX+lXOffset,lY+lYOffset))
#endif //CXIMAGE_SUPPORT_SELECTION
{
rgb1 = GetPixelColor(lX,lY);
rgb2 = imgsrc2.GetPixelColor(lX+lXOffset,lY+lYOffset);
switch(op)
{
case OpAvg:
rgbDest.rgbBlue = (BYTE)((rgb1.rgbBlue+rgb2.rgbBlue)/2);
rgbDest.rgbGreen = (BYTE)((rgb1.rgbGreen+rgb2.rgbGreen)/2);
rgbDest.rgbRed = (BYTE)((rgb1.rgbRed+rgb2.rgbRed)/2);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)((rgb1.rgbReserved+rgb2.rgbReserved)/2);
break;
case OpAdd:
rgbDest.rgbBlue = (BYTE)max(0,min(255,rgb1.rgbBlue+rgb2.rgbBlue));
rgbDest.rgbGreen = (BYTE)max(0,min(255,rgb1.rgbGreen+rgb2.rgbGreen));
rgbDest.rgbRed = (BYTE)max(0,min(255,rgb1.rgbRed+rgb2.rgbRed));
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)max(0,min(255,rgb1.rgbReserved+rgb2.rgbReserved));
break;
case OpSub:
rgbDest.rgbBlue = (BYTE)max(0,min(255,rgb1.rgbBlue-rgb2.rgbBlue));
rgbDest.rgbGreen = (BYTE)max(0,min(255,rgb1.rgbGreen-rgb2.rgbGreen));
rgbDest.rgbRed = (BYTE)max(0,min(255,rgb1.rgbRed-rgb2.rgbRed));
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)max(0,min(255,rgb1.rgbReserved-rgb2.rgbReserved));
break;
case OpAnd:
rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue&rgb2.rgbBlue);
rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen&rgb2.rgbGreen);
rgbDest.rgbRed = (BYTE)(rgb1.rgbRed&rgb2.rgbRed);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved&rgb2.rgbReserved);
break;
case OpXor:
rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue^rgb2.rgbBlue);
rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen^rgb2.rgbGreen);
rgbDest.rgbRed = (BYTE)(rgb1.rgbRed^rgb2.rgbRed);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved^rgb2.rgbReserved);
break;
case OpOr:
rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue|rgb2.rgbBlue);
rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen|rgb2.rgbGreen);
rgbDest.rgbRed = (BYTE)(rgb1.rgbRed|rgb2.rgbRed);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved|rgb2.rgbReserved);
break;
case OpMask:
if(rgb2.rgbBlue==0 && rgb2.rgbGreen==0 && rgb2.rgbRed==0)
rgbDest = rgbBackgrnd1;
else
rgbDest = rgb1;
break;
case OpSrcCopy:
if(IsTransparent(lX,lY))
rgbDest = rgb2;
else // copy straight over
rgbDest = rgb1;
break;
case OpDstCopy:
if(imgsrc2.IsTransparent(lX+lXOffset,lY+lYOffset))
rgbDest = rgb1;
else // copy straight over
rgbDest = rgb2;
break;
case OpScreen:
{
BYTE a,a1;
if (imgsrc2.IsTransparent(lX+lXOffset,lY+lYOffset)){
a=0;
} else if (imgsrc2.AlphaIsValid()){
a=imgsrc2.AlphaGet(lX+lXOffset,lY+lYOffset);
a =(BYTE)((a*imgsrc2.info.nAlphaMax)/255);
} else {
a=255;
}
if (a==0){ //transparent
rgbDest = rgb1;
} else if (a==255){ //opaque
rgbDest = rgb2;
} else { //blend
a1 = (BYTE)~a;
rgbDest.rgbBlue = (BYTE)((rgb1.rgbBlue*a1+rgb2.rgbBlue*a)/255);
rgbDest.rgbGreen = (BYTE)((rgb1.rgbGreen*a1+rgb2.rgbGreen*a)/255);
rgbDest.rgbRed = (BYTE)((rgb1.rgbRed*a1+rgb2.rgbRed*a)/255);
}
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)((rgb1.rgbReserved*a)/255);
}
break;
case OpSrcBlend:
if(IsTransparent(lX,lY))
rgbDest = rgb2;
else
{
long lBDiff = abs(rgb1.rgbBlue - rgbBackgrnd1.rgbBlue);
long lGDiff = abs(rgb1.rgbGreen - rgbBackgrnd1.rgbGreen);
long lRDiff = abs(rgb1.rgbRed - rgbBackgrnd1.rgbRed);
double lAverage = (lBDiff+lGDiff+lRDiff)/3;
double lThresh = 16;
double dLarge = lAverage/lThresh;
double dSmall = (lThresh-lAverage)/lThresh;
double dSmallAmt = dSmall*((double)rgb2.rgbBlue);
if( lAverage < lThresh+1){
rgbDest.rgbBlue = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbBlue) +
dSmallAmt)));
rgbDest.rgbGreen = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbGreen) +
dSmallAmt)));
rgbDest.rgbRed = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbRed) +
dSmallAmt)));
}
else
rgbDest = rgb1;
}
break;
default:
return;
}
SetPixelColor(lX,lY,rgbDest,bEditAlpha);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// thanks to Kenneth Ballard
void CxImage::MixFrom(CxImage & imagesrc2, long lXOffset, long lYOffset)
{
long width = imagesrc2.GetWidth();
long height = imagesrc2.GetHeight();
int x, y;
if (imagesrc2.IsTransparent()) {
for(x = 0; x < width; x++) {
for(y = 0; y < height; y++) {
if(!imagesrc2.IsTransparent(x,y)){
SetPixelColor(x + lXOffset, y + lYOffset, imagesrc2.BlindGetPixelColor(x, y));
}
}
}
} else { //no transparency so just set it <Matt>
for(x = 0; x < width; x++) {
for(y = 0; y < height; y++) {
SetPixelColor(x + lXOffset, y + lYOffset, imagesrc2.BlindGetPixelColor(x, y));
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/**
* Adjusts separately the red, green, and blue values in the image.
* \param r, g, b: can be from -255 to +255.
* \return true if everything is ok
*/
bool CxImage::ShiftRGB(long r, long g, long b)
{
if (!pDib) return false;
RGBQUAD color;
if (head.biClrUsed==0){
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
for(long y=ymin; y<ymax; y++){
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
color = BlindGetPixelColor(x,y);
color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + r)));
color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + g)));
color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + b)));
BlindSetPixelColor(x,y,color);
}
}
}
} else {
for(DWORD j=0; j<head.biClrUsed; j++){
color = GetPaletteColor((BYTE)j);
color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + r)));
color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + g)));
color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + b)));
SetPaletteColor((BYTE)j,color);
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Adjusts the color balance of the image
* \param gamma can be from 0.1 to 5.
* \return true if everything is ok
* \sa GammaRGB
*/
bool CxImage::Gamma(float gamma)
{
if (!pDib) return false;
if (gamma <= 0.0f) return false;
double dinvgamma = 1/gamma;
double dMax = pow(255.0, dinvgamma) / 255.0;
BYTE cTable[256]; //<nipper>
for (int i=0;i<256;i++) {
cTable[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));
}
return Lut(cTable);
}
////////////////////////////////////////////////////////////////////////////////
/**
* Adjusts the color balance indipendent for each color channel
* \param gammaR, gammaG, gammaB can be from 0.1 to 5.
* \return true if everything is ok
* \sa Gamma
*/
bool CxImage::GammaRGB(float gammaR, float gammaG, float gammaB)
{
if (!pDib) return false;
if (gammaR <= 0.0f) return false;
if (gammaG <= 0.0f) return false;
if (gammaB <= 0.0f) return false;
double dinvgamma, dMax;
int i;
dinvgamma = 1/gammaR;
dMax = pow(255.0, dinvgamma) / 255.0;
BYTE cTableR[256];
for (i=0;i<256;i++) {
cTableR[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));
}
dinvgamma = 1/gammaG;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -