GDI中的外部exception+错误保存特定图像

我需要从数据库中获取图像,所以我为它制作了一些代码。 问题是在某些图像中出现该错误,在其他图像中出现无效参数错误。

OleDbConnection l = new OleDbConnection(builder.ConnectionString); List listaImagens = new List(); List listaNomes = new List(); string nome = ""; try { OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [Fotografias e Manuais de Equipamentos] WHERE ID >26 AND ID < 30", l); DataSet ds = new DataSet(); adapter.Fill(ds, "Fotografias e Manuais de Equipamentos"); //string s = ds.Tables["APP_Equip_Ult_Prox_Calibracao"].Columns[16].ColumnName; foreach (DataRow row in ds.Tables["Fotografias e Manuais de Equipamentos"].Rows) { if (row["Designação Equipamento"].ToString().Equals("")) { nome = "semNome"; } else { nome = row["Designação Equipamento"].ToString(); } listaNomes.Add(row["ID"].ToString()+"_"+row["MARCA"].ToString() + "_" + row["MODELO"].ToString() + "_" + nome); try { byte[] b = (byte[])row["FOTO"]; byte[] imagebyte = OleImageUnwrap.GetImageBytesFromOLEField(b, 30000); MemoryStream ms = new MemoryStream(); ms.Write(imagebyte, 0, imagebyte.Length); listaImagens.Add(Image.FromStream(ms)); } catch (Exception) { try { byte[] b = (byte[])row["FOTO"]; byte[] imagebyte = OleImageUnwrap.GetImageBytesFromOLEField(b, 100000); MemoryStream ms = new MemoryStream(); ms.Write(imagebyte, 0, imagebyte.Length); listaImagens.Add(Image.FromStream(ms)); } catch (Exception) { byte[] b = (byte[])row["FOTO"]; byte[] imagebyte = OleImageUnwrap.GetImageBytesFromOLEField(b, 600000); MemoryStream ms = new MemoryStream(); ms.Write(imagebyte, 0, imagebyte.Length); Image img = Image.FromStream(ms); // INVALID PARAMETER ERROR CAUGHT HERE IN DEBBUG listaImagens.Add(img); } } } for (int i = 0; i < listaImagens.Count; i++) { listaImagens[i].Save("C:\\Users\\sies4578\\Desktop\\Testes\\Fotos\\" + listaNomes[i] +".png", System.Drawing.Imaging.ImageFormat.Png); //EXTERNAL EXCEPTON IN GDI+ ERROR CAUGHT HERE IN DEBBUG } } catch (Exception ex) { MessageBox.Show("Deu o berro: "+ex.Message); } } 

OleImageUnwrap.GetImageBytesFromOLEField用于从作为数据库中的图像的OLE对象中删除标头,并仅获取图像本身的字节:

  public static byte[] GetImageBytesFromOLEField(byte[] oleFieldBytes, int NumMaximoBytesSearch) { //ref http://stackoverflow.com/questions/19688641/convert-ole-object-in-datarow-into-byte-c-sharp // 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 int MaxNumberOfBytesToSearch = NumMaximoBytesSearch; byte[] imageBytes; // return value var ImageSignatures = new List(); // BITMAP_ID_BLOCK = "BM" ImageSignatures.Add(new byte[] { 0x42, 0x4D }); // JPG_ID_BLOCK = "\u00FF\u00D8\u00FF" ImageSignatures.Add(new byte[] { 0xFF, 0xD8, 0xFF }); // PNG_ID_BLOCK = "\u0089PNG\r\n\u001a\n" ImageSignatures.Add(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }); // GIF_ID_BLOCK = "GIF8" ImageSignatures.Add(new byte[] { 0x47, 0x49, 0x46, 0x38 }); // TIFF_ID_BLOCK = "II*\u0000" ImageSignatures.Add(new byte[] { 0x49, 0x49, 0x2A, 0x00 }); int NumberOfBytesToSearch = (oleFieldBytes.Count() < MaxNumberOfBytesToSearch ? oleFieldBytes.Count() : MaxNumberOfBytesToSearch); var startingBytes = new byte[NumberOfBytesToSearch]; Array.Copy(oleFieldBytes, startingBytes, NumberOfBytesToSearch); var positions = new List(); foreach (byte[] BlockSignature in ImageSignatures) { positions = IndexOfSequence(startingBytes, 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 IndexOfSequence(this byte[] buffer, byte[] pattern, int startIndex) { // ref: http://stackoverflow.com/a/332667/2144390 List positions = new List(); int i = Array.IndexOf(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(pattern)) positions.Add(i); i = Array.IndexOf(buffer, pattern[0], i + 1); } return positions; } } 

那么为什么这些错误甚至会出现呢? 我在保存部分的第18和第26个图像处获得第一个错误,而在第25个图像处于使用存储器流生成图像时得到第一个错误。

这些错误是由GetImageBytesFromOLEField()搜索图像签名的顺序引起的。 它首先搜索BMP签名,不幸的是签名很短(’BM’)所以在少数情况下它发现图像数据中的字节对并提取它认为的BMP数据。

解决方法是更改​​订单

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

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

一旦我这样做,我可以处理整个文件:

图像转换前的.mdb大小:31.8 MB
转换后但在Compact和Repair之前的.mdb大小:37.1 MB
压缩和修复后的.mdb大小:8.5 MB

编辑

这是我用来转换图像并将它们写回数据库的代码:

 private void btnStart_Click(object sender, EventArgs e) { using (var con = new OleDbConnection()) { con.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;" + @"Data Source=C:\__tmp\test\Bd Fotos Equipamentos 2.mdb;"; con.Open(); using (OleDbCommand cmdIn = new OleDbCommand(), cmdOut = new OleDbCommand()) { cmdOut.Connection = con; cmdOut.CommandText = "UPDATE [Fotografias e Manuais de Equipamentos] SET [FOTO]=? WHERE [ID]=?"; cmdOut.Parameters.Add("?", OleDbType.VarBinary); cmdOut.Parameters.Add("?", OleDbType.Integer); cmdIn.Connection = con; cmdIn.CommandText = "SELECT [ID], [FOTO] FROM [Fotografias e Manuais de Equipamentos]"; OleDbDataReader rdr = cmdIn.ExecuteReader(); while (rdr.Read()) { int i = Convert.ToInt32(rdr["ID"]); lblStatus.Text = string.Format("Processing ID {0}...", i); lblStatus.Refresh(); byte[] b = (byte[])rdr["FOTO"]; byte[] imageBytes = OleImageUnwrap.GetImageBytesFromOLEField(b); byte[] pngBytes; using (MemoryStream msIn = new MemoryStream(imageBytes), msOut = new MemoryStream()) { Image img = Image.FromStream(msIn); img.Save(msOut, System.Drawing.Imaging.ImageFormat.Png); img.Dispose(); pngBytes = msOut.ToArray(); } cmdOut.Parameters[0].Value = pngBytes; cmdOut.Parameters[1].Value = rdr["ID"]; cmdOut.ExecuteNonQuery(); } } con.Close(); } this.Close(); } 

GetImageBytesFromOLEField()代码与我之前使用的相同, MaxNumberOfBytesToSearch = 1000000