NO

Author Topic: gdi rotation problem  (Read 5441 times)

zellJunior

  • Guest
gdi rotation problem
« on: March 29, 2014, 06:05:11 PM »
Hi. I implemented the formula for rotation in 2D,
x' = x*cos(u)-y*sin(u)
y' = x*sin(u)-y*cos(u)
where : x' = is new x position, x - previous x position, u - angle in radians. Formula is corect, i know, i have read a lot of books.

The problem is that my object - deforms. I think the problem is that in windows POINT have x & y of type "long", and because of the approximations from float to long, it raises errors.

Source code for rotation function
Code: [Select]
POINT ptTemp ;
for (int i = 0 ; i < 4 ; i++)
     {
          ptTemp.x = (int) (points[i].x * cos (TWOPI * angle / 360) -
               points[i].y * sin (TWOPI * angle / 360)) ;
         
          ptTemp.y = (int) (points[i].y * cos (TWOPI * angle / 360) +
               points[i].x * sin (TWOPI * angle / 360)) ;
         
          points[i] = ptTemp ;
     }

« Last Edit: March 30, 2014, 12:50:00 PM by Stefan Pendl »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: gdi rotation problem
« Reply #1 on: March 30, 2014, 06:20:59 PM »
The float usage will give some approximation anyway, but your problem is more probably due to the different vertical and horizontal pixel aspect ratio of the screen.
If the values you get are correct the visual aspect of rotated points have aberrations.
It is not clear if you are just locating rotating points or if you are using the calculation to rotate an image.
The last task is a little bit more complex and you should always use system routines for that.
As an example the following is the rotation function of my 2D media library (that I have not published yet).
Code: [Select]
/*-@@+@@--------------------------------[Do not edit manually]------------
 Procedure: FmlRotateBmp
 Created  : Wed Aug  1 14:34:36 2012
 Modified : Sun Aug 12 21:01:44 2012

 Synopsys : Rotate an image around the center coordinates passed to the
            function.
            The nagle is in grades 0-360.
 Input    :
 Output   :
 Errors   :
 ------------------------------------------------------------------@@-@@-*/
