从 C# WPF 应用程序中读取 MS Access 数据库中的图像 [重复]

Posted

技术标签:

【中文标题】从 C# WPF 应用程序中读取 MS Access 数据库中的图像 [重复]【英文标题】:Read Image from MS Access Database from C# WPF Application [duplicate] 【发布时间】:2018-04-17 14:43:51 【问题描述】:

我的问题是:

这样我就可以连接到 MS Access 数据库并从中读取数据。 存储数据表中的数据。 无法将 byte[] 数据转换为我的 WPF 的可显示图像 应用 我正在尝试检索 jpeg 或 png 图像

这是我的数据库连接代码(成功代码)

public static void getTableItems(DataTable dt, int bodySectionNo)
    
        // gets the oledbconnection object to open and access
        var con = GetConnection();

        try
        
            con.Open(); // opens db connection
            // creates the sql query for db items change bodysection = # for different bodySections
            OleDbCommand command = new OleDbCommand("SELECT itemNo, itemName, NSN, bodySection, Image.FileName, Image.FileData, Image.FileType  FROM tblItems WHERE bodySection = " + bodySectionNo + ";", con);

            OleDbDataAdapter oleAdapter = new OleDbDataAdapter(command); // executes the command and retrieves the data from the db

            oleAdapter.Fill(dt); // fills the datatable with the query results
        
        catch(Exception e)
        
            // writes to console any errors for this connection
            Console.WriteLine("ERROR: getTableItemsForHead, " + e.Message);
        
        finally
        
            con.Close(); // closes db connection
        
    

在我的 MainWindow.xaml.cs 文件中,我尝试读取数据表、存储数据,然后将数据传递到一个元素中以供主窗口显示。 这是我的 MainWindow.xaml.cs 代码(不成功的代码)

private void populateComboBox(DataTable dt, ComboBox cb)
    
        foreach (DataRow row in dt.Rows)
        
            WrapPanel wp = new WrapPanel();
            TextBlock txtItemName = new TextBlock();
            TextBlock txtNSN = new TextBlock();
            Image img = new Image();

            // creates a textbox and adds it to wrappanel
            txtItemName.Text = Convert.ToString(row["itemName"]) + " ";
            wp.Children.Add(txtItemName);

            // creates a textbox and adds it to wrappanel
            txtNSN.Text = Convert.ToString(row["NSN"]) + " ";
            wp.Children.Add(txtNSN);

            // stores image properties from datatable
            var fileName = row["Image.FileName"];
            var fileData = (byte[])row["Image.FileData"];
            var fileType = row["Image.FileType"];

            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.CreateOptions = BitmapCreateOptions.None;
            bi.CacheOption = BitmapCacheOption.Default;
            bi.StreamSource = new MemoryStream(fileData);
            bi.EndInit();

            img.Source = bi;

            wp.Children.Add(img);

            cb.Items.Add(wp);
        
    

我尝试了多种不同的方法将 byte[] 转换为位图、位图图像、位图源、图像、图像源等。我找不到 sn-p 来解决这个“没有适合完成此操作的图像组件被找到” 它打破了 bi.EndInit();线。

System.NotSupportedException 未被用户代码处理 HResult=-2146233067 消息=没有适合的成像组件 完成这个操作被发现。来源=PresentationCore 堆栈跟踪: 在 System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream 流, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream, SafeFileHandle & safeFilehandle) 在 System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream 流, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, 布尔值 insertInDecoderCache) 在 System.Windows.Media.Imaging.BitmapImage.FinalizeCreation() 在 System.Windows.Media.Imaging.BitmapImage.EndInit() 在 CWEDA_take_1.SecondWindow.populateComboBox(DataTable dt, ComboBox cb) 在 P:\All Documents\BBMD 18\CWEDA EH\CWEDA Design 1\CWEDA 取 1\SecondWindow.xaml.cs:line 286 在 P:\All Documents\BBMD 18\CWEDA EH\CWEDA Design 1\CWEDA take 1\SecondWindow.xaml.cs:line 36 中的 CWEDA_take_1.SecondWindow..ctor() 内部异常: 错误代码=-2003292336 H结果=-2003292336 Message=找不到组件。 (来自 HRESULT 的异常:0x88982F50) 内部异常:

编辑:字节[]中的文件数据

