create bitmap image from byte array

Status
Not open for further replies.

rogs95

Member
Joined
Mar 1, 2006
Messages
11
Programming Experience
1-3
I am using a data file that contains ASCII and binary data, seperated in to records, the first two records are ASCII which i have no problem reading using system.io.filestream

The third record is a binary black and white image, i need help creating a new bitmap from this data and displaying it on the form. The binary data in the record gives me the number of pixels in each horizontal and vertical line

Any help is appreciated.
 
You can write the image bytes to a MemoryStream and use this as source for Bitmap constructor.
 
Here is the code that i am using for the memorystream but i keep getting the error that an invalid paramater has been used.

VB.NET:
[SIZE=2][COLOR=#008000]
[/COLOR][/SIZE][SIZE=2][COLOR=black]s1 = [/COLOR][/SIZE][SIZE=2][COLOR=black]New[/COLOR][/SIZE][SIZE=2][COLOR=black] FileStream(FILE_NAME, FileMode.Open, FileAccess.Read)[/COLOR]
[COLOR=black]ms = [/COLOR][/SIZE][SIZE=2][COLOR=black]New[/COLOR][/SIZE][SIZE=2][COLOR=black] MemoryStream(769166)[/COLOR]
[COLOR=black]br = [/COLOR][/SIZE][COLOR=black][SIZE=2]New[/SIZE][SIZE=2] BinaryReader(s1)[/SIZE][/COLOR]
[COLOR=black][/COLOR][SIZE=2] 
[/SIZE][SIZE=2][COLOR=black]br.BaseStream.Seek(373, SeekOrigin.Current)[/COLOR]
[/SIZE][SIZE=2][/SIZE][COLOR=black][SIZE=2]Dim[/SIZE][SIZE=2] bytesRead [/SIZE][SIZE=2]As[/SIZE][SIZE=2] [/SIZE][SIZE=2]Byte[/SIZE][SIZE=2]() = br.ReadBytes(769166)
[/SIZE][/COLOR][SIZE=2][COLOR=black] 
[/COLOR][/SIZE][SIZE=2][COLOR=black]ms.Read(bytesRead, 0, 769166)[/COLOR]
[COLOR=black][/COLOR] 
[/SIZE][SIZE=2][COLOR=black]Dim Finger As New Bitmap(ms)[/COLOR]
[/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#008000][COLOR=black]PictureBox1.Image = Finger[/COLOR]
[/COLOR][/SIZE]

If anyone can tell me what i'm missing it will be appreciated
 
You get an ArgumentException from System.Drawing.dll because stream (ms) does not contain image data or is a null reference. ms.Read reads from the stream into the bytes array buffer. You want to ms.Write to write to the stream from the bytes array buffer.

You don't need the BinaryReader, the FileStream supports both read/write of byte buffers. Actually the BinaryReader could be a problem too, it uses default utf-8 encoding that may differ from the file encoding. Just a thought.
 
Here is the code changes just using filestream and not binaryreader.
From what i understand of bitmap, it only takes memorystream, so i am trying to use s1.read to read the image into the byte array and then ms.write to write it to the memorystream, (i cannot use s1 for the binary as the image is contained in the file and needs to be brought out)

I am now getting the error that the buffer cannot be null on s1.read

VB.NET:
[SIZE=2]s1 = [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] FileStream(FILE_NAME, FileMode.Open, FileAccess.Read)
ms = [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] MemoryStream(769166)[/SIZE]
[SIZE=2][COLOR=#008000] 
[/COLOR][/SIZE][SIZE=2]s1.Seek(391, SeekOrigin.Current)
 
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] bytesRead [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Byte[/COLOR][/SIZE][SIZE=2]()
s1.Read(bytesRead, 0, 769166)
[/SIZE][SIZE=2]

ms.Write(bytesRead, 0, 769166)
 
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2]Finger As [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] Bitmap(ms)[/SIZE][SIZE=2][COLOR=#008000]
[/COLOR][/SIZE][SIZE=2]PictureBox1.Image = Finger
[/SIZE]

If anyone can tell me what i'm missing it will be appreciated
 
looks right to me, except you have to dimension the bytesRead array first:
Dim bytesRead(769165) As Byte
 
Btw, Bitmap constructor would take any stream as long as it contains a qualified image and nothing else. Since your FileStream contains various data, it is neccessary to extract only the image portion, and for that a MemoryStream is suitable.
Come to think of it, you can skip the array too:

VB.NET:
 [LEFT]s1 = New FileStream(FILE_NAME, FileMode.Open, FileAccess.Read)
[LEFT]ms = New MemoryStream()
s1.Seek(391, SeekOrigin.Current)
For i As Integer = 0 To 769165 '=769166 bytes
 ms.WriteByte(s1.ReadByte)
Next
Dim Finger As New Bitmap(ms)
PictureBox1.Image = Finger[/LEFT]


[/LEFT]

 
Thanks

That seems to work, however i am now getting an error on:
VB.NET:
[SIZE=2][COLOR=#0000ff]
Dim[/COLOR][/SIZE][SIZE=2] Finger [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] Bitmap(ms)
[/SIZE]
saying "invalid parameter used"

Although i have a feeling i maybe looking at the wrong set of bytes
 
It does work, but you have you to get the exact byte set of the image. If you need to verify the technique, you can use the same code and load a pure image file with the FileStream, transfer all the bytes to MemoryStream, then input the MemoryStream to the Bitmap constructor.
 
Here is reference for the specific context rogs95 is working in, maybe someone got some specific info about working with image bytes contained within this, drop a line if you have useful info.
"American National Standard for Information Systems — Data Format for the Interchange of Fingerprint, Facial, & Scar Mark & Tattoo (SMT) Information" http://www.griaule.com/public_download/sp500-245-a16.pdf
 
OK here we go.

There is no problem reading the type one and type two records, combined they have a length of 355 bytes, which is assigned to 'Basestart'.

The third record that i am looking at is a type 4 fingerprint image:
Field 1 gives the record length of 474739 assigned to 'Type4size'
Field 6 gives the horizontal line length of 689 assigned to 'image_width'
Field 7 gives the vertical line length of 689 assigned to 'image_height'


According to the standard the image data starts after the first 18 bytes.


VB.NET:
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] ms [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] MemoryStream
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] image_size [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Integer[/COLOR][/SIZE]
[SIZE=2]image_size = Type4size - 18
 
ms = [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] MemoryStream(image_size)[/SIZE]
 
[SIZE=2]
fs.Seek(Basestart + 18, SeekOrigin.Begin)
 
[/SIZE]
[SIZE=2][COLOR=#0000ff]For[/COLOR][/SIZE][SIZE=2] i = 0 [/SIZE][SIZE=2][COLOR=#0000ff]To[/COLOR][/SIZE][SIZE=2] image_size - 1[/SIZE]
[SIZE=2] ms.WriteByte(fs.ReadByte)
[/SIZE][SIZE=2][COLOR=#0000ff]Next[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff] 
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] Finger [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] Bitmap(ms)[/SIZE]
[SIZE=2][SIZE=2][COLOR=#008000][SIZE=2][SIZE=2][COLOR=black]PictureBox1.Image = Finger[/COLOR][/SIZE][/SIZE][/COLOR][/SIZE][/SIZE]

fs.seek moves to the first byte of the image the the image is read to memory stream to create a new bitmap. The error i am getting from New Bitmap(ms) is that an invalid parameter is used.

I am definiatly looking at the correct bytes now as one byte past the image the next set of 18 bytes starts for the next type 4 record.

When looking at the bytes it seems to go straight into the pixel data, first 20 bytes are all 255, which matches the image i am trying to open (black fingerprint on white background.


I have found this:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDrawingBitmapClassctorTopic12.asp

it seems to be able to create the image from a stream of pixels and 'image_width' and 'image_height', but need guidence of how to implement it.
 
Those numbers don't add up to a standard bitmap data array. They do correspond to the bytes of width*height, but for the bitmap data they have to be layed out in a specific manner. What I'm talking about is the Stride, which is the number of bytes per row, this have to be a multiple of 4. In your case of 8 bits per pixel (8bpp) there is one byte per pixel, so one row of 689 pixels is 689 bytes. 689 is not a multiple of 4 (172,25), 692 is (172,25 -> 173 *4 = 692). So for standard compliant bitmap data it should have been 692*689=476788 bytes, not 474721.
Here is an article with a graphics of the bitmap data array:
http://www.codersource.net/csharp_image_Processing.aspx

What could possibly be done is to read the bytes into an local one dimensional array while skipping three bytes (690-692) for each row, then put the array into memory with InterOp and just consider its pointer to be Scan0. Still not sure if the Bitmap will load regarding imageformat (8bppindexed?). Stride would be 692.

There could be other solutions, but you should understand by now that this is not regular out-of-the-box file and image processing, at least not in .Net.
 
Status
Not open for further replies.
Back
Top