Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 575
  • Last Modified:

Using StretchBlt between a form and a printer

I am trying to print TIFF images from visual basic on Windows XP. I have tried many libraries to do this. On windows 2000, I used Imaging for Windows, however it is not available in Windows XP. I have found the FreeImage library from SourceForge, and it loads the image just fine. I can even display it on the form. However, once I have it displaying on the form, I am unable to use StretchBlt to copy the image from the form's hdc to the printer's hdc... According to the MS knowledge base, this is because the devices are different. It suggests using GetDIBits and SetDIBits, but I am unsure how well this will work with the printer object.

100 points for code to transfer an image in the form's hDC (not loaded in the form's .Picture) to the printer and printed out.
  • 6
  • 4
1 Solution
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Const SRCCOPY = &HCC0020

Private Function CapturePicture(Obj As PictureBox) As StdPicture
Dim picTemp As PictureBox
    Set picTemp = Controls.Add("VB.PictureBox", "PicTemp")
    With picTemp
        .Width = Obj.Width
        .Height = Obj.Height
        .AutoRedraw = True
    End With
    With Obj
        Call BitBlt(picTemp.hDC, 0, 0, _
        .ScaleX(.ScaleWidth, .ScaleMode, vbPixels), _
        .ScaleY(.ScaleHeight, .ScaleMode, vbPixels), .hDC, 0, 0, SRCCOPY)
    End With
Set CapturePicture = picTemp.Image
Call Controls.Remove(picTemp)
End Function

Private Sub Command1_Click()
    Let Picture2.Picture = CapturePicture(Picture1)
End Sub
'To run this example
'Create Two picture boxes and one command button
'Place your image control or any control on picture1
'Copy this code to form1
'Run it

'You are having a control which have the image you want.
'You have to place that control in a PictureBox with AutoRedraw property is False
'Call this CapturePicture(PictureBox holding your image control) returns Picture
'You can use the Picture with any command uses StdPicture like PaintPicture
'Using PaintPicture you can draw this Picture to Printer Object
'Ex: Call Printer.PaintPicture(CapturePicture(Picture1), 0, 0, 100, 100)

I Hope this solves your problem. :)
cyberknetAuthor Commented:
Perhaps I can be a bit more specific about what I have, and what I want. Sorry for any confusion.

I have a form, and the FreeImage library. I load a page from the tif image, which returns me a hBitmap of the image. I call a FreeImage function which copies the bitmap to a DC. I cannot copy it directly to the printer, it is way too big, I need to scale it first. So I am copying it to the form. So at the moment in the form's hDC we have an image.

If I am reading what you say correctly, you are telling me to add a picturebox at runtime, and blit the image in the form's hdc to the picturebox's hdc, then use PaintPicture to copy the picture from the picturebox to the printer.

Is there no way to copy the bitmap to the printer directly from the form without adding and removing the picturebox? I will be calling this procedure quite frequently, and that takes quite a bit of processing time...

any ideas?

