?
Solved

Problem converting BYTE[] to image

Posted on 2008-11-13
20
Medium Priority
?
4,585 Views
Last Modified: 2012-05-05
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

0
Comment
Question by:cobolinx1
  • 11
  • 8
20 Comments
 
LVL 18

Expert Comment

by:UnifiedIS
ID: 22950382
Add this line before your return statement (line 10):
returnImage.Save(MS, System.Drawing.Imaging.ImageFormat.Bmp)

Return returnImage
0
 

Author Comment

by:cobolinx1
ID: 22950524
The error I'm getting is from  
Dim returnImage As Image = Image.FromStream(ms)
It says parameter not valid
0
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22950700
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22950776
What is the type of the field being read by dr.GetValue(0)?
0
 

Author Comment

by:cobolinx1
ID: 22950900
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
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22951035
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
 

Author Comment

by:cobolinx1
ID: 22951074
The only thing the stored procedure is returning is the field that the picture is stored in.

System.byte[]
0
 

Author Comment

by:cobolinx1
ID: 22951135
The sad thing I was able to convert it to a picture using vba. So I thought .net would be so simple.
0
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22951294
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
 

Author Comment

by:cobolinx1
ID: 22951315
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
 

Author Comment

by:cobolinx1
ID: 22951381
I get an error overload resolution failed because no accessible 'getbytes' accepts this number of arguments on line 37 & 39
0
 

Author Comment

by:cobolinx1
ID: 22951446
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
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22951508
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
 

Author Comment

by:cobolinx1
ID: 22951664
now to think of it they may be jpg. Would that make a differance?
0
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22952141
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
 

Author Comment

by:cobolinx1
ID: 22953810
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
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 22954312
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
 

Author Comment

by:cobolinx1
ID: 22954657
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
 
LVL 23

Accepted Solution

by:
Christopher Kile earned 2000 total points
ID: 22954732
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
 

Author Closing Comment

by:cobolinx1
ID: 31516381
Some are stored as pictures and doing everything we did works and some are stored as something else!!!!! Thanks for your help.
0

Featured Post

Restore individual SQL databases with ease

Veeam Explorer for Microsoft SQL Server delivers an easy-to-use, wizard-driven interface for restoring your databases from a backup. No expert SQL background required. Web interface provides a complete view of all available SQL databases to simplify the recovery of lost database

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
This article describes how to use a set of graphical playing cards to create a Draw Poker game in Excel or VB6.
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses
Course of the Month16 days, 6 hours left to enroll

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question