I needed to grab the images from a database, so I made some code for it. Issue is getting that error in some images and an Invalid Parameter error in others.
The errors were caused by the order in which GetImageBytesFromOLEField()
was searching for image signatures. It was searching for the BMP signature first, and unfortunately that signature is very short ('BM') so in a few cases it found that pair of bytes inside the data of the image and extracted what it thought was BMP data.
The fix was to change the order from
var ImageSignatures = new List<byte[]>();
// 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 });
to
var ImageSignatures = new List<byte[]>();
// 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 });
Once I did that I could process the entire file:
Size of .mdb before image conversion: 31.8 MB
Size of .mdb after conversion but before Compact and Repair: 37.1 MB
Size of .mdb after Compact and Repair: 8.5 MB
This is the code that I used to convert the images and write them back to the database:
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();
}
The GetImageBytesFromOLEField()
code is the same as I used before, with MaxNumberOfBytesToSearch = 1000000
.