Printing two TabPages on a TabControl in VB.NET - vb.net

I am using Visual Studio express 2013, VB. Simplifying the problem as much as I can, I have a form with a tab control that has 2 tab pages. I want to print both tab pages on the click of one button. Currently I am trying to use CreateGraphics on the individual tabs but I just get the first tab printing on both pages. Here is my code, can anyone please see what I am doing wrong or if I am on completely the wrong lines. It looks to me like the CreateGraphics is not retrieving the right tabpages graphics.
Private Declare Auto Function BitBlt Lib "gdi32.dll" (ByVal hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As System.Int32) As Boolean
Private Const SRCCOPY As Integer = &HCC0020
Private PagePrinting As Integer
Private Sub ToolStripButton2_Click(sender As Object, e As EventArgs) Handles ToolStripButton2.Click
If PrintDialog1.ShowDialog() = DialogResult.OK Then
PagePrinting = 0
PrintDocument1.Print()
End If
End Sub
Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
If PagePrinting = 0 Then
e.Graphics.DrawImage(GetImage1(), e.MarginBounds)
Else
e.Graphics.DrawImage(GetImage2(), e.MarginBounds)
End If
PagePrinting = PagePrinting + 1
If PagePrinting = 2 Then e.HasMorePages = False Else e.HasMorePages = True
End Sub
Private Function GetImage1() As Bitmap
Dim me_gr As Graphics = Me.BillTabControl.TabPages("PAGE1").CreateGraphics
Dim bm As New Bitmap(Me.BillTabControl.TabPages("PAGE1").ClientSize.Width, Me.BillTabControl.TabPages("PAGE1").ClientSize.Height, me_gr)
Dim bm_gr As Graphics = Graphics.FromImage(bm)
Dim bm_hdc As IntPtr = bm_gr.GetHdc
Dim me_hdc As IntPtr = me_gr.GetHdc
BitBlt(bm_hdc, 0, 0, Me.BillTabControl.TabPages("PAGE1").ClientSize.Width, Me.BillTabControl.TabPages("PAGE1").ClientSize.Height, me_hdc, 0, 0, SRCCOPY)
me_gr.ReleaseHdc(me_hdc)
bm_gr.ReleaseHdc(bm_hdc)
GetImage1 = bm
End Function
Private Function GetImage2() As Bitmap
Dim me_gr As Graphics = Me.BillTabControl.TabPages("PAGE2").CreateGraphics
Dim bm As New Bitmap(Me.BillTabControl.TabPages("PAGE2").ClientSize.Width, Me.BillTabControl.TabPages("PAGE2").ClientSize.Height, me_gr)
Dim bm_gr As Graphics = Graphics.FromImage(bm)
Dim bm_hdc As IntPtr = bm_gr.GetHdc
Dim me_hdc As IntPtr = me_gr.GetHdc
BitBlt(bm_hdc, 0, 0, Me.BillTabControl.TabPages("PAGE2").ClientSize.Width, Me.BillTabControl.TabPages("PAGE2").ClientSize.Height, me_hdc, 0, 0, SRCCOPY)
me_gr.ReleaseHdc(me_hdc)
bm_gr.ReleaseHdc(bm_hdc)
GetImage2 = bm
End Function

Have you tried selecting the second tab before creating the graphics with SelectTab?
You may also want to add a breakpoint to this line to make sure it is being called:
e.Graphics.DrawImage(GetImage2(), e.MarginBounds)

Here is the code that works.
Private Function GetImage1() As Bitmap
Dim bm As New Bitmap(Me.BillTabControl.TabPages("PAGE1").ClientSize.Width, Me.BillTabControl.TabPages("PAGE1").ClientSize.Height)
Me.BillTabControl.TabPages("PAGE1").DrawToBitmap(bm, Me.BillTabControl.TabPages("PAGE1").ClientRectangle)
GetImage1 = bm
End Function
Private Function GetImage2() As Bitmap
Dim bm As New Bitmap(Me.BillTabControl.TabPages("PAGE2").ClientSize.Width, Me.BillTabControl.TabPages("PAGE2").ClientSize.Height)
Me.BillTabControl.TabPages("PAGE2").DrawToBitmap(bm, Me.BillTabControl.TabPages("PAGE2").ClientRectangle)
GetImage2 = bm
End Function