HBITMAP FmlRotateBmp(HFMLANIM hAnim, HBITMAP hBmp, int Angle, LPPOINT RotationCenter)
{
HDC hDcSrc, hDcDst;
int  minX, maxX, minY, maxY;
HBITMAP hBmpDst;
POINT center;
POINT pOut[4];
HGDIOBJ OldSrc, OldDst;
BITMAP bitmap;


FML_TRY
{
/*
* Create working contexts and get image dimensions
*/
hDcSrc = CreateCompatibleDC(hAnim->hDC[0]);
hDcDst = CreateCompatibleDC(hAnim->hDC[0]);
GetObject(hBmp, sizeof(bitmap), &bitmap);

/*
*
* To calculate the rotated image bonding rectangle around its center we use the following equations.
* RotatePoint.X = pOrigin.X + ( Cos(Theta) * (pPoint.X - pOrigin.X) - Sin(Theta) * (pPoint.Y - pOrigin.Y) )
* RotatePoint.Y = pOrigin.Y + ( Sin(Theta) * (pPoint.X - pOrigin.X) + Cos(Theta) * (pPoint.Y - pOrigin.Y) )
*
*/

/*
* If rotation center is null set it to image center
*/
if (!RotationCenter)
{
center.x = bitmap.bmWidth  >> 1;
center.y = bitmap.bmHeight >> 1;
}
else
center = *RotationCenter;

/*
* Compute rotated coordinates
*/
pOut[0].x = center.x+(((              -center.x)*FmlCos(Angle)) - ((bitmap.bmHeight-center.y)*FmlSin(Angle)));
pOut[0].y = center.y+(((              -center.x)*FmlSin(Angle)) + ((bitmap.bmHeight-center.y)*FmlCos(Angle)));
pOut[1].x = center.x+(((bitmap.bmWidth-center.x)*FmlCos(Angle)) - ((bitmap.bmHeight-center.y)*FmlSin(Angle)));
pOut[1].y = center.y+(((bitmap.bmWidth-center.x)*FmlSin(Angle)) + ((bitmap.bmHeight-center.y)*FmlCos(Angle)));
pOut[2].x = center.x+(((              -center.x)*FmlCos(Angle)) - ((               -center.y)*FmlSin(Angle)));
pOut[2].y = center.y+(((              -center.x)*FmlSin(Angle)) + ((               -center.y)*FmlCos(Angle)));
pOut[3].x = center.x+(((bitmap.bmWidth-center.x)*FmlCos(Angle)) - ((               -center.y)*FmlSin(Angle)));
pOut[3].y = center.y+(((bitmap.bmWidth-center.x)*FmlSin(Angle)) + ((               -center.y)*FmlCos(Angle)));

/*
* Find new dimensions of image bonding rectangle
*/
minX = min(pOut[0].x, min(pOut[1].x, min (pOut[2].x, pOut[3].x)));
maxX = max(pOut[0].x, max(pOut[1].x, max (pOut[2].x, pOut[3].x)));
minY = min(pOut[0].y, min(pOut[1].y, min (pOut[2].y, pOut[3].y)));
maxY = max(pOut[0].y, max(pOut[1].y, max (pOut[2].y, pOut[3].y)));
maxX -= minX;
maxY -= minY; //Now maxX and maxY holds the bounding rectangle width and heigth

/*
* Translate rotated coordinates inside the bounding rectangle and
* normalize them to windows reversed y coordinates
*/
pOut[0].x -= minX;
pOut[0].y = bitmap.bmHeight - pOut[0].y - minY;
pOut[1].x -= minX;
pOut[1].y = bitmap.bmHeight - pOut[1].y - minY;
pOut[2].x -= minX;
pOut[2].y = bitmap.bmHeight - pOut[2].y - minY;

/*
* Create new bitmap that will holds the translated image
*/
hBmpDst = CreateCompatibleBitmap(hAnim->hDC[0],maxX, maxY);

/*
* Draw rotate image in the new bitmap
*/
OldSrc = SelectObject(hDcSrc, hBmp);
OldDst = SelectObject(hDcDst, hBmpDst);
BitBlt(hDcDst,0, 0, maxX, maxY, NULL, 0, 0, BLACKNESS);
PlgBlt(hDcDst, pOut, hDcSrc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, NULL, 0, 0);

/*
* Clean
*/
SelectObject(hDcSrc, OldSrc);
SelectObject(hDcDst, OldDst);
DeleteDC(hDcSrc);
DeleteDC(hDcDst);

return hBmpDst;
}

FML_EXCEPT(FmlRotateBmp);

return NULL;
}

I use triple buffering to avoid flikering.
To speedup the calculations I use a precomputed sine/cosine lookup table.
FML stands for Frankie's Multimedia Library.
« Last Edit: March 30, 2014, 06:23:18 PM by frankie »
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: gdi rotation problem
« Reply #2 on: March 30, 2014, 08:22:48 PM »
Silly example for PlgBlt()
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define _USE_MATH_DEFINES
#include <math.h>

static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static void RotatePoints(POINT points[], int angle, int width, int height);

static char *g_szAppName = "WTestBM";
static char *g_szFrameClass = "cWTestBM";
static HWND g_hFrame;
static HANDLE g_hInst;
HDC hDC;
HBITMAP hBM;
BITMAP bm;
POINT pts[3];
int angle;
UINT_PTR nIdEvent;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx;
MSG msg;

wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcx.lpfnWndProc = (WNDPROC) WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground= (HBRUSH)COLOR_APPWORKSPACE+1;
wcx.lpszMenuName = NULL;
wcx.lpszClassName= g_szFrameClass;
wcx.hIconSm = 0;

if (!RegisterClassEx(&wcx))
return 0;
g_hInst = hInstance;

g_hFrame = CreateWindowEx(0, g_szFrameClass, g_szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
300, 320,
NULL, NULL, g_hInst, NULL);
if(!g_hFrame) return 0;
ShowWindow(g_hFrame, nCmdShow);
UpdateWindow(g_hFrame);

while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}

