views:

389

answers:

4

Hello. I have simple database in Access .mdb file, but I don't know how to deal with: "parameter not valid" exception when Im creating Image from stream. I'v read that I need to strip 78 bytes offset (from here) but I still get a "parameter not valid" error when I call FromStream, even after stripping off the first 78 bytes.

A: 

Take a look at abother SO question/answer http://stackoverflow.com/questions/1614773/image-fromstreampostedfile-inputstream-fails-parameter-is-not-valid-asyncf as i think they deal with the same issue ..

Gaby
No, my problem is about Microsoft Access (database), not about accessing image.
dario
care to add some code in your post ?
Gaby
A: 

This doesn't work for me:

byte[] abytPic = (byte[])dt.Rows[0]["Photo"]; byte arrary with image
if ((abytPic[0] == 21) && (abytPic[1] == 28)) //It's true
{
    byte[] abytStripped = new byte[abytPic.Length - 78];
    System.Buffer.BlockCopy(abytPic, 78, abytStripped, 0, abytPic.Length - 78); 
    msPic = new emoryStream(abytStripped);
}
dario
Any ideas, where is the problem?
dario
+4  A: 

If you are reading the data directly from MS Access, you do not need to strip any header information.

Assuming the image is stored as a BLOB, which is the most common, here is code to read in the array of bytes from the database and store as an image file (sorry, VB instead of C#):

  Dim varBytes() As Byte

  Using cn As New OleDbConnection(myConnectionString)
     cn.Open()

     sqlText = "SELECT [myColumn] " _
              & "FROM [myTable] " _
              & "WHERE ([mySearchCriteria] = '" & mySearchTerm & "')"

     Using cm As New OleDbCommand(sqlText, cn)
        Dim rdr As OleDbDataReader

        rdr = cm.ExecuteReader

        rdr.Read()

        varBytes = rdr.GetValue(0)
     End Using

  End Using

  My.Computer.FileSystem.WriteAllBytes(myPath & "\myFile.emf", varBytes, True)

This example that I had laying around is one where I knew the files in the database were .emf images. If you know the extension, you can put it on the file name. If you don't, you can leave it blank and then open the resulting with an image viewer; it should start. If you need to find the extension or file type, once it is saved as a file, you can open it with any hex editor and the file type will be available from the header information.

Your question is a little bit unclear, so I'm not sure the above code is exactly what you want, but it should get you a lot closer.

EDIT:

This is the VB code that takes the array of bytes, loads it into a MemoryStream object, and then creates an Image object from the Stream. This bit of code worked just fine, and displayed the image in a picturebox on my form.

  Dim img As Image
  Dim str As New MemoryStream(varBytes)
  img = Image.FromStream(str)
  PictureBox1.Image = img

If the C# equivalent of this is not working for you, then the problem is likely in how the image is stored in the MS Access database.

EDIT:

If the image in your database is stored as a 'Package' and not a 'Long binary data', then you will need to strip the header information that MS Access adds. I've been playing with the 'Package' type of image storage with a simple .jpg file. The header in this case is much longer than 78 bytes. In this instance, it's actually 234 bytes, and MS Access also added some information to the end of the original file; about 292 bytes in this case.

It looks like your original approach was correct, you will just need to determine how many bytes to strip off the front and rear of the Byte array for your situation.

I determined it for my file by comparing the original image file, and the file exported from the database, (not to a Stream object, see my first code) in a hex editor. Once I figured out how much information (header and footer) was added by MS Access, I then knew how many bytes needed to be stripped.

EDIT:

The size of the header added by MS Access when the image is stored as 'Package' varies depending on the file type, and the original location (full path information) of the image when it was dumped into the MS Access database. So, even for the same file type, you may have a different number of bytes to strip from the header for each file. This makes it a lot more difficult, because then you will have to scan the byte array until you find the normal start-of-file information for that file type, and then strip everything before it.

All this headache is one of the reasons that it is better to store images as BLOBs 'Long binary data' in a database. Retrieval is much easier. I don't know if you have the option to do this, but if so, it would be a good idea.

Stewbob
But when Im trying to instantiate object of type Image, passing byte array (varBytes in your example) as constructor parameter, Im getting error: Parameter is not valid. Ofcourse this is a valid byte array (of length about 3000 bytes - depending of image size).
dario
Thanks it's seems that there is no one solution to obtain lenght of OleObject header. Thanks for your support.
dario
+1  A: 

I do not believe that your problem is with the database. "Parameter not valid" exceptions when dealing with imaging can be a total pain as I have dealt with them before. They're not very clear on what the problem is.

How exactly was the image placed into the database? There could be a problem with writing the image into the database before you've even attempted to pull it. Also, what file type is the image?

EDIT Here is some sample code that I've used before to get an image from a byte array.

        //takes an array of bytes and converts them to an image.
    private Image getImageFromBytes(byte[] myByteArray)
    {            
        System.IO.MemoryStream newImageStream = new System.IO.MemoryStream(myByteArray, 0, myByteArray.Length);
        return Image.FromStream(newImageStream, true);
    }
Aaron
NOTE: This is all assuming that you're getting back valid values from your database call.
Aaron