www.gusucode.com > 包含近30种图像特效的VC++小程序源码程序 > 包含近30种图像特效的VC++小程序源码程序/code/DIBSectionLite.cpp
///////////////////////////////////////////////////////////////////////// //类名:CDIBSectionLite //功能:DIB位图文件操作类(载入、显示、保存) //用法: // CDIBSectionLite dibsection; // dibsection.Load(_T("image.bmp")); // dibsection.Draw(pDC, CPoint(0,0)); // pDC的类型是CDC* // // CDIBSectionLite dibsection; // dibsection.SetBitmap(IDB_BITMAP); // dibsection.Draw(pDC, CPoint(0,0)); // pDC的类型是CDC* //修改:徐景周(jingzhou_xu@163.net) //组织:未来工作室(Future Studio) //日期:2002.1.8 //////////////////////////////////////////////////////////////////////// #include "stdafx.h" // 加入预编译头文件,jingzhou xu #include "DIBSectionLite.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // Standard colours PALETTEENTRY CDIBSectionLite::ms_StdColours[] = { { 0x00, 0x00, 0x00, 0 }, // First 2 will be palette for monochrome bitmaps { 0xFF, 0xFF, 0xFF, 0 }, { 0x00, 0x00, 0xFF, 0 }, // First 16 will be palette for 16 colour bitmaps { 0x00, 0xFF, 0x00, 0 }, { 0x00, 0xFF, 0xFF, 0 }, { 0xFF, 0x00, 0x00, 0 }, { 0xFF, 0x00, 0xFF, 0 }, { 0xFF, 0xFF, 0x00, 0 }, { 0x00, 0x00, 0x80, 0 }, { 0x00, 0x80, 0x00, 0 }, { 0x00, 0x80, 0x80, 0 }, { 0x80, 0x00, 0x00, 0 }, { 0x80, 0x00, 0x80, 0 }, { 0x80, 0x80, 0x00, 0 }, { 0x80, 0x80, 0x80, 0 }, { 0xC0, 0xC0, 0xC0, 0 }, }; ///////////////////////////////////////////////////////////////////////////// // CDIBSectionLite static functions // --- In : nBitsPerPixel - bits per pixel // --- Out : // --- Returns :The number of colours for this colour depth // --- Effect : Returns the number of color table entries given the number // of bits per pixel of a bitmap /*static*/ int CDIBSectionLite::NumColorEntries(int nBitsPerPixel) { int nColors = 0; switch (nBitsPerPixel) { case 1: nColors = 2; break; case 4: nColors = 16; break; case 8: nColors = 256; break; case 16: case 24: case 32: nColors = 0; break; // 16,24 or 32 bpp have no color table default: ASSERT(FALSE); } return nColors; } // --- In : nWidth - image width in pixels // nBitsPerPixel - bits per pixel // --- Out : // --- Returns : Returns the number of storage bytes needed for each scanline // in the bitmap // --- Effect : /*static*/ int CDIBSectionLite::BytesPerLine(int nWidth, int nBitsPerPixel) { int nBytesPerLine = nWidth * nBitsPerPixel; nBytesPerLine = ( (nBytesPerLine + 31) & (~31) ) / 8; return nBytesPerLine; } // --- In : palette - reference to a palette object which will be filled // nNumColours - number of colour entries to fill // --- Out : // --- Returns : TRUE on success, false otherwise // --- Effect : Creates a halftone color palette independant of screen color depth. // palette will be filled with the colors, and nNumColours is the No. // of colors to file. If nNumColoursis 0 or > 256, then 256 colors are used. /*static*/ BOOL CDIBSectionLite::CreateHalftonePalette(CPalette& palette, int nNumColours) { palette.DeleteObject(); int nNumStandardColours = sizeof(ms_StdColours) / sizeof(ms_StdColours[0]); int nIndex = 0; int nNumEntries = nNumColours; if (nNumEntries <= 0 || nNumEntries > 256) nNumEntries = 256; PALETTEINFO PalInfo; PalInfo.palNumEntries = (WORD) nNumEntries; // The standard colours (16) for (int i = 0; i < nNumStandardColours; i++) { if (nIndex >= nNumEntries) break; memcpy( &(PalInfo.palPalEntry[nIndex]), &(ms_StdColours[i]), sizeof(PALETTEENTRY) ); nIndex++; } // A colour cube (6 divisions = 216) for (int blue = 0; blue <= 5; blue++) for (int green = 0; green <= 5; green++) for (int red = 0; red <= 5; red++) { if (nIndex >= nNumEntries) break; PalInfo.palPalEntry[nIndex].peRed = (BYTE) ((red*255)/5); PalInfo.palPalEntry[nIndex].peGreen = (BYTE) ((green*255)/5); PalInfo.palPalEntry[nIndex].peBlue = (BYTE) ((blue*255)/5); PalInfo.palPalEntry[nIndex].peFlags = 0; nIndex++; } // A grey scale (24 divisions) for (int grey = 0; grey <= 23; grey++) { if (nIndex >= nNumEntries) break; PalInfo.palPalEntry[nIndex].peRed = (BYTE) (grey*255/23); PalInfo.palPalEntry[nIndex].peGreen = (BYTE) (grey*255/23); PalInfo.palPalEntry[nIndex].peBlue = (BYTE) (grey*255/23); PalInfo.palPalEntry[nIndex].peFlags = 0; nIndex++; } return palette.CreatePalette((LPLOGPALETTE) PalInfo); } ///////////////////////////////////////////////////////////////////////////// // CDIBSectionLite CDIBSectionLite::CDIBSectionLite() { m_hBitmap = NULL; m_bDither = FALSE; m_hDrawDib = NULL; DeleteObject(); // This will initialise to a known state - ie. empty } CDIBSectionLite::~CDIBSectionLite() { DeleteObject(); } // --- In : // --- Out : // --- Returns : // --- Effect : Resets the object to an empty state, and frees all memory used. void CDIBSectionLite::DeleteObject() { if (m_hBitmap) ::DeleteObject(m_hBitmap); m_hBitmap = NULL; m_ppvBits = NULL; memset(&m_DIBinfo, 0, sizeof(m_DIBinfo)); if (m_hDrawDib) DrawDibClose(m_hDrawDib); m_hDrawDib = NULL; m_iColorDataType = DIB_RGB_COLORS; m_iColorTableSize = 0; } ///////////////////////////////////////////////////////////////////////////// // CDIBSectionLite diagnostics #ifdef _DEBUG void CDIBSectionLite::AssertValid() const { ASSERT(m_hBitmap); DIBSECTION ds; DWORD dwSize = GetObject( m_hBitmap, sizeof(DIBSECTION), &ds ); ASSERT(dwSize == sizeof(DIBSECTION)); ASSERT(0 <= m_iColorTableSize && m_iColorTableSize <= 256); CObject::AssertValid(); } void CDIBSectionLite::Dump(CDumpContext& dc) const { CObject::Dump(dc); } #endif //_DEBUG // --- In : bDither - whether or not dithering should be enabled // --- Out : // --- Returns : TRUE on success // --- Effect : Turns dithering on by using the DrawDib functions instead of // the GDI functions BOOL CDIBSectionLite::SetDither(BOOL bDither) { BOOL bResult = TRUE; // Check for a no-change op. if ( (m_bDither == bDither) && ((m_hDrawDib && bDither) || (!m_hDrawDib && !bDither)) ) return bResult; if (m_hDrawDib != NULL) { DrawDibClose(m_hDrawDib); m_hDrawDib = NULL; } if (bDither) { if ( (m_hDrawDib = DrawDibOpen()) == NULL ) bResult = FALSE; } m_bDither = (m_hDrawDib != NULL); return bResult; } // --- In : // --- Out : // --- Returns : TRUE if dithering is used // --- Effect : Returns whether or not the DrawDib functions (and hence dithering) // is being used. BOOL CDIBSectionLite::GetDither() { return (m_bDither && (m_hDrawDib != NULL)); } ///////////////////////////////////////////////////////////////////////////// // CDIBSectionLite operations // --- In : pDC - Pointer to a device context // ptDest - point at which the topleft corner of the image is drawn // bForceBackground - Specifies whether the palette is forced to be // a background palette // --- Out : // --- Returns : TRUE on success // --- Effect : Draws the image 1:1 on the device context BOOL CDIBSectionLite::Draw(CDC* pDC, CPoint ptDest, BOOL bForceBackground /*=FALSE*/ ) { if (!m_hBitmap) return FALSE; CSize size = GetSize(); CPoint SrcOrigin = CPoint(0,0); BOOL bResult = FALSE; if (GetDither() && GetBitCount() >= 8) { DrawDibSetPalette( m_hDrawDib, (HPALETTE)m_Palette); DrawDibRealize( m_hDrawDib, pDC->GetSafeHdc(), bForceBackground); bResult = DrawDibDraw(m_hDrawDib, pDC->GetSafeHdc(), ptDest.x, ptDest.y, size.cx, size.cy, GetBitmapInfoHeader(), GetDIBits(), SrcOrigin.x, SrcOrigin.y, size.cx, size.cy, 0/*DDF_HALFTONE*/); } else { CPalette* pOldPalette = NULL; if (m_Palette.m_hObject && UsesPalette(pDC)) { pOldPalette = pDC->SelectPalette(&m_Palette, bForceBackground); pDC->RealizePalette(); } bResult = SetDIBitsToDevice(pDC->GetSafeHdc(), ptDest.x, ptDest.y, size.cx, size.cy, SrcOrigin.x, SrcOrigin.y, SrcOrigin.y, size.cy - SrcOrigin.y, GetDIBits(), GetBitmapInfo(), m_iColorDataType); if (pOldPalette) pDC->SelectPalette(pOldPalette, FALSE); } return bResult; } // --- In : pDC - Pointer to a device context // ptDest - point at which the topleft corner of the image is drawn // size - size to stretch the image // bForceBackground - Specifies whether the palette is forced to be // a background palette // --- Out : // --- Returns : TRUE on success // --- Effect : Stretch draws the image to the desired size on the device context BOOL CDIBSectionLite::Stretch(CDC* pDC, CPoint ptDest, CSize size, BOOL bForceBackground /*=FALSE*/) { if (!m_hBitmap) return FALSE; CSize imagesize = GetSize(); CPoint SrcOrigin = CPoint(0,0); BOOL bResult = FALSE; if (GetDither() && GetBitCount() >= 8) { DrawDibSetPalette( m_hDrawDib, (HPALETTE)m_Palette); DrawDibRealize( m_hDrawDib, pDC->GetSafeHdc(), bForceBackground); bResult = DrawDibDraw(m_hDrawDib, pDC->GetSafeHdc(), ptDest.x, ptDest.y, size.cx, size.cy, GetBitmapInfoHeader(), GetDIBits(), SrcOrigin.x, SrcOrigin.y, imagesize.cx, imagesize.cy, 0/*DDF_HALFTONE*/); } else { CPalette* pOldPalette = NULL; if (m_Palette.m_hObject && UsesPalette(pDC)) { pOldPalette = pDC->SelectPalette(&m_Palette, bForceBackground); pDC->RealizePalette(); } pDC->SetStretchBltMode(COLORONCOLOR); bResult = StretchDIBits(pDC->GetSafeHdc(), ptDest.x, ptDest.y, size.cx, size.cy, SrcOrigin.x, SrcOrigin.y, imagesize.cx, imagesize.cy, GetDIBits(), GetBitmapInfo(), m_iColorDataType, SRCCOPY); if (pOldPalette) pDC->SelectPalette(pOldPalette, FALSE); } return bResult; } ////////////////////////////////////////////////////////////////////////////// // Setting the bitmap... // --- In : nIDResource - resource ID // --- Out : // --- Returns : Returns TRUE on success, FALSE otherwise // --- Effect : Initialises the bitmap from a resource. If failure, then object is // initialised back to an empty bitmap. BOOL CDIBSectionLite::SetBitmap(UINT nIDResource) { return SetBitmap(MAKEINTRESOURCE(nIDResource)); } // --- In : lpszResourceName - resource name // --- Out : // --- Returns : Returns TRUE on success, FALSE otherwise // --- Effect : Initialises the bitmap from a resource. If failure, then object is // initialised back to an empty bitmap. BOOL CDIBSectionLite::SetBitmap(LPCTSTR lpszResourceName) { HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(), lpszResourceName, IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION); if (!hBmp) return FALSE; BOOL bResult = SetBitmap(hBmp); ::DeleteObject(hBmp); return bResult; } // --- In : lpBitmapInfo - pointer to a BITMAPINFO structure // lpBits - pointer to image bits // --- Out : // --- Returns : Returns TRUE on success, FALSE otherwise // --- Effect : Initialises the bitmap using the information in lpBitmapInfo to determine // the dimensions and colours, and the then sets the bits from the bits in // lpBits. If failure, then object is initialised back to an empty bitmap. BOOL CDIBSectionLite::SetBitmap(LPBITMAPINFO lpBitmapInfo, LPVOID lpBits) { DeleteObject(); if (!lpBitmapInfo || !lpBits) return FALSE; HDC hDC = NULL; try { BITMAPINFOHEADER& bmih = lpBitmapInfo->bmiHeader; // Compute the number of colours in the colour table m_iColorTableSize = NumColorEntries(bmih.biBitCount); DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof(RGBQUAD); // Copy over BITMAPINFO contents memcpy(&m_DIBinfo, lpBitmapInfo, dwBitmapInfoSize); // Should now have all the info we need to create the sucker. //TRACE(_T("Width %d, Height %d, Bits/pixel %d, Image Size %d\n"), // bmih.biWidth, bmih.biHeight, bmih.biBitCount, bmih.biSizeImage); // Create a DC which will be used to get DIB, then create DIBsection hDC = ::GetDC(NULL); if (!hDC) { TRACE0("Unable to get DC\n"); AfxThrowResourceException(); } m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*) m_DIBinfo, m_iColorDataType, &m_ppvBits, NULL, 0); ::ReleaseDC(NULL, hDC); if (!m_hBitmap) { TRACE0("CreateDIBSection failed\n"); AfxThrowResourceException(); } DWORD dwImageSize = m_DIBinfo.bmiHeader.biSizeImage; if (dwImageSize == 0) { int nBytesPerLine = BytesPerLine(lpBitmapInfo->bmiHeader.biWidth, lpBitmapInfo->bmiHeader.biBitCount); dwImageSize = nBytesPerLine * lpBitmapInfo->bmiHeader.biHeight; } // Flush the GDI batch queue GdiFlush(); memcpy(m_ppvBits, lpBits, dwImageSize); if (!CreatePalette()) { TRACE0("Unable to create palette\n"); AfxThrowResourceException(); } } catch (CException *e) { e->Delete(); _ShowLastError(); if (hDC) ::ReleaseDC(NULL, hDC); DeleteObject(); return FALSE; } return TRUE; } // --- In : hBitmap - handle to image // pPalette - optional palette to use when setting image // --- Out : // --- Returns : Returns TRUE on success, FALSE otherwise // --- Effect : Initialises the bitmap from the HBITMAP supplied. If failure, then // object is initialised back to an empty bitmap. BOOL CDIBSectionLite::SetBitmap(HBITMAP hBitmap, CPalette* pPalette /*= NULL*/) { DeleteObject(); if (!hBitmap) return FALSE; // Get dimensions of bitmap BITMAP bm; if (!::GetObject(hBitmap, sizeof(bm),(LPVOID)&bm)) return FALSE; bm.bmHeight = abs(bm.bmHeight); CWindowDC dc(NULL); CPalette* pOldPalette = NULL; try { m_iColorTableSize = NumColorEntries(bm.bmBitsPixel); // Initialize the BITMAPINFOHEADER in m_DIBinfo BITMAPINFOHEADER& bih = m_DIBinfo.bmiHeader; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = bm.bmWidth; bih.biHeight = bm.bmHeight; bih.biPlanes = 1; // Must always be 1 according to docs bih.biBitCount = bm.bmBitsPixel; bih.biCompression = BI_RGB; bih.biSizeImage = BytesPerLine(bm.bmWidth, bm.bmBitsPixel) * bm.bmHeight; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; // calls GetDIBits with NULL bits pointer to fill in the BITMAPINFOHEADER data if (!::GetDIBits(dc.m_hDC, hBitmap, 0, bm.bmHeight, NULL, m_DIBinfo, m_iColorDataType)) { TRACE0("Unable to GetDIBits\n"); AfxThrowResourceException(); } // If the driver did not fill in the biSizeImage field, then compute it // Each scan line of the image is aligned on a DWORD (32bit) boundary if (bih.biSizeImage == 0) bih.biSizeImage = BytesPerLine(bih.biWidth, bih.biBitCount) * bih.biHeight; if (pPalette) SetPalette(pPalette); else CreateHalftonePalette(m_Palette, m_iColorTableSize); if (m_Palette.GetSafeHandle()) { pOldPalette = dc.SelectPalette(&m_Palette, FALSE); dc.RealizePalette(); } // Create it! m_hBitmap = CreateDIBSection(dc.m_hDC, (const BITMAPINFO*) m_DIBinfo, m_iColorDataType, &m_ppvBits, NULL, 0); if (pOldPalette) dc.SelectPalette(pOldPalette, FALSE); pOldPalette = NULL; if (!m_hBitmap) { TRACE0("Unable to CreateDIBSection\n"); AfxThrowResourceException(); } // Need to copy the supplied bitmap onto the newly created DIBsection CDC memDC, CopyDC; if (!CopyDC.CreateCompatibleDC(&dc) || !memDC.CreateCompatibleDC(&dc)) { TRACE0("Unable to create compatible DC's\n"); AfxThrowResourceException(); } if (m_Palette.GetSafeHandle()) { memDC.SelectPalette(&m_Palette, FALSE); memDC.RealizePalette(); CopyDC.SelectPalette(&m_Palette, FALSE); CopyDC.RealizePalette(); } GdiFlush(); HBITMAP hOldMemBitmap = (HBITMAP) SelectObject(memDC.m_hDC, hBitmap); HBITMAP hOldCopyBitmap = (HBITMAP) SelectObject(CopyDC.m_hDC, m_hBitmap); CopyDC.BitBlt(0,0, bm.bmWidth, bm.bmHeight, &memDC, 0,0, SRCCOPY); SelectObject(memDC.m_hDC, hOldMemBitmap); SelectObject(CopyDC.m_hDC, hOldCopyBitmap); if (m_Palette.GetSafeHandle()) { memDC.SelectStockObject(DEFAULT_PALETTE); CopyDC.SelectStockObject(DEFAULT_PALETTE); } } catch (CException *e) { e->Delete(); _ShowLastError(); if (pOldPalette) dc.SelectPalette(pOldPalette, FALSE); DeleteObject(); return FALSE; } return TRUE; } ////////////////////////////////////////////////////////////////////////////// // Persistance... // --- In : lpszFileName - image filename // --- Out : // --- Returns : Returns TRUE on success, FALSE otherwise // --- Effect : Loads the bitmap from a bitmap file with the name lpszFileName. // If failure, then object is initialised back to an empty bitmap. BOOL CDIBSectionLite::Load(LPCTSTR lpszFileName) { CFile file; if (!file.Open(lpszFileName, CFile::modeRead)) return FALSE; // Get the current file position. DWORD dwFileStart = file.GetPosition(); // The first part of the file contains the file header. // This will tell us if it is a bitmap, how big the header is, and how big // the file is. The header size in the file header includes the color table. BITMAPFILEHEADER BmpFileHdr; int nBytes; nBytes = file.Read(&BmpFileHdr, sizeof(BmpFileHdr)); if (nBytes != sizeof(BmpFileHdr)) { TRACE0("Failed to read file header\n"); return FALSE; } // Check that we have the magic 'BM' at the start. if (BmpFileHdr.bfType != DS_BITMAP_FILEMARKER) { TRACE0("Not a bitmap file\n"); return FALSE; } // Read the header (assuming it's a DIB). DIBINFO BmpInfo; nBytes = file.Read(&BmpInfo, sizeof(BITMAPINFOHEADER)); if (nBytes != sizeof(BITMAPINFOHEADER)) { TRACE0("Failed to read BITMAPINFOHEADER\n"); return FALSE; } // Check that we have a real Windows DIB file. if (BmpInfo.bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) { TRACE0(" File is not a Windows DIB\n"); return FALSE; } // See how big the color table is in the file (if there is one). int nColors = NumColorEntries(BmpInfo.bmiHeader.biBitCount); if (nColors > 0) { // Read the color table from the file. int nColorTableSize = nColors * sizeof(RGBQUAD); nBytes = file.Read(BmpInfo.ColorTable(), nColorTableSize); if (nBytes != nColorTableSize) { TRACE0("Failed to read color table\n"); return FALSE; } } // So how big the bitmap surface is. int nBitsSize = BmpFileHdr.bfSize - BmpFileHdr.bfOffBits; // Allocate the memory for the bits and read the bits from the file. BYTE* pBits = (BYTE*) malloc(nBitsSize); if (!pBits) { TRACE0("Out of memory for DIB bits\n"); return FALSE; } // Seek to the bits in the file. file.Seek(dwFileStart + BmpFileHdr.bfOffBits, CFile::begin); // read the bits nBytes = file.Read(pBits, nBitsSize); if (nBytes != nBitsSize) { TRACE0("Failed to read bits\n"); free(pBits); return FALSE; } // Everything went OK. BmpInfo.bmiHeader.biSizeImage = nBitsSize; if (!SetBitmap((LPBITMAPINFO) BmpInfo, pBits)) { TRACE0("Failed to set bitmap info\n"); free(pBits); return FALSE; } free(pBits); return TRUE; } // --- In : lpszFileName - image filename // --- Out : // --- Returns : Returns TRUE on success, FALSE otherwise // --- Effect : Saves the image to file. BOOL CDIBSectionLite::Save(LPCTSTR lpszFileName) { BITMAPFILEHEADER hdr; LPBITMAPINFOHEADER lpbi = GetBitmapInfoHeader(); if (!lpbi || !lpszFileName) return FALSE; CFile file; if (!file.Open(lpszFileName, CFile::modeWrite|CFile::modeCreate)) return FALSE; DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof(RGBQUAD); DWORD dwFileHeaderSize = dwBitmapInfoSize + sizeof(hdr); // Fill in the fields of the file header hdr.bfType = DS_BITMAP_FILEMARKER; hdr.bfSize = dwFileHeaderSize + lpbi->biSizeImage; hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = dwFileHeaderSize; // Write the file header file.Write(&hdr, sizeof(hdr)); // Write the DIB header file.Write(lpbi, dwBitmapInfoSize); // Write DIB bits file.Write(GetDIBits(), lpbi->biSizeImage); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CDIBSectionLite palette stuff // --- In : // --- Out : // --- Returns : TRUE on success // --- Effect : Creates the palette from the DIBSection's color table. Assumes // m_iColorTableSize has been set and the DIBsection m_hBitmap created BOOL CDIBSectionLite::CreatePalette() { m_Palette.DeleteObject(); if (!m_hBitmap) return FALSE; // Create a 256 color halftone palette if there is no color table in the DIBSection if (m_iColorTableSize == 0) return CreateHalftonePalette(m_Palette, 256); HDC hDC = ::GetDC(NULL); if (!hDC) return FALSE; // Get space for the colour entries RGBQUAD *pRGB = new RGBQUAD[m_iColorTableSize]; if (!pRGB) { ReleaseDC(NULL, hDC); return CreateHalftonePalette(m_Palette, m_iColorTableSize); } // Create a memory DC compatible with the current DC CDC MemDC; MemDC.CreateCompatibleDC(CDC::FromHandle(hDC)); if (!MemDC.GetSafeHdc()) { delete [] pRGB; ::ReleaseDC(NULL, hDC); return CreateHalftonePalette(m_Palette, m_iColorTableSize); } ::ReleaseDC(NULL, hDC); HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(MemDC.GetSafeHdc(), m_hBitmap); if (!hOldBitmap) { delete [] pRGB; return CreateHalftonePalette(m_Palette, m_iColorTableSize); } // Get the colours used. int nColours = ::GetDIBColorTable(MemDC.GetSafeHdc(), 0, m_iColorTableSize, pRGB); // Clean up ::SelectObject(MemDC.GetSafeHdc(), hOldBitmap); if (!nColours) // No colours retrieved => the bitmap in the DC is not a DIB section { delete [] pRGB; return CreateHalftonePalette(m_Palette, m_iColorTableSize); } // Create and fill a LOGPALETTE structure with the colours used. PALETTEINFO PaletteInfo; PaletteInfo.palNumEntries = (WORD) m_iColorTableSize; for (int i = 0; i < nColours; i++) { PaletteInfo.palPalEntry[i].peRed = pRGB[i].rgbRed; PaletteInfo.palPalEntry[i].peGreen = pRGB[i].rgbGreen; PaletteInfo.palPalEntry[i].peBlue = pRGB[i].rgbBlue; PaletteInfo.palPalEntry[i].peFlags = 0; } for (; i < (int) m_iColorTableSize; i++) { PaletteInfo.palPalEntry[i].peRed = 0; PaletteInfo.palPalEntry[i].peGreen = 0; PaletteInfo.palPalEntry[i].peBlue = 0; PaletteInfo.palPalEntry[i].peFlags = 0; } delete [] pRGB; // Create Palette! return m_Palette.CreatePalette(&PaletteInfo); } // --- In : pPalette - new palette to use // --- Out : // --- Returns : TRUE on success // --- Effect : Sets the current palette used by the image from the supplied CPalette, // and sets the color table in the DIBSection BOOL CDIBSectionLite::SetPalette(CPalette* pPalette) { m_Palette.DeleteObject(); if (!pPalette) return FALSE; UINT nColours = pPalette->GetEntryCount(); if (nColours <= 0 || nColours > 256) return FALSE; // Get palette entries PALETTEINFO pi; pi.palNumEntries = (WORD) pPalette->GetPaletteEntries(0, nColours, (LPPALETTEENTRY) pi); // TODO: If pi.palNumEntries < m_iColorTableSize, then fill in blanks with 0's return SetLogPalette(&pi); } // --- In : pLogPalette - new palette to use // --- Out : // --- Returns : TRUE on success // --- Effect : Sets the current palette used by the image from the supplied LOGPALETTE BOOL CDIBSectionLite::SetLogPalette(LOGPALETTE* pLogPalette) { ASSERT(pLogPalette->palVersion == (WORD) 0x300); UINT nColours = pLogPalette->palNumEntries; if (nColours <= 0 || nColours > 256) { CreatePalette(); return FALSE; } // Create new palette m_Palette.DeleteObject(); if (!m_Palette.CreatePalette(pLogPalette)) { CreatePalette(); return FALSE; } if (m_iColorTableSize == 0) return TRUE; // Set the DIB colours RGBQUAD RGBquads[256]; for (UINT i = 0; i < nColours; i++) { RGBquads[i].rgbRed = pLogPalette->palPalEntry[i].peRed; RGBquads[i].rgbGreen = pLogPalette->palPalEntry[i].peGreen; RGBquads[i].rgbBlue = pLogPalette->palPalEntry[i].peBlue; RGBquads[i].rgbReserved = 0; } return FillDIBColorTable(nColours, RGBquads); } void CDIBSectionLite::CreateGradientBmp (COLORREF clrBack, COLORREF clrStart, COLORREF clrEnd, int iWidth, int iHeight, int iDirection) { RECT rectFill; // Rectangle for filling band float fStep; // How wide is each band? CBrush brush; // Brush to fill in the bar CBitmap ourNewBitmap; CWindowDC dc(NULL); CDC tempDC; CDC tempDC1; tempDC.CreateCompatibleDC(&dc); tempDC1.CreateCompatibleDC(&dc); ourNewBitmap.CreateDiscardableBitmap(&dc,iWidth,iHeight); //ourNewBitmap.CreateBitmap(iWidth,iHeight,3,32,NULL); CBitmap* pOldBitmap = tempDC.SelectObject(&ourNewBitmap); // First find out the largest color distance between the start and end colors. This distance // will determine how many steps we use to carve up the client region and the size of each // gradient rect. int r, g, b; // First distance, then starting value float rStep, gStep, bStep; // Step size for each color // Get the color differences r = (GetRValue(clrEnd) - GetRValue(clrStart)); g = (GetGValue(clrEnd) - GetGValue(clrStart)); b = (GetBValue(clrEnd) - GetBValue(clrStart)); // Make the number of steps equal to the greatest distance int nSteps = max(abs(r), max(abs(g), abs(b))); // Determine how large each band should be in order to cover the // client with nSteps bands (one for every color intensity level) if(iDirection == BMGRADIENT_DIRECTION_HORZ) fStep = (float)iWidth / (float)nSteps; else if(iDirection == BMGRADIENT_DIRECTION_VERT) fStep = (float)iHeight / (float)nSteps; // Calculate the step size for each color rStep = r/(float)nSteps; gStep = g/(float)nSteps; bStep = b/(float)nSteps; // Reset the colors to the starting position r = GetRValue(clrStart); g = GetGValue(clrStart); b = GetBValue(clrStart); // Start filling bands for (int iOnBand = 0; iOnBand < nSteps; iOnBand++) { // Set the rect we will fill with the gradient if(iDirection == BMGRADIENT_DIRECTION_HORZ) { ::SetRect(&rectFill, (int)(iOnBand * fStep), // Upper left X 0, // Upper left Y (int)((iOnBand+1) * fStep), // Lower right X iHeight+1); // Lower right Y } else if(iDirection == BMGRADIENT_DIRECTION_VERT) { ::SetRect(&rectFill, 0, // Upper left X (int)(iOnBand * fStep), // Upper left Y iWidth, // Lower right X (int)((iOnBand+1) * fStep)); // Lower right Y } // CDC::FillSolidRect is faster, but it does not handle 8-bit color depth VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand))); tempDC.FillRect(&rectFill,&brush); VERIFY(brush.DeleteObject()); // If we are past the maximum for the current position we need to get out of the loop. // Before we leave, we repaint the remainder of the client area with the background color. if(iDirection == BMGRADIENT_DIRECTION_HORZ) { if (rectFill.right > iWidth) { ::SetRect(&rectFill, rectFill.right, 0, iWidth, iHeight); VERIFY(brush.CreateSolidBrush(clrBack)); tempDC.FillRect(&rectFill, &brush); VERIFY(brush.DeleteObject()); return; } } else if(iDirection == BMGRADIENT_DIRECTION_VERT) { if (rectFill.right > iHeight) { ::SetRect(&rectFill, rectFill.right, 0, iWidth, iHeight); VERIFY(brush.CreateSolidBrush(clrBack)); tempDC.FillRect(&rectFill, &brush); VERIFY(brush.DeleteObject()); return; } } } // Create a 32 bit bitmap BITMAPINFO bih; // create DIB Section bih.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bih.bmiHeader.biWidth = iWidth; bih.bmiHeader.biHeight = iHeight; bih.bmiHeader.biPlanes = 1; bih.bmiHeader.biBitCount = 32; bih.bmiHeader.biCompression = BI_RGB; bih.bmiHeader.biSizeImage = 0; bih.bmiHeader.biXPelsPerMeter = 0; bih.bmiHeader.biYPelsPerMeter = 0; bih.bmiHeader.biClrUsed = 0; bih.bmiHeader.biClrImportant = 0; // 加入bTemp临时变量便于删除,以防止内存泄漏,jingzhou xu. DWORD* bTemp = new DWORD[iWidth*iHeight]; SetBitmap(&bih,bTemp); DWORD* pLine = (DWORD*)GetDIBits(); // 复制位到32位DIB图中,进行垂直映射复制(因为内存中位图为垂直反方向的),jingzhou xu. for(int i=0;i<iHeight;i++) { int nVFlip = iHeight-i-1; for(int j=0;j<iWidth;j++) { pLine[(nVFlip*iWidth)+j] = FixColorRef(tempDC.GetPixel(j,i)); } } delete bTemp; // Set the dc back to normal tempDC.SelectObject(pOldBitmap); } void CDIBSectionLite::Create32BitFromPicture (CPictureHolder* pPicture, int iWidth, int iHeight) { CBitmap ourNewSizedBMP; CWindowDC dc(NULL); CDC tempDC; CRect rcRender; tempDC.CreateCompatibleDC(&dc); ourNewSizedBMP.CreateDiscardableBitmap(&dc,iWidth,iHeight); // Now we need to select it into our temp DC so we can render the picture onto it CBitmap* pOldBitmap = tempDC.SelectObject(&ourNewSizedBMP); // Render the picture onto our bmp rcRender.SetRect(0,0,iWidth,iHeight); pPicture->Render(&tempDC,rcRender,rcRender); // Create a 32 bit bitmap BITMAPINFO bih; // create DIB Section bih.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bih.bmiHeader.biWidth = iWidth; bih.bmiHeader.biHeight = iHeight; bih.bmiHeader.biPlanes = 1; bih.bmiHeader.biBitCount = 32; bih.bmiHeader.biCompression = BI_RGB; bih.bmiHeader.biSizeImage = 0; bih.bmiHeader.biXPelsPerMeter = 0; bih.bmiHeader.biYPelsPerMeter = 0; bih.bmiHeader.biClrUsed = 0; bih.bmiHeader.biClrImportant = 0; // 加入bTemp临时变量便于删除,以防止内存泄漏,jingzhou xu. DWORD* bTemp = new DWORD[iWidth*iHeight]; SetBitmap(&bih,bTemp); DWORD* pLine = (DWORD*)GetDIBits(); // 复制位到32位DIB图中,进行垂直映射复制(因为内存中位图为垂直反方向的),jingzhou xu. for(int i=0;i<iHeight;i++) { int nVFlip = iHeight-i-1; for(int j=0;j<iWidth;j++) { pLine[(nVFlip*iWidth)+j] = FixColorRef(tempDC.GetPixel(j,i)); } } delete bTemp; // Set the dc back to normal tempDC.SelectObject(pOldBitmap); } inline COLORREF CDIBSectionLite::FixColorRef(COLORREF clr) { int r = GetRValue(clr); int g = GetGValue(clr); int b = GetBValue(clr); return RGB(b,g,r); } // --- In : nNumColours - number of colours to set // pRGB - colours to fill // --- Out : // --- Returns : Returns TRUE on success // --- Effect : Sets the colours used by the image. Only works if # colours <= 256 BOOL CDIBSectionLite::FillDIBColorTable(UINT nNumColours, RGBQUAD *pRGB) { if (!m_hBitmap || !pRGB || !nNumColours || !m_iColorTableSize || nNumColours > 256) return FALSE; // Create a memory DC compatible with the screen HDC hDC = ::GetDC(NULL); if (!hDC) return FALSE; CDC MemDC; MemDC.CreateCompatibleDC(CDC::FromHandle(hDC)); ::ReleaseDC(NULL, hDC); if (!MemDC.GetSafeHdc()) return FALSE; HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(MemDC.GetSafeHdc(), m_hBitmap); // Set the bitmap colours. int nColours = ::SetDIBColorTable(MemDC.GetSafeHdc(), 0, nNumColours, pRGB); // Clean up if (hOldBitmap) ::SelectObject(MemDC.GetSafeHdc(), hOldBitmap); MemDC.DeleteDC(); return (nColours > 0); } #ifdef _DEBUG // Makes trace windows a little bit more informative... void CDIBSectionLite::_ShowLastError() { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); TRACE1("Last error: %s\n", lpMsgBuf); LocalFree(lpMsgBuf); } #else void CDIBSectionLite::_ShowLastError() {} #endif