【问题标题】:Converting an OLE Image Object from MS Access for use in .NET从 MS Access 转换 OLE 图像对象以在 .NET 中使用
【发布时间】:2011-01-25 20:49:03
【问题描述】:

我正在努力将基于 Access 的系统重新开发为 c#.net,但是当 MS 从 office 2003 转到 office 2007 时,他们删除了 access 中的图片编辑器 - 这意味着以前存储的图片将不再显示在系统中。该公司的人做了一个 hack,基本上使用 VBA 在后台使用 excel 保存图像(如果需要,我可以获得更多信息)但基本上这意味着仍然可以使用访问图像控件(对象绑定帧)。

但是,我现在遇到了在 .NET 应用程序中显示这些内容的问题,并且在无数天尝试不同的字节数组操作方式之后,我几乎要放弃了。我已经尝试了至少 8 种不同的建议解决方案,并且在执行 Image.fromStream() 时,每一种都以“无法识别参数”异常结束。以下是迄今为止最接近我的代码:

    private void imageExtractTest()
    {
        LogOnDataSetTableAdapters.QueriesTableAdapter qa =
            new LogOnDataSetTableAdapters.QueriesTableAdapter();

        object docO = qa.GetLogonImage();
        if (docO == null || !(docO is byte[]))
        {
            return;
        }
        byte[] doc = (byte[])docO;

        MemoryStream ms = new MemoryStream();
        ms.Write(doc, 0, doc.Length);
        int firstByte;
        int secondByte;
        ms.Seek(0, SeekOrigin.Begin);
        firstByte = ms.ReadByte();
        secondByte = ms.ReadByte();

        if (firstByte != 0x15 && secondByte != 0x1C)
        {
            //ErrorResponse("Stored object is not an Access File.");
            return;
        }

        int fileTypeLoc = 20; // begin of the file type
        short offset; // end of the file type

        byte[] buffer = new byte[2];
        ms.Read(buffer, 0, 2);
        offset = BitConverter.ToInt16(buffer, 0);

        long seekTotal = 0;
        seekTotal += offset;

        string docType = String.Empty;
        for (int i = fileTypeLoc; i < offset; i++)
        {
            docType += (char)doc[i];
        }

        //if I query docType now I get 'Picture\0\0'

        // magic eight bytes 01 05 00 00 03 00 00 00
        ms.Seek(seekTotal, SeekOrigin.Begin);
        buffer = new byte[8];
        ms.Read(buffer, 0, 8);
        seekTotal += 8;

        // Second offset to move to 
        buffer = new byte[4];
        ms.Read(buffer, 0, 4);
        seekTotal += 4;
        long offset2 = BitConverter.ToInt32(buffer, 0);
        seekTotal += offset2;
        ms.Seek(seekTotal, SeekOrigin.Begin);

        // eight empty bytes
        buffer = new byte[8];
        ms.Read(buffer, 0, 8);
        seekTotal += 8;

        // next n bytes are the length of the file
        buffer = new byte[4];
        ms.Read(buffer, 0, 4);
        seekTotal += 4;
        long fileByteLength = BitConverter.ToInt32(buffer, 0);

        // next N bytes are the file
        byte[] data = new byte[fileByteLength];

        // store file bytes in data buffer
        ms.Read(data, 0, Convert.ToInt32(fileByteLength));

        MemoryStream imageStream = new MemoryStream(data);
        Image test = Image.FromStream(imageStream);
    }

此代码改编自here,我不需要各种文档类型识别,因为我只处理图像,但是图像类型可以是任意数量的东西 - jpg、bmp、gif、png 等。

我也尝试过保存输出的字节数组,但我也没有运气查看它。但是当我指向数据库并让它查看它时,一切都很好。 .NET Crystal Report 设计器也能够以某种方式获取这些图像 - 所以它们必须在某个地方......

有人有什么想法吗?

马龙

