VB.NET Dispose Bitmap in RAM wont work - vb.net

first of all i am relative new to Visual Basic.NET and i stuck on an problem here.
I started to code a screen2gif recorder. In main purpose it works. But if i record more than 15 to 20 seconds my ram overloads and exceed the 3,5 Gb limit for x32bit applications. The problem is that the bitmaps i create stack over and over.
Private Function getBitmap(ByVal pCtrl As Control) As Bitmap
Dim myBmp As Bitmap
If myBmp IsNot Nothing Then
myBmp.Dispose()
End If
myBmp = New Bitmap(pCtrl.Width, pCtrl.Height)
Dim g As Graphics = Graphics.FromImage(myBmp)
Dim p As New Point(pCtrl.Parent.Width - pCtrl.Parent.ClientRectangle.Width - 4, pCtrl.Parent.Height - pCtrl.Parent.ClientRectangle.Height - 4)
g.CopyFromScreen(pCtrl.Parent.Location + pCtrl.Location + p, Point.Empty, myBmp.Size)
Dim LocalMousePosition As Point
LocalMousePosition = panelTranspacrency.PointToClient(Cursor.Position)
Cursor.Draw(g, New Rectangle(New Point(LocalMousePosition.X, LocalMousePosition.Y), Cursor.Size))
Return myBmp
myBmp.Dispose()
g.Dispose()
End Function
Private Sub tmrWork_Tick(sender As Object, e As EventArgs) Handles tmrWork.Tick
counter += 1
Dim bm As Bitmap
bm = getBitmap(Me.panelTranspacrency)
bm.Save(My.Settings.outputpath & "\temp\" & counter & ".png", Drawing.Imaging.ImageFormat.Png)
bm.Dispose()
End Sub
So this is my code to create the bitmaps and save them to disk.
I mention that i used the .Dispose command but the ram wont free.
Please take a look and give me a hint. Thanks in advance.

Change
Dim g As Graphics = Graphics.FromImage(myBmp)
to
Using g As Graphics = Graphics.FromImage(myBmp)
and put End Using after your Return myBmp. And you should do the same with
Using bm As Bitmap = getBitmap(Me.panelTranspacrency)
And remove all your explicit .Dispose calls as well.
Docs
https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/using-statement

Related

VB.NET get any file thumbnail in picturebox as an image image programmatically [duplicate]

This question already has answers here:
C# get thumbnail from file via windows api
(5 answers)
Closed 1 year ago.
I am struggling to find a way on how to get any file thumbnail into my userforms picturebox (The image visible in windows explorer) using visual basic.
I have only found how to do that for image files
Dim image As Image = New Bitmap(file) 'File is a full path to the file
'Resize and preserve aspect ratio
Dim Ratio As Double = CDbl(image.Width / image.Height)
Dim H As Integer = 150
Dim W As Integer = CInt(H / Ratio)
'Set image
.Image = image.GetThumbnailImage(H, W, callback, New IntPtr())
But it doesn't work for any other type of files.
Could someone, please,help me with this code?
Try the following which is adapted from C# get thumbnail from file via windows api
Download/install NuGet package Microsoft-WindowsAPICodePack-Shell
Imports Microsoft.WindowsAPICodePack.Shell
Imports System.IO
...
Private Function GetThumbnailBytes(filename As String, desiredHeight As Integer) As Byte()
Dim thumbnailBytes As Byte()
Using sfile As ShellFile = ShellFile.FromFilePath(filename)
Dim thumbBmp As Bitmap = sfile.Thumbnail.ExtraLargeBitmap
'compute new width
Dim Ratio As Double = CDbl(thumbBmp.Width / thumbBmp.Height)
Dim height As Integer = desiredHeight
Dim width As Integer = CInt(height / Ratio)
'resize
Using resizedBmp As Bitmap = New Bitmap(thumbBmp, width, height)
Using ms As MemoryStream = New MemoryStream()
resizedBmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
thumbnailBytes = ms.ToArray()
End Using
End Using
End Using
Return thumbnailBytes
End Function
Private Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnRun.Click
Using ofd As OpenFileDialog = New OpenFileDialog()
If ofd.ShowDialog() = DialogResult.OK Then
Dim thumbnailBytes = GetThumbnailBytes(ofd.FileName, 60)
Dim thumbnail = GetThumbnail(ofd.FileName, 60)
Using ms As MemoryStream = New MemoryStream(thumbnailBytes)
PictureBox1.Image = Image.FromStream(ms)
PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
End Using
End If
End Using
End Sub
Resources
C# get thumbnail from file via windows api

How to detect graphic edges and only save that portion

I have a PictureBox, which I am using as a "Signature pad". The size is 475,175...If the user signs in a small area, I would like to only save the portion that has a signature mark. I am not sure where to begin. Any help would greatly be appreciated.
Private Sub btnSaveSignature_Click(sender As Object, e As EventArgs) Handles btnSaveSignature.Click
Dim signatureFileName = txtSignatureFileName.Text.Trim()
Dim signaturePath As String = Path.Combine(Application.StartupPath, txtSignatureFileName.Text & ".bmp")
If String.IsNullOrEmpty(signatureFileName) Then Return
If currentCurve < 0 OrElse signatureObject(currentCurve).Count = 0 Then Return
Using imgSignature As Bitmap = New Bitmap(pBoxSignature.Width, pBoxSignature.Height, PixelFormat.Format32bppRgb)
Using g As Graphics = Graphics.FromImage(imgSignature)
''BMPs require a White background. This line provide that.
g.FillRectangle(Brsh, 0, 0, pBoxSignature.Width, pBoxSignature.Height)
Call DrawSignature(g)
End Using
pBoxSignature.SizeMode = PictureBoxSizeMode.AutoSize
pBoxSavedSignature.SizeMode = PictureBoxSizeMode.AutoSize
imgSignature.Save(signaturePath, ImageFormat.Bmp)
pBoxSavedSignature.Image = New Bitmap(imgSignature)
End Using
End Sub
The above code is my Save to BMP routine. I would imagine any solution would need to go in this section.

Dealing with a memory leak when cropping images in vb.net

I keep getting a system out of memory error when I break an image up into sub images. There's nothing too fancy going on, just splitting an image into a bunch of smaller images. Here's my code:
Dim counterrr As Integer = 0
Dim sorucedir As String
Dim tardir As String
sorucedir = "C:\somedir\"
tardir = "C:\otherdir\"
Dim di2 As New DirectoryInfo(sorucedir)
Dim fiArr2 As FileInfo() = di2.GetFiles()
Dim fri2 As FileInfo
Dim hh As Integer
Dim ww As Integer
hh = 995 'height of source images
ww = 1080 'width of source images
Dim sizestepX As Integer = 180
Dim stepsizeY As Integer = 239
For i = 0 To ww - 1 Step sizestepX
For j = 0 To hh - 1 Step stepsizeY
For Each fri2 In fiArr2
Dim BM2 As Bitmap
BM2 = Image.FromFile(fri2.FullName)
''Threading.Thread.Sleep(3000)
'bm2 = Image.FromFile(fri2.FullName)
Dim BM3 As Bitmap
Dim rect As New Rectangle(i, j, sizestepX, stepsizeY)
BM3 = BM2.Clone(rect, Imaging.PixelFormat.DontCare)
counterrr += 1
Dim ss As String
ss = tardir & counterrr & ".png"
BM3.Save(ss, Imaging.ImageFormat.Png)
BM3 = Nothing
Next
Next
Next
The error comes up after creating as few as 6 images (occurs when creating the 7th image). The line where the error is thrown is this:
BM3 = BM2.Clone(rect, Imaging.PixelFormat.DontCare)
How can I modify my code so they objects are correctly disposed (?) of so they don't leak memory.
The Bitmap class, along with many of the other GDI+ classes implement IDisposable because they hold onto underlying GDI object handles which need to be released. Each process is limited by the OS to a maximum number of GDI objects, usually 10,000. You can view the total number of active GDI objects per process in the Windows task manager. To fix your problem, you need to either manually call the Dispose method on each Bitamp object you create, before it goes out of scope, or you need to wrap each Bitmap variable declaration in a Using block (so it will call Dispose for you). For instance:
Using BM2 As Bitmap = Image.FromFile(fri2.FullName)
Dim rect As New Rectangle(i, j, sizestepX, stepsizeY)
Using BM3 As Bitmap = BM2.Clone(rect, Imaging.PixelFormat.DontCare)
counterrr += 1
Dim ss As String
ss = tardir & counterrr & ".png"
BM3.Save(ss, Imaging.ImageFormat.Png)
End Using
End Using
Note: there's no point in setting the BM3 variable to Nothing at the end, like you're doing. That has no bearing on anything.

vb 2015 GDI+ bitmap placement

I've had little luck trying to find the answer to this either on stackoverflow specifically, or on the internet in general.
I have a form in a vb 2015 Windows Forms project.
On that form, I've placed six controls: four textboxes, a panel, and a button.
When I click the button, it generates a bitmap, like so:
Private Sub btnSetLeft_Click(sender As Object, e As EventArgs) Handles btnSetLeft.Click
Dim R As Integer = CInt(txtRedLeft.Text)
Dim G As Integer = CInt(txtGreenLeft.Text)
Dim B As Integer = CInt(txtBlueLeft.Text)
Dim A As Integer = CInt(txtAlphaLeft.Text)
gcL = Color.FromArgb(A, R, G, B)
Using bm As Bitmap = New Bitmap(9, 9)
Using gBM As Graphics = Graphics.FromImage(bm)
Using br As SolidBrush = New SolidBrush(gcL)
gBM.FillRectangle(br, New Rectangle(0, 0, 8, 8))
End Using
End Using
End Using
End Sub
But, after building the bitmap, I want the button to place the bitmap on the panel and then repaint the panel, thus displaying the new bitmap.
How do I do that?
It's not too hard (I simplified your example):
Dim gcL As Color = Color.Blue
Using bm As New Bitmap(9, 9)
Using gBM As Graphics = Graphics.FromImage(bm)
Using br As New SolidBrush(gcL)
gBM.FillRectangle(br, New Rectangle(0, 0, 8, 8))
End Using
End Using
panel1.BackgroundImage = bm
panel1.BackgroundImageLayout = ImageLayout.Tile
panel1.Update()
End Using

Changing the pixel color in a VB.net form?

How would I change the colour of individual pixels in a VB.NET form?
Thanks.
A hard requirement for Winforms is that you should be able to redraw the form whenever Windows asks it to. Which will happen when you minimize and restore the window. Or on older versions of Windows when you move another window across yours.
So just setting pixels on the window isn't good enough, you are going to lose them all when the window redraws. Instead use a bitmap. An additional burden is that you are going to have to keep the user interface responsive so you need to do your calculations on a worker thread. The BackgroundWorker is handy to get that right.
One way to do this is to use two bitmaps, one you fill in the worker and another that you display. Every, say, one row of pixels make a copy of the in-work bitmap and pass that to ReportProgress(). Your ProgressChanged event then disposes the old bitmap and stores the new passed one and calls Invalidate to force a repaint.
You might benefit from these resources: Setting background color of a form
DeveloperFusion forum , and extracting pixel color
Here's some demo code. It's slow to repaint, for the reasons Hans mentioned. A simple way to speed it up would be to only recalculate the bitmap after a delay.
Public Class Form1
Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
'create new bitmap
If Me.ClientRectangle.Width <= 0 Then Exit Sub
If Me.ClientRectangle.Height <= 0 Then Exit Sub
Using bmpNew As New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
'draw some coloured pixels
Using g As Graphics = Graphics.FromImage(bmpNew)
For x As Integer = 0 To bmpNew.Width - 1
For y As Integer = 0 To bmpNew.Height - 1
Dim intR As Integer = CInt(255 * (x / (bmpNew.Width - 1)))
Dim intG As Integer = CInt(255 * (y / (bmpNew.Height - 1)))
Dim intB As Integer = CInt(255 * ((x + y) / (bmpNew.Width + bmpNew.Height - 2)))
Using penNew As New Pen(Color.FromArgb(255, intR, intG, intB))
'NOTE: when the form resizes, only the new section is painted, according to e.ClipRectangle.
g.DrawRectangle(penNew, New Rectangle(New Point(x, y), New Size(1, 1)))
End Using
Next y
Next x
End Using
e.Graphics.DrawImage(bmpNew, New Point(0, 0))
End Using
End Sub
Private Sub Form1_ResizeEnd(sender As Object, e As System.EventArgs) Handles Me.ResizeEnd
Me.Invalidate() 'NOTE: when form resizes, only the new section is painted, according to e.ClipRectangle in Form1_Paint(). We invalidate the whole form here to form an entire form repaint, since we are calculating the colour of the pixel from the size of the form. Try commenting out this line to see the difference.
End Sub
End Class