YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


Visual C++ Example: Load DIB Bitmap File and Save Bitmap file and Convert dib to bitmap and rotate bitmap file

 
 
// This function converts the given bitmap to a DFB.
// Returns true if the conversion took place,
// false if the conversion either unneeded or unavailable
bool ConvertToDFB(HBITMAP& hBitmap)
{
  bool bConverted = false;
  BITMAP stBitmap;
  if (GetObject(hBitmap, sizeof(stBitmap), &stBitmap) && stBitmap.bmBits)
  {
    // that is a DIB. Now we attempt to create
    // a DFB with the same sizes, and with the pixel
    // format of the display (to omit conversions
    // every time we draw it).
    HDC hScreen = GetDC(NULL);
    if (hScreen)
    {
      HBITMAP hDfb =
              CreateCompatibleBitmap(hScreen,
      stBitmap.bmWidth, stBitmap.bmHeight);
      if (hDfb)
      {
        // now let's ensure what we've created is a DIB.
        if (GetObject(hDfb, sizeof(stBitmap),
                   &stBitmap) && !stBitmap.bmBits)
        {
          // ok, we're lucky. Now we have
          // to transfer the image to the DFB.
          HDC hMemSrc = CreateCompatibleDC(NULL);
          if (hMemSrc)
          {
            HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
            if (hOldSrc)
            {
              HDC hMemDst = CreateCompatibleDC(NULL);
              if (hMemDst)
              {
                HGDIOBJ hOldDst = SelectObject(hMemDst, hDfb);
                if (hOldDst)
                {
                  // transfer the image using BitBlt
                  // function. It will probably end in the
                  // call to driver's DrvCopyBits function.
                  if (BitBlt(hMemDst, 0, 0,
                        stBitmap.bmWidth, stBitmap.bmHeight,
                        hMemSrc, 0, 0, SRCCOPY))
                    bConverted = true; // success

                  VERIFY(SelectObject(hMemDst, hOldDst));
                }
                VERIFY(DeleteDC(hMemDst));
              }
              VERIFY(SelectObject(hMemSrc, hOldSrc));
            }
            VERIFY(DeleteDC(hMemSrc));
          }
        }

        if (bConverted)
        {
          VERIFY(DeleteObject(hBitmap)); // it's no longer needed
          hBitmap = hDfb;
        }
        else
          VERIFY(DeleteObject(hDfb));
      }
      ReleaseDC(NULL, hScreen);
    }
  }
  return bConverted;
}

// This function converts the given bitmap to a DIB.
// Returns true if the conversion took place,
// false if the conversion either unneeded or unavailable
bool ConvertToDIB(HBITMAP& hBitmap)
{
  bool bConverted = false;
  BITMAP stBitmap;
  if (GetObject(hBitmap, sizeof(stBitmap),
            &stBitmap) && !stBitmap.bmBits)
  {
    // that is a DFB. Now we attempt to create
    // a DIB with the same sizes and pixel format.
    HDC hScreen = GetDC(NULL);
    if (hScreen)
    {
      union {
        BITMAPINFO stBitmapInfo;
        BYTE pReserveSpace[sizeof(BITMAPINFO)
                     + 0xFF * sizeof(RGBQUAD)];
      };
      ZeroMemory(pReserveSpace, sizeof(pReserveSpace));
      stBitmapInfo.bmiHeader.biSize = sizeof(stBitmapInfo.bmiHeader);
      stBitmapInfo.bmiHeader.biWidth = stBitmap.bmWidth;
      stBitmapInfo.bmiHeader.biHeight = stBitmap.bmHeight;
      stBitmapInfo.bmiHeader.biPlanes = 1;
      stBitmapInfo.bmiHeader.biBitCount = stBitmap.bmBitsPixel;
      stBitmapInfo.bmiHeader.biCompression = BI_RGB;

      if (stBitmap.bmBitsPixel <= 8)
      {
        stBitmapInfo.bmiHeader.biClrUsed =
                        1 << stBitmap.bmBitsPixel;
        // This image is paletted-managed.
        // Hence we have to synthesize its palette.
      }
      stBitmapInfo.bmiHeader.biClrImportant =
                       stBitmapInfo.bmiHeader.biClrUsed;

      PVOID pBits;
      HBITMAP hDib = CreateDIBSection(hScreen,
        &stBitmapInfo, DIB_RGB_COLORS, &pBits, NULL, 0);

      if (hDib)
      {
        // ok, we're lucky. Now we have
        // to transfer the image to the DFB.
        HDC hMemSrc = CreateCompatibleDC(NULL);
        if (hMemSrc)
        {
          HGDIOBJ hOldSrc = SelectObject(hMemSrc, hBitmap);
          if (hOldSrc)
          {
            HDC hMemDst = CreateCompatibleDC(NULL);
            if (hMemDst)
            {
              HGDIOBJ hOldDst = SelectObject(hMemDst, hDib);
              if (hOldDst)
              {
                if (stBitmap.bmBitsPixel <= 8)
                {
                  // take the DFB's palette and set it to our DIB
                  HPALETTE hPalette =
                    (HPALETTE) GetCurrentObject(hMemSrc, OBJ_PAL);
                  if (hPalette)
                  {
                    PALETTEENTRY pPaletteEntries[0x100];
                    UINT nEntries = GetPaletteEntries(hPalette,
                                    0, stBitmapInfo.bmiHeader.biClrUsed,
                                    pPaletteEntries);
                    if (nEntries)
                    {
                      ASSERT(nEntries <= 0x100);
                      for (UINT nIndex = 0; nIndex < nEntries; nIndex++)
                        pPaletteEntries[nEntries].peFlags = 0;
                      VERIFY(SetDIBColorTable(hMemDst, 0,
                        nEntries, (RGBQUAD*) pPaletteEntries) == nEntries);

                    }
                  }
                }

                // transfer the image using BitBlt function.
                // It will probably end in the
                // call to driver's DrvCopyBits function.
                if (BitBlt(hMemDst, 0, 0, stBitmap.bmWidth,
                      stBitmap.bmHeight, hMemSrc, 0, 0, SRCCOPY))
                  bConverted = true; // success

                VERIFY(SelectObject(hMemDst, hOldDst));
              }
              VERIFY(DeleteDC(hMemDst));
            }
            VERIFY(SelectObject(hMemSrc, hOldSrc));
          }
          VERIFY(DeleteDC(hMemSrc));
        }

        if (bConverted)
        {
          VERIFY(DeleteObject(hBitmap)); // it's no longer needed
          hBitmap = hDib;
        }
        else
          VERIFY(DeleteObject(hDib));
      }
      ReleaseDC(NULL, hScreen);
    }
  }
  return bConverted;
}