static LRESULT CALLBACK WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
switch (wMsg)
{
case WM_TIMER:
{
HBITMAP hbmOld;
RotatePoints(pts, angle, bm.bmWidth, bm.bmHeight);
HDC hdcMem = CreateCompatibleDC(hDC);
hbmOld = SelectObject(hdcMem, hBM);
PlgBlt(hDC, pts, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, NULL, 0, 0);
DeleteDC(hdcMem);
angle += 6;
return 0;
}
case WM_CREATE:
{
hBM = (HBITMAP)LoadImage(GetModuleHandle(NULL), "WTestBM.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
GetObject(hBM, sizeof(bm), &bm);
nIdEvent = SetTimer(hWnd, 2, 100, NULL);
hDC = GetDC(hWnd);
return 0;
}
case WM_DESTROY:
KillTimer(hWnd, nIdEvent);
DeleteObject(hBM);
PostQuitMessage(0);
return (0);
}
return DefWindowProc(hWnd, wMsg, wParam, lParam);
}

static void RotatePoints(POINT points[], int angle, int width, int height)
{ // https://www.powerbasic.com/support/pbforums/showthread.php?t=46549
double dsin, dcos;
long cx, cy, ofs;
cx = width / 2;
cy = height / 2;
ofs = sqrt(width * width + height * height) / 2 - max(cx, cy);
dsin = sin(angle * M_PI/180); //sin(2 * M_PI * angle / 360);
dcos = cos(angle * M_PI/180); // cos(2 * M_PI * angle / 360);
// UL, UR, LL corners of source image
points[0].x = ofs + cx + (int)(-cx * dcos) - (-cy * dsin);
points[0].y = ofs + cy + (int)(-cx * dsin) + (-cy * dcos);
points[1].x = ofs + cx + (int)(cx * dcos) - (-cy * dsin);
points[1].y = ofs + cy + (int)(cx * dsin) + (-cy * dcos);
points[2].x = ofs + cx + (int)(-cx * dcos) - (cy * dsin);
points[2].y = ofs + cy + (int)(-cx * dsin) + (cy * dcos);
}
May the source be with you

laurro

  • Guest
Re: gdi rotation problem
« Reply #3 on: March 31, 2014, 12:39:07 AM »
and another one this time using gdi+
the code is two years old and may be bugy.
Note: don't use GetImageWidth\Height for wmf files. :(

@frankie
maybe you can give a try with this M$ cinderella
the results are much better than PlgBlt
Code: [Select]
#define UNICODE
#include <windows.h>
#include <wchar.h>
#define _USE_MATH_DEFINES
#include <math.h>

//gdi+
#pragma comment(lib,"gdiplus.lib")

#define WINGDIPAPI __stdcall

typedef enum {
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
} GpStatus, Status;

typedef enum {
DebugEventLevelFatal,
DebugEventLevelWarning
} DebugEventLevel;

typedef void (WINAPI * DebugEventProc) (DebugEventLevel level, char *message);

typedef struct GdiplusStartupInput {
UINT32 GdiplusVersion;
DebugEventProc DebugEventCallback;
BOOL SuppressBackgroundThread;
BOOL SuppressExternalCodecs;
}
GdiplusStartupInput;

typedef int (WINAPI * NotificationHookProc) (ULONG_PTR * token);
typedef void (WINAPI * NotificationUnhookProc) (ULONG_PTR token);

typedef struct GdiplusStartupOutput {
NotificationHookProc NotificationHook;
NotificationUnhookProc NotificationUnhook;
}
GdiplusStartupOutput;

GpStatus WINGDIPAPI GdiplusStartup(ULONG_PTR *token, const GdiplusStartupInput *input, GdiplusStartupOutput *output);
void WINGDIPAPI GdiplusShutdown(ULONG_PTR token);

