High Quality Full Screenshots VB.Net - vb.net

I'm trying to add a feature to my program to take a full screenshot of the users screen when they click a button. I got the program to take the screenshot and open a file dialog box to save it, the saving works. The issue is that no matter how I save the screenshot, the saved image has significant quality loss and pixelates around text and stuff. This is a massive issue because I need the image to save exactly as it is seen on the users screen, I cannot have ANY quality loss at all. I tried to save the image as a jpg and a png and both gave me quality loss. I was wondering if anyone could point me towards some code or a method that would allow me to save the screenshots at the same quality as the users screen. I would like to save the image as a JPG or a PNG if possible. Any help would greatly be appreciated!

Get the image in Bitmap format and save it as bmp.
Private Function TakeScreenShot() As Bitmap
Dim screenSize As Size = New Size(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)
Dim screenGrab As New Bitmap(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)
Dim g As Graphics = Graphics.FromImage(screenGrab)
g.CopyFromScreen(New Point(0, 0), New Point(0, 0), screenSize)
Return screenGrab
End Function

For starters, JPEG images use a lossy compression algorithm so you tend to lose quality when you save in that format. It is preferable to save as Bitmap (BMP), which is uncompressed, or PNG, which uses a lossless compression.
Here is code to copy the working area of the screen to a PNG Image.
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'the working area excludes all docked toolbars like taskbar, etc.
Dim currentScreen = Screen.FromHandle(Me.Handle).WorkingArea
'create a bitmap of the working area
Using bmp As New Bitmap(currentScreen.Width, currentScreen.Height)
'copy the screen to the image
Using g = Graphics.FromImage(bmp)
g.CopyFromScreen(New Point(0, 0), New Point(0, 0), currentScreen.Size)
End Using
'save the image
Using sfd As New SaveFileDialog() With {.Filter = "PNG Image|*.png",
.InitialDirectory = My.Computer.FileSystem.SpecialDirectories.Desktop}
If sfd.ShowDialog() = Windows.Forms.DialogResult.OK Then
bmp.Save(sfd.FileName, System.Drawing.Imaging.ImageFormat.Png)
End If
End Using
End Using
End Sub

.Net usually saves the file in 96dpi, so using following code you can save the file in higher resolution with Jpeg or other format.
'Create a new bitmap
Using Bmp As New Bitmap(800, 1000, Imaging.PixelFormat.Format32bppPArgb)
'Set the resolution to 300 DPI
Bmp.SetResolution(300, 300)
'Create a graphics object from the bitmap
Using G = Graphics.FromImage(Bmp)
'Paint the canvas white
G.Clear(Color.White)
'Set various modes to higher quality
G.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
G.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
G.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
'Create a font
Using F As New Font("Arial", 12)
'Create a brush
Using B As New SolidBrush(Color.Black)
'Draw some text
G.DrawString("Hello world", F, B, 20, 20)
End Using
End Using
End Using
'Save the file as a TIFF
Bmp.Save("c:\\test.Jpeg", Imaging.ImageFormat.Jpeg)
End Using

I've found that adding 3 lines to the above code significantly improves the quality of the image
var graphics = Graphics.FromImage(theRequestedAllocatedImage);
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
// Then call
graphics.CopyFromScreen(..)

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim screenSize As Size = New Size(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)
Dim screenGrab As New Bitmap(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)
Dim g As Graphics = Graphics.FromImage(screenGrab)
g.CopyFromScreen(New Point(0, 0), New Point(0, 0), screenSize)
PictureBox1.Image = screenGrab
PictureBox1.Image.Save("c:\picture.bmp")
End Sub

Related

Adding Text to Image Drawn with GDI+

