This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| 24-bit BGR Windows DIB Class Submitted by

Here's a simple Windows class for dealing with DIBs (Device Independent BItmaps). The DIB24 class supports the loading of BMP, EMF, GIF, ICO, JPG, and WMF files thanks to the IPicture COM interface. I wrote this class as a simple down and dirty way to load BMP and JPEG files using only native Windows DLLs, and to extract the pixel data with all the padding bytes removed (so that the image is byte-aligned rather than DWORD aligned). As a bonus I also provide support for capturing a screenshot of the Windows Desktop and loading that as an image into the DIB24 class. Regards,
David Poon.

Currently browsing [dib24.zip] (4,388 bytes) - [dib24.h] - (3,209 bytes)

    //------------------------------------------------------------------------
    // Copyright (c) 2003 David Poon
    //
    // Permission is hereby granted, free of charge, to any person
    // obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without
    // restriction, including without limitation the rights to use,
    // copy, modify, merge, publish, distribute, sublicense, and/or
    // sell copies of the Software, and to permit persons to whom
    // the Software is furnished to do so, subject to the following
    // conditions:
    //
    // The above copyright notice and this permission notice shall be
    // included in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    // OTHER DEALINGS IN THE SOFTWARE.
    //------------------------------------------------------------------------

    #if !defined(DIB24_H)
    #define DIB24_H

    #if !defined(WIN32_LEAN_AND_MEAN)
    #define WIN32_LEAN_AND_MEAN
    #endif

    #include <windows.h>
    #include <tchar.h>
    #include <olectl.h>

    //------------------------------------------------------------------------
    // 24-bit BGR Windows DIB class.
    //
    // Supports the loading of BMP, EMF, GIF, ICO, JPG, and WMF files using
    // only native Windows DLLs. No more linking to 3rd party DLLs.
    //
    // Support is also provided for capturing a screen shot of the current
    // Windows desktop and loading that as an image into the DIB24 object.
    //
    // This class stores the DIB in a top-down orientation.
    // The pixel data stored in 24-bit Windows DIBs is ordered BGR.
    //
    // All Windows DIBs are aligned to 4-byte (DWORD) memory boundaries.
    // This means that each scanline is padded with extra bytes to ensure
    // that the next scanline starts on a 4-byte memory boundary.
    //
    // To get a copy of the DIB that is BYTE (1-byte) aligned with all the
    // extra padding bytes removed, use the DIB24::copyByteAligned() method.
    //------------------------------------------------------------------------

    class DIB24
    {
    public:
        HDC dc;
        HBITMAP hBitmap;
        int width;
        int height;
        int pitch;
        BITMAPINFO info;

        DIB24();
        ~DIB24();

        BYTE *operator[](int row) {return &m_pBits[pitch * row];}
        const BYTE *operator[](int row) const {return &m_pBits[pitch * row];}

        bool create(int widthPixels, int heightPixels);
        void destroy();

        bool loadDesktop();
        bool loadBitmap(LPCTSTR filename);
        bool loadPicture(LPCTSTR filename);

        void selectObject();
        void deselectObject();

        void copyByteAligned(BYTE *pDest);

    private:
        static const int HIMETRIC_INCH;
        static int m_logpixelsx;
        static int m_logpixelsy;

        HGDIOBJ m_hPrevObj;
        BYTE *m_pBits;
    };

    #endif

