📄 ximatran.cpp
字号:
y2=newHeight-y-1;
for (x = 0; x < newWidth; x++){
imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x));
}
}
}
#endif //CXIMAGE_SUPPORT_SELECTION
} else {
//anything else but BW
BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version
int xs, ys; //x-segment and y-segment
for (xs = 0; xs < newWidth; xs+=RBLOCK) {
for (ys = 0; ys < newHeight; ys+=RBLOCK) {
if (head.biBitCount==24) {
//RGB24 optimized pixel access:
for (y = ys; y < min(newHeight, ys+RBLOCK); y++){
info.nProgress = (long)(100*y/newHeight); //<Anatoly Ivasyuk>
y2=newHeight-y-1;
dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(xs,y);
srcPtr = (BYTE*) BlindGetPixelPointer(y2, xs);
for (x = xs; x < min(newWidth, xs+RBLOCK); x++){
//imgDest.SetPixelColor(x, y, GetPixelColor(y2, x));
*(dstPtr) = *(srcPtr);
*(dstPtr+1) = *(srcPtr+1);
*(dstPtr+2) = *(srcPtr+2);
dstPtr += 3;
srcPtr += info.dwEffWidth;
}//for x
}//for y
} else {
//anything else than BW & RGB24: palette
for (y = ys; y < min(newHeight, ys+RBLOCK); y++){
info.nProgress = (long)(100*y/newHeight); //<Anatoly Ivasyuk>
y2=newHeight-y-1;
for (x = xs; x < min(newWidth, xs+RBLOCK); x++){
imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y2, x));
}//for x
}//for y
}//if
#if CXIMAGE_SUPPORT_ALPHA
if (AlphaIsValid()){
for (y = ys; y < min(newHeight, ys+RBLOCK); y++){
y2=newHeight-y-1;
for (x = xs; x < min(newWidth, xs+RBLOCK); x++){
imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x));
}//for x
}//for y
}//if (has alpha)
#endif //CXIMAGE_SUPPORT_ALPHA
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsValid()){
imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom;
imgDest.info.rSelectionBox.right = info.rSelectionBox.top;
imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right;
imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left;
for (y = ys; y < min(newHeight, ys+RBLOCK); y++){
y2=newHeight-y-1;
for (x = xs; x < min(newWidth, xs+RBLOCK); x++){
imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x));
}//for x
}//for y
}//if (has alpha)
#endif //CXIMAGE_SUPPORT_SELECTION
}//for ys
}//for xs
}//if
//select the destination
if (iDst) iDst->Transfer(imgDest);
else Transfer(imgDest);
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool CxImage::Negative()
{
if (!pDib) return false;
if (head.biBitCount<=8){
if (IsGrayScale()){ //GRAYSCALE, selection
if (pSelection){
for(long y=info.rSelectionBox.bottom; y<info.rSelectionBox.top; y++){
for(long x=info.rSelectionBox.left; x<info.rSelectionBox.right; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
BlindSetPixelIndex(x,y,(BYTE)(255-BlindGetPixelIndex(x,y)));
}
}
}
} else {
BYTE *iSrc=info.pImage;
for(unsigned long i=0; i < head.biSizeImage; i++){
*iSrc=(BYTE)~(*(iSrc));
iSrc++;
}
}
} else { //PALETTE, full image
RGBQUAD* ppal=GetPalette();
for(DWORD i=0;i<head.biClrUsed;i++){
ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue);
ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen);
ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed);
}
}
} else {
if (pSelection==NULL){ //RGB, full image
BYTE *iSrc=info.pImage;
for(unsigned long i=0; i < head.biSizeImage; i++){
*iSrc=(BYTE)~(*(iSrc));
iSrc++;
}
} else { // RGB with selection
RGBQUAD color;
for(long y=info.rSelectionBox.bottom; y<info.rSelectionBox.top; y++){
for(long x=info.rSelectionBox.left; x<info.rSelectionBox.right; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
color = BlindGetPixelColor(x,y);
color.rgbRed = (BYTE)(255-color.rgbRed);
color.rgbGreen = (BYTE)(255-color.rgbGreen);
color.rgbBlue = (BYTE)(255-color.rgbBlue);
BlindSetPixelColor(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,nHeight};
CxPoint2 newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom;
newP1.x = (float)p1.x;
newP1.y = (float)p1.y;
newP2.x = (float)(p2.x*cos_angle - p2.y*sin_angle);
newP2.y = (float)(p2.x*sin_angle + p2.y*cos_angle);
newP3.x = (float)(p3.x*cos_angle - p3.y*sin_angle);
newP3.y = (float)(p3.x*sin_angle + p3.y*cos_angle);
newP4.x = (float)(p4.x*cos_angle - p4.y*sin_angle);
newP4.y = (float)(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 = rightBottom.y;
rightTop.x = rightBottom.x;
rightTop.y = leftTop.y;
newWidth = (int) floor(0.5f + rightTop.x - leftTop.x);
newHeight= (int) floor(0.5f + 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 = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){
info.nProgress = (long)(100*newY/newHeight);
if (info.nEscape) break;
for (x = (int)leftTop.x, newX = 0; x<=(int)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 = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){
info.nProgress = (long)(100*newY/newHeight);
if (info.nEscape) break;
for (x = (int)leftTop.x, newX = 0; x<=(int)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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -