External Exception in GDI+ error saving specific image

前端 未结 1 376
误落风尘
误落风尘 2021-01-16 13:05

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.



        
相关标签:
1条回答
  • 2021-01-16 13:11

    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

    Edit

    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.

    0 讨论(0)
提交回复
热议问题