I am displaying images using a timer and picturebox. The images seem to be adding on top of each other instead of displaying one, then removing that one, and loading another.
As the images are displayed, I would like to overlay text on the images.
Here is the code I am using to create images and text
Dim fname As String = (Actually an array in images(jpg) that display with timer)
Dim bm As New Bitmap(fname)
PicBox.Image = bm
findex -= 1 (index of image array)
Dim g As Graphics = PicBox.CreateGraphics
g.DrawImage(bm, 300, 10)
g.DrawString("Kishman Tukus", New Font("Arial", 24, FontStyle.Bold), Brushes.Green, 400, 100)
g.ResetTransform() '
g.Dispose()
I need the images to display in the picturebox one at a time using the timer and I need to overlay
text on the images too.
can someone help me stop the images from adding to the picturebox instead of displaying one at a time?
Or even better, don't use a PictureBox at all, just display images with text overlay?
In any case, i need to stop the memory bleed.
thank you
I think it's important how you load the images. Do you really load each image by filename each time you show it? That's misleading, as you mentioned there is an array. The distinction is you keep references to these images and you are modifying each one. Remember this is a reference type so the original items gets modified. So you end up with text repeatedly being written over itself. The irony is that if you did actually load the image each tick, then you wouldn't actually have this problem :)
I made something along the lines of what you have (I think), where we use Object.Clone to make a copy in memory of each bitmap which you can modify without modifying the original image.
Private images As New List(Of Bitmap)()
Dim findex As Integer = 0
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim bmCopy = DirectCast(images(findex).Clone(), Bitmap)
Using g As Graphics = Graphics.FromImage(bmCopy)
g.DrawString(Guid.NewGuid().ToString(), New Font("Arial", 24, FontStyle.Bold), Brushes.Green, 400, 100)
End Using
PicBox.Image = bmCopy
findex = (findex + 1) Mod images.Count()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
images.Add(My.Resources.Image1)
images.Add(My.Resources.Image2)
Timer1.Interval = 1000
Timer1.Enabled = True
End Sub
There is no memory leak. You can check the memory increase but the GC eventually clears it out.
I would expect to see something more like:
Dim bm As New Bitmap(fname)
Using g As Graphics = Graphics.FromImage(bm)
g.DrawString("Kishman Tukus", New Font("Arial", 24, FontStyle.Bold), Brushes.Green, 400, 100)
End Using
PicBox.Image = bm

How do I take a screenshot of my project file, and then export/convert said file into a PDF, using vb.net?

I am trying to take the contents of my project file and turning/export it as a PDF. For context, here is the layout of my project file:
Don't mind the numbers, I was just testing that part of the code, my only issue is finding a way in taking that project file and turning it into a PDF. I tried breaking down this task into two buttons, the 2) Save File and 3) Create PDF buttons, though now I'm just getting more confused the more I try to do this.
Here is my code for the "2) Save File" button:
Private Sub Screenshot_Click(sender As Object, e As EventArgs) Handles Screenshot.Click
Dim bmp As New Bitmap(Me.Width, Me.Height)
Me.DrawToBitmap(bmp, New Rectangle(0, 0, Me.Width, Me.Height))
PictureBox1.Image = bmp
bmp.Save(My.Computer.FileSystem.SpecialDirectories.Desktop & "\" & ".png", Imaging.ImageFormat.Png)
SaveFileDialog1.ShowDialog()
SaveFileDialog1.Title = "Save file"
SaveFileDialog1.InitialDirectory = "E:\French"
Dim location As String
location = SaveFileDialog1.FileName
bmp.Save(SaveFileDialog1.ShowDialog())
End Sub
The 3) Create PDF button doesn't currently have any special code, all I did was to try and create a bitmap and then taking that bitmap and turning it into a PDF:
Private Sub PDFbutton_Click(sender As Object, e As EventArgs) Handles PDFbutton.Click
Dim bmpScreenshot As Bitmap = New Bitmap(Width, Height, PixelFormat.Format32bppArgb)
' Create a graphics object from the bitmap
Dim gfxScreenshot As Graphics = Graphics.FromImage(bmpScreenshot)
' Take a screenshot of the entire Form1
gfxScreenshot.CopyFromScreen(Me.Location.X, Me.Location.Y, 0, 0, Me.Size, CopyPixelOperation.SourceCopy)
' Save the screenshot
bmpScreenshot.Save("D:\Form1.jpg", ImageFormat.Jpeg)
End Sub
Just started working on vb.net, so I'm still new at this. I'll gladly take any help and/or advice!

Saving the image of a picturebox

