📄 ximatran.cpp
字号:
color.rgbBlue = (BYTE)(255-color.rgbBlue); SetPixelColor(x,y,color); } } } } //<DP> invert transparent color too info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); } return true;}////////////////////////////////////////////////////////////////////////////////#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS////////////////////////////////////////////////////////////////////////////////#if CXIMAGE_SUPPORT_TRANSFORMATION////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool CxImage::Rotate(float angle, CxImage* iDst){ if (!pDib) return false; // Copyright (c) 1996-1998 Ulrich von Zadow // Negative the angle, because the y-axis is negative. double ang = -angle*acos((float)0)/90; int newWidth, newHeight; int nWidth = GetWidth(); int nHeight= GetHeight(); double cos_angle = cos(ang); double sin_angle = sin(ang); // Calculate the size of the new bitmap POINT p1={0,0}; POINT p2={nWidth,0}; POINT p3={0,nHeight}; POINT p4={nWidth-1,nHeight}; POINT newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom; newP1.x = p1.x; newP1.y = p1.y; newP2.x = (long)floor(p2.x*cos_angle - p2.y*sin_angle); newP2.y = (long)floor(p2.x*sin_angle + p2.y*cos_angle); newP3.x = (long)floor(p3.x*cos_angle - p3.y*sin_angle); newP3.y = (long)floor(p3.x*sin_angle + p3.y*cos_angle); newP4.x = (long)floor(p4.x*cos_angle - p4.y*sin_angle); newP4.y = (long)floor(p4.x*sin_angle + p4.y*cos_angle); leftTop.x = min(min(newP1.x,newP2.x),min(newP3.x,newP4.x)); leftTop.y = min(min(newP1.y,newP2.y),min(newP3.y,newP4.y)); rightBottom.x = max(max(newP1.x,newP2.x),max(newP3.x,newP4.x)); rightBottom.y = max(max(newP1.y,newP2.y),max(newP3.y,newP4.y)); leftBottom.x = leftTop.x; leftBottom.y = 2+rightBottom.y; rightTop.x = 2+rightBottom.x; rightTop.y = leftTop.y; newWidth = rightTop.x - leftTop.x; newHeight= leftBottom.y - leftTop.y; CxImage imgDest; imgDest.CopyInfo(*this); imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); imgDest.SetPalette(GetPalette());#if CXIMAGE_SUPPORT_ALPHA if(AlphaIsValid()) //MTA: Fix for rotation problem when the image has an alpha channel { imgDest.AlphaCreate(); imgDest.AlphaClear(); }#endif //CXIMAGE_SUPPORT_ALPHA int x,y,newX,newY,oldX,oldY; if (head.biClrUsed==0){ //RGB for (y = leftTop.y, newY = 0; y<=leftBottom.y; y++,newY++){ info.nProgress = (long)(100*newY/newHeight); if (info.nEscape) break; for (x = leftTop.x, newX = 0; x<=rightTop.x; x++,newX++){ oldX = (long)(x*cos_angle + y*sin_angle - 0.5); oldY = (long)(y*cos_angle - x*sin_angle - 0.5); imgDest.SetPixelColor(newX,newY,GetPixelColor(oldX,oldY));#if CXIMAGE_SUPPORT_ALPHA imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value#endif //CXIMAGE_SUPPORT_ALPHA } } } else { //PALETTE for (y = leftTop.y, newY = 0; y<=leftBottom.y; y++,newY++){ info.nProgress = (long)(100*newY/newHeight); if (info.nEscape) break; for (x = leftTop.x, newX = 0; x<=rightTop.x; x++,newX++){ oldX = (long)(x*cos_angle + y*sin_angle - 0.5); oldY = (long)(y*cos_angle - x*sin_angle - 0.5); imgDest.SetPixelIndex(newX,newY,GetPixelIndex(oldX,oldY));#if CXIMAGE_SUPPORT_ALPHA imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value#endif //CXIMAGE_SUPPORT_ALPHA } } } //select the destination if (iDst) iDst->Transfer(imgDest); else Transfer(imgDest); return true;}/////////////////////////////////////////////////////////////////////////////////** * Rotates image around it's center. * Method can use interpolation with paletted images, but does not change pallete, so results vary. * (If you have only four colours in a palette, there's not much room for interpolation.) * * \param angle - angle in degrees (positive values rotate clockwise) * \param *iDst - destination image (if null, this image is changed) * \param inMethod - interpolation method used * (IM_NEAREST_NEIGHBOUR produces aliasing (fast), IM_BILINEAR softens picture a bit (slower) * IM_SHARPBICUBIC is slower and produces some halos...) * \param ofMethod - overflow method (how to choose colour of pixels that have no source) * \param replColor - replacement colour to use (OM_COLOR, OM_BACKGROUND with no background colour...) * \param optimizeRightAngles - call faster methods for 90, 180, and 270 degree rotations. Faster methods * are called for angles, where error (in location of corner pixels) is less * than 0.25 pixels. * \param bKeepOriginalSize - rotates the image without resizing. * * \author ***bd*** 2.2004 */bool CxImage::Rotate2(float angle, CxImage *iDst, InterpolationMethod inMethod, OverflowMethod ofMethod, RGBQUAD *replColor, bool const optimizeRightAngles, bool const bKeepOriginalSize){ if (!pDib) return false; //no dib no go double ang = -angle*acos(0.0f)/90.0f; //convert angle to radians and invert (positive angle performs clockwise rotation) float cos_angle = (float) cos(ang); //these two are needed later (to rotate) float sin_angle = (float) sin(ang); //Calculate the size of the new bitmap (rotate corners of image) CxPoint2 p[4]; //original corners of the image p[0]=CxPoint2(-0.5f,-0.5f); p[1]=CxPoint2(GetWidth()-0.5f,-0.5f); p[2]=CxPoint2(-0.5f,GetHeight()-0.5f); p[3]=CxPoint2(GetWidth()-0.5f,GetHeight()-0.5f); CxPoint2 newp[4]; //rotated positions of corners //(rotate corners) if (bKeepOriginalSize){ for (int i=0; i<4; i++) { newp[i].x = p[i].x; newp[i].y = p[i].y; }//for } else { for (int i=0; i<4; i++) { newp[i].x = (p[i].x*cos_angle - p[i].y*sin_angle); newp[i].y = (p[i].x*sin_angle + p[i].y*cos_angle); }//for i if (optimizeRightAngles) { //For rotations of 90, -90 or 180 or 0 degrees, call faster routines if (newp[3].Distance(CxPoint2(GetHeight()-0.5f, 0.5f-GetWidth())) < 0.25) //rotation right for circa 90 degrees (diagonal pixels less than 0.25 pixel away from 90 degree rotation destination) return RotateRight(iDst); if (newp[3].Distance(CxPoint2(0.5f-GetHeight(), -0.5f+GetWidth())) < 0.25) //rotation left for ~90 degrees return RotateLeft(iDst); if (newp[3].Distance(CxPoint2(0.5f-GetWidth(), 0.5f-GetHeight())) < 0.25) //rotation left for ~180 degrees return Rotate180(iDst); if (newp[3].Distance(p[3]) < 0.25) { //rotation not significant if (iDst) iDst->Copy(*this); //copy image to iDst, if required return true; //and we're done }//if }//if }//if //(read new dimensions from location of corners) float minx = (float) min(min(newp[0].x,newp[1].x),min(newp[2].x,newp[3].x)); float miny = (float) min(min(newp[0].y,newp[1].y),min(newp[2].y,newp[3].y)); float maxx = (float) max(max(newp[0].x,newp[1].x),max(newp[2].x,newp[3].x)); float maxy = (float) max(max(newp[0].y,newp[1].y),max(newp[2].y,newp[3].y)); int newWidth = (int) floor(maxx-minx+0.5f); int newHeight= (int) floor(maxy-miny+0.5f); float ssx=((maxx+minx)- ((float) newWidth-1))/2.0f; //start for x float ssy=((maxy+miny)- ((float) newHeight-1))/2.0f; //start for y float newxcenteroffset = 0.5f * newWidth; float newycenteroffset = 0.5f * newHeight; if (bKeepOriginalSize){ ssx -= 0.5f * GetWidth(); ssy -= 0.5f * GetHeight(); } //create destination image CxImage imgDest; imgDest.CopyInfo(*this); imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); imgDest.SetPalette(GetPalette());#if CXIMAGE_SUPPORT_ALPHA if(AlphaIsValid()) imgDest.AlphaCreate(); //MTA: Fix for rotation problem when the image has an alpha channel#endif //CXIMAGE_SUPPORT_ALPHA RGBQUAD rgb; //pixel colour RGBQUAD rc; if (replColor!=0) rc=*replColor; else { rc.rgbRed=255; rc.rgbGreen=255; rc.rgbBlue=255; rc.rgbReserved=0; }//if float x,y; //destination location (float, with proper offset) float origx, origy; //origin location int destx, desty; //destination location y=ssy; //initialize y if (!IsIndexed()){ //RGB24 //optimized RGB24 implementation (direct write to destination): BYTE *pxptr;#if CXIMAGE_SUPPORT_ALPHA BYTE *pxptra=0;#endif //CXIMAGE_SUPPORT_ALPHA for (desty=0; desty<newHeight; desty++) { info.nProgress = (long)(100*desty/newHeight); if (info.nEscape) break; //initialize x x=ssx; //calculate pointer to first byte in row pxptr=(BYTE *)imgDest.BlindGetPixelPointer(0, desty);#if CXIMAGE_SUPPORT_ALPHA //calculate pointer to first byte in row if (AlphaIsValid()) pxptra=imgDest.AlphaGetPointer(0, desty);#endif //CXIMAGE_SUPPORT_ALPHA for (destx=0; destx<newWidth; destx++) { //get source pixel coordinate for current destination point //origx = (cos_angle*(x-head.biWidth/2)+sin_angle*(y-head.biHeight/2))+newWidth/2; //origy = (cos_angle*(y-head.biHeight/2)-sin_angle*(x-head.biWidth/2))+newHeight/2; origx = cos_angle*x+sin_angle*y; origy = cos_angle*y-sin_angle*x; if (bKeepOriginalSize){ origx += newxcenteroffset; origy += newycenteroffset; } rgb = GetPixelColorInterpolated(origx, origy, inMethod, ofMethod, &rc); //get interpolated colour value //copy alpha and colour value to destination#if CXIMAGE_SUPPORT_ALPHA if (pxptra) *pxptra++ = rgb.rgbReserved;#endif //CXIMAGE_SUPPORT_ALPHA *pxptr++ = rgb.rgbBlue; *pxptr++ = rgb.rgbGreen; *pxptr++ = rgb.rgbRed; x++; }//for destx y++; }//for desty } else { //non-optimized implementation for paletted images for (desty=0; desty<newHeight; desty++) { info.nProgress = (long)(100*desty/newHeight); if (info.nEscape) break; x=ssx; for (destx=0; destx<newWidth; destx++) { //get source pixel coordinate for current destination point origx=(cos_angle*x+sin_angle*y); origy=(cos_angle*y-sin_angle*x); if (bKeepOriginalSize){ origx += newxcenteroffset; origy += newycenteroffset; } rgb = GetPixelColorInterpolated(origx, origy, inMethod, ofMethod, &rc); //***!*** SetPixelColor is slow for palleted images#if CXIMAGE_SUPPORT_ALPHA if (AlphaIsValid()) imgDest.SetPixelColor(destx,desty,rgb,true); else #endif //CXIMAGE_SUPPORT_ALPHA imgDest.SetPixelColor(destx,desty,rgb,false); x++; }//for destx y++; }//for desty } //select the destination 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, GetPixelColor(x, y)); else //PALETTE imgDest.SetPixelIndex(wid-x-1, y2, GetPixelIndex(x, y));#if CXIMAGE_SUPPORT_ALPHA if (AlphaIsValid()) imgDest.AlphaSet(wid-x-1, y2,AlphaGet(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()) 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)) { //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -