Problem converting BYTE[] to image

Can someone give me a good example on converting a byte array into an image. I keep getting an error that the paramenter is not valid. when I'm trying to convert it to a picture. I return the BYTE[] from the database fine.
sub main
Dim myimg As Image
   myimg = byteArrayToImage(DownloadFile(3))
myimg.save("C:\test.bmp")
end sub
 
Public Function byteArrayToImage(ByVal byteArrayIn As Byte()) As Image
        Dim ms As New MemoryStream(byteArrayIn)
        Dim returnImage As Image = Image.FromStream(ms)
        Return returnImage
    End Function
 
Private Function downloadFileFromDatabase(ByVal kfile As Long) As Byte()
        Dim conn As SqlConnection = Nothing
        Dim cmd As SqlCommand = Nothing
        Dim kFileName As SqlParameter = Nothing
        Dim dr As SqlDataReader = Nothing
        Dim result As Byte() = Nothing
        Try
 
            conn = New SqlConnection(ConnectionString())
            cmd = New SqlCommand("DownloadFile", conn)
            cmd.CommandType = System.Data.CommandType.StoredProcedure
 
            kFileName = New SqlParameter("@ID", System.Data.SqlDbType.BigInt, 8)
            kFileName.Value = kfile
 
            cmd.Parameters.Add(kFileName)
 
            conn.Open()
            dr = cmd.ExecuteReader()
            dr.Read()
 
            result = CType(dr.GetValue(0), Byte())
 
            dr.Close()
            conn.Close()
 
            conn.Dispose()
            cmd.Dispose()
 
        Catch e As Exception
 
            MsgBox(e.Message)
            result = Nothing
        End Try
        Return result
    End Function

Open in new window

cobolinx1Asked:
Who is Participating?
 
Christopher KileConnect With a Mentor Commented:
I suspect that the format of the data is BMP, not JPG.  Also, check out this entry from TechNet:
http://technet.microsoft.com/en-us/library/ms156342.aspx
This indicates that you may have to removed OLE header information from the BLOB before you display it (Access processes this information, but .NET would reject it as not being proper image format).
0
 
UnifiedISCommented:
Add this line before your return statement (line 10):
returnImage.Save(MS, System.Drawing.Imaging.ImageFormat.Bmp)

Return returnImage
0
 
cobolinx1Author Commented:
The error I'm getting is from  
Dim returnImage As Image = Image.FromStream(ms)
It says parameter not valid
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

 
Christopher KileCommented:
From the definition of Image.FromStream():

You must keep the stream open for the lifetime of the Image.

But, as soon as you return from byteArrayToImage(), the stream you used to construct the image (which is a local variable) is released for garbage collection.
Try either combining everything into one function or make the stream variable a module/class variable, as in the attached code snippet.

Private ms as MemoryStream
sub main
Dim myimg As Image
   myimg = byteArrayToImage(DownloadFile(3))
myimg.save("C:\test.bmp")
end sub
 
Public Function byteArrayToImage(ByVal byteArrayIn As Byte()) As Image
        ms = New MemoryStream(byteArrayIn)
        Dim returnImage As Image = Image.FromStream(ms)
        Return returnImage
    End Function
 
Private Function downloadFileFromDatabase(ByVal kfile As Long) As Byte()
        Dim conn As SqlConnection = Nothing
        Dim cmd As SqlCommand = Nothing
        Dim kFileName As SqlParameter = Nothing
        Dim dr As SqlDataReader = Nothing
        Dim result As Byte() = Nothing
        Try
 
            conn = New SqlConnection(ConnectionString())
            cmd = New SqlCommand("DownloadFile", conn)
            cmd.CommandType = System.Data.CommandType.StoredProcedure
 
            kFileName = New SqlParameter("@ID", System.Data.SqlDbType.BigInt, 8)
            kFileName.Value = kfile
 
            cmd.Parameters.Add(kFileName)
 
            conn.Open()
            dr = cmd.ExecuteReader()
            dr.Read()
 
            result = CType(dr.GetValue(0), Byte())
 
            dr.Close()
            conn.Close()
 
            conn.Dispose()
            cmd.Dispose()
 
        Catch e As Exception
 
            MsgBox(e.Message)
            result = Nothing
        End Try
        Return result
    End Function

Open in new window

0
 
Christopher KileCommented:
What is the type of the field being read by dr.GetValue(0)?
0
 