Related

vb.net avoid zoom in picturebox when drawing line(using XNA) in maximized form

I'm drawing lines in a picturebox inside a form, when I maximize the form the picturebox change height and width automatically because of anchor bounds.
Problem is that the lines are rendered in wrong way on the maximized window,and lines that should be 1 pixel width seem bigger. I'm missing some zoom proprety in picturebox control?
There is a way to avoid that?
I'm using XNA 4.0, here the basic code where pbGame is my picturebox.
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Private quit As Boolean = False
Public grafix As GraphicsDevice
Private Function initialize(ByRef surface As PictureBox) As Boolean
Try
Dim pparam As New PresentationParameters
pparam.DeviceWindowHandle = surface.Handle
pparam.IsFullScreen = False
Dim grafixAdapt As GraphicsAdapter = GraphicsAdapter.DefaultAdapter
grafix = New GraphicsDevice(grafixAdapt, GraphicsProfile.HiDef, pparam)
initialize = True
Catch ex As Exception
initialize = False
End Try
End Function
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
'Set up the initialize function found above
If InitializeGraphics(pbGame) AndAlso InitializeEffect(grafix) Then
BackgroundWorker1.RunWorkerAsync()
Else
MessageBox.Show("There was a problem initializing XNA.")
Me.Close()
End If
End Sub
Private effect As BasicEffect
Private Function InitializeEffect(ByVal graphics As GraphicsDevice) As Boolean
effect = New BasicEffect(graphics)
Try
effect.VertexColorEnabled = True
effect.Projection = Matrix.CreateOrthographicOffCenter(0, graphics.Viewport.Width, graphics.Viewport.Height, 0, 0, 1)
InitializeEffect = True
Catch ex As Exception
InitializeEffect = False
End Try
End Function
Private Function Set2dLine(ByVal x1 As Integer, ByVal y1 As Integer, ByVal z1 As Integer, _
ByVal x2 As Integer, ByVal y2 As Integer, ByVal z2 As Integer, _
ByVal color As Color) As VertexPositionColor()
Dim vertices1, vertices2 As New VertexPositionColor
vertices1.Position = New Vector3(x1, y1, z1)
vertices1.Color = color
vertices2.Position = New Vector3(x2, y2, z2)
vertices2.Color = color
Return {vertices1, vertices2}
End Function
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Do Until quit = True
grafix.Clear(Color.CornflowerBlue)
effect.CurrentTechnique.Passes(0).Apply()
Dim newline() As VertexPositionColor = Set2dLine(50, 10, 0, 150, 10, 0, Color.Black)
grafix.DrawUserPrimitives(PrimitiveType.LineList, newline, 0, 1)
grafix.Present()
Loop
End Sub

vb.net camera pinvoke error

