1

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 ?

Community
  • 1
  • 1
bumble_bee_tuna
  • 3,533
  • 7
  • 43
  • 83
  • 1
    @puretppc Thanks, you beat me to that edit lol – bumble_bee_tuna Feb 04 '14 at 03:57
  • 1
    No problem. Oh my bad. I should've let you edit it first but I'm trying to go for the gold badge so if I see something worth formatting I will do it. – puretppc Feb 04 '14 at 03:58
  • 1
    @puretpcc No worries looks better then the way I had it anyway lol – bumble_bee_tuna Feb 04 '14 at 04:01
  • 1
    re: "given the volume of records I am dealing with" - How many would that be? Bear in mind that using an adaptation of [this](http://stackoverflow.com/a/21500533/2144390) to process *n* images wouldn't necessarily mean that you need to start/stop an Access process *n* times. For what it's worth, my creaky old notebook updated 1000 OLE images in just under 3.5 minutes. – Gord Thompson Feb 04 '14 at 09:29
  • @GordThompson I put the code as I tried it above haven't actually been able to get that to work ( as I said I was originally hoping to not have use ole at all, rather just bmp[] byte array). I'm not familiar with interop can you tell me what I'm doin wrong. The form name is "Contact Entry" the table is "Contact" and the columns are are "[Contact ID#]" and "[Photo]" – bumble_bee_tuna Feb 04 '14 at 18:29
  • re: your code - One thing I notice is that you are opening a form named "Contact Entry" and then trying to close a form named "Photo". Which form is the one you created with *just* the `Bound Object Frame` on it (form bound to table [Contact], frame bound to field [Photo])? – Gord Thompson Feb 04 '14 at 19:23
  • @GordThompson Ahh ... The original form is "Contact Entry" with user data and "Photo" column. Are you telling me I need to make a blank form with just an Id and Photo column and then move the image back to the main "Contact Entry" table ? – bumble_bee_tuna Feb 04 '14 at 19:32
  • No, you need a separate form with **just** the `Bound Object Frame` on it so there's no question that it will have the focus when the form opens. (You don't need an ID *control* because your form can reference the ID *field* directly.) When you Paste into that `Bound Object Frame` the data is OLE wrapped and then written to the table. (There is no need to "move" anything from one form to another.) – Gord Thompson Feb 04 '14 at 19:41
  • @GordThompson Ok so the separate form makes sense. How will the existing form (Contact Entry) know which image corresponds to what ID. Thats in the header data ? – bumble_bee_tuna Feb 04 '14 at 19:44
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46778/discussion-between-gord-thompson-and-bumble-bee-tuna) – Gord Thompson Feb 04 '14 at 19:44

2 Answers2

1

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

Community
  • 1
  • 1
Gord Thompson
  • 116,920
  • 32
  • 215
  • 418
0
'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.