【问题讨论】:

    标签: c# .net ms-access ole


    【解决方案1】:

    尝试从 .NET 检索 MS-access OLE 图像字段比它的价值更令人头疼。在this post 中有一些关于这个主题的很好的讨论和信息。

    最终,成功实现此目的的最佳且最简单的解决方案是使用您的工作查看方法将这些图像保存为单独的文件,然后将这些文件作为 BLOB 字段而不是图像字段导入数据库。然后您可以轻松地将它们读入 .NET。

    【讨论】:

      【解决方案2】:

      这不是 C# 代码,但这里有一个 Delphi example 的解决此问题的方法。

      它使用IOLEObject 来绘制存储的任何内容,而不是尝试读出原始数据。 步骤:

      1. 读取 OLE 对象前面的 Access Header
      2. 读出 OLE1 流
      3. 将 OLE1 流转换为 OLE2 IStorage 对象
      4. 使用OLELoad“运行”OLE Ojbect。
      5. 致电OLEDraw 将图像绘制到您选择的画布上。

      【讨论】:

        【解决方案3】:

        在我的情况下,以下功能有效。数据由 VB6 应用程序存储。

        public static byte[] ConvertOleBytesToRawBytes(byte[] oleBytes)
        {
           // The default encoding is in my case - Western European (Windows), Code Page 1252
           return Encoding.Convert(Encoding.Unicode, Encoding.Default, (byte[])oleBytes);
        }
        

        【讨论】:

          【解决方案4】:

          试试这个来自微软的 KB http://support.microsoft.com/kb/317701 文章。它包含有关如何在 winforms 应用程序中访问和显示图像 blob 的信息。

          【讨论】:

          • 感谢您提供的信息,但我认为您误解了这个问题。那篇文章只是解释了如何将图像文件存储到数据库中。不是如何将已存储的 OLE 对象转换为图像。显然 OLE 只是魔法......
          【解决方案5】:

          我需要对大约 1600 个不同扩展类型的对象执行完全相同的操作。就我而言,它是一个已经使用了几十年的遗留数据库。多年来,通过 OLE 对象框架添加了许多不同类型的文件。一些看起来像“图像”的项目原来是带有嵌入图像的 Word 文档……不知道里面还有哪些其他文件类型?我所知道的是,我研究并尝试了一个多星期的不同提取方法。甚至所有的Steven Leban's 提取工具,如 OLEtoDisk、A2KExportOLEtoJPEG 和 SaveOLEtoBitmap。每一个都会提取一些图像......但它们不是一个适合所有人的尺寸......它是一团糟!

          最后,我使用以下方法通过 VBA 对每个图像执行了自动屏幕截图。虽然这可能不是最理想的,但它适用于每种文件类型。但是屏幕截图方法捕获全屏的屏幕截图。一旦我将它们全部提取出来,我就不得不使用 PhotoShop 进行另一个自动化过程来批量裁剪所有照片。不理想,但有效!

          Private Sub CaptureAllImages()
              On Error Resume Next
              Me.RecordsetClone.MoveFirst
              Do While Not Me.RecordsetClone.EOF
                  Me.Bookmark = Me.RecordsetClone.Bookmark
                  Call Pause(2)
                  Call SaveClip2Bit("C:\Users\agriggs\Desktop\Parts Images\MasterPart_" & Me.MasterPartNumber & ".bmp")
                  Me.RecordsetClone.MoveNext
              Loop
          
          End Sub
          
          Public Function Pause(NumberOfSeconds As Variant)
              On Error GoTo Error_GoTo
          
              Dim PauseTime As Variant
              Dim start As Variant
              Dim Elapsed As Variant
          
              PauseTime = NumberOfSeconds
              start = Timer
              Elapsed = 0
              Do While Timer < start + PauseTime
                  Elapsed = Elapsed + 1
                  If Timer = 0 Then
                      ' Crossing midnight
                      PauseTime = PauseTime - Elapsed
                      start = 0
                      Elapsed = 0
                  End If
                  DoEvents
              Loop
          
          Exit_GoTo:
              On Error GoTo 0
              Exit Function
          Error_GoTo:
              Debug.Print Err.Number, Err.Description, Erl
              GoTo Exit_GoTo
          End Function
          

          我尝试了几个不同的屏幕截图模块,但发现SaveClip2Bit 效果最好。最后,我添加了一个常见的暂停功能,以确保图像在继续下一个之前保存到磁盘。您可以想象 1600 张图像需要很长时间才能提取,但我现在可以但这个项目要休息了!

          【讨论】:

            猜你喜欢
            • 2012-05-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-10
            • 2010-09-11
            • 1970-01-01
            • 1970-01-01
            • 2016-10-11
            相关资源
            最近更新 更多