This question may have been asked before but im just starting out with VB.Net and was given this application to fix that uses the webcam of the pc/ tablet but I cant figure out the pinvoke error
here is my code:
Imports System.IO
Public Class frm
CaptureWebCam
Const CAP As Short = &H400S
Const CAP_DRIVER_CONNECT As Integer = CAP + 10
Const CAP_DRIVER_DISCONNECT As Integer = CAP + 11
Const CAP_EDIT_COPY As Integer = CAP + 30
Const CAP_SET_PREVIEW As Integer = CAP + 50
Const CAP_SET_PREVIEWRATE As Integer = CAP + 52
Const CAP_SET_SCALE As Integer = CAP + 53
Const WS_CHILD As Integer = &H40000000
Const WS_VISIBLE As Integer = &H10000000
Const SWP_NOMOVE As Short = &H2S
Const SWP_NOSIZE As Short = 1
Const SWP_NOZORDER As Short = &H4S
Const HWND_BOTTOM As Short = 1
Dim iDevice As Integer = 0 ' Normal device ID
Dim hHwnd As Integer ' Handle value to preview window
Public image_base64String As String
' Declare function from AVI capture DLL.
Declare Auto Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Object) As Integer
Declare Auto Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Integer, ByVal hWndInsertAfter As Integer, ByVal x As Integer, ByVal y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As Integer) As Integer
Declare Auto Function DestroyWindow Lib "user32" (ByVal hndw As Integer) As Boolean
Declare Auto Function capCreateCaptureWindowA Lib "avicap32.dll" (ByVal lpszWindowName As String, ByVal dwStyle As Integer, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Short, ByVal hWndParent As Integer, ByVal nID As Integer) As Integer
Private Sub OpenForm()
Dim iHeight As Integer = picCapture.Height
Dim iWidth As Integer = picCapture.Width
' Open Preview window in picturebox .
' Create a child window with capCreateCaptureWindowA so you can display it in a picturebox.
hHwnd = capCreateCaptureWindowA(iDevice, WS_VISIBLE Or WS_CHILD, 0, 0, 600, 480, picCapture.Handle, IntPtr.Zero)
' Connect to device
If SendMessage(hHwnd, CAP_DRIVER_CONNECT, iDevice, IntPtr.Zero) Then
' Set the preview scale
SendMessage(hHwnd, CAP_SET_SCALE, True, IntPtr.Zero)
' Set the preview rate in milliseconds
SendMessage(hHwnd, CAP_SET_PREVIEWRATE, 66, IntPtr.Zero)
' Start previewing the image from the camera
SendMessage(hHwnd, CAP_SET_PREVIEW, True, IntPtr.Zero)
' Resize window to fit in picturebox
SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, picCapture.Width, picCapture.Height, SWP_NOMOVE Or SWP_NOZORDER)
Else
' Error connecting to device close window
DestroyWindow(hHwnd)
End If
End Sub
Private Function btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCapture.Click
Dim data As IDataObject
Dim bmap As Image
' Copy image to clipboard
SendMessage(hHwnd, CAP_EDIT_COPY, 0, 0)
' Get image from clipboard and convert it to a bitmap
data = Clipboard.GetDataObject()
If data.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
bmap = CType(data.GetData(GetType(System.Drawing.Bitmap)), Image)
picCapture.Image = bmap
Dim saveFileDialog1 As New SaveFileDialog()
saveFileDialog1.Filter = "Jpeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif"
saveFileDialog1.Title = "Save an Image File"
saveFileDialog1.FileName = "Image001"
If saveFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
' If the file name is not an empty string open it for saving.
If saveFileDialog1.FileName <> "" Then
' Saves the Image via a FileStream created by the OpenFile method.
Dim fs As System.IO.FileStream = CType(saveFileDialog1.OpenFile(), System.IO.FileStream)
picCapture.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg)
fs.Close()
End If
End If
End If
End Function
Public Function getImage() As String
Dim bmap As Image
Dim ms As New MemoryStream
bmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim bytes() As Byte = ms.ToArray
' Dim image_base64String As String = Convert.ToBase64String(bytes)
image_base64String = Convert.ToBase64String(bytes)
'MsgBox(image_base64String)
Return image_base64String
End Function
Private Sub frmcap_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Leave
' Disconnect from device
SendMessage(hHwnd, CAP_DRIVER_DISCONNECT, iDevice, 0)
' close window
DestroyWindow(hHwnd)
End Sub
Private Sub frmCaptureWebCam_Load(sender As Object, e As EventArgs) Handles MyBase.Load
OpenForm()
End Sub
End Class
you will notice that I'm also trying to return the image via the image_base64 variable
Can someone help me with the code as I get the following error:
PInvokeStackImbalance was detected
Message: A call to PInvoke function
'GCOS3_Mobile_Host_Application!GCOS3_Mobile_Host_Application.frmCaptureWebCam::SendMessage'
has unbalanced the stack. This is likely because the managed PInvoke
signature does not match the unmanaged target signature. Check that
the calling convention and parameters of the PInvoke signature match
the target unmanaged signature.
SendMessage declaration according to pinvoke should be like this
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Also see the tips for Overloads there.
In your code you have declared lParam, which provides additional message-specific information, as object.
And you are passing IntPtr.Zero, so I think using ByVal lParam As IntPtr will be more specific.
I used the emgu library and got it to return the base 64 string:
Imports Emgu.CV
Imports Emgu.CV.Util
Imports System.IO
Public Class frmEmguCapture
Private imagecapture As Capture
Private imageCaptureReady As Boolean = False
Public b64 As String
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles tmrUpdateImage.Tick
tmrUpdateImage.Enabled = False
If imageCaptureReady Then
pbWebCamStream.Visible = True
lblConnecting.Visible = False
btnCapture.Enabled = True
pbWebCamStream.Image = imagecapture.QueryFrame.Bitmap
tmrUpdateImage.Enabled = True
Else
MessageBox.Show("Error connecting to camera.", "Error conecting to camera.", MessageBoxButtons.OK, MessageBoxIcon.Error)
Me.Close()
End If
End Sub
Public Function btnCapture_Click(sender As Object, e As EventArgs) Handles btnCapture.Click
tmrUpdateImage.Enabled = False
pbWebCamStream.Visible = True
lblConnecting.Visible = False
btnCapture.Enabled = True
pbWebCamStream.Image = imagecapture.QueryFrame.Bitmap
Dim bmap As Image
bmap = imagecapture.QueryFrame.Bitmap
Dim ms As New MemoryStream
bmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim bytes() As Byte = ms.ToArray
Dim image_base64String As String = Convert.ToBase64String(bytes)
image_base64String = Convert.ToBase64String(bytes)
b64 = image_base64String
imagecapture.Dispose()
Me.Close()
'MsgBox(image_base64String)
Return image_base64String
End Function
Private Sub frmEmguCapture_Load(sender As Object, e As EventArgs) Handles MyBase.Load
tmrLoad.Enabled = True
End Sub
Private Sub tmrLoad_Tick(sender As Object, e As EventArgs) Handles tmrLoad.Tick
tmrLoad.Enabled = False
Try
imagecapture = New Capture
imageCaptureReady = True
tmrUpdateImage.Enabled = True
Catch ex As Exception
MessageBox.Show("Error connecting to camera.", "Error conecting to camera.", MessageBoxButtons.OK, MessageBoxIcon.Error)
Me.Close()
End Try
End Sub
End Class