Introduction

CDibData is a class used to simplify loading, saving, converting (color-depth), and accessing bitmap image bits. It was originally designed as a utility class to allow direct access to the image bits of a bitmap object. Upon realizing that it would be a useful class, on its' own, I decided to expand its' abilities to include: loading, saving, and conversion of bitmaps. The class does not require that the bitmap be loaded as a DIBSECTION in order to be useful, that was the original requirement when it was created.

I have also included a copy of Quantize.cpp by Jeff Prosise; Quantize.cpp can be found in the MFC library for those interested in reading about it.

Ok after reading this article and testing the code: blast me, find the bugs, tell me how to improve the code and/or Doxygen generated documentation. Do your best to break the code, even you guys in quality control (who specialize in the ridiculous). If there is some thing wrong, I want to know!

Background

The main references used to develop this were "Programming Windows Fifth Edition" by Charles Petzold, and the MFC library. Most of the references are listed in CDibData.cpp.

Using the code

The DIB is stored internally in a single block of globally allocated memory suitable for transfer via the clipboard using the CF_DIB format. Since CDibData was not designed as a replacement for CBitmap, it does not maintain a copy of the original bitmap handle.

If you have not installed the Windows SDK from Microsoft, you will get some compilation errors when compiling in debug mode. The reason for this is that BITMAPV5HEADER was not defined in the SDK that came with Visual C++ 6.0. Since BITMAPV5HEADER is only used for displaying debugging information, it should be easy to comment out the code.

Note: When an CDibData object contains a compressed DIB, you no longer have direct access to the image bits. Therefore, you can save the DIB image to file but not convert it or use any function that requires direct access to the image bits.

Examples of how to load a bitmap file:

Collapse Copy Code
// Loading file using CDibData::LoadDIB()
// This method also allows for the loading of 2 bits-per-pixels bitmaps by
// converting them to 4 bits-per-pixels when loading.
HBITMAP hBitmap = m_DibData.LoadDIB(lpszPathName);
if( !hBitmap )
    return FALSE;
    