cobolinx1Author Commented:
I'm still getting parameter not valid. I made ms a module variable and moved the
imagefrom stream in the downloadFileFromDatabase function

  result = CType(dr.GetValue(0), Byte())
            ms = New MemoryStream(result)
            Dim returnImage As Image = Image.FromStream(ms)
            returnImage.Save("c:\test.bmp")

Open in new window

0
 
Christopher KileCommented:
There's two possible reasons for the argument exception, and these are listed below (from the definition for Image.FromStream()):
ArgumentException
The stream does not have a valid image format
-or-
stream is a null reference (Nothing in Visual Basic).  
In case my earlier question was not clear (also, I expect you didn't receive it before sending your last reply), what is the SQL type of the field you are reading with dr.GetValue(0)? Is it a BLOB?
0
 
cobolinx1Author Commented:
The only thing the stored procedure is returning is the field that the picture is stored in.

System.byte[]
0
 
cobolinx1Author Commented:
The sad thing I was able to convert it to a picture using vba. So I thought .net would be so simple.
0
 
Christopher KileCommented:
Also, may I recommend you use the SQLDataReader.GetBytes() method instead of .GetValue()?
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getbytes(VS.71).aspx
This links to the .NET 1.1 version, but it also contains links to more recent versions of the function.  I've included a code snippet using GetBytes() to get the length of the buffer, to Redim the buffer array to the correct size, then use GetBytes() to get the actual data into the byte array.  Try it and tell me what happens.
 
 

Private ms as MemoryStream
Private bAry() as Byte
 
sub main
Dim myimg As Image
   myimg = byteArrayToImage(DownloadFile(3))
myimg.save("C:\test.bmp")
end sub
 
Public Function byteArrayToImage(ByVal byteArrayIn As Byte()) As Image
        ms = New MemoryStream(byteArrayIn)
        Dim returnImage As Image = Image.FromStream(ms)
        Return returnImage
    End Function
 
Private Function downloadFileFromDatabase(ByVal kfile As Long) As Byte()
        Dim conn As SqlConnection = Nothing
        Dim cmd As SqlCommand = Nothing
        Dim kFileName As SqlParameter = Nothing
        Dim dr As SqlDataReader = Nothing
        Dim result As Byte() = Nothing
        Try
 
            conn = New SqlConnection(ConnectionString())
            cmd = New SqlCommand("DownloadFile", conn)
            cmd.CommandType = System.Data.CommandType.StoredProcedure
 
            kFileName = New SqlParameter("@ID", System.Data.SqlDbType.BigInt, 8)
            kFileName.Value = kfile
 
            cmd.Parameters.Add(kFileName)
 
            conn.Open()
            dr = cmd.ExecuteReader()
            dr.Read()
 
	    Dim bufferLen as Integer = dr.GetBytes(0, 0, Nothing, 0)
	    Redim bAry(bufferLen - 1)
	    dr.GetBytes(0, 0, bAry, 0)
	    
            dr.Close()
            conn.Close()
 
            conn.Dispose()
            cmd.Dispose()
 
        Catch e As Exception
 
            MsgBox(e.Message)
            result = Nothing
        End Try
        Return bAry
    End Function

Open in new window

0
 
cobolinx1Author Commented:
When I return the byte array into the memory stream there is a length. There is a picture in the field I just can't get the bytes into a memory stream and then into a picture.
0
 
cobolinx1Author Commented:
I get an error overload resolution failed because no accessible 'getbytes' accepts this number of arguments on line 37 & 39
0
 
cobolinx1Author Commented:
I changed
Dim bufferLen as Integer = dr.GetBytes(0, 0, Nothing, 0)
to
Dim bufferLen as Integer = dr(0).GetBytes(0, 0, Nothing, 0)

and got public member 'getbytes' on type 'bytes' not found
0
 
Christopher KileCommented:
I've corrected the code to avoid the overload resolution error.  Still, this does not seem to be your problem.  My guess is that the image stored in your database is not compatible with the Image type.  What is the format of your stored images?  
Private ms as MemoryStream
Private bAry() as Byte
 
sub main
Dim myimg As Image
   myimg = byteArrayToImage(DownloadFile(3))
myimg.save("C:\test.bmp")
end sub
 
Public Function byteArrayToImage(ByVal byteArrayIn As Byte()) As Image
        ms = New MemoryStream(byteArrayIn)
        Dim returnImage As Image = Image.FromStream(ms)
        Return returnImage
    End Function
 
Private Function downloadFileFromDatabase(ByVal kfile As Long) As Byte()
        Dim conn As SqlConnection = Nothing
        Dim cmd As SqlCommand = Nothing
        Dim kFileName As SqlParameter = Nothing
        Dim dr As SqlDataReader = Nothing
        Dim result As Byte() = Nothing
        Try
 
            conn = New SqlConnection(ConnectionString())
            cmd = New SqlCommand("DownloadFile", conn)
            cmd.CommandType = System.Data.CommandType.StoredProcedure
 
            kFileName = New SqlParameter("@ID", System.Data.SqlDbType.BigInt, 8)
            kFileName.Value = kfile
 
            cmd.Parameters.Add(kFileName)
 
            conn.Open()
            dr = cmd.ExecuteReader()
            dr.Read()
 
	    Dim bufferLen as Integer = dr.GetBytes(0, 0, Nothing, 0, Integer.MaxValue)
	    Redim bAry(bufferLen - 1)
	    dr.GetBytes(0, 0, bAry, 0, bufferLen)
	    
            dr.Close()
            conn.Close()
 
            conn.Dispose()
            cmd.Dispose()
 
        Catch e As Exception
 
            MsgBox(e.Message)
            result = Nothing
        End Try
        Return bAry
    End Function

Open in new window

0
 
cobolinx1Author Commented:
now to think of it they may be jpg. Would that make a differance?
0
 
Christopher KileCommented:
JPG should load without a problem.  I suspect they may not be stored correctly in your database.  Do you have an independent way of verifying that the JPGs in your database are stored in complete and correct formats?
0
 
cobolinx1Author Commented:
I can get them out using vba to show them in an access report using the following code:
Option Compare Database
Option Explicit
 
Private Const pixel As Double = 15
Public Const signatureID As String = "signature"
Public Const defaultPicturePath As String = "C:\Windows\Temp\picture.jpg"
Private Const noImage As String = "(none)"
 
Public Sub hideImage(img As Access.Image)
    img.Picture = noImage
    img.Visible = False
End Sub
 
Public Sub prepareImage(img As Access.Image, data As Variant, Optional picturePath As String = defaultPicturePath)
    On Error GoTo writeImage_Err
    If (IsNull(data) Or IsEmpty(data)) Then GoTo writeImage_Err
    
    If (LenB(data) = 0) Then GoTo writeImage_Err
    
    Dim binData() As Byte
    binData = data
    
    On Error GoTo 0
    
TryAgain:
    On Error GoTo TryAgain
    Open picturePath For Binary Access Write As #1
    On Error GoTo 0
    
    Put #1, , binData
    
    Close #1
    
    On Error GoTo deleteFile
    img.Picture = picturePath
    img.Visible = True
    Exit Sub
    
deleteFile:
    Kill picturePath
writeImage_Err:
    hideImage img
    Exit Sub
End Sub
 
Public Sub drawSignature(rpt As Access.Report, data As Variant, left As Long, top As Long)
 
    On Error GoTo drawSignature_Err
    If (IsNull(data) Or IsEmpty(data)) Then GoTo drawSignature_Err
    
    Dim Size As Long
    Size = LenB(data)
    
    If (Size < 4) Then GoTo drawSignature_Err
    On Error GoTo 0
    
    Dim binData() As Byte
    
    binData = data
    
    Dim idLen As Long
    
    Dim position As Long
    
    position = LBound(binData)
    
    idLen = decodeBigEndian(binData, position)
    
    Dim sigIDB() As Byte
    
    sigIDB = StrConv(signatureID, vbFromUnicode)
    
    Dim i As Long
    
    If (idLen <> Len(signatureID)) Then
        Exit Sub
    End If
    
    position = position + 4
    
    For i = 0 To idLen - 1
        If binData(position + i) <> sigIDB(i) Then
            Exit Sub
        End If
    Next i
    
    ' it's a good stream
    
    position = position + idLen
    
    Dim width As Long
    Dim height As Long
    
    If (position + 7 >= Size) Then
        Exit Sub
    End If
    width = decodeBigEndian(binData, position)
    position = position + 4
    height = decodeBigEndian(binData, position)
    position = position + 4
    
    Dim lines As Long
    
    lines = decodeBigEndian(binData, position)
    
    position = position + 4
    
    Do While lines > 0
        Dim points As Long
        
        If (position + 3 >= Size) Then
            Exit Sub
        End If
        points = decodeBigEndian(binData, position)
        position = position + 4
        
        If points > 0 Then
            Dim x As Long
            Dim y As Long
            
            If (position + 7 >= Size) Then
                Exit Sub
            End If
            x = decodeBigEndian(binData, position)
            position = position + 4
            
            y = decodeBigEndian(binData, position)
            position = position + 4
            
            points = points - 1
            
            Do
                Dim newx As Long
                Dim newy As Long
                
                If (position + 7 >= Size) Then
                    Exit Sub
                End If
                newx = decodeBigEndian(binData, position)
                position = position + 4
                
                newy = decodeBigEndian(binData, position)
                position = position + 4
                
                rpt.Line (left + x * pixel, top + y * pixel)-(left + newx * pixel, top + newy * pixel)
                x = newx
                y = newy
                points = points - 1
            Loop While points > 0
        End If
        lines = lines - 1
    Loop
    Exit Sub
drawSignature_Err:
    Exit Sub
End Sub
 
Private Function decodeBigEndian(data() As Byte, position As Long) As Long
    decodeBigEndian = data(position + 3) Mod 128
    decodeBigEndian = (decodeBigEndian * 256) + data(position + 2)
    decodeBigEndian = (decodeBigEndian * 256) + data(position + 1)
    decodeBigEndian = (decodeBigEndian * 256) + data(position)
    
    If (data(position + 3) >= 128) Then
        decodeBigEndian = decodeBigEndian - 1073741824 - 1073741824
    End If
End Function

Open in new window

0
 
Christopher KileCommented:
Suddenly I see the problem, maybe.  I didn't realize until I looked at your last message that you were reading an image type from an Access database.  Try writing the byte array to a file with a JPG extension, then see if the file displays properly.  Use a BinaryWriter, remember to Flush it before closing it.  
0
 
cobolinx1Author Commented:
The data is in a SQL Server database and I just linked it to an access database for the above code. I'm now trying to just get it directly from SQL Server. I'm actually getting bytes in the file but I cant see the picture
    Public Sub Getpicture(ByVal imgnum As Integer)
        Dim myconnection As New SqlConnection(My.Settings.SQLSERVERCONN)
        Dim getEmp As New SqlCommand("SELECT signature FROM mytable WHERE ID = @ID ", myconnection)
        getEmp.Parameters.AddWithValue("@ID", imgnum)
        Dim fs As FileStream
        ' Writes the BLOB to a file (*.jpg). 
        Dim bw As BinaryWriter
        ' Streams the BLOB to the FileStream object. 
        Dim bufferSize As Integer = 100
        ' Size of the BLOB buffer. 
        Dim outbyte As Byte() = New Byte(bufferSize - 1) {}
        ' The BLOB byte[] buffer to be filled by GetBytes. 
        Dim retval As Long
        ' The bytes returned from GetBytes. 
        Dim startIndex As Long = 0
        ' The starting position in the BLOB output. 
 
        ' Open the connection and read data into the DataReader. 
        myconnection.Open()
        Dim myReader As SqlDataReader = getEmp.ExecuteReader(CommandBehavior.SequentialAccess)
 
        While myReader.Read()
 
 
            ' Create a file to hold the output. 
            fs = New FileStream("image" & imgnum & ".jpg", FileMode.OpenOrCreate, FileAccess.Write)
            bw = New BinaryWriter(fs)
 
            ' Reset the starting byte for the new BLOB. 
            startIndex = 0
 
            ' Read the bytes into outbyte[] and retain the number of bytes returned. 
            retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize)
 
            ' Continue reading and writing while there are bytes beyond the size of the buffer. 
            While retval = bufferSize
                bw.Write(outbyte)
                bw.Flush()
 
                ' Reposition the start index to the end of the last buffer and fill the buffer. 
                startIndex += bufferSize
                retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize)
            End While
 
            ' Write the remaining buffer. 
            bw.Write(outbyte, 0, CInt(retval))
            bw.Flush()
 
            ' Close the output file. 
            bw.Close()
            fs.Close()
        End While
 
        ' Close the reader and the connection. 
        myReader.Close()
        myconnection.Close()
    End Sub

Open in new window

0
 
cobolinx1Author Commented:
Some are stored as pictures and doing everything we did works and some are stored as something else!!!!! Thanks for your help.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.