#define BeginGdiPlus(t)\
GdiplusStartupInput start##t = { 1, NULL, FALSE, FALSE };\
GdiplusStartup(&(t), &start##t, NULL)

#define EndGdiPlus(t) GdiplusShutdown((t))

typedef enum {
ImageTypeUnknown,
ImageTypeBitmap,
ImageTypeMetafile
} ImageType;

typedef struct {
float m[5][5];
} ColorMatrix;

typedef enum {
InterpolationModeInvalid = -1,
InterpolationModeDefault = 0,
InterpolationModeLowQuality = 1,
InterpolationModeHighQuality = 2,
InterpolationModeBilinear = 3,
InterpolationModeBicubic = 4,
InterpolationModeNearestNeighbor = 5,
InterpolationModeHighQualityBilinear = 6,
InterpolationModeHighQualityBicubic = 7
} InterpolationMode;

typedef enum {
MatrixOrderPrepend = 0,
MatrixOrderAppend = 1
} GpMatrixOrder;

typedef enum {
ColorAdjustTypeDefault,
ColorAdjustTypeBitmap,
ColorAdjustTypeBrush,
ColorAdjustTypePen,
ColorAdjustTypeText,
ColorAdjustTypeCount,
ColorAdjustTypeAny
} ColorAdjustType;

typedef enum {
ColorMatrixFlagsDefault = 0,
ColorMatrixFlagsSkipGrays = 1,
ColorMatrixFlagsAltGray = 2
} ColorMatrixFlags;

typedef enum {
UnitWorld,
UnitDisplay,
UnitPixel,
UnitPoint,
UnitInch,
UnitDocument,
UnitMillimeter
} GpUnit, Unit;

typedef void GpGraphics, *Graphics;
typedef void GpImage, *Image;
typedef void GpImageAttributes, *ImageAttributes;

typedef BOOL(CALLBACK *ImageAbort) (void *);
typedef ImageAbort DrawImageAbort;

GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type);
GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, unsigned int *width);
GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, unsigned int *height);
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics);
GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, float dx, float dy, GpMatrixOrder order);
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics);
GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, float angle, GpMatrixOrder order);
GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics);
GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics, InterpolationMode interpolationMode);
GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, int x, int y, int width, int height);
GpStatus WINGDIPAPI GdipCreateImageAttributes(GpImageAttributes **imageattr);
GpStatus WINGDIPAPI GdipSetImageAttributesColorMatrix(GpImageAttributes *imageattr, ColorAdjustType type, BOOL enableFlag, const ColorMatrix *colorMatrix, const ColorMatrix *grayMatrix, ColorMatrixFlags flags);
GpStatus WINGDIPAPI GdipDrawImageRectRectI(GpGraphics *graphics, GpImage *image, int dstx, int dsty, int dstwidth, int dstheight, int srcx, int srcy, int srcwidth, int srcheight, GpUnit srcUnit, const GpImageAttributes *imageAttributes, DrawImageAbort callback, void *callbackData);
GpStatus WINGDIPAPI GdipDisposeImageAttributes(GpImageAttributes *imageattr);
GpStatus WINGDIPAPI GdipLoadImageFromFile(const wchar_t *filename, GpImage **image);
GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image);
//end gdi+ specifics


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int RotateImage(HDC, Image, int, int, int, int, RECT *, ColorMatrix *, InterpolationMode, int, BOOL);
int GetImageWidth(Image);
int GetImageHeight(Image);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };

ULONG_PTR token;
BeginGdiPlus(token);

wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = L"windowclassname";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

RegisterClass(&wc);
HWND hwnd = CreateWindow(wc.lpszClassName, L"title", WS_OVERLAPPEDWINDOW, 10, 10, 500, 500, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
EndGdiPlus(token);
return (int)msg.wParam;
}


__inline double get_angle(double ax, double ay, double bx, double by)
{
return atan2(by - ay, bx - ax) * 180.0 / M_PI;
}



LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static double angle;
static Image image;

