GDI+ 将带有图像的 Datagridview 数据保存到 XML 时出现一般错误
Generic error in GDI+ saving Datagridview data with images to XML
首先 - 感谢您提供的所有信息和片段。欣赏它。我的问题;
我正在尝试将一些 datagridview 数据(包括图像)保存到 XML 文件中。然后尝试再次在网格中读回它。据我所知,我正在使用数据集 & table(无界)来轻松 [=26=] 写作 - 绑定不适用于图像列。
我可以保存数据,然后再读入。但是 - 当我再次尝试保存数据时 - 它在 "Sub Savetofile" 中的以下行失败:
Img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
出现以下错误:
An unhandled exception of type
System.Runtime.InteropServices.ExternalException' occurred in
System.Drawing.dll Additional information: A generic error occurred in
GDI+.
知道我遗漏了什么吗?
Private Sub SaveToFile(sender As Object, e As EventArgs) Handles SaveToolStripMenuItem.Click
Dim rows As Integer = DataGridView1.Rows.Count - 1
Dim cols As Integer = DataGridView1.Columns.Count - 1
Dim MyByte As Byte() = Nothing
Dim Img As Image = Nothing
Dim ms = New MemoryStream()
DataSet1.Observations.Rows.Clear()
For i = 0 To rows
For j = 0 To cols
If j = 0 Then
Img = DataGridView1.Rows(i).Cells(j).Value
Img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
MyByte = ms.ToArray()
DataSet1.Observations.Rows.Add.Item(1) = Compress(MyByte)
ms.close()
ElseIf j >= 1 Then
If DataGridView1.Rows(i).Cells(j).Value IsNot Nothing Then
DataSet1.Observations.Rows(i).Item(j + 1) = DataGridView1.Rows(i).Cells(j).Value.ToString
End If
End If
Next
Next
File.Delete("C:\test2.quad")
DataSet1.WriteXml("C:\test2.quad")
End Sub
Private Sub OpenFile(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
Dim ms = New MemoryStream()
Dim MyByte As Byte()
DataSet1.Clear()
DataGridView1.Rows.Clear()
DataSet1.ReadXml("C:\test2.quad")
Dim rows As Integer = DataSet1.Observations.Rows.Count - 2
Dim cols As Integer = DataSet1.Observations.Columns.Count - 1
For i = 0 To rows
For j = 1 To cols
If j = 1 Then
MyByte = Decompress(DataSet1.Observations.Rows(i).Item(1))
Dim stream As New MemoryStream(MyByte)
DataGridView1.Rows.Add(Image.FromStream(stream))
stream.Close()
ElseIf j >= 2 And DataSet1.Observations.Rows(i).Item(j) IsNot Nothing Then
DataGridView1.Rows(i).Cells(j - 1).Value = DataSet1.Observations.Rows(i).Item(j).ToString
End If
Next
Next
End Sub
该错误是一个包罗万象的错误,包括从拒绝文件访问到 运行 资源不足的所有内容。在这种情况下,这是因为您一遍又一遍地重复使用相同的 MemoryStream
。
但您不必手动转换图像和 "compress" 它们。如果 DataTable
有一个 Byte()
列,DataGridView
将知道如何转换它以用作图像。 WriteXML
方法也会自动将字节编码为 Base64 字符串(并读回)。
样本:
Dim dtX = New DataTable("dtX")
Dim imgs As Image() = {My.Resources.ballblack, My.Resources.ballblue,
My.Resources.ballgreen, My.Resources.ballorange,
My.Resources.ballpurple, My.Resources.ballred,
My.Resources.ballyellow}
' columns to use
dtX.Columns.Add(New DataColumn("Name", GetType(String)))
dtX.Columns.Add(New DataColumn("Descr", GetType(String)))
dtX.Columns.Add(New DataColumn("Img", GetType(Byte())))
Dim dr As DataRow
Dim g As Int32
For n As Int32 = 0 To 9
dr = dtX.NewRow
dr(0) = RD.GetNames(2)
dr(1) = RD.GetLorem(40)
g = RNG.Next(0, 7) ' pick random index
Using ms As New MemoryStream
imgs(g).Save(ms, ImageFormat.Png)
dr(2) = ms.ToArray()
End Using
dtX.Rows.Add(dr)
Next
' "Before"
dgv1.DataSource = dtX
' save to XML
dtX.WriteXml("C:\Temp\DTX.xml", XmlWriteMode.WriteSchema)
- RD只是一个随机数据生成器。忽略它。
XmlWriteMode.WriteSchema
非常重要。当您读回数据时,您希望目标 DataTable
知道将该 Base64 字符串转换回 Byte
数组而不是显示 iVBORw0KGgoAAAANSUhEUgAAABA...
- 还要注意
Using
块。这将在最后处理 MemoryStream
并允许它释放它分配的任何资源。这 在您的代码 中缺失,因此 MemoryStream 除了泄漏之外还在累积数据:
- 如果我在非常小的图像上使用相同的图像,流的大小报告
334, 684, 1014, 1361...
。它正在累积图像数据,除第一个图像外的所有图像都会损坏,从而导致 GDI 错误。
往返测试代码:
Dim dtXYZ = New DataTable()
' or use a dataset
dtXYZ.ReadXml("C:\Temp\DTX.xml")
dgv1.DataSource = dtXYZ
前后数据相同。
首先 - 感谢您提供的所有信息和片段。欣赏它。我的问题;
我正在尝试将一些 datagridview 数据(包括图像)保存到 XML 文件中。然后尝试再次在网格中读回它。据我所知,我正在使用数据集 & table(无界)来轻松 [=26=] 写作 - 绑定不适用于图像列。
我可以保存数据,然后再读入。但是 - 当我再次尝试保存数据时 - 它在 "Sub Savetofile" 中的以下行失败:
Img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
出现以下错误:
An unhandled exception of type System.Runtime.InteropServices.ExternalException' occurred in System.Drawing.dll Additional information: A generic error occurred in GDI+.
知道我遗漏了什么吗?
Private Sub SaveToFile(sender As Object, e As EventArgs) Handles SaveToolStripMenuItem.Click
Dim rows As Integer = DataGridView1.Rows.Count - 1
Dim cols As Integer = DataGridView1.Columns.Count - 1
Dim MyByte As Byte() = Nothing
Dim Img As Image = Nothing
Dim ms = New MemoryStream()
DataSet1.Observations.Rows.Clear()
For i = 0 To rows
For j = 0 To cols
If j = 0 Then
Img = DataGridView1.Rows(i).Cells(j).Value
Img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
MyByte = ms.ToArray()
DataSet1.Observations.Rows.Add.Item(1) = Compress(MyByte)
ms.close()
ElseIf j >= 1 Then
If DataGridView1.Rows(i).Cells(j).Value IsNot Nothing Then
DataSet1.Observations.Rows(i).Item(j + 1) = DataGridView1.Rows(i).Cells(j).Value.ToString
End If
End If
Next
Next
File.Delete("C:\test2.quad")
DataSet1.WriteXml("C:\test2.quad")
End Sub
Private Sub OpenFile(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
Dim ms = New MemoryStream()
Dim MyByte As Byte()
DataSet1.Clear()
DataGridView1.Rows.Clear()
DataSet1.ReadXml("C:\test2.quad")
Dim rows As Integer = DataSet1.Observations.Rows.Count - 2
Dim cols As Integer = DataSet1.Observations.Columns.Count - 1
For i = 0 To rows
For j = 1 To cols
If j = 1 Then
MyByte = Decompress(DataSet1.Observations.Rows(i).Item(1))
Dim stream As New MemoryStream(MyByte)
DataGridView1.Rows.Add(Image.FromStream(stream))
stream.Close()
ElseIf j >= 2 And DataSet1.Observations.Rows(i).Item(j) IsNot Nothing Then
DataGridView1.Rows(i).Cells(j - 1).Value = DataSet1.Observations.Rows(i).Item(j).ToString
End If
Next
Next
End Sub
该错误是一个包罗万象的错误,包括从拒绝文件访问到 运行 资源不足的所有内容。在这种情况下,这是因为您一遍又一遍地重复使用相同的 MemoryStream
。
但您不必手动转换图像和 "compress" 它们。如果 DataTable
有一个 Byte()
列,DataGridView
将知道如何转换它以用作图像。 WriteXML
方法也会自动将字节编码为 Base64 字符串(并读回)。
样本:
Dim dtX = New DataTable("dtX")
Dim imgs As Image() = {My.Resources.ballblack, My.Resources.ballblue,
My.Resources.ballgreen, My.Resources.ballorange,
My.Resources.ballpurple, My.Resources.ballred,
My.Resources.ballyellow}
' columns to use
dtX.Columns.Add(New DataColumn("Name", GetType(String)))
dtX.Columns.Add(New DataColumn("Descr", GetType(String)))
dtX.Columns.Add(New DataColumn("Img", GetType(Byte())))
Dim dr As DataRow
Dim g As Int32
For n As Int32 = 0 To 9
dr = dtX.NewRow
dr(0) = RD.GetNames(2)
dr(1) = RD.GetLorem(40)
g = RNG.Next(0, 7) ' pick random index
Using ms As New MemoryStream
imgs(g).Save(ms, ImageFormat.Png)
dr(2) = ms.ToArray()
End Using
dtX.Rows.Add(dr)
Next
' "Before"
dgv1.DataSource = dtX
' save to XML
dtX.WriteXml("C:\Temp\DTX.xml", XmlWriteMode.WriteSchema)
- RD只是一个随机数据生成器。忽略它。
XmlWriteMode.WriteSchema
非常重要。当您读回数据时,您希望目标DataTable
知道将该 Base64 字符串转换回Byte
数组而不是显示iVBORw0KGgoAAAANSUhEUgAAABA...
- 还要注意
Using
块。这将在最后处理MemoryStream
并允许它释放它分配的任何资源。这 在您的代码 中缺失,因此 MemoryStream 除了泄漏之外还在累积数据:- 如果我在非常小的图像上使用相同的图像,流的大小报告
334, 684, 1014, 1361...
。它正在累积图像数据,除第一个图像外的所有图像都会损坏,从而导致 GDI 错误。
- 如果我在非常小的图像上使用相同的图像,流的大小报告
往返测试代码:
Dim dtXYZ = New DataTable()
' or use a dataset
dtXYZ.ReadXml("C:\Temp\DTX.xml")
dgv1.DataSource = dtXYZ
前后数据相同。