MemoryStream bug?

  • Thread starter Thread starter Don
  • Start date Start date
D

Don

When I run the following code, the MemoryStream's Position is always set to
762 instead of 0, which is what I would expect:


Dim bmp As Image
Dim ms As MemoryStream

bmp = New System.Drawing.Bitmap("C:\2068.bmp")
ms = New MemoryStream
bmp.Save(ms, bmp.RawFormat)
Console.WriteLine("MemoryStream Position = " & ms.Position)
ms.Close()


This is happening on two different computers for me. Does this happen to
anyone else? Is there a reason why the memory stream's position is set to
762 instead of 0? Or is it proper practice to always manually set stream
positions to zero when first creating them?

- Don
 
Don,
| Does this happen to
| anyone else?
Yes

| Is there a reason why the memory stream's position is set to
| 762 instead of 0?
Yes, as I suspect that the bmp.Save statement wrote 762 bytes of information
to the stream.

| bmp.Save(ms, bmp.RawFormat)
| Console.WriteLine("MemoryStream Position = " & ms.Position)

Seeing as Image.Save is writing information to the stream, I would expect
the stream's position to actually move, so when I write more information to
the stream the stream is positioned to a "writable" position...

| Or is it proper practice to always manually set stream
| positions to zero when first creating them?
No, I don't set the position when first creating them.

Hope this helps
Jay

| When I run the following code, the MemoryStream's Position is always set
to
| 762 instead of 0, which is what I would expect:
|
|
| Dim bmp As Image
| Dim ms As MemoryStream
|
| bmp = New System.Drawing.Bitmap("C:\2068.bmp")
| ms = New MemoryStream
| bmp.Save(ms, bmp.RawFormat)
| Console.WriteLine("MemoryStream Position = " & ms.Position)
| ms.Close()
|
|
| This is happening on two different computers for me. Does this happen to
| anyone else? Is there a reason why the memory stream's position is set to
| 762 instead of 0? Or is it proper practice to always manually set stream
| positions to zero when first creating them?
|
| - Don
|
|
 
Don said:
bmp = New System.Drawing.Bitmap("C:\2068.bmp")
ms = New MemoryStream
bmp.Save(ms, bmp.RawFormat)
Console.WriteLine("MemoryStream Position = " & ms.Position)
ms.Close()


This is happening on two different computers for me. Does this happen to
anyone else? Is there a reason why the memory stream's position is set to
762 instead of 0?

I assume it's caused by writing the data to the stream. By writing data the
input position will be incremented by the number of bytes written to the
stream.
 
I've tried this with two different sized images, both about 30K in size, and
the Position was initialized to 762 in both cases. Using a hex editor I
determined that this was exactly 762 bytes into the actual image. It seems
like an arbitrary position in the middle of the stream.

- Don
 
Jay B. Harlow said:
Don,
| Does this happen to
| anyone else?
Yes

Have you tried it? What were the results?

| Is there a reason why the memory stream's position is set to
| 762 instead of 0?
Yes, as I suspect that the bmp.Save statement wrote 762 bytes of
information to the stream.

Nope. The image that was loaded into the memory stream was about 30,000
bytes.

| bmp.Save(ms, bmp.RawFormat)
| Console.WriteLine("MemoryStream Position = " & ms.Position)

Seeing as Image.Save is writing information to the stream, I would
expect the stream's position to actually move, so when I write more
information to the stream the stream is positioned to a "writable"
position...

That would make sense if the Position also equalled the length of the image
stored into the stream, but it doesn't.

| Or is it proper practice to always manually set stream
| positions to zero when first creating them?

No, I don't set the position when first creating them.

I didn't do this either, at first, and it always resulted in a corrupt image
when I tried to make one from the stream because the first 762 bytes were
chopped off.

- Don
 
Don,

I only can say that I don't do the way you do.

Have a look at this sample that I made yesterday for somebody else.

