📄 ximatran.cpp
字号:
if (iDst) iDst->Transfer(imgDest);
else Transfer(imgDest);
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool CxImage::Rotate180(CxImage* iDst)
{
if (!pDib) return false;
long wid = GetWidth();
long ht = GetHeight();
CxImage imgDest;
imgDest.CopyInfo(*this);
imgDest.Create(wid,ht,GetBpp(),GetType());
imgDest.SetPalette(GetPalette());
#if CXIMAGE_SUPPORT_ALPHA
if (AlphaIsValid()) imgDest.AlphaCreate();
#endif //CXIMAGE_SUPPORT_ALPHA
long x,y,y2;
for (y = 0; y < ht; y++){
info.nProgress = (long)(100*y/ht); //<Anatoly Ivasyuk>
y2=ht-y-1;
for (x = 0; x < wid; x++){
if(head.biClrUsed==0)//RGB
imgDest.SetPixelColor(wid-x-1, y2, BlindGetPixelColor(x, y));
else //PALETTE
imgDest.SetPixelIndex(wid-x-1, y2, BlindGetPixelIndex(x, y));
#if CXIMAGE_SUPPORT_ALPHA
if (AlphaIsValid()) imgDest.AlphaSet(wid-x-1, y2,BlindAlphaGet(x, y));
#endif //CXIMAGE_SUPPORT_ALPHA
}
}
//select the destination
if (iDst) iDst->Transfer(imgDest);
else Transfer(imgDest);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Resizes the image. mode can be 0 for slow (bilinear) method ,
* 1 for fast (nearest pixel) method, or 2 for accurate (bicubic spline interpolation) method.
* The function is faster with 24 and 1 bpp images, slow for 4 bpp images and slowest for 8 bpp images.
*/
bool CxImage::Resample(long newx, long newy, int mode, CxImage* iDst)
{
if (newx==0 || newy==0) return false;
if (head.biWidth==newx && head.biHeight==newy){
if (iDst) iDst->Copy(*this);
return true;
}
float xScale, yScale, fX, fY;
xScale = (float)head.biWidth / (float)newx;
yScale = (float)head.biHeight / (float)newy;
CxImage newImage;
newImage.CopyInfo(*this);
newImage.Create(newx,newy,head.biBitCount,GetType());
newImage.SetPalette(GetPalette());
if (!newImage.IsValid()){
strcpy(info.szLastError,newImage.GetLastError());
return false;
}
switch (mode) {
case 1: // nearest pixel
{
for(long y=0; y<newy; y++){
info.nProgress = (long)(100*y/newy);
if (info.nEscape) break;
fY = y * yScale;
for(long x=0; x<newx; x++){
fX = x * xScale;
newImage.SetPixelColor(x,y,GetPixelColor((long)fX,(long)fY));
}
}
break;
}
case 2: // bicubic interpolation by Blake L. Carlson <blake-carlson(at)uiowa(dot)edu
{
float f_x, f_y, a, b, rr, gg, bb, r1, r2;
int i_x, i_y, xx, yy;
RGBQUAD rgb;
BYTE* iDst;
for(long y=0; y<newy; y++){
info.nProgress = (long)(100*y/newy);
if (info.nEscape) break;
f_y = (float) y * yScale - 0.5f;
i_y = (int) floor(f_y);
a = f_y - (float)floor(f_y);
for(long x=0; x<newx; x++){
f_x = (float) x * xScale - 0.5f;
i_x = (int) floor(f_x);
b = f_x - (float)floor(f_x);
rr = gg = bb = 0.0f;
for(int m=-1; m<3; m++) {
r1 = KernelBSpline((float) m - a);
yy = i_y+m;
if (yy<0) yy=0;
if (yy>=head.biHeight) yy = head.biHeight-1;
for(int n=-1; n<3; n++) {
r2 = r1 * KernelBSpline(b - (float)n);
xx = i_x+n;
if (xx<0) xx=0;
if (xx>=head.biWidth) xx=head.biWidth-1;
if (head.biClrUsed){
rgb = GetPixelColor(xx,yy);
} else {
iDst = info.pImage + yy*info.dwEffWidth + xx*3;
rgb.rgbBlue = *iDst++;
rgb.rgbGreen= *iDst++;
rgb.rgbRed = *iDst;
}
rr += rgb.rgbRed * r2;
gg += rgb.rgbGreen * r2;
bb += rgb.rgbBlue * r2;
}
}
if (head.biClrUsed)
newImage.SetPixelColor(x,y,RGB(rr,gg,bb));
else {
iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3;
*iDst++ = (BYTE)bb;
*iDst++ = (BYTE)gg;
*iDst = (BYTE)rr;
}
}
}
break;
}
default: // bilinear interpolation
if (!(head.biWidth>newx && head.biHeight>newy && head.biBitCount==24)) {
// (c) 1999 Steve McMahon (steve@dogma.demon.co.uk)
long ifX, ifY, ifX1, ifY1, xmax, ymax;
float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy;
BYTE r,g,b;
RGBQUAD rgb1, rgb2, rgb3, rgb4;
xmax = head.biWidth-1;
ymax = head.biHeight-1;
for(long y=0; y<newy; y++){
info.nProgress = (long)(100*y/newy);
if (info.nEscape) break;
fY = y * yScale;
ifY = (int)fY;
ifY1 = min(ymax, ifY+1);
dy = fY - ifY;
for(long x=0; x<newx; x++){
fX = x * xScale;
ifX = (int)fX;
ifX1 = min(xmax, ifX+1);
dx = fX - ifX;
// Interpolate using the four nearest pixels in the source
if (head.biClrUsed){
rgb1=GetPaletteColor(GetPixelIndex(ifX,ifY));
rgb2=GetPaletteColor(GetPixelIndex(ifX1,ifY));
rgb3=GetPaletteColor(GetPixelIndex(ifX,ifY1));
rgb4=GetPaletteColor(GetPixelIndex(ifX1,ifY1));
}
else {
BYTE* iDst;
iDst = info.pImage + ifY*info.dwEffWidth + ifX*3;
rgb1.rgbBlue = *iDst++; rgb1.rgbGreen= *iDst++; rgb1.rgbRed =*iDst;
iDst = info.pImage + ifY*info.dwEffWidth + ifX1*3;
rgb2.rgbBlue = *iDst++; rgb2.rgbGreen= *iDst++; rgb2.rgbRed =*iDst;
iDst = info.pImage + ifY1*info.dwEffWidth + ifX*3;
rgb3.rgbBlue = *iDst++; rgb3.rgbGreen= *iDst++; rgb3.rgbRed =*iDst;
iDst = info.pImage + ifY1*info.dwEffWidth + ifX1*3;
rgb4.rgbBlue = *iDst++; rgb4.rgbGreen= *iDst++; rgb4.rgbRed =*iDst;
}
// Interplate in x direction:
ir1 = rgb1.rgbRed + (rgb3.rgbRed - rgb1.rgbRed) * dy;
ig1 = rgb1.rgbGreen + (rgb3.rgbGreen - rgb1.rgbGreen) * dy;
ib1 = rgb1.rgbBlue + (rgb3.rgbBlue - rgb1.rgbBlue) * dy;
ir2 = rgb2.rgbRed + (rgb4.rgbRed - rgb2.rgbRed) * dy;
ig2 = rgb2.rgbGreen + (rgb4.rgbGreen - rgb2.rgbGreen) * dy;
ib2 = rgb2.rgbBlue + (rgb4.rgbBlue - rgb2.rgbBlue) * dy;
// Interpolate in y:
r = (BYTE)(ir1 + (ir2-ir1) * dx);
g = (BYTE)(ig1 + (ig2-ig1) * dx);
b = (BYTE)(ib1 + (ib2-ib1) * dx);
// Set output
newImage.SetPixelColor(x,y,RGB(r,g,b));
}
}
} else {
//high resolution shrink, thanks to Henrik Stellmann <henrik.stellmann@volleynet.de>
const long ACCURACY = 1000;
long i,j; // index for faValue
long x,y; // coordinates in source image
BYTE* pSource;
BYTE* pDest = newImage.info.pImage;
long* naAccu = new long[3 * newx + 3];
long* naCarry = new long[3 * newx + 3];
long* naTemp;
long nWeightX,nWeightY;
float fEndX;
long nScale = (long)(ACCURACY * xScale * yScale);
memset(naAccu, 0, sizeof(long) * 3 * newx);
memset(naCarry, 0, sizeof(long) * 3 * newx);
int u, v = 0; // coordinates in dest image
float fEndY = yScale - 1.0f;
for (y = 0; y < head.biHeight; y++){
info.nProgress = (long)(100*y/head.biHeight); //<Anatoly Ivasyuk>
if (info.nEscape) break;
pSource = info.pImage + y * info.dwEffWidth;
u = i = 0;
fEndX = xScale - 1.0f;
if ((float)y < fEndY) { // complete source row goes into dest row
for (x = 0; x < head.biWidth; x++){
if ((float)x < fEndX){ // complete source pixel goes into dest pixel
for (j = 0; j < 3; j++) naAccu[i + j] += (*pSource++) * ACCURACY;
} else { // source pixel is splitted for 2 dest pixels
nWeightX = (long)(((float)x - fEndX) * ACCURACY);
for (j = 0; j < 3; j++){
naAccu[i] += (ACCURACY - nWeightX) * (*pSource);
naAccu[3 + i++] += nWeightX * (*pSource++);
}
fEndX += xScale;
u++;
}
}
} else { // source row is splitted for 2 dest rows
nWeightY = (long)(((float)y - fEndY) * ACCURACY);
for (x = 0; x < head.biWidth; x++){
if ((float)x < fEndX){ // complete source pixel goes into 2 pixel
for (j = 0; j < 3; j++){
naAccu[i + j] += ((ACCURACY - nWeightY) * (*pSource));
naCarry[i + j] += nWeightY * (*pSource++);
}
} else { // source pixel is splitted for 4 dest pixels
nWeightX = (int)(((float)x - fEndX) * ACCURACY);
for (j = 0; j < 3; j++) {
naAccu[i] += ((ACCURACY - nWeightY) * (ACCURACY - nWeightX)) * (*pSource) / ACCURACY;
*pDest++ = (BYTE)(naAccu[i] / nScale);
naCarry[i] += (nWeightY * (ACCURACY - nWeightX) * (*pSource)) / ACCURACY;
naAccu[i + 3] += ((ACCURACY - nWeightY) * nWeightX * (*pSource)) / ACCURACY;
naCarry[i + 3] = (nWeightY * nWeightX * (*pSource)) / ACCURACY;
i++;
pSource++;
}
fEndX += xScale;
u++;
}
}
if (u < newx){ // possibly not completed due to rounding errors
for (j = 0; j < 3; j++) *pDest++ = (BYTE)(naAccu[i++] / nScale);
}
naTemp = naCarry;
naCarry = naAccu;
naAccu = naTemp;
memset(naCarry, 0, sizeof(int) * 3); // need only to set first pixel zero
pDest = newImage.info.pImage + (++v * newImage.info.dwEffWidth);
fEndY += yScale;
}
}
if (v < newy){ // possibly not completed due to rounding errors
for (i = 0; i < 3 * newx; i++) *pDest++ = (BYTE)(naAccu[i] / nScale);
}
delete [] naAccu;
delete [] naCarry;
}
}
#if CXIMAGE_SUPPORT_ALPHA
if (AlphaIsValid()){
newImage.AlphaCreate();
for(long y=0; y<newy; y++){
fY = y * yScale;
for(long x=0; x<newx; x++){
fX = x * xScale;
newImage.AlphaSet(x,y,AlphaGet((long)fX,(long)fY));
}
}
}
#endif //CXIMAGE_SUPPORT_ALPHA
//select the destination
if (iDst) iDst->Transfer(newImage);
else Transfer(newImage);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* New simpler resample. Adds new interpolation methods and simplifies code (using GetPixelColorInterpolated
* and GetAreaColorInterpolated). It also (unlike old method) interpolates alpha layer.
*
* \param newx, newy - size of resampled image
* \param inMethod - interpolation method to use (see comments at GetPixelColorInterpolated)
* If image size is being reduced, averaging is used instead (or simultaneously with) inMethod.
* \param ofMethod - what to replace outside pixels by (only significant for bordering pixels of enlarged image)
* \param iDst - pointer to destination CxImage or NULL.
* \param disableAveraging - force no averaging when shrinking images (Produces aliasing.
* You probably just want to leave this off...)
*
* \author ***bd*** 2.2004
*/
bool CxImage::Resample2(
long newx, long newy,
InterpolationMethod const inMethod,
OverflowMethod const ofMethod,
CxImage* const iDst,
bool const disableAveraging)
{
if (newx<=0 || newy<=0 || !pDib) return false;
if (head.biWidth==newx && head.biHeight==newy) {
//image already correct size (just copy and return)
if (iDst) iDst->Copy(*this);
return true;
}//if
//calculate scale of new image (less than 1 for enlarge)
float xScale, yScale;
xScale = (float)head.biWidth / (float)newx;
yScale = (float)head.biHeight / (float)newy;
//create temporary destination image
CxImage newImage;
newImage.CopyInfo(*this);
newImage.Create(newx,newy,head.biBitCount,GetType());
newImage.SetPalette(GetPalette());
if (!newImage.IsValid()){
strcpy(info.szLastError,newImage.GetLastError());
return false;
}
//and alpha channel if required
#if CXIMAGE_SUPPORT_ALPHA
if (AlphaIsValid()) newImage.AlphaCreate();
BYTE *pxptra = 0; // destination alpha data
#endif
float sX, sY; //source location
long dX,dY; //destination pixel (int value)
if ((xScale<=1 && yScale<=1) || disableAveraging) {
//image is being enlarged (or interpolation on demand)
if (!IsIndexed()) {
//RGB24 image (optimized version with direct writes)
RGBQUAD q; //pixel colour
BYTE *pxptr; //pointer to destination pixel
for(dY=0; dY<newy; dY++){
info.nProgress = (long)(100*dY/newy);
if (info.nEscape) break;
sY = (dY + 0.5f) * yScale - 0.5f;
pxptr=(BYTE*)(newImage.BlindGetPixelPointer(0,dY));
#if CXIMAGE_SUPPORT_ALPHA
pxptra=newImage.AlphaGetPointer(0,dY);
#endif
for(dX=0; dX<newx; dX++){
sX = (dX + 0.5f) * xScale - 0.5f;
q=GetPixelColorInterpolated(sX,sY,inMethod,ofMethod,0);
*pxptr++=q.rgbBlue;
*pxptr++=q.rgbGreen;
*pxptr++=q.rgbRed;
#if CXIMAGE_SUPPORT_ALPHA
if (pxptra) *pxptra++=q.rgbReserved;
#endif
}//for dX
}//for dY
} else {
//enlarge paletted image. Slower method.
for(dY=0; dY<newy; dY++){
info.nProgress = (long)(100*dY/newy);
if (info.nEscape) break;
sY = (dY + 0.5f) * yScale - 0.5f;
for(dX=0; dX<newx; dX++){
sX = (dX + 0.5f) * xScale - 0.5f;
newImage.SetPixelColor(dX,dY,GetPixelColorInterpolated(sX,sY,inMethod,ofMethod,0),true);
}//for x
}//for y
}//if
} else {
//image size is being reduced (averaging enabled)
for(dY=0; dY<newy; dY++){
info.nProgress = (long)(100*dY/newy); if (info.nEscape) break;
sY = (dY+0.5f) * yScale - 0.5f;
for(dX=0; dX<newx; dX++){
sX = (dX+0.5f) * xScale - 0.5f;
newImage.SetPixelColor(dX,dY,GetAreaColorInterpolated(sX, sY, xScale, yScale, inMethod, ofMethod,0),true);
}//for x
}//for y
}//if
#if CXIMAGE_SUPPORT_ALPHA
if (AlphaIsValid() && pxptra == 0){
for(long y=0; y<newy; y++){
dY = (long)(y * yScale);
for(long x=0; x<newx; x++){
dX = (long)(x * xScale);
newImage.AlphaSet(x,y,AlphaGet(dX,dY));
}
}
}
#endif //CXIMAGE_SUPPORT_ALPHA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -