Question

This is an extension of my previous question. I'm basically:

  1. retrieving an OleImage from an access database

  2. stripping the oleheader

  3. Cropping and resizing the Image

  4. Saving the image back to database (Stuck here)

So I've gotten to step 4. Initially I was hoping that the application code would recognize the BMP byte[] array. However after saving it back to the database:

    private void SaveImage(string imgPath, int ID)
    {
        var myconn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\SUFDB2006.mdb");
        var pic = File.ReadAllBytes(imgPath);

        var cmd = new OleDbCommand { CommandType = CommandType.Text, CommandText = "UPDATE Contact SET Photo = @p1 WHERE [Contact ID#] = 7707", Connection = myconn };
        myconn.Open();
        cmd.Parameters.AddWithValue("@p1", pic);
        cmd.ExecuteNonQuery();
        myconn.Close();
    }

it is not recognized by the picture box on the form (Access :( Go figure).

So apparently I need to convert the bmp back to an Oleimage.

  1. Is it possible to simply append the original Ole header back on the bmp and update the record ?

  2. Is there some sort of switch on the access picture box control that I can flip to get it to recognize the bmp byte array ? (I know this is a long shot and I'm really not trying to mess with the access code because its super old)

  3. If the answers to the above are negative is there away to convert these back to Ole Images without having to shell the access application ?

@GordThompson had an answer:

    private void OleShellAccessUpdate(string bmp, int Id)
    {
        int recordIdToUpdate = 75;
        string bmpPath = bmp;

        var paths = new System.Collections.Specialized.StringCollection();
        paths.Add(bmpPath);
        Clipboard.SetFileDropList(paths);

        var accApp = new Microsoft.Office.Interop.Access.Application();
        accApp.OpenCurrentDatabase(@"E:\SUFDB2006.mdb");
        accApp.DoCmd.OpenForm("Contact Entry", Microsoft.Office.Interop.Access.AcFormView.acNormal, null, "[Contact ID#]=" + recordIdToUpdate);
        accApp.DoCmd.RunCommand(Microsoft.Office.Interop.Access.AcCommand.acCmdPaste);
        accApp.DoCmd.Close(Microsoft.Office.Interop.Access.AcObjectType.acForm, "Photo", Microsoft.Office.Interop.Access.AcCloseSave.acSaveNo);
        accApp.CloseCurrentDatabase();
        accApp.Quit();
        this.Close();
    }

However given the volume of records I am dealing with this is not really a practical solution in this case. I need a way to do this without shelling the application. So I have a few questions:

Edit - Directed at Gords comment

I put the above code as I tried it, haven't got it to work successfully. The reason I say too many records (75,000) is I'm already getting allot of memory pressure errors because the images i'm resizing are so large and i'm running them through several methods to find a face, crop around the face, and then desaturate the image. Obviously I can break this up into sequences but at a certain point I would like something I can run in a reasonable amount of passes. This was my concern about shelling access.--------- Back to question

Edit 2

Microsoft Support Article Found this article through another question

"Pitfalls

This test will not work with the Photo column in the Employees table of the sample Northwind database distributed with Access and SQL Server. The bitmap images stored in the Photo column are wrapped with the header information created by the Visual Basic 6.0 OLE Container control.

If you need to use an Access database to test this code, you will need to create the column in the Access table as type OLE Object, and use the System.Data.OleDb namespace with the Microsoft Jet 4.0 Provider in place of the System.Data.SqlClient namespace."

This alludes to using the "System.Data.OleDb" namespace. Is there a specific datatype that corresponds to the Ole Photo type ?

Was it helpful?

Solution

After a brief chat it seems that the Access.Application (automation) approach outlined here (with a slightly modified version of the code appearing in this question) might be feasible after all. Processing 75,000 records could take a few hours based on my timing test (1000 records took just under 3.5 minutes on my oldest machine), but that would almost certainly be much faster than the time required to research, write, and debug native C# code to do the "OLE wrapping" directly.

Image illustrating steps needed to be take in access to make the code work

OTHER TIPS

'SqlConnection objCon = new SqlConnection(con);
                objCon.Open();
                SqlCommand cmd = new SqlCommand("Studentinsertadmission", objCon);
  cmd.Parameters.Add(new SqlParameter("@Studentid",Convert.ToInt32( studentid.Text)));
                cmd.Parameters.Add(new SqlParameter("@StudentName", firstname.Text));
                cmd.Parameters.Add(new SqlParameter("@Image", image.image  ));
cmd.CommandType = CommandType.StoredProcedure;
                int rows = cmd.ExecuteNonQuery();
                objCon.Close();

                MessageBox.Show("Record Inserted Successfully! ");'
Try this it works deppending on the component.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top