MFC文档/视图架构,GDI绘图/打印。我有一个DIB后台缓冲区,我需要显示和打印。
经过漫长而痛苦的过程后,我得出的结论是,我需要使用由CreateDIBSection创建的DIB (而不是使用CreateCompatibleBitmap创建的DDB ),并且我必须使用StretchDIBits (而不是StretchBlt)将其写入打印机dc。
但我没法让这玩意儿动起来。
下面是我要做的:
在我的初始化例程中,我设置了后台缓冲区,如下所示:
// Prepare device context:
CClientDC aDC(this);
OnPrepareDC(&aDC);
// Setup proper backbuffer:
_pMemDc = new CDC;
_pMemDc->CreateCompatibleDC(&aDC);
memset(&_bitmapInfo, 0, sizeof(BITMAPINFO));
_bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
_bitmapInfo.bmiHeader.biWidth = _sizeBackBuffer.cx;
_bitmapInfo.bmiHeader.biHeight = -_sizeBackBuffer.cy; // top-down
_bitmapInfo.bmiHeader.biPlanes = 1;
_bitmapInfo.bmiHeader.biBitCount = 24; // Maybe 32?
_bitmapInfo.bmiHeader.biCompression = BI_RGB;
HANDLE hMemBitmap = CreateDIBSection(aDC.GetSafeHdc(), &_bitmapInfo, DIB_RGB_COLORS, (void**)&_pBitmapRawBits, 0, 0);
_hOldSelBitmap = (HBITMAP)_pMemDc->SelectObject(hMemBitmap);带下划线的变量是(私有)成员变量,声明如下:
CDC *_pMemDc; // Backbuffer memory dc
HBITMAP _hOldSelBitmap;
BITMAPINFO _bitmapInfo; // Backbuffer DIB (header-only)
unsigned char *_pBitmapRawBits; // Pointer to pixel data of DIB
SIZE _sizeBackBuffer; // Size of backbuffer, i.e. size of that DIB下面是我在OnDraw覆盖中所做的事情:
首先,我将绘制的区域如下所示(简化代码):
CRect rectClipBoxPlayground;
if (pDC->IsPrinting())
{
rectClipBoxPlayground = _printingParams.pPrintInfo->m_rectDraw;
}
else
{
pDC->GetClipBox(&rectClipBoxPlayground);
}然后,我在后台缓冲区中计算相应的rect坐标,它通常比DC大得多。这个计算的细节在这里无关紧要,我只想说
CRect rectClipBoxBackBuffer;表示后台缓冲区的相应矩形(在后台缓冲区的像素坐标中)。
然后,我使用_pMemDc内存dc绘制我的后台缓冲区。
最后是我遇到麻烦的地方:把我的DIB传输到目标dc (屏幕或打印机)。下面是我要做的:
// Copy back buffer to screen/printer dc:
pDC->SetStretchBltMode(HALFTONE);
SetBrushOrgEx(pDC->GetSafeHdc(), 0, 0, 0);
// BELOW COMMENTED CODE OF StretchBlt WORKS(!) INSTEAD OF StretchDIBits.
//
//BOOL bSuccess = pDC->StretchBlt(rectClipBoxPlayground.left, rectClipBoxPlayground.top,
// rectClipBoxPlayground.Width(), rectClipBoxPlayground.Height(),
// _pMemDc, rectClipBoxBackBuffer.left, rectClipBoxBackBuffer.top,
// rectClipBoxBackBuffer.Width(), rectClipBoxBackBuffer.Height(), SRCCOPY);
HBITMAP hMemBitmap = (HBITMAP)_pMemDc->SelectObject(_hOldSelBitmap);
DWORD dwLines = StretchDIBits(pDC->GetSafeHdc(),
rectClipBoxPlayground.left, rectClipBoxPlayground.top, rectClipBoxPlayground.Width(), rectClipBoxPlayground.Height(),
rectClipBoxBackBuffer.left, rectClipBoxBackBuffer.top, rectClipBoxBackBuffer.Width(), rectClipBoxBackBuffer.Height(),
_pBitmapRawBits, &_bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
_pMemDc->SelectObject(hMemBitmap);问题是,StretchBlt的注释掉的代码可以完美地工作(除了在一些打印机上打印),但是我不能使用它,因为一些打印机对它有问题。所以我必须使用StretchDIBits。请注意,我首先暂时从DIB的内存dc中取消选择,这样它就不会与任何dc关联。然后我使用了StretchDIBits,但就是不能工作!输出是混乱的,就像我给出了错误的坐标一样,区域的绘制偏离了它们应该绘制的位置,有时完全是黑色的。所以我一定遗漏了一些东西(可能是非常微不足道的东西)。帮助!我尝试更改rectClipBoxBackBuffer.top和bitmapInfo.bmiHeader.biHeight的符号,结果发生了变化,但没有任何东西像它应该的那样工作。
我做错了什么??
发布于 2012-01-29 04:01:06
微软关于StretchDIBits的文档是完全错误的。我发现Y轴的方向必须改变。现在,以下代码可以正常工作:
// Copy back buffer to screen dc:
pDC->SetStretchBltMode(HALFTONE);
SetBrushOrgEx(pDC->GetSafeHdc(), 0, 0, 0);
HBITMAP hMemBitmap = (HBITMAP)_pMemDc->SelectObject(_hOldSelBitmap);
DWORD dwLines = StretchDIBits(pDC->GetSafeHdc(),
rectClipBoxPlayground.left, rectClipBoxPlayground.top, rectClipBoxPlayground.Width(), rectClipBoxPlayground.Height(),
rectClipBoxBackBuffer.left, _sizeBackBuffer.cy - rectClipBoxBackBuffer.top - rectClipBoxBackBuffer.Height(), rectClipBoxBackBuffer.Width(), rectClipBoxBackBuffer.Height(),
_pBitmapRawBits, &_bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
_pMemDc->SelectObject(hMemBitmap);附言:现在它可以用于屏幕绘图和打印预览,但在实际打印时失败,这是我在这里讨论的原始问题:How to print DIB backbuffer on printer - GDI, MFC
发布于 2012-01-29 01:24:43
如果要使用StretchDIBits,请不要选择DIB into/out DC。DC只能包含DDB位图,如果您提供DIB,DC将对其进行转换。
https://stackoverflow.com/questions/9030747
复制相似问题