\\\Needs two pictureboxes and a button on a form
Private Sub Form1_Load(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim fo As New OpenFileDialog
If fo.ShowDialog = DialogResult.OK Then
Dim fs As New IO.FileStream(fo.FileName, _
IO.FileMode.Open)
Dim br As New IO.BinaryReader(fs)
Dim abyt As Byte()
abyt = br.ReadBytes(CInt(fs.Length))
br.Close()
'just to show the sample without a fileread error
Dim ms As New IO.MemoryStream(abyt)
Me.PictureBox1.Image = Image.FromStream(ms)
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim abyt As Byte()
Dim ms As New IO.MemoryStream
PictureBox1.Image.Save(ms, Imaging.ImageFormat.Bmp)
abyt = ms.GetBuffer
Dim ms2 As New IO.MemoryStream(abyt)
Me.PictureBox2.Image = Image.FromStream(ms2)
Me.PictureBox1.Image = Nothing
End Sub
////
I hope this helps a little bit?

Cor
 
Don,
| Have you tried it? What were the results?
I have written to a memory stream lots of times, each time I write to it,
the Position property moved the number of bytes that I wrote. Ergo the point
of my yes!

I have not specifically used the Image.Save method.

| Nope. The image that was loaded into the memory stream was about 30,000
| bytes.
Then obviously ms.Position needs to be about 30,000 then doesn't it! My
point is that ms.Position will not be zero as you wrote data to the Stream.

| That would make sense if the Position also equalled the length of the
image
| stored into the stream, but it doesn't.
Ah! There's the rub! I would expect Position should equal the length of the
image file. Oddly enough ms.Length equals the length of the image file.

Have you looked at what is actually in the memory stream? Is only the first
762 bytes of the image written? Has only the image header been written,
instead of the image header & actual bit information?


Interesting enough if start with a jpeg or save to a jpeg:

| > | bmp.Save(ms, Imaging.ImageFormat.Jpeg)
| > | Console.WriteLine("MemoryStream Position = " & ms.Position)

Then ms.Position & ms.Length do match, so it seems to me that writing a
Bitmap has some special quirk to it, unfortunately I don't bitmaps as much
as I use Jpegs. Have you tried writing to a FileStream instead of a
MemoryStream? Do you have the same problem? I see the same results with a
FileStream or MemoryStream, which suggests the "bug" aka quirk is really in
the Image.Save method when using ImageFormat.Bmp. A quick (very quick)
search of support.microsoft.com has not offered any suggestions.

Have you considered asking "down the hall" in the
microsoft.public.dotnet.framework.drawing newsgroup about any special quirks
on saving a Bitmap (.BMP) file?

Hope this helps
Jay

|
| | > Don,
| > | Does this happen to
| > | anyone else?
| > Yes
|
| Have you tried it? What were the results?
|
|
| > | Is there a reason why the memory stream's position is set to
| > | 762 instead of 0?
| > Yes, as I suspect that the bmp.Save statement wrote 762 bytes of
| > information to the stream.
|
| Nope. The image that was loaded into the memory stream was about 30,000
| bytes.
|
|
| >
| > | bmp.Save(ms, bmp.RawFormat)
| > | Console.WriteLine("MemoryStream Position = " & ms.Position)
| >
| > Seeing as Image.Save is writing information to the stream, I would
| > expect the stream's position to actually move, so when I write more
| > information to the stream the stream is positioned to a "writable"
| > position...
|
| That would make sense if the Position also equalled the length of the
image
| stored into the stream, but it doesn't.
|
|
| > | Or is it proper practice to always manually set stream
| > | positions to zero when first creating them?
| >
| > No, I don't set the position when first creating them.
|
| I didn't do this either, at first, and it always resulted in a corrupt
image
| when I tried to make one from the stream because the first 762 bytes were
| chopped off.
|
| - Don
|
|
 
Don,
Mystery solved!

Its how Bitmap.Save is implemented!

Based on the TraceStream class (below) Bitmap.Save writes rows from the end
of the file to the beginning of the file.

Try the following with the TraceStream class:

Dim bmp As Image
Dim ms As IO.MemoryStream

bmp = New System.Drawing.Bitmap("C:\2068.bmp")
ms = New IO.MemoryStream
Dim ts As New TraceStream(ms)
bmp.Save(ts, bmp.RawFormat)
Console.WriteLine("MemoryStream Position = " & ms.Position)
ms.Close()

Notice the initial SetLength and then how the Position decreases & one "row"
of bytes are written. Hence the Stream is left at the length of the header +
the length of one "row" in bytes, your 762 and not the about 30,000 I would
expect (based on your other message).


A quick TraceStream class, it writes trace information on selected
methods...

---x--- cut here ---x--- begin TraceStream.vb ---x---
Option Strict On
Option Explicit On

Imports System.IO

Public Class TraceStream
Inherits Stream

Private ReadOnly m_stream As Stream

Public Sub New(ByVal stream As Stream)
If stream Is Nothing Then Throw New ArgumentNullException("stream")
m_stream = stream
End Sub

Private Sub WriteTrace(ByVal format As String, ByVal ParamArray args()
As Object)
Dim message As String = String.Format(format, args)
Trace.WriteLine(message, "TraceStream")
End Sub

Public Overrides ReadOnly Property CanRead() As Boolean
Get
Return m_stream.CanRead
End Get
End Property

Public Overrides ReadOnly Property CanSeek() As Boolean
Get
Return m_stream.CanSeek
End Get
End Property

Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return m_stream.CanWrite
End Get
End Property

Public Overrides ReadOnly Property Length() As Long
Get
Return m_stream.Length
End Get
End Property

Public Overrides Property Position() As Long
Get
Return m_stream.Position
End Get
Set(ByVal value As Long)
WriteTrace("Position={0}", value)
m_stream.Position = value
End Set
End Property

Public Overrides Sub Flush()
WriteTrace("Flush")
m_stream.Flush()
End Sub

Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As
Integer, ByVal count As Integer) As Integer
WriteTrace("Read(buffer={0}, offset={1}, count={2})", buffer,
offset, count)
Return m_stream.Read(buffer, offset, count)
End Function

