Home > C++ Classes, Programming > Loading Images under Windows (an OLE Image Loader)

Loading Images under Windows (an OLE Image Loader)

August 1st, 2009 Leave a comment Go to comments

OLE can be used to open a few of image file formats (JPEG, BMP, GIF but no PNG) on Windows. I have put together a simple C++ class that will open image and read image files.

Basically, here is how you can proceed to open an image with OLE (this is actually inspired from this codeproject article):

Obtain an IStream Pointer

Load the file into global memory and create an IStream*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// open the file
HANDLE hFile = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

// allocate storage to read the file
DWORD dwFileSize = GetFileSize(hFile, NULL);
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
LPVOID pvData = GlobalLock(hGlobal);
DWORD dwBytesRead = 0;

// read the file
BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);
GlobalUnlock(hGlobal);
CloseHandle(hFile);

// create the IStream* from the global memory
LPSTREAM pstm = NULL;
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm);

Import with OleLoadPicture

1
2
LPPICTURE picture;
hr = ::OleLoadPicture(pstm, dwFileSize, FALSE, IID_IPicture, (LPVOID *)&(picture));

Obtain Image Information

Once we have obtained the PICTURE object, we can query its size:

1
2
3
4
5
6
7
8
9
long hmWidth = 0, hmHeight = 0;
picture->get_Width (&hmWidth);
picture->get_Height(&hmHeight);

HDC Screen = ::CreateCompatibleDC(0);

int width = MulDiv(hmWidth, GetDeviceCaps(Screen, LOGPIXELSX), HIMETRIC_INCH);
int height = MulDiv(hmHeight, GetDeviceCaps(Screen, LOGPIXELSY), HIMETRIC_INCH);
::DeleteDC(Screen);

Load the Image

Finally, loading the image has to be done within a custom DC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
HDC hDC = CreateCompatibleDC(0);

BITMAPINFO bmInfo = {0};
bmInfo.bmiHeader.biSize = sizeof(BITMAPINFO);
bmInfo.bmiHeader.biSizeImage = 0;
bmInfo.bmiHeader.biPlanes = 1;
bmInfo.bmiHeader.biBitCount = 32; // or 24 if you don't care about alpha
bmInfo.bmiHeader.biWidth = width;
bmInfo.bmiHeader.biHeight = height;

unsigned char *pixels;
HBITMAP bm = CreateDIBSection(hDC, &bmInfo, DIB_RGB_COLORS, (void**)&pixels, NULL, 0);
HGDIOBJ old = SelectObject(hDC, bm);

RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = width;
rc.bottom = height;

HRESULT hrP =
picture->Render(hDC, 0, 0, width, height, 0, hmHeight, hmWidth, -hmHeight, &rc);

BITMAP b;
SelectObject(hDC, old);
GetObject(bm, sizeof(b), &b);
int rowLength = b.bmWidthBytes;

// allocate a buffer
unsigned char *data = new unsigned char[width*height*4];

// load the texture into the data buffer
GetBitmapBits(bm, b.bmHeight*rowLength, data);

DeleteObject(bm);
DeleteDC(hDC);

Special Case – Loading Alpha Correctly

Older BMP did not support 32 bit with alpha channel. Support for an alpha channel was added in XP I believe. As a consequence, some BMP have been written as 32bit with an unused (at the time) alpha channel that’s completely transparent. If you plan on using the alpha channel from the BMP files, it’s generally a good idea to check if the entire alpha channel is transparent. In such a case, we would assume that the entire channel should make it fully opaque. This is what the following piece of code does:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// scan to check if the alpha is all transparent
bool allTransp = true;
unsigned char *row = data;

for (int y = 0; allTransp && y < b.bmHeight; ++y)
{
    for (int x = 0; allTransp && x < b.bmWidth; ++x)
    {
        int a = row[x*4+3];
        if (a != 0)
            allTransp = false;
    }
    row += rowLength;
}

if (allTransp)
{
    // if everything is transparent, make everything opaque
    row = data;
    for (int y = 0; y < b.bmHeight; ++y)
    {
        for (int x = 0; x < b.bmWidth; ++x)
        {
            row[x*4+3] = 255;
        }
        row += rowLength;
    }
}
Categories: C++ Classes, Programming Tags:
  1. No comments yet.
  1. No trackbacks yet.
*

Please leave these two fields as-is:

Protected by Invisible Defender. Showed 403 to 158,454 bad guys.