Raz-Soft » Blog Archive » Printing a TBitmap with StretchDIBits Buy Cheap Software
Internauti »
« Convert Units

Printing a TBitmap with StretchDIBits

  The simple way to print a TBitmap is to use the Draw method of a TPrinter Canvas ThePrinterCanvas->Draw ( PositionX, PositionY, TheBitmap);. This works, except that on many machines this will fail to print (or print out too small). The following code will print the TBitmap at a size that is adjusted for the printer device using StretchDIBits. You could change the scaling and have it print to whatever size you want...

The image must contain a Bitmap. This particular function will only work if it is a Bitmap, icons and cursors will not work.

C++:
  1. /********************************************************************************************
  2. *  NAME:
  3. *           PrintImage
  4. *  PURPOSE:
  5. *           Print a bitmap with  StretchDIBits
  6. *  NOTES:
  7. *           The image must contain a Bitmap. This particular function will only
  8. *            work if it is a Bitmap, icons and cursors will not work.
  9. *
  10. *  PARAMS:   PrinterCanvas : printer canvas (TPrinter->Canvas)
  11. *          pX : bitmap X position on printer page
  12. *          pY : bitmap Y position on printer page
  13. *          TheBitmap: TBitmap to be printed
  14. *  RETURNS:
  15. *               void
  16. **********************************************************************************************/
  17. void __fastcall TForm1::PrintImage(TCanvas *PrinterCanvas,int pX,int pY, Graphics::TBitmap *TheBitmap)
  18. {
  19.  
  20.     // create a memory dc for the image
  21.     HDC h_dc = TheBitmap->Canvas->Handle;
  22.     int bmp_w = TheBitmap->Width, bmp_h = TheBitmap->Height;
  23.  
  24.     HDC h_mem_dc = ::CreateCompatibleDC (h_dc);
  25.     HBITMAP h_mem_bmp = ::CreateCompatibleBitmap (h_dc, bmp_w, bmp_h);
  26.     HBITMAP h_old_bmp = ::SelectObject (h_mem_dc, h_mem_bmp);
  27.  
  28.     // fix up bad video drivers
  29.     bool is_pal_dev = false;
  30.     LOGPALETTE *pal;
  31.     HPALETTE h_pal, h_old_pal;
  32.  
  33.     if ( ::GetDeviceCaps (TheBitmap->Canvas->Handle, RASTERCAPS) & RC_PALETTE)
  34.     {
  35.         pal = static_cast<LOGPALETTE*>(malloc (sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256)));
  36.         memset (pal, 0, sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256));
  37.         pal->palVersion = 0x300;
  38.         pal->palNumEntries = ::GetSystemPaletteEntries(TheBitmap->Canvas->Handle, 0, 256, pal->palPalEntry);
  39.         if (pal->palNumEntries != 0)
  40.         {
  41.             h_pal = ::CreatePalette (pal);
  42.             h_old_pal = ::SelectPalette (h_mem_dc, h_pal, false);
  43.             is_pal_dev = true;
  44.         }
  45.         else
  46.         {
  47.             free (pal);
  48.         }
  49.     }
  50.  
  51.     // copy the image on to the memory dc
  52.     ::BitBlt (h_mem_dc, 0, 0, bmp_w, bmp_h, h_dc, 0, 0, SRCCOPY);
  53.  
  54.     if (is_pal_dev)
  55.     {
  56.         ::SelectPalette (h_mem_dc, h_old_pal, false);
  57.         ::DeleteObject (h_pal);
  58.     }
  59.  
  60.     // delete the mem dc
  61.     ::SelectObject (h_mem_dc, h_old_bmp);
  62.     ::DeleteDC (h_mem_dc);
  63.  
  64.     // get memory for a BITMAPIFO Structure
  65.     HANDLE h_bmp_info = ::GlobalAlloc (GHND, sizeof (BITMAPINFO) + (sizeof (RGBQUAD) * 256));
  66.     BITMAPINFO* bmp_info = static_cast<BITMAPINFO*>(::GlobalLock (h_bmp_info));
  67.     //Set up the structure
  68.    
  69.     memset (bmp_info, NULL, sizeof (BITMAPINFO) + (sizeof (RGBQUAD) * 255));
  70.     bmp_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  71.     bmp_info->bmiHeader.biPlanes = 1;
  72.     bmp_info->bmiHeader.biBitCount = 16;//or 8
  73.     bmp_info->bmiHeader.biWidth = bmp_w;
  74.     bmp_info->bmiHeader.biHeight = bmp_h;
  75.     bmp_info->bmiHeader.biCompression = BI_RGB;
  76.  
  77.     // find out how much memory for the bits
  78.     ::GetDIBits (h_dc, h_mem_bmp, 0, bmp_h, NULL, bmp_info, DIB_RGB_COLORS);
  79.  
  80.     // Allocate memory for the bits
  81.     HANDLE h_bits = GlobalAlloc (GHND, bmp_info->bmiHeader.biSizeImage);
  82.     void *bits = ::GlobalLock (h_bits);
  83.  
  84.     // this time get the bits
  85.     ::GetDIBits (h_dc, h_mem_bmp, 0, bmp_h, bits, bmp_info, DIB_RGB_COLORS);
  86.  
  87.     // fix up for bad video driver
  88.     if (is_pal_dev)
  89.     {
  90.         for (int i = 0; i <pal->palNumEntries; i++)
  91.         {
  92.             bmp_info->bmiColors[i].rgbRed = pal->palPalEntry[i].peRed;
  93.             bmp_info->bmiColors[i].rgbGreen = pal->palPalEntry[i].peGreen;
  94.             bmp_info->bmiColors[i].rgbBlue = pal->palPalEntry[i].peBlue;
  95.         }
  96.         free (pal);
  97.     }
  98.  
  99.  
  100.     // fix up for print with palette
  101.     is_pal_dev = false;
  102.     if ( ::GetDeviceCaps (h_dc, RASTERCAPS) & RC_PALETTE)
  103.     {
  104.         pal = static_cast<LOGPALETTE*>(malloc (sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256)));
  105.         memset (pal, 0, sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256));
  106.         pal->palVersion = 0x300;
  107.         pal->palNumEntries = 256;
  108.         for (int i = 0; pal->palNumEntries; i++)
  109.         {
  110.             pal->palPalEntry[i].peRed = bmp_info->bmiColors[i].rgbRed;
  111.             pal->palPalEntry[i].peGreen = bmp_info->bmiColors[i].rgbGreen;
  112.             pal->palPalEntry[i].peBlue = bmp_info->bmiColors[i].rgbBlue;
  113.         }
  114.         h_pal = CreatePalette(pal);
  115.         free (pal);
  116.         h_old_pal = SelectPalette(PrinterCanvas->Handle, h_pal, false);
  117.         is_pal_dev = true;
  118.     }
  119.  
  120.  
  121. //  adjust bitmap dimensions for the printer device:
  122.     int PrnXRes= GetDeviceCaps(PrinterCanvas->Handle, LOGPIXELSX); //Get dpi of printer along width
  123.     int PrnYRes= GetDeviceCaps(PrinterCanvas->Handle, LOGPIXELSY); //Get dpi of printer along height
  124.     bmp_w= floor(((double)TheBitmap->Width / (double)Screen->PixelsPerInch) * (double)PrnXRes);
  125.     bmp_h= floor(((double)TheBitmap->Height / (double)Screen->PixelsPerInch) * (double)PrnYRes);
  126.  
  127.     // send the bits to the printer
  128.     StretchDIBits(PrinterCanvas->Handle, pX,pY, bmp_w, bmp_h,
  129.         0, 0, TheBitmap->Width,TheBitmap->Height, bits,bmp_info, DIB_RGB_COLORS, SRCCOPY);
  130.  
  131.     // clean up
  132.     ::DeleteObject (h_mem_bmp);
  133.     if (is_pal_dev)
  134.     {
  135.         ::SelectObject (PrinterCanvas->Handle, h_old_pal);
  136.         ::DeleteObject (h_pal);
  137.     }
  138.     ::GlobalUnlock (bits);
  139.     ::GlobalFree (h_bits);
  140.     ::GlobalUnlock (bmp_info);
  141.     ::GlobalFree (h_bmp_info);
  142. }

related things:

Author: Raz | On February 2nd, 2007 | C++ Builder, [ En ] | No Comments

Q: So what can I do next?
A: You can Buy me a Beer or Coffee. You can say Hi! or peek on the related stuff. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

No comments yet

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong> and all YM emotions