MFC doc / view架构,GDI绘图/打印。我有一个需要显示和打印的DIB后备缓冲区。
经过漫长而痛苦的道路后,我得出结论,而不是我需要使用CreateDIBSection创建的DIB(而不是使用CreateCompatibleBitmap创建的DDB),我必须使用StretchDIBits(而不是StretchBlt)将其blit到打印机DC上。 / p>
但是我无法让这件事发挥作用。
以下是我的工作:
在我的初始化例程中,我设置了后备缓冲区,如下所示:
// 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);
}
然后我计算后备缓冲区中相应的矩形坐标,它通常(比)大得多。这个计算的细节在这里是无关紧要的,我只是说
CRect rectClipBoxBackBuffer;
表示后备缓冲区的相应矩形(在后备缓冲区的像素坐标中)。
然后我使用_pMemDc memory dc。
绘制我的后备缓冲区最后出现了我遇到麻烦的部分:将我的DIB打到目标直流(屏幕或打印机)上。这是我的工作:
// 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。请注意,我首先暂时从存储器DC中取消选择DIB,以便它不与任何直流相关联。然后我使用StretchDIBits,但事情就是行不通!输出搞砸了,就像我给出了不正确的坐标一样,区域从它们应该被绘制的位置被抽出,有时甚至是全黑的。所以我必须遗漏一些东西(也许是非常微不足道的东西)。救命!我尝试更改rectClipBoxBackBuffer.top和bitmapInfo.bmiHeader.biHeight的符号,结果发生了变化,但没有任何效果。
我做错了什么?
答案 0 :(得分:0)
如果要使用StretchDIBits,请不要选择DIB进/出DC。 DC只能包含DDB位图,如果你提供DIB,DC会转换它。
答案 1 :(得分:0)
Microsoft关于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);
P.S。:现在它适用于屏幕绘图和打印预览,但实际打印失败,这是我在此讨论的原始问题:How to print DIB backbuffer on printer - GDI, MFC