I'm opening a file called tempImage.jpg and showing it on a form in a PictureBox. I then click a button called Clear and the file is removed from the PictureBox using PictureBox2.Image = Nothing, however I'm unable to delete the file as it is locked open. How can I release it so I can delete it? I'm using VB.NET and a forms app.
Thanks
When you use PictureBox2.Image = Nothing you're waiting for the garbage collector to finalize the resource before it releases it. You want to release it immediately, so you need to dispose of the image:
Image tmp = PictureBox2.Image
PictureBox2.Image = Nothing
tmp.Dispose()
If you're using Image.FromFile, you need to call .Dispose() on the image. When you go to clear it out, do something like...
Image currentImage = pictureBox.Image
pictureBox.Image = Nothing
currentImage.Dispose()
That will release the file.
take control of the file
'to use the image
Dim fs As New IO.FileStream("c:\foopic.jpg", IO.FileMode.Open, IO.FileAccess.Read)
PictureBox1.Image = Image.FromStream(fs)
'to release the image
PictureBox1.Image = Nothing
fs.Close()
is there a equivalent to using in vb.net
this is what i would do in c#
using( filestream fs = new filestream)
{
//whatever you want to do in here
}
//closes after your done
As i can't comment yet (not enough experience points), this is an answer for the above
"is there a equivalent to using in vb.net"
Yes, in .Net 2.0 and above you can use "Using".
In .Net 1.0 and 1.1 however, you would need to dispose if the object in the finally block
Dim fs As System.IO.FileStream = Nothing
Try
'Do stuff
Finally
'Always check to make sure the object isnt nothing (to avoid nullreference exceptions)
If fs IsNot Nothing Then
fs.Close()
fs = Nothing
End If
End Try
Adding the closing of the stream in the finally block ensures that it will get closed no matter what (as opposed to the connection getting opened, a line of code bombing out beneath before the stream is closed, and the stream staying open and locking the file)
Related
Title says it all, How do I save a file from the application resources to the desktop for example?
In the future it will create a directory and store it in there, essentially I'm making a game installer, but none of this matters right now.
I have tried about 6 different code methods and all of them failed, kept throwing errors about not being able to convert an icon/image to a 1-dimensional array. Or that "Icon" or "Image" is not a member of System.Drawing.Icon
Any help would be appreciated
Thank you!
EDIT: Posting some code I've tried.
#1 ('Length' is not a member of System.Drawing.Icon)
Dim File01 As System.IO.FileStream = New System.IO.FileStream("C:\Users\" + Environment.UserName + "\Desktop\" + "EXAMPLE_Icon.ico", IO.FileMode.Create) File01.Write(My.Resources.EXAMPLE_Icon, 0, My.Resources.EXAMPLE_Icon.length) File01.Close()
#2 ('System.Drawing.Icon' cannot be converted to '1-dimensional array of Byte)
Dim filePath = Path.Combine("C:\Users\" + Environment.UserName + "\Desktop\", "EXAMPLE_Icon.ico") File.WriteAllBytes(filePath, My.Resources.EXAMPLE_Icon)
#3 ('RawFormat' is not a member of 'System.Drawing.Icon')
Dim filePath = Path.Combine("C:\Users\" + Environment.UserName + "\Desktop\", "EXAMPLE_Icon.ico") Using icon = My.Resources.EXAMPLE_Icon icon.Save("C:\Users\" + Environment.UserName + "\Desktop\", icon.RawFormat) End Using
Build the destination path using Path.Combine() when the path is composited.
Many known System locations have a predefined value in Environment.SpecialFolder: in your case, Environment.SpecialFolder.Desktop. Environment.GetFolderPath() accepts one of these values and returns the correct file system path.
This returns the Path of the Desktop folder for the current User:
Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
The Icon object has a Save() method that accepts a Stream as argument.
You can pass a FileStream to save the Icon to a File, preserving its format, or a MemoryStream, then use File.WriteAllBytes() to save the MemoryStream's buffer calling its ToArray() method.
Using a Resource name, as a string, using ResourceManager.GetObject():
Dim iconPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "myIcon.ico")
Using stream As New FileStream(iconPath, FileMode.Create, FileAccess.Write, FileShare.None),
ico = TryCast(My.Resources.ResourceManager.GetObject("myIcon"), Icon)
ico?.Save(stream)
End Using
Or, depending on what fits better in the context of your operations:
Using stream As New FileStream(iconPath, FileMode.Create, FileAccess.Write, FileShare.None)
My.Resources.myIcon.Save(stream)
End Using
GC.Collect()
Note: here, I'm calling GC.Collect() after calling Save() directly on the Icon object generated by My.Resources. The Docs don't exactly explain it: My.Resources is a factory, it doesn't return the object stored in the Project's Resources, it generates a new object (a different one each time) from the data stored as a Resource. With My.Resources.myIcon.Save(stream), we create a new object, save its data to disc, but never actually dispose of it. Calling GC.Collect() right after, the memory used is reclaimed immediately. If we don't, that memory is never reclaimed (we're leaking).
It's probably better to assign the generated object a to temporary variable declared with a Using statement. The two methods that follow can make use of GC.Collect(), calling it right after, to reclaim the allocated memory immediately, but it's not strictly required, we're not really leaking resources.
Open up Visual Studio's Diagnostic Tools to test the behavior with and without GC.Collect(), calling these methods multiple times.
Using stream As New FileStream(iconPath, FileMode.Create, FileAccess.Write, FileShare.None),
ico = My.Resources.myIcon
ico.Save(stream)
End Using
' GC.Collect() <= Not strictly required, but test the difference
Or using a MemoryStream:
Using ms As New MemoryStream(),
ico As Icon = My.Resources.myIcon
ico.Save(ms)
ms.Position = 0
File.WriteAllBytes(iconPath, ms.ToArray())
End Using
' GC.Collect() <= Not strictly required, but test the difference
I'm using this code to save image
PictureBox1.Image.Save(filePath)
after that I crop image and I want to save it again by replacing the old one with the new cropped one
any help please
regards,,,
Use the following code when you load the image into the PictureBox instead of the one you are currently using and you'll be fine just saving later. The using statement ensures the file is released once the image is loaded.
Replace filePath with your own.
Using stream as new FileStream(filePath, FileMode.Open, FileAccess.Read)
PictureBox1.Image = Image.FromStream(stream)
End Using
EDIT
From your last comment I can see this code
Try
Me.Opacity = 0%
Me.PictureBox1.Image = cc()
PictureBox1.Image.Save(filePath)
source = Image.FromFile(filePath)
PictureBox1.Image = source
TextBox1.Text = filePath
Me.Opacity = 100%
Catch ex As Exception
MsgBox(ex.Message)
End Try
You don't need to reload the image to the PictureBox after saving. Just get rid of the following lines.
source = Image.FromFile(filePath)
PictureBox1.Image = source
That should solve your problem at least for now as you won't be saving the image to the same image you load it from (you didn't actually load it). But you will have to find a better solution for your whole algorithm later :)
This's the answer
Dim bmp1 As New Bitmap(PictureBox1.Image)
If System.IO.File.Exists(filePath) Then
System.IO.File.Delete(filePath)
End If
bmp1.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg)
' Dispose of the image files.
bmp1.Dispose()
So I am creating a program that needs to be able to read line by line from a .cfg (config) file, it can open it happily; here is the code:
OpenConfig.ShowDialog()
file = OpenConfig.FileName()
fileReader()
However when it tries to read the file, using this code:
Function fileReader()
Dim reader As New StreamReader(file)
Dim vLb As ListBox = shopTabs.SelectedTab.Controls.Item(10) 'Listbox Variable
For i = 0 To reader.Peek
textline(i) = reader.ReadLine()
vLb.Items.Add(i)
Next
Return True
End Function
It throws an exception at the line:
textline(i) = reader.ReadLine()
Any help would be greatly appreciated as I can't work out why it does so.
Your code could be simplified into the following code:
Using openConfig As New OpenFileDialog()
If openConfig.ShowDialog(Me) = DialogResult.OK Then
For Each s As String In File.ReadAllLines(openConfig.FileName)
ListBox1.Items.Add(s)
Next
End If
End Using
As I commented, your code does some things that are highly questionable and undoubtedly difficult to maintain, such as referencing a control by the index property.
I suspect that your project would benefit from using UserControls too, since I'm guessing you have the same controls placed in every tab (a ListBox is always control index #10?).
When using the axAcroPdfLib.AxAcroPDF control in my Windows Forms application, I'm not able to reload the same image. The image is initially loaded with the LoadFile() method.
Upon using the LoadFile() method again on the same path AFTER saving changes to the PDF, the control becomes blank (no PDF shown).
If I set the src property of the control to the path, I get a message saying the file does not begin with '%PDF-'. But it does. I opened it with Word and it clearly begins with %PDF-. It's not corrupt or locked either.
I've even tried closing, disposing, or setting it to Nothing, and then completely re-instantiating it as I did the first time it's loaded - no effect. The window closes and shows with the control blank.
Loading a different file via the above methods has the same effect - blank.
Using Windows 7 64-bit, VS 2010, VB.NET.
The code is below. For right now, I'm just trying to draw a simple line on it.
Private Sub _btnBarCode_Click(ByVal sender As Object, ByVal e As EventArgs) Handles _btnBarCode.Click
Dim pdfReader As iTextSharp.text.pdf.PdfReader = Nothing
Try
pdfReader = New iTextSharp.text.pdf.PdfReader(File.ReadAllBytes(_path))
Using fs As New FileStream(_path, FileMode.Create, FileAccess.Write)
Using pdfStamper = New iTextSharp.text.pdf.PdfStamper(pdfReader, fs)
Dim pdfPage As iTextSharp.text.pdf.PdfContentByte = pdfStamper.GetOverContent(1)
Using barCodeForm As New FBarCode
barCodeForm.Barcode = _barCode
If (barCodeForm.ShowDialog(Me) = DialogResult.OK) Then
Dim screenBarCode As Point = barCodeForm.Location
Dim clientBarCode As Point = Point.op_Subtraction(PointToClient(screenBarCode), New Point(0, 50)) '_pdfControl.Location '_imgView.Location
clientBarCode = New Point(10, 50)
Dim barcodeImg As New Bitmap(200, 50)
Using gc As Graphics = Graphics.FromImage(barcodeImg)
gc.DrawLine(Pens.Red, New Point(10, 10), New Point(20, 20))
'barCodeForm._barCode.DrawBarCode(gc, clientBarCode)
End Using
Dim convert As ImageConverter = New ImageConverter()
Dim bmpBytes As Byte() = DirectCast(convert.ConvertTo(barcodeImg, GetType(Byte())), Byte())
Dim thisImage As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(bmpBytes)
thisImage.SetAbsolutePosition(clientBarCode.X, clientBarCode.Y)
thisImage.SetDpi(72, 72)
pdfPage.AddImage(thisImage)
rdrAdobePdf.LoadFile(_path) 'Blank pdf
'rdrAdobePdf.src = _path '"Does not begin with '%PDF-' (even though it does)
'Me.Close()
'_myParent.ResetPdfViewer()
'ReloadPdfViewer(Me.Barcode)
End If
End Using
End Using
End Using
Catch ex As Exception
MessageBox.Show(ex.Message, "An error occurred.")
Return
Finally
If Not pdfReader Is Nothing Then pdfReader.Close()
End Try
End Sub
Any ideas what could be the problem here?
Problem was solved by getting the reloading code out of that click method. Putting it in another click method solved the problem - not sure why. The code I used just ran .LoadFile, then Form.Show() and Form.Activate().
Is there something that needs to be done with the following code to release the memory it uses?
Dim objImage As MemoryStream
Dim objwebClient As WebClient
Dim sURL As String = Trim(m_StationInterface.PicLocation)
objwebClient = New WebClient
objImage = New MemoryStream(objwebClient.DownloadData(sURL))
m_imgLiftingEye.Image = Image.FromStream(objImage)
The code is on a popup form that shouldn't ever get disposed. A new image is loaded onto the form every time it pops up. However, the process size for the application continues to grow each time it makes it through that code block.
I've tried objImage.Close() and .Flush(), objWebClient.Dispose(). The process size still grows by a good 4mb after every call. It's like the old image is kept in memory.
Image implements IDisposable, so you should Dispose the old image before replacing it with a new one.
Something like (bear with me, I haven't used VB in a while):
Dim objImage As MemoryStream
Dim objwebClient As WebClient
Dim sURL As String = Trim(m_StationInterface.PicLocation)
objwebClient = New WebClient
objImage = New MemoryStream(objwebClient.DownloadData(sURL))
If m_imgLiftingEye.Image Is Not Nothing Then
m_imgLiftingEye.Image.Dispose()
End If
m_imgLiftingEye.Image = Image.FromStream(objImage)
Try this:
Function GetImage() As Image
Using wc As New WebClient(), _
ms As New MemoryStream(wc.DownloadData(m_StationInterface.PicLocation.Trim())
GetImage = Image.FromStream(ms).Clone()
End Using
End Function
MemoryStream implements the IDisposable interface, so you should call Dispose on that object when you are done using it:
objImage = New MemoryStream(objwebClient.DownloadData(sURL))
m_imgLiftingEye.Image = Image.FromStream(objImage)
objImage.Dispose()
I would guess your conclusion was right; the image (in the memory stream) does remain in the memory.
Update: as Marc pointed out Image.FromStream requires the stream to remain open for the lifetime of the image. To resolve this the MemoryStream variable should be declared in same scope as the image (as a field in the form). When loading the image, there should first be a check whether the MemoryStream already is open and if so, close and dispose it before using the variable for a new stream (let's assume that we call it m_imageStream). Since the image also implements IDisposable, the same is true for that one:
If Not m_imageStream Is Nothing Then
m_imageStream.Dispose()
End If
If m_imgLiftingEye.Image Is Not Nothing Then
m_imgLiftingEye.Image.Dispose()
End If
m_imageStream = New MemoryStream(objwebClient.DownloadData(sURL))
m_imgLiftingEye.Image = Image.FromStream(m_imageStream)
I know I already gave one answer, but I've been thinking since then...
You said that this form should never be disposed. In that case, when exactly is this image load happening? My previous answer assumed it was during the form Shown event. However, if it's during the form Load event, it should only happen once total.
That is, unless more than one instance of the form is being created. If that's the case, and the previous form isn't being reused, you're ending up with multiple copies of the same form loaded in memory, each with its own copy of the image.
You could try
set objImage = nothing
set objwebClient = nothing
Often, like with ADO, if you don't explicitly set it to nothing it doesn't get released properly.