Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting an OLE Image Object from MS Access for use in .NET

I'm working on redeveloping an Access based system into c#.net, however when MS went from office 2003 to office 2007 they removed the picture editor within access - which meant that previously stored pictures would no longer display in the system. The guys at the company did a hack that basically saved the images with VBA using excel in the background (I can get more information if you need it) but basically it meant the access image controls could still be used (Object bound frames).

However, I now have the problem of trying to display these in .NET applications, and after countless days of trying different ways of manipulating the byte array I'm close to giving up. I have tried at least 8 different suggested solutions and each one ends with a 'Parameter not recognised' exception when doing Image.fromStream(). Below is the code which has got me the closest so far:

    private void imageExtractTest()
    {
        LogOnDataSetTableAdapters.QueriesTableAdapter qa =
            new LogOnDataSetTableAdapters.QueriesTableAdapter();

        object docO = qa.GetLogonImage();
        if (docO == null || !(docO is byte[]))
        {
            return;
        }
        byte[] doc = (byte[])docO;

        MemoryStream ms = new MemoryStream();
        ms.Write(doc, 0, doc.Length);
        int firstByte;
        int secondByte;
        ms.Seek(0, SeekOrigin.Begin);
        firstByte = ms.ReadByte();
        secondByte = ms.ReadByte();

        if (firstByte != 0x15 && secondByte != 0x1C)
        {
            //ErrorResponse("Stored object is not an Access File.");
            return;
        }

        int fileTypeLoc = 20; // begin of the file type
        short offset; // end of the file type

        byte[] buffer = new byte[2];
        ms.Read(buffer, 0, 2);
        offset = BitConverter.ToInt16(buffer, 0);

        long seekTotal = 0;
        seekTotal += offset;

        string docType = String.Empty;
        for (int i = fileTypeLoc; i < offset; i++)
        {
            docType += (char)doc[i];
        }

        //if I query docType now I get 'Picture\0\0'

        // magic eight bytes 01 05 00 00 03 00 00 00
        ms.Seek(seekTotal, SeekOrigin.Begin);
        buffer = new byte[8];
        ms.Read(buffer, 0, 8);
        seekTotal += 8;

        // Second offset to move to 
        buffer = new byte[4];
        ms.Read(buffer, 0, 4);
        seekTotal += 4;
        long offset2 = BitConverter.ToInt32(buffer, 0);
        seekTotal += offset2;
        ms.Seek(seekTotal, SeekOrigin.Begin);

        // eight empty bytes
        buffer = new byte[8];
        ms.Read(buffer, 0, 8);
        seekTotal += 8;

        // next n bytes are the length of the file
        buffer = new byte[4];
        ms.Read(buffer, 0, 4);
        seekTotal += 4;
        long fileByteLength = BitConverter.ToInt32(buffer, 0);

        // next N bytes are the file
        byte[] data = new byte[fileByteLength];

        // store file bytes in data buffer
        ms.Read(data, 0, Convert.ToInt32(fileByteLength));

        MemoryStream imageStream = new MemoryStream(data);
        Image test = Image.FromStream(imageStream);
    }

This code was adapted from here, I didn't need the various doctypes identification as I'm only dealing with images, however the image type could be any number of things - jpg, bmp, gif, png etc.

I've also tried saving the outputted byte array but I've had no luck viewing that either. But when I point access to the database and get it to view it, everything is fine. Also the .NET Crystal Report designer is able to get these images some how - so they must be in there somewhere...

Has anyone got any ideas?

Marlon

like image 655
Marlon Avatar asked Mar 10 '10 11:03

Marlon


People also ask

What is OLE object in MS Access?

Earlier versions of Access used a technology called Object Linking and Embedding (OLE) to store images and documents. By default, OLE created a bitmap equivalent of the image or document. Those bitmap files could become quite large — as much as 10 times larger than the original file.

What is the difference between OLE and attachment?

Explanation: The Attachment data type, introduced in Access 2007, is very similar to the OLE Object data type in that you can use it to store complex data. However, unlike the OLE Object data type, you can store multiple attachments in a single record. These files are stored in a binary field in a hidden system table.

What is an OLE object in database?

OLE DB (Object Linking and Embedding, Database, sometimes written as OLEDB or OLE-DB), an API designed by Microsoft, allows accessing data from a variety of sources in a uniform manner.


2 Answers

Trying to retrieve an MS-access OLE image field from .NET is way more headache than it is worth. There is some good discussion and info about this topic in this post.

Ultimately, your best, and easiest, solution to be successful with this is to use your working viewing method to save these images as separate files, then import those files into the database as BLOB fields, rather than image fields. Then you can easily read them into .NET.

like image 93
Stewbob Avatar answered Sep 20 '22 15:09

Stewbob


It is not C# code but here is an Delphi example of a way to solve this problem.

It uses the IOLEObject to draw whatever is stored instead of trying to read out the raw data. Steps:

  1. Read the Access Header in front of the OLE Object
  2. Read out the OLE1 stream
  3. Convert the OLE1 stream to an OLE2 IStorage Object
  4. Use OLELoad to "run" the OLE Ojbect.
  5. Call OLEDraw to draw out the image to a canvas of your choice.
like image 34
Mark Elder Avatar answered Sep 22 '22 15:09

Mark Elder