So I have this code:
Private Sub button28_Click(sender As Object, e As EventArgs) Handles button28.Click
Dim bounds As Rectangle
Dim screenshot As System.Drawing.Bitmap
Dim graph As Graphics
bounds = PicOuterBorder.Bounds
screenshot = New System.Drawing.Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
picFinal.Image = screenshot
'this takes a screenshot
End Sub
PicOuterBorder is a picturebox on my form. PicFinal is another display picturebox. But this code gets me this: Which is basically a screenshot of a window in the size of PicOuterBorder starting from the origin of my screen. However, Me.Bounds instead of PicOuterBorder.Bounds works and gets a perefect screenshot of just my form. I want picFinal to have a screenshot of just PicOuterBorder
Try below code. You have to map the control coordinates to screen coordinates using PointToScreen. I have placed PicOuterBorder inside the panel PanelPicture. PanelPicture is without any border, while PicOuterBorder can have any type of border style. Below code takes the snapshot of the panel.
Private Sub button28_Click(sender As Object, e As EventArgs) Handles button28.Click
Dim graph As Graphics = Nothing
Dim bounds As Rectangle = Nothing
Dim screenshot As System.Drawing.Bitmap
Dim location As Drawing.Point = PanelPicture.PointToScreen(Drawing.Point.Empty)
screenshot = New System.Drawing.Bitmap(PanelPicture.Width, PanelPicture.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(location.X, location.Y, 0, 0, PanelPicture.Size, CopyPixelOperation.SourceCopy)
picFinal.Image = screenshot
graph.Dispose()
End Sub
Adapt your code for something like this:
Public Sub SaveImage(filename As String, image As Image, Encoder As ImageCodecInfo, EncParam As EncoderParameter)
Dim path As String = System.IO.Path.Combine(My.Application.Info.DirectoryPath, filename & ".jpg")
Dim mySource As New Bitmap(image.Width, image.Height)
Dim grfx As Graphics = Graphics.FromImage(mySource)
grfx.DrawImageUnscaled(image, Point.Empty)
grfx.Dispose()
mySource.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg)
mySource.Dispose()
End Sub

How to place a transparent picture box above a web browser control

I want a webbrowser control on the background and a picturebox above it where I can draw and then it will appear above the webbrowser control. It's like I am writing on some paper which already has something written on it. I have placed a webbrowser control and a picture box above it both with same dimensions.
I know similar question has been asked a lot of time on this website in different forms but none of the solutions mentioned are working for me.
The solutions mentioned are usually for picturebox over picturebox not picturebox over webbrowser control. simply putting webbrowser control instead of picture does not work. Here is the code I used. The square that should have been formed was not formed.
Public Class Form1
Dim BMP As New Drawing.Bitmap(640, 480)
Dim GFX As Graphics = Graphics.FromImage(BMP)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PictureBox1.Controls.Add(WebBrowser1)
PictureBox1.Location = New Point(0, 0)
PictureBox1.BackColor = Color.Transparent
Dim blackPen As New Pen(Color.Black, 3)
Dim point1 As New Point(100, 100)
Dim point2 As New Point(100, 200)
Dim point3 As New Point(200, 200)
Dim point4 As New Point(200, 100)
Dim curvePoints As Point() = {point1, point2, point3, point4}
GFX.FillRectangle(Brushes.White, 0, 0, PictureBox1.Width, PictureBox1.Height)
GFX.DrawPolygon(blackPen, curvePoints)
PictureBox1.Image = BMP
End Sub
End Class
It did not work the other way around either, I mean drawing first and than making the picturebox transparent.

Capture Image of Entire Panel Control In Vb.net

I have added some richtextboxes and some picture boxes in a panel control with scrolling option enabled. I want to capture image of Panel control along with all its child controls. I tried various solutions available on net but still not able to find perfect solution to do my job. The best one available (which dose not capture what is off the scroll bars) is given below. Please help me to do this.
Dim bmp As New Bitmap(Panel1.Width, Panel1.Height)
Using gr As Graphics = Graphics.FromImage(bmp)
gr.CopyFromScreen(Panel1.PointToScreen(Point.Empty), Point.Empty, Panel1.Size)
End Using
Private Function TakeScreenShot(ByVal Control As Control) As Bitmap
Dim tmpImg As New Bitmap(Control.Width, Control.Height)
Using g As Graphics = Graphics.FromImage(tmpImg)
G.CopyFromScreen(Panel1.PointToScreen(New Point(0, 0)), New Point(0, 0), New Size(Panel1.Width, Panel1.Height))
End Using
Return tmpImg
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TakeScreenShot(Panel1).Save("D:\Screenshot.png", System.Drawing.Imaging.ImageFormat.Png)
End Sub