-
>i think the above posts explain it pretty well...
>hDC = GetDC(hwnd);
I tried all that. :(
I also searched for example code written by other people, but nothing worked. What I ever I did, it would fail one in 20 times or so.
I do read the manuals. Whatever was wrong with my code, it was something subtle that I couldn't figure out.
-
what do you mean it would fail one in 20 times?
does it compile?
-
>does it compile?
Of course. And it ran. And it worked - 1 in 20 times. But when it failed, GetDIBits would return invalid colour values in around half the image.
I tried other's people code which was doing exactly the same thing I was, and that had the same problem. I have no issues with stability on my machine (i.e. no graphic card problems).
Withouta really proper understanding of what was going on, and how the API was being used (which I have been unable to get from MSDN), I was unable to find a solution.
In the end, I resolved my problem by calling a third party API, which I guess just wrapped GetDIBits, but it worked. So it must have been something wrong with what I was doing.
Here was my code. Although I got my application to work now, I would still be interested to know what I did wrong.
Code:
int Gfx::create(Gfx& dst, void* src, int y, int cnt)
{
// (this code DOES NOT seem to work reliably)
// Creates gfx data and fills it with contents of bitmap from
// platform specific bitmap object src. At the moment, this method
// only works under windows. Does nothing under any other platform.
// If this method fails, rslt.data is NULL(0) & returns
// platform specific error code. Error is -1 if operation
// is not supported on platform.
int err;
if (y < 0) y = 0;
// Ensure existing is destroyed.
destroy(dst);
#ifdef AIDAWIN
// WINDOWS IMPLEMENTATION
// src must not be 'selected into a device'
err = 0;
HDC hdc = 0;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
try
{
// Make temporary compatible device
hdc = GetDC(0); // CreateCompatibleDC
GdiFlush();
// Get dimensions first
GetDIBits(hdc, (HBITMAP)src, 0, 0, 0, &bmi, DIB_RGB_COLORS);
// We always want positive height (bottom up bmp)
bmi.bmiHeader.biHeight = abs(bmi.bmiHeader.biHeight);
// Work out full size count if needed
if (cnt <= 0) cnt = bmi.bmiHeader.biHeight - y;
// Fill data
dst.pDim.x = bmi.bmiHeader.biWidth;
dst.pDim.y = cnt;
// Check we can handle range
err = ERROR_INVALID_PARAMETER;
if (y + cnt <= bmi.bmiHeader.biHeight && cnt > 0)
{
// Set pixel format to be retrieved
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
** HERE sz includes packing bytes
int sz = dst.rowsz() * dst.pDim.y;
if (sz > 0)
{
// Create memory array
dst.pData = new char[sz];
** HERE GetDiBits
err = 0;
if (GetDIBits(hdc, src, y, cnt, dst.pData,
&bmi, DIB_RGB_COLORS) == 0)
{
// Error - destroy memory and
// error code will be set below
destroy(dst);
ShowMessage("Y " + IntToStr(y));
ShowMessage("CNT : " +IntToStr(cnt));
throw Exception("Error " + IntToStr(GetLastError()));
}
}
}
// If no data - set error code
if (dst.pData == 0)
{
dst.pDim = Axy();
if (err == 0) err = GetLastError();
}
// Free temporary device context
ReleaseDC(0, hdc);
}
catch(...)
{
// Clean-up
destroy(dst);
ReleaseDC(hdc);
throw;
}
#else
// NOT SUPPORTED
err = -1;
#endif
return err;
}
-
Davros: I can't explain your problem, and I have no intention of reading through your code since I don't remember what parameters do what, and have no desire to read the documentations again ;) But I did use GetDIBits once when I was trying to generate rotated bitmaps for my GDI graphics library, and never had any problems with it; if you care, you can sift through this and see if anything helps:
Code:
HBITMAP GFX::getRotatedBmp(HBITMAP orig, double angle, int rPointX, int rPointY)
{
if(orig == NULL)
return NULL;
HBITMAP img;
HDC dcSrc = CreateCompatibleDC(dcFront);
RECT bounds = getBmpDimensions(orig);
int width = bounds.right + 1;
int height = bounds.bottom + 1;
img = CreateCompatibleBitmap(dcFront, width, height);
BITMAPINFO bi = {0};
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = width;
bi.bmiHeader.biHeight = height;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
unsigned char* srcBits = new unsigned char[4 * width * height];
if(!GetDIBits(dcSrc, orig, 0, height, srcBits, &bi, DIB_RGB_COLORS))
{
delete[] srcBits;
return NULL;
}
unsigned char* destBits = new unsigned char[4 * width * height];
float sine = (float)sin(angle), cosine = (float)cos(angle); //Store result to save time
float cX = (float)rPointX, cY = (float)(bounds.bottom - rPointY); //Typecast & convert from normal coords
float tempX, tempY; //Offset on source to centre the image
tempX = (cX*(cosine-1) - cY*sine);
tempY = (cY*(cosine-1) + cX*sine);
int origX, origY;
unsigned char* destLine = destBits;
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
origX = (int)(((float)x + tempX)*cosine + ((float)y + tempY)*sine);
origY = (int)(((float)y + tempY)*cosine - ((float)x + tempX)*sine);
if(origX >= 0 && origY >= 0 && origX < bounds.right && origY < bounds.bottom)
{
destLine[(x << 2) ] = srcBits[((origX + width*origY) << 2) ];
destLine[(x << 2) + 1] = srcBits[((origX + width*origY) << 2) + 1];
destLine[(x << 2) + 2] = srcBits[((origX + width*origY) << 2) + 2];
}
else
{
destLine[(x << 2) ] = 0;
destLine[(x << 2) + 1] = 0;
destLine[(x << 2) + 2] = 0;
}
}
destLine += (width << 2);
}
SetDIBits(dcSrc, img, 0, height, destBits, &bi, DIB_RGB_COLORS);
DeleteDC(dcSrc);
delete[] srcBits;
delete[] destBits;
return img;
}
-
>I have no intention of reading through your code
I can understand that. I did try simplifying my code in a previous post, but found I made so many typo errors in the simplification, that it made the effort pointless.
>if you care, you can sift through this and see if anything helps
Thanks. I will do so.
Cheers for the reply.