【问题标题】:Convert Access image OLE Object into raw image byte array in C#在 C# 中将 Access 图像 OLE 对象转换为原始图像字节数组
【发布时间】:2013-11-10 09:41:17
【问题描述】:

对于我的真正问题Invalid parameter when retrieving image from DB,我似乎无法全部找到答案,所以我可以一点一点地尝试。 在 C# 和 MS Access 2010 中使用 Visual Studio 2012。我的解决方案是与 Web 无关的应用程序。

我不确定这部分,所以这里我的问题是如何正确地从查询中获取 row 中的 OLE 对象 的图像一个字节数组 (byte[]),因为这肯定不是我使用以下代码的方式。 我所说的行是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);
                    }    
                }

GetImageBytesFromOLEField 方法可以在here 找到。它给我的错误是关于 string strVTemp = strTemp.Substring(0, 300);

行的索引长度

同样,这里的主要问题是如何将 DataRow row["FOTO"] 中的 OLE Object 转换为 byte[] 以然后在那个方法中使用。

【问题讨论】:

  • 如果你尝试Byte[] b = (Byte[])row["FOTO"];会发生什么?我刚刚检查了一下,row["FOTO"] 应该已经是 System.Byte[] 类型的对象,所以也许你的数据已经是你需要的格式(字节数组),你需要的只是一个显式转换。跨度>
  • @GordThompson 在这种情况下: A:如果我运行 method,我会得到自定义 无法确定 OLE 对象的标头大小。 B:如果我不运行那个method,我会收到this 问题中提到的Invalid Parameter 错误
  • 我刚试过Byte[] imagebyte = GetImageBytesFromOLEField((Byte[])dr["FOTO"]);,对我来说效果很好。如果您愿意,可以将一行提取到单独数据库文件中的单独表中(必要时混淆敏感数据,但不会弄乱 [FOTO] 字段)并将其上传到 wikisend.com。然后,如果您在此处发布链接,我可以下载它并查看 [FOTO] 列中的内容。
  • @GordThompson Here 是。

标签: c# ms-access bytearray ms-access-2010 datarow


【解决方案1】:

这里的问题是嵌入的图像不是简单的BMPJPEG。这是一个

Microsoft Word Picture

并且 OLE 标头信息比原始 GetImageBytesFromOLEField() 代码的 300 字节窗口大得多。 (也就是说,在扫描了 300 个字节后,它就放弃了“无法确定标头大小...”。)

以下是该代码在其自己的类中的更新版本。粗略测试包括提供的Microsoft Word Picture、简单的BMP 和简单的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;
        }
    }
}

【讨论】:

  • 谢谢,代码似乎完美地解决了这个特定问题。希望这也足以解决另一个问题。
  • 实际上已经接近了,对一些有用但现在至少有一个图像最终给出了自定义错误无法确定 OLE 对象的标题大小跨度>
  • @MicaelFlorêncio 如果你像以前一样发送它,我可以看看字节。 (不过,没有关于修复的承诺。)
  • @MicaelFlorêncio 顺便说一句,该表中有多少行(图像)?那些 OLE 对象非常臃肿。之前的测试图像(OLE 包装的 JPEG)在数据库中大于 2.5MB,但是当我将其转储到磁盘并通过 GIMP 重新保存为 PNG 时,它缩小到 128KB。
  • @MicaelFlorêncio 对于这个,5000 字节的扫描是不够的。数据从大约 6900 字节开始。将 MaxNumberOfBytesToSearch5000 更改为 10000 并且它起作用了。 16.5MB JPEG 文件,但是当我在 GIMP 中打开它并将其导出为 PNG 时,它缩小到 3.5MB。
猜你喜欢
  • 1970-01-01
  • 2019-05-06
  • 2016-10-11
  • 2019-11-08
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多