Domanda

I can't seem to get an answer all together for my real issue Invalid parameter when retrieving image from DB So Imma try piece by piece. Working with Visual Studio 2012 in C# and MS Access 2010. My solution is an app non-web related.

I'm not sure about this part so here my question is on how to correctly get the image of an OLE Object that is in a row from a query into a byte array (byte[]), because certainly it isn't how I'm doing it with the following code. The row I'm talking about is row["FOTO"].

                OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [APP_Equipamento_Geral] WHERE COD_ETIQ like '%" + codigo + "%'", l);
                DataSet ds = new DataSet();
                adapter.Fill(ds, "[APP_Equipamento_Geral]");
                string s = ds.Tables["[APP_Equipamento_Geral]"].Columns[16].ColumnName;
                foreach (DataRow row in ds.Tables["[APP_Equipamento_Geral]"].Rows)
                {
                    eq.NSerie = row["N_SERIE"].ToString();
                    eq.NInventario = row["Codigo"].ToString(); 

                    if (row["FOTO"] != DBNull.Value && row["FOTO"] != null)
                    {
                        string str = row["FOTO"].ToString();
                        byte[] b = stringToByteArray(str);
                        byte[] imagebyte = GetImageBytesFromOLEField(b); //Error caught here

                        MemoryStream ms = new MemoryStream();
                        ms.Write(imagebyte, 0, imagebyte.Length);
                    }    
                }

The method GetImageBytesFromOLEField can be found here. The error that it's giving me it's about the length of the index at the line string strVTemp = strTemp.Substring(0, 300);

Again, main question here is how to turn the OLE Object in the DataRow row["FOTO"] into byte[] to then use in that method.

È stato utile?

Soluzione

The problem here is that the imbedded image was not a simple BMP or JPEG. It was a

Microsoft Word Picture

and the OLE header information was considerably larger than the 300 byte window of the original GetImageBytesFromOLEField() code. (That is, after scanning 300 bytes it just gave up with "Unable to determine header size...".)

The following is an updated version of that code in its own class. Cursory testing included the supplied Microsoft Word Picture, a simple BMP, and a simple JPEG.

using System;
using System.Collections.Generic;
using System.Linq;

namespace OleImageTest
{
    public static class OleImageUnwrap
    {
        public static byte[] GetImageBytesFromOLEField(byte[] oleFieldBytes)
        {
            // adapted from http://blogs.msdn.com/b/pranab/archive/2008/07/15/removing-ole-header-from-images-stored-in-ms-access-db-as-ole-object.aspx

            const int maxNumberOfBytesToSearch = 10000;
            byte[] imageBytes;  // return value

            var imageSignatures = new List<byte[]>();
            // PNG_ID_BLOCK = "\x89PNG\r\n\x1a\n"
            imageSignatures.Add(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A });
            // JPG_ID_BLOCK = "\xFF\xD8\xFF"
            imageSignatures.Add(new byte[] { 0xFF, 0xD8, 0xFF });
            // GIF_ID_BLOCK = "GIF8"
            imageSignatures.Add(new byte[] { 0x47, 0x49, 0x46, 0x38 });
            // TIFF_ID_BLOCK = "II*\x00"
            imageSignatures.Add(new byte[] { 0x49, 0x49, 0x2A, 0x00 });
            // BITMAP_ID_BLOCK = "BM"
            imageSignatures.Add(new byte[] { 0x42, 0x4D });

            int numberOfBytesToSearch = (oleFieldBytes.Count() < maxNumberOfBytesToSearch ? oleFieldBytes.Count() : maxNumberOfBytesToSearch);
            var startingBytes = new byte[numberOfBytesToSearch];
            Array.Copy(oleFieldBytes, startingBytes, numberOfBytesToSearch);

            var positions = new List<int>();
            foreach (byte[] blockSignature in imageSignatures)
            {
                positions = startingBytes.IndexOfSequence(blockSignature, 0);
                if (positions.Count > 0)
                {
                    break;
                }
            }
            int iPos = -1;
            if (positions.Count > 0)
            {
                iPos = positions[0];
            }

            if (iPos == -1)
                throw new Exception("Unable to determine header size for the OLE Object");

            imageBytes = new byte[oleFieldBytes.LongLength - iPos];
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            ms.Write(oleFieldBytes, iPos, oleFieldBytes.Length - iPos);
            imageBytes = ms.ToArray();
            ms.Close();
            ms.Dispose();
            return imageBytes;
        }

        private static List<int> IndexOfSequence(this byte[] buffer, byte[] pattern, int startIndex)
        {
            // ref: http://stackoverflow.com/a/332667/2144390
            List<int> positions = new List<int>();
            int i = Array.IndexOf<byte>(buffer, pattern[0], startIndex);
            while (i >= 0 && i <= buffer.Length - pattern.Length)
            {
                byte[] segment = new byte[pattern.Length];
                Buffer.BlockCopy(buffer, i, segment, 0, pattern.Length);
                if (segment.SequenceEqual<byte>(pattern))
                    positions.Add(i);
                i = Array.IndexOf<byte>(buffer, pattern[0], i + 1);
            }
            return positions;
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top