Как напечатать буфер DIB на принтере - GDI, MFC - PullRequest
1 голос
/ 26 января 2012

Я использую архитектуру doc / view MFC для реализации печати.Я использую двойную буферизацию, все рисую на свой буфер, который является битовой картой DIB.Чем я использую StretchBlt, чтобы скопировать этот DIB на принтер DC.

Странная вещь - предварительный просмотр печати работает хорошо!Когда я печатаю на виртуальном принтере PDF, он работает хорошо!Но когда я печатаю на реальном принтере (я тестирую на двух разных принтерах - одинаковые результаты) - он просто печатает «мусор».«Мусор» означает, что иногда он печатает полностью черную страницу, иногда он печатает несколько первых страниц несколько раз, то есть печатает неправильную часть DIB, как если бы я перепутал координаты с StretchBlt, но я ничего не испортил, я проверилнесколько раз, плюс почему тогда предварительный просмотр печати работает безупречно?

Я перепробовал множество вариантов:

  1. Использование памяти DC, совместимой с экраном DC, при печати. ​​
  2. Используя DC памяти, совместимый с DC принтера, и выбирая в него мой DIB.
  3. Используя DC памяти, совместимый с DC принтера, и используя выделенный DIB, на который я копирую свой оригинальный буфер DIB буфера.и т.д.

Но результаты такие же.Ниже приведен код, где я создаю DIB.Я думаю, что формат DIB может быть проблемой, поэтому, пожалуйста, посоветуйте, если с ним что-то не так.Я пытался использовать как 24, так и 32 бита в качестве значений для bmiHeader.biBitCount.

// Setup proper backbuffer:

_CleanupBackBufferStuff();

_pMemDc = new CDC;
_pMemDc->CreateCompatibleDC(&aDC);

BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = _sizeBackBuffer.cx;
bmi.bmiHeader.biHeight = -_sizeBackBuffer.cy; // top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24; // Tried 32 as well
bmi.bmiHeader.biCompression = BI_RGB;

unsigned char *pBitmapRawBits = 0;

HANDLE hMemBitmap = CreateDIBSection(aDC.GetSafeHdc(), &bmi, DIB_RGB_COLORS, (void**)&pBitmapRawBits, 0, 0);

_hOldSelBitmap = (HBITMAP)_pMemDc->SelectObject(hMemBitmap);

Также вот код для StretchBlt (здесь ничего особенного):

pDC->SetStretchBltMode(HALFTONE);
SetBrushOrgEx(pDC->GetSafeHdc(), 0, 0, 0);

BOOL bSuccess = pDC->StretchBlt(rectClipBoxPlayground.left, rectClipBoxPlayground.top, rectClipBoxPlayground.Width(), rectClipBoxPlayground.Height(), 
        _pMemDc, rectClipBoxBackBuffer.left, rectClipBoxBackBuffer.top, rectClipBoxBackBuffer.Width(), rectClipBoxBackBuffer.Height(), SRCCOPY);

StretchBlt возвращаетtrue, также (pDC->GetDeviceCaps(RASTERCAPS) & RC_STRETCHBLT) также true.

ОБНОВЛЕНИЕ: После комментария Адриана я изменил свой код, чтобы использовать StretchDIBits.Проблема все та же!Ниже приведен код, который я использую в настоящее время:

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

Он по-прежнему ведет себя как неправильные исходные координаты.Он либо печатает одну из первых нескольких страниц (независимо от того, какую страницу я выбираю), либо печатает почти полностью черные страницы.Предварительный просмотр печати работает отлично, поэтому я думаю, что не должно быть проблем с моим кодом вычисления координат.Он работает в режиме предварительного просмотра, работает с виртуальным (pdf) принтером, сбой при печати на реальном принтере.Что за черт? ....

1 Ответ

2 голосов
/ 26 января 2012

Убедитесь, что вы не выбрали DIBSECTION более чем на один DC одновременно. Это может вызвать все виды непредсказуемого поведения.

Для печати вы, вероятно, можете вообще обойти DC памяти, если вы держите под рукой bmi и pBitmapRawBits. Убедитесь, что DIBSECTION не выбран в any DC, а затем вызовите SetDIBitsToDevice или StretchDIBits, чтобы передать изображение на DC принтера.

Если у вас все еще есть проблемы, вы можете проверить возможности своих принтеров. Не все драйверы поддерживают все методы передачи растровых изображений. Я считаю, что система печати должна скрывать эти различия от вас, но, возможно, нет. Позвоните GetDeviceCaps на вашем принтере и проверьте RASTERCAPS на наличие RC_BITBLT и друзей.

...