m_Bitmap.Attach(hBitmap);
Collapse Copy Code
// Loading file using LoadImage()
HBITMAP hBitmap = (HBITMAP)::LoadImage(
    NULL, lpszPathName, IMAGE_BITMAP,
    0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if( !hBitmap )
    return FALSE;
    
if( m_Bitmap.Attach(hBitmap) )
    m_DibData.CreateDIB(&m_Bitmap);
Collapse Copy Code
// Loading file directly into a CDibData object
// Note: DibXXXX() functions are actualy just defined wrappers for
// GlobalXXXX() functions (used internally for debugging).
try
{
    // Copy DIB from file
    CFile cf(lpszPathName, CFile::modeRead);

    // Read bitmap file header
    BITMAPFILEHEADER bmfh;
    cf.Read((void*)&bmfh, sizeof(BITMAPFILEHEADER));

    // Verify file type
    if( bmfh.bfType != 0x4D42 )
    {
        cf.Close();
        return NULL;
    }

    // Read DIB from file
    DWORD dwLen = cf.GetLength() - sizeof(BITMAPFILEHEADER);
    hDib = DibAlloc(dwLen);
    pDib = DibLock(hDib);
    if( pDib )
        cf.Read((void*)pDib, (UINT)dwLen);
    cf.Close();

    if( !pDib )
    {
        if( hDib )
            DibFree(hDib);
        return NULL;
    }

    DibUnlock(hDib);
}
catch( CFileException* /*e*/)
{
    if( pDib )
        DibUnlock(hDib);
    if( hDib )
        DibFree(hDib);
    return NULL;
}

// Attach DIB to this object
if( !Attach(hDib) )
{
    DibFree(hDib);
    return NULL;
}

Examples of how to save a bitmap file:

Collapse Copy Code
// Save file using internally stored DIB data.
m_DibData.CreateDIB.SaveDIB(lpszPathName);
Collapse Copy Code
// Save compressed file using internally stored DIB data.
m_DibData.CreateDIB.SaveDIB(lpszPathName, NULL, TRUE);
Collapse Copy Code
// Save file using external bitmap source.
m_DibData.CreateDIB.SaveDIB(lpszPathName, &m_Bitmap);
Collapse Copy Code
// Save compressed file using external bitmap source.
m_DibData.CreateDIB.SaveDIB(lpszPathName, &m_Bitmap, TRUE);

Examples of converting from one format to another:

Collapse Copy Code
// Convert internally stored DIB data to new format
// Note: Use delete to destroy pDibClass when finished with object
CDibData* pDibClass = m_DibData.GetConvertedDIB(wNewColorDepth);
Collapse Copy Code
// Convert internally stored DIB data to new format using palette optimization
CDibData* pDibClass = m_DibData.GetConvertedDIB(wNewColorDepth, TRUE);
Collapse Copy Code
// Create converted CDibData object from CBitmap object
CDibData ddObj;
ddObj.CreateDIB(&m_Bitmap);
CDibData* pDibClass = ddObj.GetConvertedDIB(wNewColorDepth, TRUE);

Example of 90 degree rotation:

Collapse Copy Code
// Create source DIB
CDibData dibSrc;
if( !dibSrc.CreateDIB(&bmpSrc) )
    return FALSE;
    
int x, y, t;
int cx = dibSrc.GetWidth();
int cy = dibSrc.GetHeight();

BOOL bResult = FALSE;

// Create rotated destination bitmap bits object
CBitmap bmpDest;
{
    CDC dcDest;
    dcDest.CreateCompatableDC(NULL);
    CBitmap* pOldBitmap = dcDest.SelectObject(&bmpSrc);
    BOOL bRet = bmpDest.CreateCompatibleBitmap(&dcDest, cy, cx);
    dcDest.SelectObject(pOldBitmap);
    dcDest.DeleteDC();
    if( !bRet )
        return bRet;
}

CDibData dibDest;
if( !dibDest.CreateDIB(&bmpDest) )
    return FALSE;

// Rotate right (90 degrees)
if( nRotations == 0 )
{
    for( x = 0; x < cx; ++x )
    {
        t = cy - 1;
        for( y = 0; y < cy; ++y, --t )
            dibDest.CopyPixelValue( t, x, dibSrc, x, y);
    }
}
// Rotate left (90 degrees)
else
{
    for( y = 0; y < cy; ++y )
    {
        t = cx - 1;
        for( x = 0; x < cx; ++x, --t )
            dibDest.CopyPixelValue(y, t, dibSrc, x, y);
    }
}

// Copy destination bits to destination bitmap
if( !dibDest.SetDIBits(&bmpDest) )
    return FALSE;

Points of Interest

Some of you may be interested in the following:

  • Question: What is with the style used to write the comments proceeding each function?
  • Answer: I decided to use Doxygen to generate documentation for this object. I've used it before to help me understand other peoples code, but never to create accurate documentation of mine. You will find Doxygen.dat in the CDibData directory used by the Doxygen wizard to generate documentation for the CDibData class.
  • Question: Can GetDIBits() be used to convert bitmaps from one format to another?
  • Answer: Yes, but when converting to a lower color depth you loose important color information. The reason for this is that GetDIBits() does no color optimization.
  • Question: Why use CDibData::LoadDIB() instead of LoadImage()?
  • Answer: CDibData::LoadDIB() can load top-down bitmaps and 2 bits-per-pixel bitmaps, LoadImage() can not. It is my understanding that WinCE supports 2 bits-per-pixel (shades of gray) bitmaps therefore, I decided to support loading, saving, and manipulation of 2 bits-per-pixel bitmaps. Although CDibData recognizes and can manipulate 2 bits-per-pixel bitmaps it must convert it to 4 bits-per-pixel, when loading, in order to create an HBITMAP handle that can be used by GDI on non-WinCE devices (a.k.a. your monitor).
  • Question: Does CDibData support WinCE?
  • Answer: No, although CDibData supports 2 bits-per-pixel manipulation, it is designed to work on a PC. The main reason for supporting 2 bits-per-pixels is that some one has to create the bitmaps used by WinCE. I would also like to note that CDibData does not remember the original format of the bitmap that was loaded therefore, you will have to convert it back to 2 bits-per-pixels when saving.
  • Question: Does CDibData support the newest bitmap header types?
  • Answer: No, CDibData only supports DIBs with a BITMAPINFOHEADER.
  • Question: Why not use GetBitmapBits() to get access to image bits?
  • Answer: See Q131896 in the MFC library.

 

 

 

 

 

Copyright ?1998-2022 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net