Currently browsing [dib24.zip] (4,388 bytes) - [dib24.cpp] - (8,373 bytes)

    //------------------------------------------------------------------------
    // Copyright (c) 2003 David Poon
    //
    // Permission is hereby granted, free of charge, to any person
    // obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without
    // restriction, including without limitation the rights to use,
    // copy, modify, merge, publish, distribute, sublicense, and/or
    // sell copies of the Software, and to permit persons to whom
    // the Software is furnished to do so, subject to the following
    // conditions:
    //
    // The above copyright notice and this permission notice shall be
    // included in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    // OTHER DEALINGS IN THE SOFTWARE.
    //------------------------------------------------------------------------

    #include <stdexcept>
    #include <cstdio>
    #include "dib24.h"

    // HIMETRIC units per inch - taken from MFC source code for CDC class.
    const int DIB24::HIMETRIC_INCH = 2540;

    int DIB24::m_logpixelsx = 0;
    int DIB24::m_logpixelsy = 0;

    DIB24::DIB24()
    {
        dc = 0;
        hBitmap = 0;
        width = 0;
        height = 0;
        pitch = 0;

        m_hPrevObj = 0;
        m_pBits = 0;

        memset(&info, 0, sizeof(BITMAPINFO));

        if (!m_logpixelsx && !m_logpixelsy)
        {
            HDC hScreenDC = CreateCompatibleDC(GetDC(0));

            if (!hScreenDC)
            {
                throw std::runtime_error(
                    _T("failed to init m_logpixelsx and/or m_logpixelsy"));
            }

            m_logpixelsx = GetDeviceCaps(hScreenDC, LOGPIXELSX);
            m_logpixelsy = GetDeviceCaps(hScreenDC, LOGPIXELSY);

            DeleteDC(hScreenDC);
        }
    }

    DIB24::~DIB24()
    {
        destroy();
    }

    bool DIB24::create(int widthPixels, int heightPixels)
    {
        destroy();

        width = widthPixels;
        height = heightPixels;
        pitch = ((width * 24 + 31) & ~31) >> 3;
        dc = CreateCompatibleDC(0);

        if (!dc)
            return false;

        memset(&info, 0, sizeof(info));

        info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        info.bmiHeader.biBitCount = 24;
        info.bmiHeader.biWidth = width;
        info.bmiHeader.biHeight = -height;
        info.bmiHeader.biCompression = BI_RGB;
        info.bmiHeader.biPlanes = 1;

        hBitmap = CreateDIBSection(dc, &info, DIB_RGB_COLORS,
            reinterpret_cast<void**>(&m_pBits), 0, 0);

        if (!hBitmap)
        {
            destroy();
            return false;
        }

        GdiFlush();
        return true;
    }

    void DIB24::destroy()
    {
        deselectObject();

        if (hBitmap)
        {
            DeleteObject(hBitmap);
            hBitmap = 0;
        }

        if (dc)
        {
            DeleteDC(dc);
            dc = 0;
        }
    }

    bool DIB24::loadDesktop()
    {
        // Takes a screen capture of the current Windows desktop and stores
        // the image in the DIB24 object.

        HWND hDesktop = GetDesktopWindow();

        if (!hDesktop)
            return false;

        int desktopWidth = GetSystemMetrics(SM_CXSCREEN);
        int desktopHeight = GetSystemMetrics(SM_CYSCREEN);
        HDC hDesktopDC = GetDCEx(hDesktop, 0, DCX_CACHE | DCX_WINDOW);

        if (!hDesktopDC)
            return false;

        if (!create(desktopWidth, desktopHeight))
        {
            ReleaseDC(hDesktop, hDesktopDC);
            return false;
        }

        selectObject();

        if (!BitBlt(dc, 0, 0, width, height, hDesktopDC, 0, 0, SRCCOPY))
        {
            destroy();
            ReleaseDC(hDesktop, hDesktopDC);
            return false;
        }

        deselectObject();
        ReleaseDC(hDesktop, hDesktopDC);
        return true;
    }

    bool DIB24::loadBitmap(LPCTSTR filename)
    {
        // Loads a BMP image and stores it in the DIB24 object.

        HANDLE hImage = LoadImage(GetModuleHandle(0), filename, IMAGE_BITMAP,
            0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

        if (!hImage)
            return false;

        BITMAP bitmap = {0};

        if (!GetObject(hImage, sizeof(bitmap), &bitmap))
        {
            DeleteObject(hImage);
            return false;
        }

        HDC hImageDC = CreateCompatibleDC(0);

        if (!hImageDC)
        {
            DeleteObject(hImage);
            return false;
        }

        SelectObject(hImageDC, hImage);

        int h = (bitmap.bmHeight < 0) ? -bitmap.bmHeight : bitmap.bmHeight;

        if (create(bitmap.bmWidth, h))
        {
            selectObject();

            if (!BitBlt(dc, 0, 0, width, height, hImageDC, 0, 0, SRCCOPY))
            {
                destroy();
                DeleteDC(hImageDC);
                DeleteObject(hImage);
                return false;
            }

            deselectObject();
        }

        DeleteDC(hImageDC);
        DeleteObject(hImage);
        return true;
    }

    bool DIB24::loadPicture(LPCTSTR filename)
    {
        // Loads an image using the IPicture COM interface and stores the
        // image in the DIB24 object.
        //
        // Supported image formats: BMP, EMF, GIF, ICO, JPG, WMF.

        bool status = false;
        FILE *fp = _tfopen(filename, _T("rb"));

        if (fp)
        {
            fseek(fp, 0, SEEK_END);

            long length = ftell(fp);
            HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, length);

            if (hGlobal)
            {
                void *p = GlobalLock(hGlobal);

                if (!p)
                {
                    fclose(fp);
                }
                else
                {
                    rewind(fp);
                    fread(p, length, 1, fp);
                    GlobalUnlock(hGlobal);
                    fclose(fp);

                    IStream *pIStream = 0;
                    HRESULT hr = 0;

                    hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pIStream);

                    if (SUCCEEDED(hr))
                    {
                        IPicture *pIPicture = 0;

                        hr = OleLoadPicture(pIStream, length, FALSE,
                                IID_IPicture, reinterpret_cast<LPVOID*>(&pIPicture));

                        if (SUCCEEDED(hr))
                        {
                            LONG lWidth = 0;
                            LONG lHeight = 0;

                            pIPicture->get_Width(&lWidth);
                            pIPicture->get_Height(&lHeight);

                            //int w = MulDiv(lWidth, m_logpixelsx, HIMETRIC_INCH);
                            //int h = MulDiv(lHeight, m_logpixelsy, HIMETRIC_INCH);

                            int w = (lWidth * m_logpixelsx) / HIMETRIC_INCH;
                            int h = (lHeight * m_logpixelsy) / HIMETRIC_INCH;

                            if (create(w, h))
                            {
                                selectObject();

                                hr = pIPicture->Render(dc, 0, 0, width, height,
                                        0, lHeight, lWidth, -lHeight, 0);

                                if (SUCCEEDED(hr))
                                    status = true;

                                deselectObject();
                            }

                            pIPicture->Release();
                        }

                        pIStream->Release();
                    }
                }
            }

            GlobalFree(hGlobal);
        }

        return status;
    }

    void DIB24::selectObject()
    {
        if (dc)
            m_hPrevObj = SelectObject(dc, hBitmap);
    }

    void DIB24::deselectObject()
    {
        if (dc && m_hPrevObj)
        {
            SelectObject(dc, m_hPrevObj);
            m_hPrevObj = 0;
        }
    }

    void DIB24::copyByteAligned(BYTE *pDest)
    {
        // 'pDest' must already point to a chunk of allocated memory of the
        // correct size (i.e., width pixels X height pixels X 24 bits).
        //
        // The returned image will be byte aligned, and the pixel format
        // will be BGR (as per Windows DIB standards).

        if (pDest)
        {
            const int widthBytes = width * 3;

            for (int y = 0; y < height; ++y)
                memcpy(&pDest[widthBytes * y], &m_pBits[pitch * y], widthBytes);
        }
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.