[2008] Image Control Resources in WPF
I am trying to write an image viewer that will show JPEG files. I can get them to show using an Image control with no trouble.
I have a button on the form that I want to use to rotate the displayed image by 90 degrees, save the changes to disk and then reload the image in the Image control.
I am using the following code:
Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
Dim extension As String = Path.GetExtension("c:\jpg.jpg")
Dim rootFilename As String = Path.GetDirectoryName("c:\jpg.jpg") & "\" & _
Path.GetFileNameWithoutExtension("c:\jpg.jpg")
Dim dtstart As DateTime = Now
Dim imageSource As BitmapSource = Image1.Source
imageSource = New TransformedBitmap(imageSource, New RotateTransform(90))
Dim encoder As New JpegBitmapEncoder
encoder.QualityLevel = 80
encoder.Frames.Add(BitmapFrame.Create(imageSource))
imageSource = Nothing
Dim fs As New IO.FileStream(rootFilename & extension & "-bak", FileMode.Create, FileAccess.Write)
encoder.Save(fs)
fs.Dispose()
Dim dtend As DateTime = DateTime.Now
Dim sw As New IO.StreamWriter("c:\testing\results.txt", True)
sw.WriteLine("WPF Start at: " & dtstart.ToLongTimeString)
sw.WriteLine("WPD End at: " & dtend.ToLongTimeString)
sw.Dispose()
encoder = Nothing
Image1.Source = Nothing
IO.File.Delete(rootFilename & extension)
IO.File.Move(rootFilename & extension & "-bak", rootFilename & extension)
Image1.Source = New BitmapImage(New Uri(rootFilename & extension))
End Sub
At the line "IO.File.Delete(rootFileName & extension)", I keep getting an error that "c:\jpg.jpg" cannot be accessed because it is being used by another process. I have pored over the code and I think I've disposed of all of the resources that relate to "c:\jpg.jpg", right? What am I missing? I'm tired and may be missing something really easy, but I'm new to WPF, and some of it's confusing to me, so please be gentle. :)
Re: [2008] Image Control Resources in WPF
I haven't looked too closely at your code but I would suggest that you make use of the Using statement to ensure that disposable objects get disposed.
Re: [2008] Image Control Resources in WPF
I'm pretty sure the only two variables in that code block that implement IDisposable are the FileStream (which doesn't lock "c:\jpg.jpg", but does lock "c:\jpg.jpg-bak"), and the StreamWriter (again, not locking "c:\jpg.jpg"), both of which I actually dispose of.
I guess I could replace "Dim fs ... fs.Dispose" with "Using fs ... End Using", but what's the difference? Does a "Using ... End Using" block dispose of resources better than calling .Dispose on an object?
Also, it appears that the BitmapSource and JpegBitmapEncoder objects don't implement IDisposable, so you clear their resources by setting them equal to Nothing, right? Do I need to force a Garbage Collection between doing so and trying to access the file again?
Thanks for any help!
Re: [2008] Image Control Resources in WPF
I guess what I'm looking for is the Image control equivalent of the PictureBox.Image.Dispose method.
Re: [2008] Image Control Resources in WPF
I've never used WPF in anger so I'm not sure if there's a better way, and I feel like there must be, but the Bitmapimage class has a StreamSource property that is type Stream, so you can dispose that.
Re: [2008] Image Control Resources in WPF
JMc,
I'm not sure I understood your post. Do you not use WPF because you're angry with it? Or do you think I'm using it out of anger?
Also, I've tried and tried to figure the code out, but I still come back to the same issue that when I try to delete the file to replace it with the modified file, the debugger tells me the file is already locked by another process. I don't suppose there is any way to query a file and see what process has it locked, it there?
Can anyone else (or you, JMc) take a look at the code and see a problem?
This is really frustrating me.
By the way, JMc, I've looked for a way to access the StreamSource property and dispose of it, but I can't find a way to get to it using the objects I've declared. Am I missing something? (Of course I am, or else I wouldn't be posting, right?)
Thanks to anyone who helps me!!!
Re: [2008] Image Control Resources in WPF
I think I might have figured out a way to solve the problem, even if I can't figure out why a link to the file exists despite my best intentions.
Here are 3 subs that I've written to try to make sure the file is closed after it's opened:
Code:
Private Sub LoadImage(ByVal strFileName As String)
Dim bytes() As Byte = LoadImageData(strFileName)
Image1.Source = CreateImage(bytes, 0, 0)
End Sub
Private Shared Function LoadImageData(ByVal filePath As String) As Byte()
Dim fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
Dim br As New BinaryReader(fs)
Dim imageBytes As Byte() = br.ReadBytes(CInt(fs.Length))
br.Close()
fs.Close()
Return imageBytes
End Function
Private Function CreateImage(ByVal imageData As Byte(), ByVal decodePixelWidth As Integer, ByVal decodePixelHeight As Integer) As BitmapSource
Dim result As New BitmapImage()
result.BeginInit()
If (decodePixelWidth > 0) Then
result.DecodePixelWidth = decodePixelWidth
End If
If (decodePixelHeight > 0) Then
result.DecodePixelHeight = decodePixelHeight
End If
result.StreamSource = New MemoryStream(imageData)
result.CreateOptions = BitmapCreateOptions.None
result.CacheOption = BitmapCacheOption.Default
result.EndInit()
Return result
End Function
I actually borrowed some of this code from a blog, so I'm a little uncertain about the BeginInit ... EndInit block, but it appears that the whole solution allows the file to be loaded into a byte() array and then the file is let go and I can do what I want with the array.
Hope this helps someone!