Public Overrides Function Seek(ByVal offset As Long, ByVal origin As
System.IO.SeekOrigin) As Long
WriteTrace("Seek(offset={0}, origin={1})", offset, origin)
Return m_stream.Seek(offset, origin)
End Function

Public Overrides Sub SetLength(ByVal value As Long)
WriteTrace("SetLength(value={0})", value)
m_stream.SetLength(value)
End Sub

Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As
Integer, ByVal count As Integer)
WriteTrace("Write(buffer={0}, offset={1}, count={2})", buffer,
offset, count)
m_stream.Write(buffer, offset, count)
End Sub

Public Overrides Sub WriteByte(ByVal value As Byte)
WriteTrace("WriteByte(value={0})", value)
m_stream.WriteByte(value)
End Sub

End Class
---x--- cut here ---x--- end TraceStream.vb ---x---

Hope this helps
Jay

| When I run the following code, the MemoryStream's Position is always set
to
| 762 instead of 0, which is what I would expect:
|
|
| Dim bmp As Image
| Dim ms As MemoryStream
|
| bmp = New System.Drawing.Bitmap("C:\2068.bmp")
| ms = New MemoryStream
| bmp.Save(ms, bmp.RawFormat)
| Console.WriteLine("MemoryStream Position = " & ms.Position)
| ms.Close()
|
|
| This is happening on two different computers for me. Does this happen to
| anyone else? Is there a reason why the memory stream's position is set to
| 762 instead of 0? Or is it proper practice to always manually set stream
| positions to zero when first creating them?
|
| - Don
|
|
 
Cor Ligthert,


many thanks!!

your code is wonderful..^^
but I can't still solve this problem..

Save Image in SQL DB ----------------------------------
Dim picturedata as byte()
Dim ms As New IO.MemoryStream
picturebox1.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
picturedata = ms.GetBuffer

....SQL process...
Dim myCommand As New SqlCommand(myInsertQuery, myConnection)
myCommand.CommandText = "InsertData"
Dim myParm1 As SqlParameter = myCommand.Parameters.Add("@image",
SqlDbType.image)
myParm1.Value = picturedata


Load image -----------------------------------------------
.....
if myreader.Read()

Dim picutredata as byte()
picturedata = myreader("image")
Dim ms as New IO.Memorystream(picturedata)
pictureBox1.image = image.Fromstream(ms) ---> argument error


I don't know what is a problem.. could you help me?

Joe
 
Joe,

I had to make this sample the day before yesterday, because I have a
standard sample for database hanlding in which I saw than that I had removed
the transforming from an image directly. However for your database handling
you can look at the original sample.

Try to look all around things handling this sampling as writting to disk
from the image and dataset. (I will probably make a more compact one from
this in short future).

http://groups-beta.google.com/group/microsoft.public.dotnet.languages.vb/msg/9bbd27ce29590856?hl=en

I hope this helps,

Cor
 
Cor,
Aren't you getting extra data at the end of the file?

As MemoryStream.GetBuffer returns the entire buffer (MemoryStream.Capacity)
for the MemoryStream which may contain "buffer" after the actual file end
(MemoryStream.Length). Normally I use MemoryStream.ToArray when I want a
copy of the "entire" file.

| abyt = ms.GetBuffer

Hope this helps
Jay

| Don,
|
| I only can say that I don't do the way you do.
|
| Have a look at this sample that I made yesterday for somebody else.
|
| \\\Needs two pictureboxes and a button on a form
| Private Sub Form1_Load(ByVal sender As _
| System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
| Dim fo As New OpenFileDialog
| If fo.ShowDialog = DialogResult.OK Then
| Dim fs As New IO.FileStream(fo.FileName, _
| IO.FileMode.Open)
| Dim br As New IO.BinaryReader(fs)
| Dim abyt As Byte()
| abyt = br.ReadBytes(CInt(fs.Length))
| br.Close()
| 'just to show the sample without a fileread error
| Dim ms As New IO.MemoryStream(abyt)
| Me.PictureBox1.Image = Image.FromStream(ms)
| End If
| End Sub
| Private Sub Button1_Click(ByVal sender As System.Object, _
| ByVal e As System.EventArgs) Handles Button1.Click
| Dim abyt As Byte()
| Dim ms As New IO.MemoryStream
| PictureBox1.Image.Save(ms, Imaging.ImageFormat.Bmp)
| abyt = ms.GetBuffer
| Dim ms2 As New IO.MemoryStream(abyt)
| Me.PictureBox2.Image = Image.FromStream(ms2)
| Me.PictureBox1.Image = Nothing
| End Sub
| ////
| I hope this helps a little bit?
|
| Cor
|
|
 
Jay,

You know that I never search long for an extra byte less or more.

However when I know it than I keep notice of it.

Therefore thanks I will check this and make changes accoording to that.

Cor
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top