在使用MFC时,似乎在绘制PixelFormat8bppIndexed
时出现了问题。
示例PixelFormat8bppIndexed
:
使用其他格式都可以。
我认为问题出在
(*pBitmapInfo)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
(*pBitmapInfo)->bmiHeader.biBitCount = 8;
(*pBitmapInfo)->bmiHeader.biCompression = BI_RGB;
(*pBitmapInfo)->bmiHeader.biWidth = (*width);
(*pBitmapInfo)->bmiHeader.biHeight = (*height);
(*pBitmapInfo)->bmiHeader.biPlanes = 1;
(*pBitmapInfo)->bmiHeader.biSizeImage = ((*width) * (*height) * 1);
(*pBitmapInfo)->bmiHeader.biClrUsed = 256;
(*pBitmapInfo)->bmiHeader.biClrImportant = 0;
for (int i = 0; i < 256; i++)
{
(*pBitmapInfo)->bmiColors[0].rgbBlue = i;
(*pBitmapInfo)->bmiColors[0].rgbRed = i;
(*pBitmapInfo)->bmiColors[0].rgbGreen = i;
(*pBitmapInfo)->bmiColors[0].rgbReserved = 0;
}
该如何解决?
代码:
void ConvertImage(WCHAR *filename, Gdiplus::PixelFormat pixelformat, BITMAPINFO** pBitmapInfo, void** imageData, int* width, int* height)
{
#pragma region GDI+
*pBitmapInfo = new BITMAPINFO();
ULONG written;
LARGE_INTEGER zero;
zero.QuadPart = 0;
ULARGE_INTEGER liSize;
Gdiplus::GdiplusStartupInput tmp;
ULONG_PTR token;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
Gdiplus::Bitmap *image = Gdiplus::Bitmap::FromFile(filename, false);
Gdiplus::Bitmap* destination = image->Clone(0, 0, image->GetWidth(), image->GetHeight(),
pixelformat);
CLSID clsid_bmp;
CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid_bmp);
IStream *stream = NULL;
HRESULT hr = CreateStreamOnHGlobal(0, TRUE, &stream);
if (!SUCCEEDED(hr))
printf("problems");
destination->Save(stream, &clsid_bmp);
IStream_Size(stream, &liSize);
stream->Seek(zero, STREAM_SEEK_SET, NULL);
unsigned char *info = new unsigned char[liSize.QuadPart];
stream->Read(info, liSize.QuadPart, &written);
BYTE *outImageData = new BYTE[(liSize.QuadPart - 54)];
memcpy(outImageData, info + 54, (liSize.QuadPart - 54));
*width = *(int*)&info[18];
*height = *(int*)&info[22];
switch (pixelformat)
{
case PixelFormat32bppARGB:
(*pBitmapInfo)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
(*pBitmapInfo)->bmiHeader.biBitCount = 32;
(*pBitmapInfo)->bmiHeader.biCompression = BI_RGB;
(*pBitmapInfo)->bmiHeader.biWidth = *width;
(*pBitmapInfo)->bmiHeader.biHeight = *height;
(*pBitmapInfo)->bmiHeader.biPlanes = 1;
(*pBitmapInfo)->bmiHeader.biSizeImage = ((*width) * (*height) * 4);
break;
case PixelFormat24bppRGB:
(*pBitmapInfo)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
(*pBitmapInfo)->bmiHeader.biBitCount = 24;
(*pBitmapInfo)->bmiHeader.biCompression = BI_RGB;
(*pBitmapInfo)->bmiHeader.biWidth = *width;
(*pBitmapInfo)->bmiHeader.biHeight = *height;
(*pBitmapInfo)->bmiHeader.biPlanes = 1;
(*pBitmapInfo)->bmiHeader.biSizeImage = ((*width) * (*height) * 3);
break;
case PixelFormat16bppRGB555:
(*pBitmapInfo)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
(*pBitmapInfo)->bmiHeader.biBitCount = 16;
(*pBitmapInfo)->bmiHeader.biCompression = BI_RGB;
(*pBitmapInfo)->bmiHeader.biWidth = *width;
(*pBitmapInfo)->bmiHeader.biHeight = *height;
(*pBitmapInfo)->bmiHeader.biPlanes = 1;
(*pBitmapInfo)->bmiHeader.biSizeImage = ((*width) * (*height) * 2);
break;
case PixelFormat8bppIndexed:
(*pBitmapInfo)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
(*pBitmapInfo)->bmiHeader.biBitCount = 8;
(*pBitmapInfo)->bmiHeader.biCompression = BI_RGB;
(*pBitmapInfo)->bmiHeader.biWidth = (*width);
(*pBitmapInfo)->bmiHeader.biHeight = (*height);
(*pBitmapInfo)->bmiHeader.biPlanes = 1;
(*pBitmapInfo)->bmiHeader.biSizeImage = ((*width) * (*height) * 1);
(*pBitmapInfo)->bmiHeader.biClrUsed = 256;
(*pBitmapInfo)->bmiHeader.biClrImportant = 0;
for (int i = 0; i < 256; i++)
{
(*pBitmapInfo)->bmiColors[0].rgbBlue = i;
(*pBitmapInfo)->bmiColors[0].rgbRed = i;
(*pBitmapInfo)->bmiColors[0].rgbGreen = i;
(*pBitmapInfo)->bmiColors[0].rgbReserved = 0;
}
break;
}
*imageData = outImageData;
delete destination;
delete image;
delete[]info;
Gdiplus::GdiplusShutdown(token);
#pragma endregion
}
void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
CMFCApplicationColorsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
BITMAPINFO* pBitmapInfo = NULL;
void *imageData = NULL;
int *width = new int;
int *height = new int;
ConvertImage(L"E:\TestImage.bmp", PixelFormat8bppIndexed, &pBitmapInfo, &imageData, width, height);
//ConvertImage(L"E:\TestImage.bmp", PixelFormat16bppRGB555, &pBitmapInfo, &imageData, width, height);
::StretchDIBits(pDC->GetSafeHdc(), 0, 0, *width, *height, 0, 0, *width, *height, imageData, pBitmapInfo, DIB_PAL_COLORS, SRCCOPY);
delete[] imageData;
delete pBitmapInfo;
delete width;
delete height;
// TODO: add draw code for native data here
}
答案 0 :(得分:2)
Gdiplus::GetHBITMAP
允许直接检索HBITMAP
。在大多数情况下,这足以在GDI +中使用GDI功能。
如果由于某种原因必须使用StretchDIBits
,则首先使用GetDIBits
来检索bits
和BITMAPINFO
为BITMAPINFO
分配内存时,请确保为调色板添加额外的内存,以防使用8位位图:
sizeof(BITMAPINFO) + palettesize
您还可以使用帮助器类gdiplus_init
确保始终调用启动/关闭。
#include <vector>
...
class gdiplus_init
{
ULONG_PTR token;
public:
gdiplus_init()
{
Gdiplus::GdiplusStartupInput tmp;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
}
~gdiplus_init()
{
Gdiplus::GdiplusShutdown(token);
}
};
bool getbits(const wchar_t *filename, Gdiplus::PixelFormat pixelformat,
std::vector<BYTE> &bitmapinfo, std::vector<BYTE> &bits, int &w, int &h)
{
gdiplus_init init;
WORD bpp = 0;
int usage = DIB_RGB_COLORS;
int palettesize = 0;
switch(pixelformat)
{
case PixelFormat8bppIndexed:
bpp = 8;
usage = DIB_PAL_COLORS;
palettesize = 256 * sizeof(RGBQUAD);
break;
case PixelFormat16bppRGB555: bpp = 16; break;
case PixelFormat16bppRGB565: bpp = 16; break;
case PixelFormat24bppRGB: bpp = 24; break;
case PixelFormat32bppRGB: bpp = 32; break;
default:return false;
}
auto src = Gdiplus::Bitmap::FromFile(filename);
if(src->GetLastStatus() != Gdiplus::Status::Ok)
return false;
auto dst = src->Clone(0, 0, src->GetWidth(), src->GetHeight(),
pixelformat);
w = src->GetWidth();
h = src->GetHeight();
HBITMAP hbitmap;
Gdiplus::Color color;
dst->GetHBITMAP(color, &hbitmap);
//allocate enough memory for bitmapinfo and initialize to zero
//it's sizeof BITMAPINFO structure + size of palette
bitmapinfo.resize(sizeof(BITMAPINFO) + palettesize, 0);
//fill the first 6 parameters
BITMAPINFO* ptr = (BITMAPINFO*)bitmapinfo.data();
ptr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //don't skip
ptr->bmiHeader.biWidth = w;
ptr->bmiHeader.biHeight = h;
ptr->bmiHeader.biPlanes = 1;
ptr->bmiHeader.biBitCount = bpp;
ptr->bmiHeader.biCompression = BI_RGB;
//magic formula to calculate the size:
//this is roughly w * h * bytes_per_pixel, it's written this way
//to account for "bitmap padding"
DWORD size = ((w * bpp + 31) / 32) * 4 * h;
//allocate memory for image
bits.resize(size, 0);
//finally call GetDIBits to fill bits and bitmapinfo
HDC hdc = GetDC(0);
GetDIBits(hdc, hbitmap, 0, h, &bits[0], (BITMAPINFO*)&bitmapinfo[0], usage);
ReleaseDC(0, hdc);
//cleanup
delete src;
delete dst;
return true;
}
void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
...
std::vector<BYTE> bi; //automatic storage
std::vector<BYTE> bits;
int w, h;
//24-bit test
if(getbits(L"c:\\test\\24bit.bmp", PixelFormat24bppRGB, bi, bits, w, h))
StretchDIBits(dc, 0, 0, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_RGB_COLORS, SRCCOPY);
//8-bit test
if(getbits(L"c:\\test\\8bit.bmp", PixelFormat8bppIndexed, bi, bits, w, h))
StretchDIBits(dc, 0, 220, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_PAL_COLORS, SRCCOPY);
}