ID: Q186589
The information in this article applies to:
While the Windows GDI provides numerous functions that allow developers to display bitmaps into rectangular areas, it doesn't provide a way to display into areas defined by an arbitrary set of vertices. The sample code in this article demonstrates a simple way to map a bitmap from a rectangular area into an area defined by four vertices. You can use this technique to rotate, invert, stretch, or twist a bitmap.
NOTE: For simplicity, the code is written to use GetPixel() and SetPixel() to retrieve and set pixel values in the referenced display contexts. You can achieve much greater performance by rewriting the code to use DIB sections and directly manipulating the bits of the surface.
#define SHIFTS 15 // Extend ints to limit round-off error.
#define THRESH (1 << SHIFTS) // Threshold for pixel size value.
/* CopySourceToDest()
*
* Re-map a rectangular area into an area defined by four vertices.
*
* This function does all the real re-mapping work by recursively
* dividing both the source and destination areas until the
* area specified by the destination is a single pixel. At this
* point, it copies the pixel from the source to the destination.
*
* By quartering both the source and the destination areas, the
* relationship between the area in the source and the area in the
* destination is preserved.
*
* NOTES:
* This function would be much faster if it were implemented to
* directly manipulate the surface bits of a DIB section rather than
* using GetPixel() / SetPixel().
*/
void CopySourceToDest(HDC hdcDst, POINT ul, POINT ur, POINT lr,
POINT ll, HDC hdcSrc, LONG x1, LONG y1,
LONG x2, LONG y2)
{
POINT tm,lm,rm,bm,m;
LONG mx,my;
// Does the destination area specify a single pixel?
if ((abs(ul.x - ur.x) < THRESH) &&
(abs(ul.x - lr.x) < THRESH) &&
(abs(ul.x - ll.x) < THRESH) &&
(abs(ul.y - ur.y) < THRESH) &&
(abs(ul.y - lr.y) < THRESH) &&
(abs(ul.y - ll.y) < THRESH))
{ // Yes.
COLORREF cr;
cr = GetPixel(hdcSrc, (x1 >> SHIFTS), (y1 >> SHIFTS));
SetPixel(hdcDst, (ul.x >> SHIFTS), (ul.y >> SHIFTS), cr);
} else { // No
// Quarter the source and the destination, and then recurse.
tm.x = (ul.x + ur.x) >> 1;
tm.y = (ul.y + ur.y) >> 1;
bm.x = (ll.x + lr.x) >> 1;
bm.y = (ll.y + lr.y) >> 1;
lm.x = (ul.x + ll.x) >> 1;
lm.y = (ul.y + ll.y) >> 1;
rm.x = (ur.x + lr.x) >> 1;
rm.y = (ur.y + lr.y) >> 1;
m.x = (tm.x + bm.x) >> 1;
m.y = (tm.y + bm.y) >> 1;
mx = (x1 + x2) >> 1;
my = (y1 + y2) >> 1;
CopySourceToDest(hdcDst, ul, tm, m, lm, hdcSrc, x1, y1,
mx, my);
CopySourceToDest(hdcDst, tm, ur, rm, m, hdcSrc, mx, y1,
x2, my);
CopySourceToDest(hdcDst, m, rm, lr, bm, hdcSrc, mx, my,
x2, y2);
CopySourceToDest(hdcDst, lm, m, bm, ll, hdcSrc, x1, my,
mx, y2);
};
};
/* WarpBlt()
*
* Re-map a rectangular area into an area defined by four vertices .
*
*/
void WarpBlt(HDC hdcDst, POINT ul, POINT ur, POINT lr, POINT ll,
HDC hdcSrc, LONG x1, LONG y1, LONG x2, LONG y2)
{
// Shift all values to help reduce round-off error.
ul.x <<= SHIFTS;
ul.y <<= SHIFTS;
ur.x <<= SHIFTS;
ur.y <<= SHIFTS;
lr.x <<= SHIFTS;
lr.y <<= SHIFTS;
ll.x <<= SHIFTS;
ll.y <<= SHIFTS;
x1 <<= SHIFTS;
y1 <<= SHIFTS;
x2 <<= SHIFTS;
y2 <<= SHIFTS;
CopySourceToDest(hdcDst, ul, ur, lr, ll,
hdcSrc, x1, y1, x2, y2);
}
/* DemonstrateWarpBlt()
*
* Re-map the image of the entire screen into an area
* defined by four random vertices .
*
*/
void DemonstrateWarpBlt(HWND hWnd)
{
HDC hdcScreen = GetDC(NULL); // Source DC.
HDC hdcWindow = GetDC(hWnd); // Destination DC.
POINT ul,ur,lr,ll; // Vertices for the destination area.
int iXRes, iYRes; // Extents of the screen.
RECT rc; // Extents of the window.
// Get the size of the screen.
iXRes = GetDeviceCaps(hdcScreen, HORZRES);
iYRes = GetDeviceCaps(hdcScreen, VERTRES);
// Get the size of our client area.
GetClientRect(hWnd, &rc);
// Define a random destination area that fits in the client area.
ul.x = rand() % rc.right;
ul.y = rand() % rc.bottom;
ur.x = rand() % rc.right;
ur.y = rand() % rc.bottom;
lr.x = rand() % rc.right;
lr.y = rand() % rc.bottom;
ll.x = rand() % rc.right;
ll.y = rand() % rc.bottom;
// Copy the entire screen into the destination area.
WarpBlt(hdcWindow, ul, ur, lr, ll,
hdcScreen, 0, 0, iXRes, iYRes);
}
Additional query words: kbDSupport kbdsd kbGDI kbBitmap kbDevContext
kbDisplay
Keywords : kbcode
Version : WINNT:
Platform : winnt
Issue type : kbhowto
Last Reviewed: June 2, 1998