Howdy All,
I have an object model that stores images for use in a graphics
application. Rather than reading the images and keeping them in memory,
which has a HUGE footprint, I instead read the file into an array of
bytes, convert the array of bytes into a memory stream, then use the
Image.FromStream method to create the image. When I am done with that
image, I dispose of the image object, but keep the memory stream open
so it is quick to access next time. This sort of works and has a much
smaller footprint. However, whenever I try to display the image in a
picture box, I get the following error:
A generic GDI+ error occurred.
Invalid parameter used.
System.ArgumentException: Invalid parameter used.
at System.Drawing.Image.get_Width()
at System.Drawing.Image.get_Size()
at System.Windows.Forms.PictureBox.get_ImageRectangle()
at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
at
System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e,
Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32
msg, IntPtr wparam, IntPtr lparam)
The code that creates the memory stream and image from the stream is as
follows:
Public Sub LoadImageStream()
If m_ImageStream Is Nothing Then
If m_Path.Length > 0 AndAlso System.IO.File.Exists(m_Path) Then
SyncLock m_ImageLockObject
Dim fs As New System.IO.FileStream(m_Path, IO.FileMode.Open,
IO.FileAccess.Read, IO.FileShare.Read)
Dim arr(CInt(fs.Length - 1)) As Byte
fs.Read(arr, 0, CInt(fs.Length))
fs.Close()
m_ImageStream = New System.IO.MemoryStream(arr)
End SyncLock
End If
End If
End Sub
Public ReadOnly Property Image() As System.Drawing.Bitmap
Get
If m_ImageStream Is Nothing Then
LoadImageStream()
DisposeImage()
End If
If m_Image Is Nothing AndAlso Not m_ImageStream Is Nothing Then
m_Image = CType(System.Drawing.Bitmap.FromStream(m_ImageStream,
True), System.Drawing.Bitmap)
End If
Return m_Image
End Get
End Property
The image loads from the stream with no problem. But, when I try to
display the image in the picture box, I get the error.
I have seen tons of posts related to this. But, I have yet to find a
solution to the problem.
Does anyone have a solution, or is there some better method of caching
these images in memory?
Thanks,
Matthew Roberts
mroberts_hm<at>hotmail<dot>com
matthewroberts<at>srcp<dot>com
Michael Phillips, Jr. - 27 Oct 2005 15:43 GMT
When you create a bitmap from a stream,
The bitmap takes control of the stream and the
stream must remain open for the life of the bitmap.
This is a GDI+ requirement.
When you dispose of the bitmap, the stream is invalid and must
be recreated when you create another bitmap.
> Howdy All,
>
[quoted text clipped - 72 lines]
> mroberts_hm<at>hotmail<dot>com
> matthewroberts<at>srcp<dot>com
Matthew - 27 Oct 2005 16:23 GMT
The stream is remaining open. However, I was unaware that the memory
stream becomes "currupt" once the bitmap is disposed. However, in this
case, I am simply trying to display one image without disposing of
either, and I still get the error. I have even tried using "FromFile",
and it will throw the error once the image tries to draw on the
PictureBox. If, however, I clone the bitmap and try to display the
clone, all is well.
My question then would be, if the methods I am using to cache images
are not working (by caching the file streams which are small, rather
than caching the entire image which is large once decompressed), how
can I cache the images in a small footprint manner so that I do not
have to retrieve them from the file system every time I want to display
them. I need speed when switching from one image to another, so reading
from the file system is not a solution. I thought by having the file
streams cached in memory, I would work it out, but obviously this is
causing problems in GDI+.
The even stranger thing is, I have this same caching technique in
another object model that we use in production. It works 99% of the
time, but then gives that error sometimes when it tries to paint. I
created a workaround by recreating the image controls whenever this
happens, but it is a hack.
So, what would you recommend to cache images in a small footprint for
fast display?
Thanks,
Matthew
Michael Phillips, Jr. - 27 Oct 2005 19:56 GMT
Each image that you create owns the stream
until you dispose of the image.
You can not write to a stream that was opened for reading
for any image.
You can still cache your uncompressed images.
> m_ImageStream = New System.IO.MemoryStream(arr)
You can create an array of bytes that hold uncompressed
images. Do the file IO once to fill the array with your
uncompressed images.
Just create a new Stream from the same cached byte array
every time you need to display a different image.
The cached byte array remains compressed until you associate
it with a stream for display purposes.
> The stream is remaining open. However, I was unaware that the memory
> stream becomes "currupt" once the bitmap is disposed. However, in this
[quoted text clipped - 25 lines]
> Thanks,
> Matthew