Printing a TImage

By: Kevin Scardina

Abstract: This document describes how to print a TImage that contains a Bitmap at a size that you scale to.

The simple way to print a TImage is to use the print method of a TForm that contains only the bitmap. This works, except that on many machines this will print out too small, or will fail to print. The following code will print the TImage at a size that is scaled to fit the whole page. You could change the scaling and have it print to whatever size you want.


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



/*-----------------------------------------------------------------------
This function is the OnClick event of a TButton that is on a TForm.  
On the TForm is also a TImage named image.
------------------------------------------------------------------------*/
void __fastcall Tmain_form::print_image_btnClick(TObject *Sender)
{
    TPrinter *p = Printer();

    // create a memory dc for the image
    HDC h_dc = image->Picture->Bitmap->Canvas->Handle;
    int bmp_w = image->Picture->Bitmap->Width,
    bmp_h = image->Picture->Bitmap->Height;
    HDC h_mem_dc = ::CreateCompatibleDC (h_dc);
    HBITMAP h_mem_bmp = ::CreateCompatibleBitmap (h_dc, bmp_w, bmp_h);
    HBITMAP h_old_bmp = ::SelectObject (h_mem_dc, h_mem_bmp);

    // fix up bad video drivers
    bool is_pal_dev = false;
    LOGPALETTE *pal;
    HPALETTE h_pal, h_old_pal;

    if (::GetDeviceCaps (image->Canvas->Handle, RASTERCAPS) & RC_PALETTE)
    {
        pal = static_cast(malloc (sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256)));
        memset (pal, 0, sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256));
        pal->palVersion = 0x300;
        pal->palNumEntries = ::GetSystemPaletteEntries(image->Canvas->Handle, 0, 256, pal->palPalEntry);
        if (pal->palNumEntries != 0)
        {
            h_pal = ::CreatePalette (pal);
            h_old_pal = ::SelectPalette (h_mem_dc, h_pal, false);
            is_pal_dev = true;
        }
        else
        {
            free (pal);
        }
    }

    // copy the image on to the memory dc
    ::BitBlt (h_mem_dc, 0, 0, bmp_w, bmp_h, h_dc, 0, 0, SRCCOPY);

    if (is_pal_dev)
    {
        ::SelectPalette (h_mem_dc, h_old_pal, false);
        ::DeleteObject (h_pal);
    }

    // delete the mem dc
    ::SelectObject (h_mem_dc, h_old_bmp);
    ::DeleteDC (h_mem_dc);

    // get memory for a BITMAPIFO Structure
    HANDLE h_bmp_info = ::GlobalAlloc (GHND, sizeof (BITMAPINFO) + (sizeof (RGBQUAD) * 256));
    BITMAPINFO* bmp_info = static_cast(::GlobalLock (h_bmp_info));
    //Set up the structure
    memset (bmp_info, NULL, sizeof (BITMAPINFO) + (sizeof (RGBQUAD) * 255));
    bmp_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmp_info->bmiHeader.biPlanes = 1;
    bmp_info->bmiHeader.biBitCount = 8;
    bmp_info->bmiHeader.biWidth = bmp_w;
    bmp_info->bmiHeader.biHeight = bmp_h;
    bmp_info->bmiHeader.biCompression = BI_RGB;

    // find out how much memory for the bits
    ::GetDIBits (h_dc, h_mem_bmp, 0, bmp_h, NULL, bmp_info, DIB_RGB_COLORS);

    // Allocate memory for the bits
    HANDLE h_bits = GlobalAlloc (GHND, bmp_info->bmiHeader.biSizeImage);
    void *bits = ::GlobalLock (h_bits);

    // this time get the bits
    ::GetDIBits (h_dc, h_mem_bmp, 0, bmp_h, bits, bmp_info, DIB_RGB_COLORS);

    // fix up for bad video driver
    if (is_pal_dev)
    {
        for (int i = 0; i < pal->palNumEntries; i++)
        {
            bmp_info->bmiColors[i].rgbRed = pal->palPalEntry[i].peRed;
            bmp_info->bmiColors[i].rgbGreen = pal->palPalEntry[i].peGreen;
            bmp_info->bmiColors[i].rgbBlue = pal->palPalEntry[i].peBlue;
        }
        free (pal);
    }

    // begin the printing
    p->BeginDoc ();

    // scale print size
    int scale_x, scale_y;
    if (p->PageWidth < p->PageHeight)
    {
        scale_x = p->PageWidth;
        scale_y = image->Picture->Height * (p->PageWidth / bmp_w);
    }
    else
    {
        scale_x = image->Picture->Width * (p->PageHeight / bmp_h);
        scale_y = p->PageHeight;
    }

    // fix up for print with palette
    is_pal_dev = false;
    if (::GetDeviceCaps (h_dc, RASTERCAPS) & RC_PALETTE)
    {
        pal = static_cast(malloc (sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256)));
        memset (pal, 0, sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 256));
        pal->palVersion = 0x300;
        pal->palNumEntries = 256;
        for (int i = 0; pal->palNumEntries; i++)
        {
            pal->palPalEntry[i].peRed = bmp_info->bmiColors[i].rgbRed;
            pal->palPalEntry[i].peGreen = bmp_info->bmiColors[i].rgbGreen;
            pal->palPalEntry[i].peBlue = bmp_info->bmiColors[i].rgbBlue;
        }
        h_pal = CreatePalette(pal);
        free (pal);
        h_old_pal = SelectPalette(p->Canvas->Handle, h_pal, false);
        is_pal_dev = true;
    }

    // send the bits to the printer
    StretchDIBits(p->Canvas->Handle, 0, 0, scale_x, scale_y,
		0, 0, bmp_w, bmp_h, bits,bmp_info, DIB_RGB_COLORS, SRCCOPY);

    // end the print
    p->EndDoc ();

    // clean up
    ::DeleteObject (h_mem_bmp);
    if (is_pal_dev)
    {
        ::SelectObject (p->Canvas->Handle, h_old_pal);
        ::DeleteObject (h_pal);
    }
    ::GlobalUnlock (bits);
    ::GlobalFree (h_bits);
    ::GlobalUnlock (bmp_info);
    ::GlobalFree (h_bmp_info);
}



Server Response from: ETNASC02