switch (msg)
{
case WM_CREATE:
{
GdipLoadImageFromFile(L"test.jpg", &image);
if(!image)
{
MessageBox(hwnd, L"no test.jpg for me ?", L"error", 0);
return -1;
}
return 0;
}

case WM_MOUSEMOVE:
{
RECT rc;
GetClientRect(hwnd, &rc);
angle = get_angle(LOWORD(lParam), HIWORD(lParam), rc.right / 2, rc.bottom / 2);
InvalidateRect(hwnd, NULL, 0);
}
break;

case WM_RBUTTONDOWN:
{
}
break;

case WM_ERASEBKGND:
return 0;

case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
GetClientRect(hwnd, &rc);
HDC hdc = BeginPaint(hwnd, &ps);
HDC dc = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
SelectObject(dc, hBitmap);
PatBlt(dc, 0, 0, rc.right, rc.bottom, WHITENESS);

if (image)
{

RECT rect = { 9, 1, 1, 0 }; //call for help
RotateImage(dc, image, rc.right / 2, rc.bottom / 2, GetImageWidth(image), GetImageHeight(image), &rect, NULL, InterpolationModeBilinear, angle, FALSE);
MoveToEx(dc, rect.left, rect.top, NULL);
LineTo(dc, rect.right, rect.top);
LineTo(dc, rect.right, rect.bottom);
LineTo(dc, rect.left, rect.bottom);
LineTo(dc, rect.left, rect.top);

RotateImage(dc, image, rc.right / 2, rc.bottom / 2, GetImageWidth(image), GetImageHeight(image), NULL, NULL, InterpolationModeBilinear, angle, FALSE);
}


//if (image)
//{
//RotateImage(dc, image, rc.right / 2, rc.bottom / 2, GetImageWidth(image), GetImageHeight(image), NULL, NULL, InterpolationModeBilinear, angle, TRUE);
//}


//if (image)
//{
//ColorMatrix grayscale = { .299f, .299f, .299f, .0f, .0f, .587f, .587f, .587f, .0f, .0f, .114f, .114f, .114f, .0f, .0f, .0f, .0f, .0f, 1.0f, .0f, .0f, .0f, .0f, .0f, 1.0f };

//RotateImage(dc, image, rc.right / 2, rc.bottom / 2, GetImageWidth(image), GetImageHeight(image), NULL, &grayscale, InterpolationModeBilinear, angle, FALSE);
//}


//if (image)//clip
//{
//RECT rect = { 100, 100, 200, 100 };
//RotateImage(dc, image, rc.right / 2, rc.bottom / 2, 200, 100, &rect, NULL, InterpolationModeBilinear, angle, 1);
//}

BitBlt(hdc, 0, 0, rc.right, rc.bottom, dc, 0, 0, SRCCOPY);
DeleteDC(dc);
DeleteObject(hBitmap);
EndPaint(hwnd, &ps);
}
break;

case WM_DESTROY:
{
if(image)
GdipDisposeImage(image);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}



/////////////////////////////
int GetImageWidth(Image image)
{
UINT Width;
return ((GdipGetImageWidth(image, &Width) == 0) ? ((int)Width) : (-1));
}
//////////////////////////////
int GetImageHeight(Image image)
{
UINT Height;
return ((GdipGetImageHeight(image, &Height) == 0) ? ((int)Height) : (-1));
}
////////////////
int RotateImage(
                HDC                hdc,
                Image              image,
                int                centerX,
                int                centerY,
                int                dstWidth,
                int                dstHeight,
                RECT               *srcRect,
                ColorMatrix        *colorMatrix,
                InterpolationMode  interpolationMode,
            int                degree,
            BOOL               crop
                )
{
if ((dstWidth <= 0) || (dstHeight <= 0))
return 2;

float rad = (3.14159f * (float)degree) / 180.f;
float cosU = cosf(rad);
float sinU = sinf(rad);

float ptX = (dstWidth * cosU - dstHeight * sinU);
float ptY = (dstHeight * cosU + dstWidth * sinU);

if (srcRect && (srcRect->left == 9) && (srcRect->top == 1) && (srcRect->right == 1) && (srcRect->bottom == 0) && (crop == FALSE))
{
float pt1X = (-dstHeight * sinU);
float pt1Y = (dstHeight * cosU);
float pt3X = (dstWidth * cosU);
float pt3Y = (dstWidth * sinU);
float minX = min(0, min(pt1X, min(ptX, pt3X)));
float maxX = max(0, max(pt1X, max(ptX, pt3X)));
float minY = min(0, min(pt1Y, min(ptY, pt3Y)));
float maxY = max(0, max(pt1Y, max(ptY, pt3Y)));
int _w = (int)ceilf(maxX - minX);
int _h = (int)ceilf(maxY - minY);
srcRect->left = centerX - _w / 2;
srcRect->top = centerY - _h / 2;
srcRect->right = srcRect->left + _w;
srcRect->bottom = srcRect->top + _h;
return 911;
}

if ((!hdc) || (!image))
return 2;

if (srcRect && ((srcRect->left < 0) || (srcRect->top < 0) || (srcRect->right <= 0) || (srcRect->bottom <= 0)))
return 2;

int _mode = 0;
if ((interpolationMode < 0) || (interpolationMode > 7))
_mode = 0;
else
_mode = interpolationMode;

int status = 2;

Graphics graphics = NULL;

HDC dc = NULL;
HBITMAP bmp = NULL;
if (crop)
{
dc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc, dstWidth, dstHeight);
SelectObject(dc, bmp);
BitBlt(dc, 0, 0, dstWidth, dstHeight, hdc, centerX - dstWidth / 2, centerY - dstHeight / 2, SRCCOPY);
status = GdipCreateFromHDC(dc, &graphics);
}
else
{
status = GdipCreateFromHDC(hdc, &graphics);
}
if (status != 0)
{
if (crop)
{
DeleteDC(dc);
DeleteObject(bmp);
}
return status;
} //->