Increased points to 105 (it's all I have)

cyberknetAuthor Commented:
Maybe posting some code that I tried your method with would help too: (all variables are declared further up in the proc, which I did not copy)

    ' mlngBitmap() is an array of hBitmaps
    ' mlngActiveBitmap is the current index
    ' lng[Height/Width] is the bitmap [height/width]
    ' lngScaleHeight is the height scaled to fit on the paper
    ' lngScaleWidth is the width, scaled to fit on the paper
    ' Please contact me for any more questions pertaining
    ' to the code.

    Call FreeImage_RenderBitmap(mlngBitmap(mlngActiveBitmap), hDC) ' renders a hBitmap to a DC
    Set pctTemp = Controls.Add("VB.PictureBox", "pctTemp")
    SetPicture pctTemp, lngWidth, lngHeight, lngScaleWidth, lngScaleHeight ' blits from form hDC to pctTemp hDC
    ' The following statement ALWAYS results i nerror 481
    ' Invalid Picture. I think this is because the
    ' width and height of pctTemp.Picture are still set to
    ' 0.
    Printer.PaintPicture pctTemp.Picture, 0, 0
    Controls.Remove pctTemp

Public Function SetPicture(pctPicture As PictureBox, lngWidth As Long, lngHeight As Long, lngScaleWidth As Long, lngScaleHeight As Long)
    StretchBlt pctPicture.hDC, 1, 1, lngScaleWidth, lngScaleHeight, hDC, 1, 1, lngWidth, lngHeight, vbSrcCopy
End Function
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

cyberknetAuthor Commented:
I earned some more points, so I am increasing the number of points to 185 for a short, clear, correct answer that does not require adding a picturebox to the form.
cyberknetAuthor Commented:
for some reason It is not letting me increase to 185, even though I just earned 80 more points. sorry guys.
I guess, you have some knowledge about handling StdPicture and using it on printer. So, i can explain what i know, without example.
In Form or PictureBox there is a property called Image, which captures what is on it, as StdPicture. Picture property will return only the picture assigned to it.

So, you can use Image property to read whats on hDC to StdPicture.

You can also try BitBlt API to copy image on hDC to directly to other hDC like Printer.hDC.
(I haven't tested on printer, but should work logically)

For all API Commands define size in pixels.
Autoredraw Property must be false to read from hDC by API
cyberknetAuthor Commented:
You cannot bitblt from form hDC to printer hDC. They are different device types. How do we read from hDC to StdPicture? If I can get what is in the hDC to the StdPicture (bitblt does not do this) then I can use PaintPicture on the printer object, which will remove any need for the solution to employe GetDIBits / SetDIBits, which are very difficult to code with.
I assume the image you want is on the Form. (as you used some library function to load it on Form)
So, you can read whats on the form by image property.
The dimension of the image is the dimension of the form

Dim Img as StdPicture
Set Img = Form1.Image

Call Printer.PaintPicture(Img,0,0,Form1.ScaleWidth, Form1.ScaleHeight)

My suggestion is:
Create a temporary PictureBox on form with visible=false and autoredraw=false.
Resize the PictureBox to the dimension of the huge picture you have.
Fill the PictureBox's hDC with your picture.
Use PictureBox's Image property directly with printer.paintpicture.

Your must be aware of:
Printers are high resolution. so you have to streach the image directly on printer to obtail maximum clearity.

So, dont streach the image with API.
You can use PaintPicture to streach.
Eg: Call Printer.PaintPicture(Img,0,0,SrcWidth,SrcHeight,0,0,100,100)

Dim Img as StdPicture
Set Img = Form1.Image

Printer.PaintPicture(Img,0,0,Form1.ScaleWidth, Form1.ScaleHeight)

Sorry, if you cannot understand my way of expression.
cyberknetAuthor Commented:
form.Image does exactly what I need. Too bad that I now find out my image library does not work as expected. However, the solution was right. Thank you for your help.

For those who search later:

Blit to a hDC. (picturebox is best, a form's Image property is limited to the width of the form, not the width of the image)
set the Picture property of that object to its Image property. Image reads from the hDC of the object, not it's Picture object.
Use Printer.PaintPicture to copy it from the object to the printer.

this is so blinding simple, I can't believe I didn't know it. Thanks to Rubyn for pointing this out.
Thanks, You explained well for others.
But have clear idea to print it on printer. So u dont have to waste papers. :)

'Pixels value of Screen and Printer may be different but Twips are same.

'Pixel is the smallest possible dot on any device
printer.TwipsPerPixelX 'Resolution of Printer '4 for 360dpi

Screen.TwipsPerPixelX  'Resolution of Screen. Normally 15

Printer.Width          'Paper Width & Height in Twips

Printer.ScaleWidth     'Printable Area Scaled by ScaleMode

ScaleX(Value,FromMode,ToMode) 'For Unit Conversion

Refer MSDN for all properties to get clear idea. But ScaleMode property is not supported in VB.NET, in VB.NET all devices are measured only in pixels.

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 6
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now