Невозможно реализовать печать DIB с помощью GDI (MFC) - PullRequest
0 голосов
/ 27 января 2012

MFC документ / вид архитектуры, GDI рисунок / печать.У меня есть буфер DIB, который мне нужно отобразить и напечатать.

После долгой и мучительной дороги я пришел к выводу, что мне нужно использовать DIB, созданный с помощью CreateDIBSection (а не DDB, созданный с помощью CreateCompatibleBitmap), и у меня естьперетащить его на принтер постоянного тока с помощью StretchDIBits (а не StretchBlt).

Но я не могу заставить эту вещь работать.

Вот что я делаю:

В моей подпрограмме инициализации я установил backbuffer, как это:

// 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);
}

Затем я вычисляю соответствующие прямоугольные координаты в моем буфере, которыйобычно (намного) больше, чем DC.Детали этого вычисления здесь не имеют значения, я просто говорю, что

CRect rectClipBoxBackBuffer;

представляет соответствующий прямоугольник backbuffer (в пиксельных координатах backbuffer).

Затем я рисую на свой backbuffer, используя_pMemDc memory 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, результаты изменились, но ничего не работает, как должно.

Что я делаю не так ?? *

Ответы [ 2 ]

0 голосов
/ 29 января 2012

Документация 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 .: Теперь он работает для рисования экрана и предварительного просмотра, но не для реальной печати, о чем я и говорил в своей первоначальной проблеме: Как напечатать буфер DIB на принтере - GDI, MFC

0 голосов
/ 28 января 2012

Не выбирайте DIB на вход / выход DC, если вы собираетесь использовать StretchDIBits. DC может содержать только битовую карту DDB, если вы предоставите DIB, DC преобразует его.

...