3

I need to print a vtkImageData to a printer CDC. I figured out to do so after reviewing this and this. One is to use the vtk interface and set the pixels of a CImage, then draw the CImage to the CDC:

CImage c_image;
c_image.Create(dims[0], dims[1], 24);
for (int y=0; y<dims[1]; y++)
{
  for (int x=0; x<dims[0]; x++)
  {
    float r = i_image->GetScalarComponentAsFloat(extent[0] + x, extent[2] + dims[1] - y - 1, 0, 0);
    float g = i_image->GetScalarComponentAsFloat(extent[0] + x, extent[2] + dims[1] - y - 1, 0, 1);
    float b = i_image->GetScalarComponentAsFloat(extent[0] + x, extent[2] + dims[1] - y - 1, 0, 2);
    c_image.SetPixelRGB(x, y, r, g, b);
  }
}

Another is to use CreateDIBSection() and then attach the bitmap to a CImage and draw the CImage to a CDC:

HBITMAP hBitmap = nullptr;
  BITMAPINFOHEADER bmih;
  bmih.biSize     = sizeof(BITMAPINFOHEADER);
  bmih.biWidth    = dims[0];
  bmih.biHeight   = dims[1];
  bmih.biPlanes   = 1;
  bmih.biBitCount = i_image->GetNumberOfScalarComponents() * 8;
  bmih.biCompression  = BI_RGB ;
  bmih.biSizeImage    = 0;
  bmih.biXPelsPerMeter    =   10;
  bmih.biYPelsPerMeter    =   10;
  bmih.biClrUsed  =0;
  bmih.biClrImportant =0;

  BITMAPINFO dbmi;
  ZeroMemory(&dbmi, sizeof(dbmi));  
  dbmi.bmiHeader = bmih;
  dbmi.bmiColors->rgbBlue = 0;
  dbmi.bmiColors->rgbGreen = 0;
  dbmi.bmiColors->rgbRed = 0;
  dbmi.bmiColors->rgbReserved = 0;
  void* bits = nullptr;

  // Create DIB
  hBitmap = CreateDIBSection(i_printer_dc_ptr->GetSafeHdc(), &dbmi, DIB_RGB_COLORS, &bits, NULL, 0);
  if (hBitmap == nullptr) {
      ::MessageBox(NULL, __T("Could not load the desired image image"), __T("Error"), MB_OK);
      return;
  }
  ::memcpy(bits, i_image->GetScalarPointer(), i_image->GetNumberOfScalarComponents() * dims[0] * dims[1]);
  c_image.Attach(hBitmap);

Both require copying all the bytes once and then printing to the CDC. Is there a way to avoid this intermediary copy and just print the bytes directly to the CDC? Or just create a HBITMAP that points to the existing bytes without copying them?

Community
  • 1
  • 1
A.E. Drew
  • 2,097
  • 1
  • 16
  • 24

1 Answers1

3

Yes, you can use the SetDIBitsToDevice() function to copy bits directly to a DC.

Note the restriction about alignment:

The scan lines must be aligned on a DWORD except for RLE-compressed bitmaps.

One common problem is that the resulting bitmap ends up upside-down (because bitmaps are natively bottom-up in Windows). If this occurs, negate the height in the BITMAPINFO structure.

Jonathan Potter
  • 36,172
  • 4
  • 64
  • 79