round edges of programatic label

I am trying to create labels which have all four corners rounded, the label is being created programatically as seen below:
Dim lbl1 As Label = New Label()
lbl1.AutoSize = False 'allow resizing
lbl1.BackColor = Color.Yellow
lbl1.Text = newid
lbl1.Height = 46
lbl1.Width = 42
lbl1.Padding = New Padding(1, 1, 1, 1)
How would I switch from the square corners to a more XP styled rounding.
Imports System.Runtime.InteropServices
<DllImport("Gdi32.dll", EntryPoint:="CreateRoundRectRgn")> _
Private Shared Function CreateRoundRectRgn(ByVal iLeft As Integer, ByVal iTop As Integer, ByVal iRight As Integer, ByVal iBottom As Integer, ByVal iWidth As Integer, ByVal iHeight As Integer) As IntPtr
End Function
ex.)
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("Gdi32.dll", EntryPoint:="CreateRoundRectRgn")> _
Private Shared Function CreateRoundRectRgn(ByVal iLeft As Integer, ByVal iTop As Integer, ByVal iRight As Integer, ByVal iBottom As Integer, ByVal iWidth As Integer, ByVal iHeight As Integer) As IntPtr
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim newid$ = "mylabel"
Dim lbl1 As Label = New Label()
With lbl1
lbl1.AutoSize = False 'allow resizing
lbl1.BackColor = Color.Yellow
lbl1.Text = newid
lbl1.Height = 46
lbl1.Width = 42
lbl1.Padding = New Padding(1, 1, 1, 1)
lbl1.Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(2, 2, lbl1.Width - 2, lbl1.Height - 2, 5, 1))
End With
Me.Controls.Add(lbl1)
End Sub
End Class

PrintWindow / CopyFromScreen getting selected area