if (crop)
{
status = GdipTranslateWorldTransform(graphics, dstWidth / 2 - ptX / 2, dstHeight / 2 - ptY / 2, 0);
}
else
{
status = GdipTranslateWorldTransform(graphics, centerX - ptX / 2, centerY - ptY / 2, 0);
}
if (status != 0)
{
if (crop)
{
DeleteDC(dc);
DeleteObject(bmp);
}
GdipDeleteGraphics(graphics);
return status;
} //->

status = GdipRotateWorldTransform(graphics, (float)degree, 0);
if (status != 0)
{
if (crop)
{
DeleteDC(dc);
DeleteObject(bmp);
}
GdipDeleteGraphics(graphics);
return status;
} //->

GdipSetInterpolationMode(graphics, _mode);

ImageType type = 0;
status = GdipGetImageType(image, &type);
if (status != 0)
{
if (crop)
{
DeleteDC(dc);
DeleteObject(bmp);
}
GdipDeleteGraphics(graphics);
return status;
} //->

switch (type)
{
case 0:
{
GdipResetWorldTransform(graphics);
GdipDeleteGraphics(graphics);
if (crop)
{
DeleteDC(dc);
DeleteObject(bmp);
}
return 13;
}

case 2: //metafiles
{
status = GdipDrawImageRectI(graphics, image, 0, 0, dstWidth, dstHeight);
GdipResetWorldTransform(graphics);
GdipDeleteGraphics(graphics);
if (crop)
{
BitBlt(hdc, centerX - dstWidth / 2, centerY - dstHeight / 2, dstWidth, dstHeight, dc, 0, 0, SRCCOPY);
DeleteDC(dc);
DeleteObject(bmp);
}
return status;
} //metafiles

case 1: //bitmaps
{
if (srcRect == NULL)
{
if (colorMatrix != NULL)
{
ImageAttributes imageattr = NULL;
GdipCreateImageAttributes(&imageattr);
GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeBitmap, TRUE, colorMatrix, NULL, FALSE);
status = GdipDrawImageRectRectI(graphics, image, 0, 0, dstWidth, dstHeight, 0, 0, GetImageWidth(image), GetImageHeight(image), 2, imageattr, NULL, NULL);
GdipDisposeImageAttributes(imageattr);
}
else
{
status = GdipDrawImageRectRectI(graphics, image, 0, 0, dstWidth, dstHeight, 0, 0, GetImageWidth(image), GetImageHeight(image), 2, NULL, NULL, NULL);
}
GdipResetWorldTransform(graphics);
GdipDeleteGraphics(graphics);
if (crop)
{
BitBlt(hdc, centerX - dstWidth / 2, centerY - dstHeight / 2, dstWidth, dstHeight, dc, 0, 0, SRCCOPY);
DeleteDC(dc);
DeleteObject(bmp);
}
return status;
}

else
{
if (colorMatrix != NULL)
{
ImageAttributes imageattr = NULL;
GdipCreateImageAttributes(&imageattr);
GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeBitmap, TRUE, colorMatrix, NULL, FALSE);
status = GdipDrawImageRectRectI(graphics, image, 0, 0, dstWidth, dstHeight, srcRect->left, srcRect->top, srcRect->right, srcRect->bottom, 2, imageattr, NULL, NULL);
GdipDisposeImageAttributes(imageattr);
}
else
{
status = GdipDrawImageRectRectI(graphics, image, 0, 0, dstWidth, dstHeight, srcRect->left, srcRect->top, srcRect->right, srcRect->bottom, 2, NULL, NULL, NULL);
}
GdipResetWorldTransform(graphics);
GdipDeleteGraphics(graphics);
if (crop)
{
BitBlt(hdc, centerX - dstWidth / 2, centerY - dstHeight / 2, dstWidth, dstHeight, dc, 0, 0, SRCCOPY);
DeleteDC(dc);
DeleteObject(bmp);
}
return status;

}
}
break; //bitmaps
} //switch
return status;
}



Laur