?
Solved

Using StretchBlt between a form and a printer

Posted on 2003-03-20
10
Medium Priority
?
551 Views
Last Modified: 2007-12-19
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.
0
Comment
Question by:cyberknet
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
10 Comments
 
LVL 5

Expert Comment

by:Rubyn
ID: 8180286
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. :)
0
 
LVL 1

Author Comment

by:cyberknet
ID: 8181145
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)

0
 
LVL 1

Author Comment

by:cyberknet
ID: 8181723
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
    Refresh
       
    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
    Printer.EndDoc
    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
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:cyberknet
ID: 8182602
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.
0
 
LVL 1

Author Comment

by:cyberknet
ID: 8182799
for some reason It is not letting me increase to 185, even though I just earned 80 more points. sorry guys.
0
 
LVL 5

Expert Comment

by:Rubyn
ID: 8183368
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)

Tips
For all API Commands define size in pixels.
Autoredraw Property must be false to read from hDC by API
0
 
LVL 1

Author Comment

by:cyberknet
ID: 8183481
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.
0
 
LVL 5

Accepted Solution

by:
Rubyn earned 420 total points
ID: 8183631
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.
0
 
LVL 1

Author Comment

by:cyberknet
ID: 8183793
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.
0
 
LVL 5

Expert Comment

by:Rubyn
ID: 8183918
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
printer.TwipsPerPixelY

Screen.TwipsPerPixelX  'Resolution of Screen. Normally 15
Screen.TwipsPerPixelY

Printer.Width          'Paper Width & Height in Twips
Printer.Height

Printer.ScaleWidth     'Printable Area Scaled by ScaleMode
Printer.ScaleHeight

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

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.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

There are many ways to remove duplicate entries in an SQL or Access database. Most make you temporarily insert an ID field, make a temp table and copy data back and forth, and/or are slow. Here is an easy way in VB6 using ADO to remove duplicate row…
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Suggested Courses
Course of the Month9 days, 4 hours left to enroll

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question