Hey all i have this code here:
Dim p As Process = Process.GetProcessesByName("Cal").FirstOrDefault
Dim target_hwnd As Long = FindWindow(vbNullString, "Calculator")
If p IsNot Nothing Then
SetWindowPos(target_hwnd, 0, winSize(0), winSize(1), winSize(2), winSize(3), 0)
AppActivate(p.Id)
Dim img As New Bitmap(145, 145) 'size fo the caption area
Dim gr As Graphics = Graphics.FromImage(img)
'sets the offsets and use image size to set region
gr.CopyFromScreen(New Point(winSize(0) + 44, winSize(1) + 179), Point.Empty, img.Size)
img.Save("test.jpg", Drawing.Imaging.ImageFormat.Jpeg)
Process.Start("test.jpg")
End If
As long as i have the window in view it takes the screen shot just fine without any problems. However when i move the form off screen (where i am unable to see it) it only captures a black image.
I've been trying this code out:
Private Declare Function PrintWindow Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal hdcBlt As IntPtr, ByVal nFlags As UInt32) As Boolean
Dim screenCapture As Bitmap
Dim otherForm As New Form
Private Sub CaptureScreen()
Dim target_hwnd As Long = FindWindow(vbNullString, "Calculator")
SetWindowPos(target_hwnd, 0, winSize(0), winSize(1), winSize(2), winSize(3), 0)
screenCapture = New Bitmap(245, 245)
Dim g As Graphics = Graphics.FromImage(screenCapture)
Dim hdc As IntPtr = g.GetHdc
Form1.PrintWindow(target_hwnd, hdc, Nothing)
g.ReleaseHdc(hdc)
g.Flush()
g.Dispose()
If IO.File.Exists("d:\test.jpg") Then
IO.File.Delete("d:\test.jpg")
End If
screenCapture.Save("d:\test.jpg", Drawing.Imaging.ImageFormat.Jpeg)
End Sub
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
CaptureScreen()
End Sub
Now the above code DOES capture an image even when the window is off screen. The problem with the code above is that i can't tell it to only capture an area within that window that i was able to do with the CopyFromScreen i first posted.
Is this possible using the PrintWindow?
I was able to do this:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim fileName = "Calculator.jpg"
Dim fileNameCrop = "Calculator-crop.jpg"
' |--b|---|x|
' | | | a|-Form Left to image area
' | V | | b|-Form Top to image area
' a-->[c] | | | c|-Image area Width to capture
' | | | | | c|-Image area Height to capture
' |_________| V V V V
Dim CropRect As New Rectangle(97, 189, 36, 29)
Dim OrignalImage = Image.FromFile(fileName)
Dim CropImage = New Bitmap(CropRect.Width, CropRect.Height)
Using grp = Graphics.FromImage(CropImage)
grp.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
grp.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
grp.DrawImage(OrignalImage, New Rectangle(0, 0, CropRect.Width, CropRect.Height), CropRect, GraphicsUnit.Pixel)
CropImage.Save(fileNameCrop)
End Using
OrignalImage.Dispose()
CropImage.Dispose()
'delete org image
If FileIO.FileSystem.FileExists(fileName) Then FileIO.FileSystem.DeleteFile(fileName)
End Sub
And just crop out the area after i saved the forms image from the first code posted in the OP.

VB.NET DrawImage to certain position

I tried to rebuild the BitBlt function in VB.NET, and it works not sooo bad, but my image is always blitted/drawn on 0,0 on the destination bitmap.
Does anybody see my mistake?
As one can see, I am trying to copy the rect (0, 0, 50, 50) from the source bitmap to the point (25,25) in the destination bitmap, but it does not do that:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Make a Bitmap to hold the result.
Dim bm As New Bitmap(Me.PictureBox1.Width, Me.PictureBox1.Height)
CopyBitmap(Me.PictureBox1.Image, bm, 25, 25, 50, 50, 0, 0)
Me.PictureBox2.Image = bm
End Sub
Public Sub CopyBitmap(ByRef uSource As Bitmap, ByRef uTarget As Bitmap, ByVal uDestX As Integer, ByVal uDestY As Integer, ByVal uSrcWidth As Integer, ByVal uSrcHeight As Integer, ByVal uSrcX As Integer, ByVal uSrcY As Integer)
Dim nSrc As New Rectangle
nSrc = Rectangle.FromLTRB(uSrcX, uSrcY, uSrcX + uSrcWidth, uSrcY + uSrcHeight)
Dim nDst As New Rectangle
nDst = Rectangle.FromLTRB(uDestX, uDestY, uDestX + uSrcWidth, uDestY + uSrcHeight)
Using g As Graphics = Graphics.FromImage(uTarget)
' Draw the specified section of the source bitmap to the new one
g.DrawImage(uSource, nSrc, nDst, GraphicsUnit.Pixel)
End Using
End Sub
Doh, I swapped nSrc and nDst.
The 2nd argument in DrawImage should be nDst, and the 3rd argument should be nSrc.