编辑:解决方案!!我之前想通了,但忘记上传我的解决方案:

我必须首先通过搜索标题块来确定图像类型。

    // Converts byte array from database to image source
    public static BitmapImage convertByteSource(byte[] oleFieldBytes)
    

        if (oleFieldBytes == null || oleFieldBytes.Length == 0) return null;


        const string BITMAP_ID_BLOCK = "BM";
        const string JPG_ID_BLOCK = "\u00FF\u00D8\u00FF";
        const string PNG_ID_BLOCK = "\u0089PNG\r\n\u001a\n";
        byte[] imageBytes;

        // Get a UTF7 Encoded string version
        Encoding u8 = Encoding.UTF7;
        string strTemp = u8.GetString(oleFieldBytes);

        // Get the first 300 characters from the string
        string strVTemp = strTemp.Substring(0, 300);

        // Search for the block
        int iPos = -1;
        if (strVTemp.IndexOf(BITMAP_ID_BLOCK) != -1)
            iPos = strVTemp.IndexOf(BITMAP_ID_BLOCK);
        else if (strVTemp.IndexOf(JPG_ID_BLOCK) != -1)
            iPos = strVTemp.IndexOf(JPG_ID_BLOCK);
        else if (strVTemp.IndexOf(PNG_ID_BLOCK) != -1)
            iPos = strVTemp.IndexOf(PNG_ID_BLOCK);
        else
            throw new Exception("Unable to determine header size for the OLE Object");

        // From the position above get the new image
        if (iPos == -1)
            throw new Exception("Unable to determine header size for the OLE Object");

        //Array.Copy(
        imageBytes = new byte[oleFieldBytes.LongLength - iPos];
        MemoryStream ms = new MemoryStream();
        ms.Write(oleFieldBytes, iPos, oleFieldBytes.Length - iPos);
        imageBytes = ms.ToArray();
        ms.Close();

        // creates new bitmapimage
        BitmapImage bi = new BitmapImage();
        bi.BeginInit();// inits bitmapimage
        bi.CreateOptions = BitmapCreateOptions.None;
        bi.CacheOption = BitmapCacheOption.Default;
        bi.StreamSource = new MemoryStream(imageBytes);
        bi.EndInit();

        return bi;
    

【问题讨论】:

这里的问题是实际图像缓冲区之前 20 字节的(未知)标头。虽然可以安全地跳过它,但仍然值得一看:blogs.msdn.microsoft.com/pranab/2008/07/15/… 【参考方案1】:

此页面中的代码看起来与您那里的代码有些不同:http://csharphelper.com/blog/2015/07/display-images-in-an-access-database-in-wpf-and-c/

以防万一这可行并且将来链接断开。代码确实:

if (reader.IsDBNull(6))
    imgCover.Source = null;
else
    imgCover.Source =
        BytesToImage((byte[])reader.GetValue(6));

那个方法:

// Convert a byte array into a BitmapImage.
private static BitmapImage BytesToImage(byte[] bytes)

    var bm = new BitmapImage();
    using (MemoryStream stream = new MemoryStream(bytes))
    
        stream.Position = 0;
        bm.BeginInit();
        bm.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
        bm.CacheOption = BitmapCacheOption.OnLoad;
        bm.UriSource = null;
        bm.StreamSource = stream;
        bm.EndInit();
    
    return bm;

【讨论】:

虽然stream.Position = 0 是多余的,但bm.CreateOptions = BitmapCreateOptions.PreservePixelFormat 只有在你真的想要的时候才有意义。通常你不会。除此之外,当您想在 EndInit 之后立即关闭流时,设置 bm.CacheOption = BitmapCacheOption.OnLoad 很重要。在问题中并非如此。虽然是很好的做法,但对于 MemoryStream 来说并不是绝对必要的。现在,剩下的答案是什么? 我仍然遇到同样的错误,不过感谢您的尝试。

以上是关于从 C# WPF 应用程序中读取 MS Access 数据库中的图像 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

比较c#中sql server和ms访问的数据类型

WPF C#,从音频文件中获取信息

用于 C# 和 WPF 的高级全局键盘钩子,用于读取键盘楔形卡扫描仪

从资源中添加 .wav 文件(WPF C#)

wpf - 根据条件从 MS 访问数据库中选择数据

C# 如何在wpf中使用response 或者功能与其方法类似的