// ========================================================================== // Class Implementation : COXDIB // ========================================================================== // Source file : oxdib.cpp // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" // standard MFC include #include "oxdib.h" // class specification #include "limits.h" // For long -> int truncation #ifndef NO_DITHER #include "oxhlftne.h" // conversion tables and halftone palettefor 16 bit #endif // NO_DITHER #include #include #include "UTB64Bit.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[]=__FILE__; #endif #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B') #define SIZE_ERROR_BUF 255 IMPLEMENT_SERIAL(COXDIB, CObject, 1) #define new DEBUG_NEW ///////////////////////////////////////////////////////////////////////////// // Definition of static members // Data members ------------------------------------------------------------- // protected: // HDIB m_hDIB; // --- Handle(Global memory) to DIB (or NULL) when not connected to a DIB // CPalette* m_pPalette; // --- Pointer to the pallet belonging to the DIB (or NULL if none) // private: // Member functions --------------------------------------------------------- // public: COXDIB::COXDIB() : m_hDIB(NULL), m_pPalette(NULL) { ASSERT_VALID(this); } COXDIB::COXDIB(HDIB hDIB) : m_hDIB(NULL), m_pPalette(NULL) { // Copy the DIB memory and initialize the palette of the copy m_hDIB=CopyHandle (hDIB); if (m_hDIB != NULL) { LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); InitPalette(lpDIB); ::GlobalUnlock(m_hDIB); } ASSERT_VALID(this); } BOOL COXDIB::ClearSystemPalette() { //*** A dummy palette setup struct { WORD Version; WORD NumberOfEntries; PALETTEENTRY aEntries[256]; } Palette = { 0x300, 256 }; HPALETTE ScreenPalette=0; HDC ScreenDC; int Counter; UINT nMapped=0; BOOL bOK=FALSE; int nOK=0; // Reset everything in the system palette to black for(Counter=0; Counter < 256; Counter++) { Palette.aEntries[Counter].peRed=0; Palette.aEntries[Counter].peGreen=0; Palette.aEntries[Counter].peBlue=0; Palette.aEntries[Counter].peFlags=PC_NOCOLLAPSE; } // Create, select, realize, deselect, and delete the palette ScreenDC=::GetDC(NULL); ScreenPalette=::CreatePalette((LOGPALETTE*)&Palette); if (ScreenPalette) { ScreenPalette=::SelectPalette(ScreenDC, ScreenPalette, FALSE); nMapped=::RealizePalette(ScreenDC); ScreenPalette=::SelectPalette(ScreenDC, ScreenPalette, FALSE); bOK=::DeleteObject(ScreenPalette); } nOK=::ReleaseDC(NULL, ScreenDC); return bOK && (nOK==1); } BOOL COXDIB::GetSystemPalette(CPalette* pPalette) { ASSERT(pPalette != NULL); HDC hDC; // handle to a DC HANDLE hLogPal; // handle to a logical palette LPLOGPALETTE lpLogPal; // pointer to a logical palette // Find out how many palette entries we want. hDC=GetDC(NULL); if (hDC==NULL) return FALSE; // For non-palette devices, there's no palette available if ((::GetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE) != RC_PALETTE) { TRACE(_T("COXDIB::GetSystemPalette : No palette device\n")); return FALSE; } // Find out the number of palette entries on this device. int nColors=GetDeviceCaps(hDC, SIZEPALETTE); // Sometimes we'll use the # of system reserved // colors for our palette size. if (nColors==0) nColors=GetDeviceCaps(hDC, NUMCOLORS); ASSERT(nColors != 0); // Allocate room for the palette and lock it. hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * nColors); // if not enough memory, clean up and return NULL if (hLogPal==NULL) { TRACE(_T("COXDIB::GetSystemPalette : Not enough memory for logical palette\n")); ReleaseDC(NULL, hDC); return FALSE; } // get a pointer to the logical palette lpLogPal=(LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal); // set version and number of palette entries lpLogPal->palVersion=PALVERSION; lpLogPal->palNumEntries=(WORD)nColors; // Copy the current system palette into our logical palette ::GetSystemPaletteEntries(hDC, 0, nColors, (LPPALETTEENTRY)(lpLogPal->palPalEntry)); // Go ahead and create the palette. Once it's created, // we no longer need the LOGPALETTE, so free it. // -- create the palette and get handle to it BOOL bResult=pPalette->CreatePalette(lpLogPal); ::GlobalUnlock((HGLOBAL) hLogPal); ::GlobalFree((HGLOBAL) hLogPal); ReleaseDC(NULL, hDC); return bResult; } HPALETTE COXDIB::CreateDIBPalette(LPBITMAPINFO lpbmi,int& nNumColors) { LPBITMAPINFOHEADER lpbi=NULL; LPLOGPALETTE lpPal=NULL; HANDLE hLogPal=NULL; HPALETTE hPal=NULL; int i=0; // ... Initialize return variable nNumColors=0; lpbi=(LPBITMAPINFOHEADER)lpbmi; if(lpbi->biBitCount<=8) nNumColors=(1<biBitCount); else nNumColors=0; // No palette needed for 24 BPP DIB if(lpbi->biClrUsed>0) nNumColors=lpbi->biClrUsed; // Use biClrUsed if (nNumColors!=0) { hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE)+sizeof (PALETTEENTRY)*nNumColors); lpPal=(LPLOGPALETTE)::GlobalLock(hLogPal); lpPal->palVersion=(WORD)0x300; lpPal->palNumEntries=(WORD)nNumColors; for(i=0; ipalPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed; lpPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen; lpPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue; lpPal->palPalEntry[i].peFlags=0; } hPal=::CreatePalette(lpPal); ::GlobalUnlock(hLogPal); ::GlobalFree(hLogPal); } return hPal; } BOOL COXDIB::LoadResource(LPCTSTR lpszResourceName, HINSTANCE hInstance/*=NULL*/) { BOOL bResult=FALSE; HRSRC hRsrc=NULL; HGLOBAL hGlobal=NULL; HBITMAP hBitmapFinal=NULL; HPALETTE hPal=NULL; LPBITMAPINFOHEADER lpbi=NULL; HDC hdc=NULL; int iNumColors=0; CPalette palette; if(hInstance==NULL) hInstance=AfxFindResourceHandle(lpszResourceName,RT_BITMAP); if(hInstance!=NULL) hRsrc=::FindResource(hInstance,lpszResourceName,RT_BITMAP); if(hRsrc!=NULL) hGlobal=::LoadResource(hInstance,hRsrc); if(hGlobal!=NULL) { lpbi=(LPBITMAPINFOHEADER)::LockResource(hGlobal); if(lpbi!=NULL) { hdc=::GetDC(NULL); if(hdc!=NULL) { hPal=CreateDIBPalette((LPBITMAPINFO)lpbi,iNumColors); if((hPal==NULL)&&(::GetDeviceCaps(hdc,SIZEPALETTE)==256)) { // .... Trying to show bitmap without palette on // 256-color display so let's use halftone palette // (better than nothing) if(GetHalfTonePalette(&palette)) hPal=(HPALETTE)palette.Detach(); } if(hPal != NULL) { SelectPalette(hdc, hPal, FALSE); RealizePalette(hdc); } hBitmapFinal=::CreateDIBitmap(hdc,(LPBITMAPINFOHEADER)lpbi, (LONG)CBM_INIT, (LPSTR)lpbi+lpbi->biSize+iNumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpbi,DIB_RGB_COLORS); palette.Attach(hPal); bResult=(BitmapToDIB(hBitmapFinal,&palette)!=NULL); ::DeleteObject((HGDIOBJ)palette.Detach()); ::DeleteObject((HGDIOBJ)hPal); ::DeleteObject((HGDIOBJ)hBitmapFinal); ::DeleteObject((HGDIOBJ)hPal); ::ReleaseDC(NULL,hdc); } ::UnlockResource(hGlobal); } ::FreeResource(hGlobal); } return bResult; } HDIB WINAPI COXDIB::MakeCopy() { return CopyHandle(m_hDIB); } CBitmap* COXDIB::MakeBitmap(CDC* pDC, CSize& bmSize) { BITMAP bm; DWORD dwFore, dwBack; LPSTR lpDIB; // pointer to packed-DIB PDIB lpbmih; // pointer to a Win 3.0-style DIB LPBITMAPINFO lpbmi; // pointer to the bitmap info lpDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); // point to the header (whether Win 3.0 and old) lpbmi=(LPBITMAPINFO)lpDIB; lpbmih=(PDIB)lpDIB; // checks to see whether DIB buffer is properly loaded // ... Check for valid DIB handle if (m_hDIB==NULL) { TRACE(_T("COXDIB::MakeBitmap : DIB not loaded, nothing to copy to bitmap\n")); bmSize.cx=bmSize.cy=0; ::GlobalUnlock((HGLOBAL) m_hDIB); return NULL; } // checks to see wether DIB header is valid // ... Check for valid DIB header compression member (must be uncompressed=BI_RGB) if (lpbmi->bmiHeader.biCompression != BI_RGB || lpbmih->biCompression != BI_RGB) { TRACE(_T("COXDIB::MakeBitmap : DIB compressed, unable to handle bitmap\n")); ::GlobalUnlock((HGLOBAL) m_hDIB); return NULL; } // this code conditions the bitmap for mono or color int nPlanes=pDC->GetDeviceCaps(PLANES); int nBitsPixel=pDC->GetDeviceCaps(BITSPIXEL); CBitmap* pConfigBitmap=new CBitmap; char bits[100]; if (GetNumBitsPerPixel(lpDIB)==1) { pConfigBitmap->CreateBitmap(1, 1, 1, 1, bits); } else { pConfigBitmap->CreateBitmap(1, 1, nPlanes, nBitsPixel, bits); } CBitmap* pOriginalBitmap = (CBitmap*) pDC->SelectObject(pConfigBitmap); // CreateDIBitmap "switches bits" for mono bitmaps, depending on colors, // so we'll fool it if(GetMonoColors(dwFore,dwBack,lpDIB)) { SetMonoColors(0L,0xFFFFFFL,lpDIB); } // Get the DIB's palette, then select it into DC HPALETTE hPal=NULL; // Our DIB's palette HPALETTE hOldPal=NULL; // Previous palette if (m_pPalette != NULL) { hPal=(HPALETTE) m_pPalette->m_hObject; // ... Select as background since we have // already realized in forground if needed hOldPal=::SelectPalette(pDC->m_hDC, hPal, TRUE); pDC->RealizePalette(); } #ifdef WIN32 HBITMAP hBitmap=::CreateDIBitmap(pDC->GetSafeHdc(), lpbmih, CBM_INIT, (CONST BYTE*) FindDIBBits(lpDIB), lpbmi, DIB_RGB_COLORS); #else HBITMAP hBitmap=::CreateDIBitmap(pDC->GetSafeHdc(), lpbmih, CBM_INIT, FindDIBBits(lpDIB), lpbmi, DIB_RGB_COLORS); #endif // ... Reselect old palette if (hOldPal != NULL) { ::SelectPalette(pDC->m_hDC, hOldPal, TRUE); } if (hBitmap==NULL) { TRACE(_T("COXDIB::MakeBitmap: null bitmap\n")); delete pDC->SelectObject(pOriginalBitmap); // delete config bitmap ::GlobalUnlock((HGLOBAL) m_hDIB); return NULL; // untested error logic } if(GetNumBitsPerPixel(lpDIB)==1) { SetMonoColors(dwFore,dwBack,lpDIB); } // Can't use CBitmap::FromHandle here because we need to // delete the object later CBitmap* pBitmap=new CBitmap; pBitmap->Attach(hBitmap); pBitmap->GetObject(sizeof(bm), &bm); bmSize.cx=bm.bmWidth; bmSize.cy=bm.bmHeight; delete pDC->SelectObject(pBitmap); // delete configuration bitmap ::GlobalUnlock((HGLOBAL) m_hDIB); return pOriginalBitmap; } HDIB COXDIB::Detach() { HDIB hDIB=m_hDIB; m_hDIB=NULL; return hDIB; } BOOL COXDIB::IsEmpty() const { return (m_hDIB==NULL); } void COXDIB::Empty() { ASSERT_VALID(this); if (m_hDIB != NULL) { ::GlobalFree((HGLOBAL) m_hDIB); m_hDIB=NULL; delete m_pPalette; // May already be NULL m_pPalette=NULL; } ASSERT_VALID(this); } void COXDIB::SetMonoColors(DWORD dwForeground, DWORD dwBackground, LPSTR lpDIBHeader /*==NULL */) { BOOL bWasLockedBefore=TRUE; // ... Check for valid Info pointer if(lpDIBHeader==NULL) { lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB); if(lpDIBHeader==NULL) { TRACE(_T("COXDIB::SetMonoColors : fails with null pointer\n")); return; } bWasLockedBefore=FALSE; } ASSERT(GetNumBitsPerPixel(lpDIBHeader)==1); if(GetNumBitsPerPixel(lpDIBHeader)!=1) { if(!bWasLockedBefore) ::GlobalUnlock((HGLOBAL)lpDIBHeader); return; } LPBITMAPINFOHEADER lpbmih; // pointer to a Win 3.0-style DIB // point to the header (whether Win 3.0 and old) lpbmih=(LPBITMAPINFOHEADER)lpDIBHeader; #ifdef WIN32 ULONG* pPalette=(ULONG*)((LPSTR) lpbmih + sizeof(BITMAPINFOHEADER)); #else unsigned long far* pPalette= (unsigned long far*)((LPSTR) lpbmih + sizeof(BITMAPINFOHEADER)); #endif dwForeground=RGB(GetBValue(dwForeground),GetGValue(dwForeground), GetRValue(dwForeground)); dwBackground=RGB(GetBValue(dwBackground),GetGValue(dwBackground), GetRValue(dwBackground)); *pPalette=dwForeground; *(++pPalette)=dwBackground; if(!bWasLockedBefore) ::GlobalUnlock((HGLOBAL)lpDIBHeader); return; } /////////////////////////////////////////////////////////////////// BOOL COXDIB::GetMonoColors(DWORD& dwForeground, DWORD& dwBackground, LPSTR lpDIBHeader /*==NULL */) { BOOL bWasLockedBefore=TRUE; // ... Check for valid Info pointer if (lpDIBHeader==NULL) { lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB); if(lpDIBHeader==NULL) { TRACE(_T("COXDIB::GetMonoColors : fails with null pointer\n")); return FALSE; } bWasLockedBefore=FALSE; } if (GetNumBitsPerPixel(lpDIBHeader) != 1) { if(!bWasLockedBefore) ::GlobalUnlock((HGLOBAL)lpDIBHeader); return FALSE; } LPBITMAPINFOHEADER lpbmih; // pointer to a Win 3.0-style DIB // point to the header (whether Win 3.0 and old) lpbmih=(LPBITMAPINFOHEADER)lpDIBHeader; unsigned long far* pPalette=(unsigned long far*) ((LPSTR) lpbmih + sizeof(BITMAPINFOHEADER)); dwForeground=*pPalette; dwBackground=*(++pPalette); if(!bWasLockedBefore) ::GlobalUnlock((HGLOBAL)lpDIBHeader); return TRUE; } BOOL COXDIB::Paint(CDC* pDC, const CRect& rDCRect, const CRect& rDIBRect) { ASSERT_VALID(this); LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER LPSTR lpDIBBits; // Pointer to DIB bits BOOL bSuccess=FALSE; // Success/fail flag HPALETTE hPal=NULL; // Our DIB's palette HPALETTE hOldPal=NULL; // Previous palette // ... Check for valid DIB handle if (m_hDIB==NULL) { TRACE(_T("COXDIB::PaintDIB : DIB not loaded, nothing to paint\n")); return FALSE; } // Lock down the DIB, and get a pointer to the beginning of the bit buffer lpDIBHdr =(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); lpDIBBits=FindDIBBits(lpDIBHdr); // Get the DIB's palette, then select it into DC if (m_pPalette != NULL) { hPal=(HPALETTE) m_pPalette->m_hObject; // ... Select as background since we have // already realized in forground if needed hOldPal=::SelectPalette(pDC->m_hDC, hPal, FALSE); ::RealizePalette(pDC->m_hDC); } // ... Make sure to use the stretching mode best for color pictures ::SetStretchBltMode(pDC->m_hDC, COLORONCOLOR); // Determine whether to call Stretcm_hDIBits() or SetDIBitsToDevice() if ((rDCRect.Width()==rDIBRect.Width()) && (rDCRect.Height()==rDIBRect.Height()) && (pDC->GetMapMode()==MM_TEXT)) bSuccess=::SetDIBitsToDevice(pDC->m_hDC, // pDC->m_hDC rDCRect.left, // DestX rDCRect.top, // DestY rDCRect.Width(), // nDestWidth rDCRect.Height(), // nDestHeight rDIBRect.left, // SrcX (int)GetSize(lpDIBHdr).cy - rDIBRect.top - rDIBRect.Height(), // SrcY 0, // nStartScan (WORD)GetSize(lpDIBHdr).cy, // nNumScans lpDIBBits, // lpBits (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo DIB_RGB_COLORS); // wUsage else bSuccess=::StretchDIBits(pDC->m_hDC, // pDC->m_hDC rDCRect.left, // DestX rDCRect.top, // DestY rDCRect.Width(), // nDestWidth rDCRect.Height(), // nDestHeight rDIBRect.left, // SrcX rDIBRect.top, // SrcY rDIBRect.Width(), // wSrcWidth rDIBRect.Height(), // wSrcHeight lpDIBBits, // lpBits (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo DIB_RGB_COLORS, // wUsage SRCCOPY); // dwROP ::GlobalUnlock((HGLOBAL) m_hDIB); // ... Reselect old palette if (hOldPal != NULL) { ::SelectPalette(pDC->m_hDC, hOldPal, TRUE); } return bSuccess; } LPSTR COXDIB::FindDIBBits(LPSTR lpDIBHeader/*=NULL*/) { ASSERT_VALID(this); BOOL bWasLockedBefore=TRUE; // if handle to DIB is invalid, return NULL if (lpDIBHeader==NULL) { lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB); if(lpDIBHeader==NULL) { TRACE(_T("COXDIB::FindDIBBits: DIB not loaded, cannot find bits\n")); return NULL; } bWasLockedBefore=FALSE; } LPSTR lpResult; lpResult=(lpDIBHeader + *(LPDWORD)lpDIBHeader + GetPaletteSize(lpDIBHeader)); if(!bWasLockedBefore) ::GlobalUnlock((HGLOBAL)lpDIBHeader); return lpResult; } CSize COXDIB::GetSize(LPSTR lpbi/*=NULL*/) const { ASSERT_VALID(this); BOOL bOwnDIB=FALSE; // if handle to DIB is invalid, return (0,0) if (lpbi==NULL) { if (m_hDIB==NULL) { TRACE(_T("COXDIB::GetSize: DIB not loaded, returning (0,0)\n")); return CSize(0,0); } else { lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); bOwnDIB=TRUE; } } LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB CSize sResult; // point to the header (whether Win 3.0 and old) lpbmi=(LPBITMAPINFOHEADER)lpbi; lpbmc=(LPBITMAPCOREHEADER)lpbi; // return the DIB width if it is a Win 3.0 DIB if (IS_WIN30_DIB(lpbi)) { // Truncating long to int ASSERT(lpbmi->biWidth < INT_MAX); ASSERT(lpbmi->biHeight < INT_MAX); sResult=CSize((int)lpbmi->biWidth, (int)lpbmi->biHeight); } else // it is an other-style DIB, so return its width sResult=CSize(lpbmc->bcWidth, lpbmc->bcHeight); if (bOwnDIB) { ::GlobalUnlock((HGLOBAL) m_hDIB); } return sResult; } WORD COXDIB::GetPaletteSize(LPSTR lpDIBHeader/*=NULL*/) const { ASSERT_VALID(this); BOOL bWasLockedBefore=TRUE; // if handle to DIB is invalid, return 0 if (lpDIBHeader==NULL) { lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB); if(lpDIBHeader==NULL) { TRACE(_T("COXDIB::GetPaletteSize: DIB not loaded, returning 0\n")); return 0; } bWasLockedBefore=FALSE; } // calculate the size required by the palette BOOL bWin30; bWin30=(IS_WIN30_DIB (lpDIBHeader)); WORD nResult=0; if (bWin30) nResult=(WORD)(GetNumColors(lpDIBHeader) * sizeof(RGBQUAD)); else nResult=(WORD)(GetNumColors(lpDIBHeader) * sizeof(RGBTRIPLE)); if(!bWasLockedBefore) ::GlobalUnlock((HGLOBAL)lpDIBHeader); return nResult; } CPalette* COXDIB::GetPalette() const { ASSERT_VALID(this); return m_pPalette; } WORD COXDIB::GetNumBitsPerPixel(LPSTR lpbi) const { ASSERT_VALID(this); BOOL bOwnDIB=FALSE; // if handle to DIB is invalid, return 0 if (lpbi==NULL) { if (m_hDIB==NULL) { TRACE(_T("COXDIB::GetNumBitsPerPixel: DIB not loaded, returning 0\n")); return 0; } else { lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); bOwnDIB=TRUE; } } WORD wBitCount; // DIB bit count // Calculate the number of bits per pixel for the DIB. if (IS_WIN30_DIB(lpbi)) wBitCount=((LPBITMAPINFOHEADER)lpbi)->biBitCount; else wBitCount=((LPBITMAPCOREHEADER)lpbi)->bcBitCount; if (bOwnDIB) { ::GlobalUnlock((HGLOBAL) m_hDIB); } return wBitCount; } WORD COXDIB::GetNumColors(LPSTR lpbi) const { ASSERT_VALID(this); BOOL bOwnDIB=FALSE; // if handle to DIB is invalid, return 0 if (lpbi==NULL) { if (m_hDIB==NULL) { TRACE(_T("COXDIB::GetNumColors: DIB not loaded, returning 0\n")); return 0; } else { lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); bOwnDIB=TRUE; } } WORD wBitCount; // DIB bit count // If this is a Windows-style DIB, the number of colors in the // color table can be less than the number of bits per pixel // allows for (i.e. lpbi->biClrUsed can be set to some value). // If this is the case, return the appropriate value. if (IS_WIN30_DIB(lpbi)) { DWORD dwClrUsed; dwClrUsed=((LPBITMAPINFOHEADER)lpbi)->biClrUsed; if (dwClrUsed != 0) { if (bOwnDIB) { ::GlobalUnlock((HGLOBAL) m_hDIB); } return (WORD)dwClrUsed; } } // Calculate the number of colors in the color table based on // the number of bits per pixel for the DIB. if (IS_WIN30_DIB(lpbi)) wBitCount=((LPBITMAPINFOHEADER)lpbi)->biBitCount; else wBitCount=((LPBITMAPCOREHEADER)lpbi)->bcBitCount; if (bOwnDIB) { ::GlobalUnlock((HGLOBAL) m_hDIB); } // return number of colors based on bits per pixel switch (wBitCount) { case 1: return 2; case 4: return 16; case 8: return 256; default: return 0; } } COXDIB::COXDIB(const COXDIB& DIBSrc) : m_hDIB(NULL), m_pPalette(NULL) { ASSERT_VALID(this); ASSERT_VALID(&DIBSrc); TRACE(_T("COXDIB::COXDIB: Warning, copying bitmap\n")); // Copy DIB memory m_hDIB=CopyHandle(DIBSrc.m_hDIB); if(m_hDIB!=NULL) { LPSTR pDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); // Initialize the palette of the copy InitPalette(pDIB); ::GlobalUnlock(m_hDIB); } } COXDIB& COXDIB::operator=(const COXDIB& DIBSrc) { if(this==&DIBSrc) return *this; ASSERT_VALID(this); ASSERT_VALID(&DIBSrc); // Call COXDIB::operator=(HDIB hDIBSrc) to make a deep copy *this=DIBSrc.m_hDIB; // ... Make sure deep copy is made and succeeded // ... The handles must be different, except when they are both NULL ASSERT((m_hDIB != DIBSrc.m_hDIB) || ((m_hDIB==NULL) && (DIBSrc.m_hDIB==NULL))); ASSERT_VALID(this); return *this; } COXDIB& COXDIB::operator=(HDIB hDIBSrc) { ASSERT_VALID(this); if (hDIBSrc != NULL) { LPSTR pDIBSrc=(LPSTR)::GlobalLock((HGLOBAL)hDIBSrc); if (!IS_WIN30_DIB(pDIBSrc)) { TRACE(_T("COXDIB::operator=: DIB is an other-style DIB (copy not supported)\n")); ASSERT(FALSE); } else { // If this already contains a DIB, delete first Empty(); // Copy DIB memory m_hDIB=CopyHandle(hDIBSrc); if (m_hDIB != NULL) { LPSTR pDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); // Initialize the palette of the copy InitPalette(pDIB); ::GlobalUnlock(m_hDIB); } } ::GlobalUnlock(hDIBSrc); } ASSERT_VALID(this); return *this; } CBitmap* COXDIB::MakeBitmapFromDIB(CDC* pDC) { ASSERT_VALID(this); ASSERT_VALID(pDC); if (pDC==NULL) return NULL; BOOL bOwnDIB=FALSE; // if handle to DIB is invalid, return 0 LPSTR lpbi=NULL; // pointer to packed-DIB if (lpbi==NULL) { if (m_hDIB==NULL) { TRACE(_T("COXDIB::MakeBitmapFromDIB: DIB not loaded, returning 0\n")); return 0; } else { lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); bOwnDIB=TRUE; } } LPSTR lpDIBHdr, lpDIBBits; HBITMAP hBitmap; CPalette* pOldPal=NULL; // Lock down the DIB, and get a pointer to the beginning of the bit buffer lpDIBHdr =lpbi; lpDIBBits=FindDIBBits(lpDIBHdr); if (m_pPalette != NULL) { pOldPal=pDC->SelectPalette (m_pPalette, FALSE); pDC->RealizePalette(); } hBitmap=::CreateDIBitmap (pDC->GetSafeHdc(), (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, lpDIBBits, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS); if (hBitmap==NULL) { TRACE(_T("COXDIB::MakeBitmapFromDIB: null bitmap\n")); if (bOwnDIB) { ::GlobalUnlock((HGLOBAL) m_hDIB); } return NULL; // untested error logic } if (pOldPal != NULL) pDC->SelectPalette (pOldPal, FALSE); CBitmap* pBitmap=new CBitmap; pBitmap->Attach(hBitmap); if (bOwnDIB) { ::GlobalUnlock((HGLOBAL) m_hDIB); } return pBitmap; } BOOL COXDIB::SetPaletteUsage(CPalette* pPal, UINT wUsage) { PALETTEENTRY ape[256]; RGBQUAD FAR* pRgb; WORD FAR* pw; int nColors; int n; if (pPal==NULL) pPal=CPalette::FromHandle((HPALETTE)GetStockObject(DEFAULT_PALETTE)); if (m_hDIB==NULL) return FALSE; PDIB pdib=(PDIB)::GlobalLock((HGLOBAL)m_hDIB); nColors=DibNumColors(pdib); if (nColors==3 && DibCompression(pdib)==BI_BITFIELDS) nColors=0; if (nColors>0) { pRgb=DibColors(pdib); switch (wUsage) { // // Set the DIB color table to palette indexes // case DIB_PAL_COLORS: for (pw=(WORD FAR*)pRgb, n=0; n < nColors; n++, pw++) *pw=(WORD)n; break; // // Set the DIB color table to RGBQUADS // default: case DIB_RGB_COLORS: nColors=__min(nColors, 256); pPal->GetPaletteEntries(0, nColors, ape); for (n=0; n < nColors; n++) { pRgb[n].rgbRed =ape[n].peRed; pRgb[n].rgbGreen =ape[n].peGreen; pRgb[n].rgbBlue =ape[n].peBlue; pRgb[n].rgbReserved=0; } break; } } ::GlobalUnlock((HGLOBAL)m_hDIB); return TRUE; } BOOL COXDIB::CreateEmptyDIB(WORD wBitsPerPix, DWORD dwWidth, DWORD dwHeight) { PDIB lpbi; DWORD dwSizeImage; int i; DWORD FAR* pdw; dwSizeImage=dwHeight * WIDTHBYTES(dwWidth*wBitsPerPix); lpbi=(PDIB)GlobalAllocPtr(GHND, sizeof(BITMAPINFOHEADER) + dwSizeImage + 1024); if (lpbi==NULL) return NULL; InitBitmapInfoHeader(lpbi, dwWidth, dwHeight, wBitsPerPix); pdw=(DWORD FAR*)((LPBYTE)lpbi + (int)lpbi->biSize); for (i=0; i < (int)lpbi->biClrUsed / 16; i++) { *pdw++=0x00000000; // 0000 black *pdw++=0x00800000; // 0001 dark red *pdw++=0x00008000; // 0010 dark green *pdw++=0x00808000; // 0011 mustard *pdw++=0x00000080; // 0100 dark blue *pdw++=0x00800080; // 0101 purple *pdw++=0x00008080; // 0110 dark turquoise *pdw++=0x00C0C0C0; // 1000 gray *pdw++=0x00808080; // 0111 dark gray *pdw++=0x00FF0000; // 1001 red *pdw++=0x0000FF00; // 1010 green *pdw++=0x00FFFF00; // 1011 yellow *pdw++=0x000000FF; // 1100 blue *pdw++=0x00FF00FF; // 1101 pink (magenta) *pdw++=0x0000FFFF; // 1110 cyan *pdw++=0x00FFFFFF; // 1111 white } // Discard existing DIB and assign newly created Empty(); m_hDIB=(HDIB)GlobalPtrHandle(lpbi); GlobalUnlockPtr(lpbi); return TRUE; } BOOL COXDIB::ResizeDIB(DWORD dwWidth, DWORD dwHeight) { if (m_hDIB==NULL) return FALSE; PDIB pdibSource=(PDIB)::GlobalLock((HGLOBAL)m_hDIB); WORD wBitPixel= GetNumBitsPerPixel((LPSTR)pdibSource); int nBytePerPixel=wBitPixel / 8; if (nBytePerPixel <= 0) { TRACE(_T("In COXDIB::ResizeDIB: Resizing only supported for 24 and 8 bit DIB's\n")); ::GlobalUnlock((HGLOBAL)m_hDIB); return FALSE; } // Create a new empty destination memory block to hold the new resized DIB // needs the same number of bits per pixel as the source DIB // we're going to use some pointers to the DIB Bits, so lock down the memory block DWORD dwSizeImage=dwHeight * (DWORD)((dwWidth * wBitPixel / 8 + 3)& ~3); PDIB pDIBDest=(PDIB)GlobalAllocPtr(GHND, sizeof(BITMAPINFOHEADER) + dwSizeImage + 1024); if (pDIBDest==NULL) { TRACE(_T("COXDIB::ResizeDIB: Could not create an empty but allocated DIB\n")); ::GlobalUnlock((HGLOBAL)m_hDIB); return FALSE; } // The destination DIB must have the same bitmap info header + palette as the source DIB // so copy a (bitmap info + palette) memory block. DWORD_PTR dwInfoAndPal=(BYTE*)DibPtr(pdibSource) - (BYTE*)pdibSource; memcpy(pDIBDest, pdibSource, (size_t)dwInfoAndPal); // because its a resize adjust the old values (stored in the new memory // block by the memcpy) to the new size values pDIBDest->biWidth = dwWidth; pDIBDest->biHeight = dwHeight; pDIBDest->biSizeImage = dwSizeImage; // Assign and precalculate some values, to use in the formula // P=2 * (D - S) with D is destination and S is Source // When do we put a pixel extra or leave one out : (first version of formula) // accumulator += P // accumulator>S is the same as accumulator / S>1 // We spotted some rounding errors --> second formula // (accumulator + sign(accumulator)S) / 2 * S>1=divresult // then accumulator -= 2 * S * divresult; DWORD dwSourceWidth=DibWidth(pdibSource); DWORD dwSourceHeight=DibHeight(pdibSource); DWORD dwOffsetWidth=2 * (dwWidth - dwSourceWidth); DWORD dwOffsetHeight=2 * (dwHeight - dwSourceHeight); WORD* WidthCopyArray=new WORD[dwSourceWidth]; WORD* pWCpy=WidthCopyArray; int nTempTotal=0; int nAccumulator=0; int nDivResult=0; // Compute the transformation array for one scanline int Pixel; int nSourceWidth=(int)dwSourceWidth; int nDoubleSWidth=2 * nSourceWidth; for(Pixel=0; Pixel < nSourceWidth; Pixel++) { // Per new pixel the acc must be incremented nAccumulator += (int)dwOffsetWidth; // Do we need to write a pixel nDivResult=(nAccumulator + nSourceWidth * ((nAccumulator>0) ? 1 : -1)) / nDoubleSWidth; ASSERT(nDivResult >=-1); if (nDivResult != 0) // we needed to write or delete a pixel, so adjust the acc to account for that nAccumulator -= nDoubleSWidth * nDivResult; // write the number of pixels to write in the correct place in the array and // move the array pointer one place further *(pWCpy++)=(WORD)(nDivResult + 1); #ifdef _DEBUG nTempTotal += nDivResult + 1; #endif } #ifdef _DEBUG ASSERT(dwWidth==(DWORD)nTempTotal); #endif WORD* HeightCopyArray=new WORD[dwSourceHeight]; WORD* pHCpy=HeightCopyArray; // Compute the transformation array for the different scanlines (= height DIB) nTempTotal=0; nAccumulator=0; int Scanline; int nSourceHeight=(int)dwSourceHeight; int nDoubleSHeight=2 * nSourceHeight; for(Scanline=0; Scanline < nSourceHeight; Scanline++) { nAccumulator += (int)dwOffsetHeight; nDivResult=(nAccumulator + nSourceHeight * ((nAccumulator>0) ? 1 : -1)) / nDoubleSHeight; ASSERT(nDivResult >=-1); if (nDivResult != 0) nAccumulator -= nDoubleSHeight * nDivResult; *(pHCpy++)=(WORD)(nDivResult + 1); #ifdef _DEBUG nTempTotal += nDivResult + 1; #endif } ASSERT(dwHeight==(DWORD)nTempTotal); // Reset the transformation array pointers to their begin pHCpy=HeightCopyArray; pWCpy=WidthCopyArray; // Get pointers to begin of each bitmap BYTE _huge* pSourceScanline=(BYTE _huge*)DibXY(pdibSource, 0, 0); BYTE _huge* pWithinSourceScanline=pSourceScanline; BYTE _huge* pDestScanline=(BYTE _huge*)DibXY(pDIBDest, 0, 0); BYTE _huge* pWithinDestScanline=pDestScanline; // Step through, resizing each pixel in each scan line // to its required size int OldScanline=0; ULONG ul; while(OldScanline < nSourceHeight) { // If equal to 0, this scanline disappears, so skip and proceed with next one if (*pHCpy != 0) { DWORD nDup=0; int OldPixel=0; pWCpy=WidthCopyArray; // iterate the pixels on one scanline while(OldPixel < nSourceWidth) { nDup=*(pWCpy++); // if the pixel we're dealing with has to be copied several times while(nDup>0) { for(int j=0; j < nBytePerPixel; j++) *(pWithinDestScanline++)=*(pWithinSourceScanline + j); nDup--; } pWithinSourceScanline += nBytePerPixel; OldPixel++; } ASSERT((pWithinDestScanline - pDestScanline)==(LONG)dwWidth * nBytePerPixel); ul=(ULONG)(ULONG_PTR)pWithinDestScanline; ul +=3; ul >>=2; ul <<=2; pWithinDestScanline=(LPBYTE)ULongToPtr(ul); DWORD dwAlignedScanLineLength=PtrToLong(pWithinDestScanline - pDestScanline); nDup=1; while(nDup < *pHCpy) { memcpy(pWithinDestScanline, pDestScanline, (size_t)dwAlignedScanLineLength); pWithinDestScanline += dwAlignedScanLineLength; nDup++; } // align the source and destination pointers on DWORD boundaries ul=(ULONG)(ULONG_PTR)pWithinDestScanline; ul +=3; ul >>=2; ul <<=2; pWithinDestScanline=(LPBYTE)ULongToPtr(ul); pDestScanline=pWithinDestScanline; } else pWithinSourceScanline += nSourceWidth * nBytePerPixel; // align the source and destination pointers on DWORD boundaries ul=(ULONG)(ULONG_PTR)pWithinSourceScanline; ul +=3; ul >>=2; ul <<=2; pWithinSourceScanline=(LPBYTE)LongToPtr(ul); OldScanline++; pHCpy++; } delete[] WidthCopyArray; delete[] HeightCopyArray; ::GlobalUnlock((HGLOBAL)m_hDIB); GlobalUnlockPtr(pDIBDest); // Release the old source DIB handle // and assign the new DIB memory handle to this COXDIB object ::GlobalFree((HGLOBAL) m_hDIB); m_hDIB=(HDIB)GlobalPtrHandle(pDIBDest); return TRUE; } BOOL COXDIB::GetHalfTonePalette(CPalette* pPalette) { ASSERT(pPalette != NULL); BOOL bResult(FALSE); CDC* pDC=CWnd::GetDesktopWindow()->GetDC(); if (pDC==NULL) { TRACE(_T("COXDIB::GetHalfTonePalette: Could not allocate a DC for the desktopwindow\n")); return FALSE; } // Find out the number of palette entries on this device. int nColors=pDC->GetDeviceCaps(SIZEPALETTE); // For non-palette devices, we'll use the # of system // colors for our palette size. if (nColors==0) nColors=pDC->GetDeviceCaps(NUMCOLORS); if (nColors < 256) { CWnd::GetDesktopWindow()->ReleaseDC(pDC); return FALSE; } #ifdef WIN32 bResult=pPalette->CreateHalftonePalette(pDC); #else HANDLE hLogPal; // handle to a logical palette LPLOGPALETTE lpLogPal; // pointer to a logical palette // Allocate room for the palette and lock it. hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*256); // if not enough memory, clean up and return NULL if (hLogPal==NULL) { TRACE(_T("COXDIB::GetHalfTonePalette: Not enough memory for logical palette\n")); CWnd::GetDesktopWindow()->ReleaseDC(pDC); return FALSE; } // get a pointer to the logical palette lpLogPal=(LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal); // set version and number of palette entries lpLogPal->palVersion=PALVERSION; lpLogPal->palNumEntries=(WORD)256; // Copy the Halftone palette into our logical palette memcpy(lpLogPal->palPalEntry, aHalfTonePalette, sizeof(aHalfTonePalette)); // Go ahead and create the palette. Once it's created, // we no longer need the LOGPALETTE, so free it. // -- create the palette and get handle to it bResult=pPalette->CreatePalette(lpLogPal); ::GlobalUnlock((HGLOBAL) hLogPal); ::GlobalFree((HGLOBAL) hLogPal); #endif CWnd::GetDesktopWindow()->ReleaseDC(pDC); return bResult; } #ifndef NO_DITHER BOOL COXDIB::HalfToneDitherDIB() { if (m_hDIB==NULL) return FALSE; PDIB pdibSource=(PDIB)::GlobalLock((HGLOBAL)m_hDIB); // Only work on 24-bit sources if(GetNumBitsPerPixel((LPSTR)pdibSource) < 24) { TRACE(_T("COXDIB::SetHalfTone: Setting halftone only works for 24 bit images\n")); ::GlobalUnlock((HGLOBAL)m_hDIB); return FALSE; } CPalette* pHalfTonePal=new CPalette; if (!GetHalfTonePalette(pHalfTonePal)) { TRACE(_T("COXDIB::SetHalfTone: Could not create a halftone palette\n")); ::GlobalUnlock((HGLOBAL)m_hDIB); delete pHalfTonePal; return FALSE; } BOOL bWinGHalfTone=FALSE; // test whether the halftone palette is a WING halftone palette (Win95) or // a Win NT halftone palette PALETTEENTRY PaletteEntry; pHalfTonePal->GetPaletteEntries(1, 1, &PaletteEntry); if (NT_REF != RGB(PaletteEntry.peRed, PaletteEntry.peGreen, PaletteEntry.peBlue)) bWinGHalfTone=TRUE; //Create an 8-bit DIB to halftone to COXDIB* pHalfToneDIB=new COXDIB; if (!pHalfToneDIB->CreateEmptyDIB(8, DibWidth(pdibSource), DibHeight(pdibSource))) { TRACE(_T("In COXDIB::SetHalfTone(): Could not create an empty but allocated DIB\n")); ::GlobalUnlock((HGLOBAL)m_hDIB); delete pHalfToneDIB; delete pHalfTonePal; return FALSE; } int Scanline; // Fill in the DIB color table with the halftone palette pHalfToneDIB->SetPaletteUsage(pHalfTonePal, DIB_RGB_COLORS); PDIB pDIBDest=(PDIB)::GlobalLock((HGLOBAL)(pHalfToneDIB->m_hDIB)); // Step through, converting each pixel in each scan line // to the nearest halftone match for(Scanline=0; Scanline < (int)DibHeight(pdibSource); Scanline++) { BYTE _huge* pSourceScanline=(BYTE _huge*)DibXY(pdibSource, 0, Scanline); BYTE _huge* pDestScanline=(BYTE _huge*)DibXY(pDIBDest, 0, Scanline); int Pixel; for(Pixel=0; Pixel < (int)DibWidth(pdibSource); Pixel++) { // This is the meat of the halftoning algorithm: // Convert an RGB into an index into the halftone palette. // First, extract the raw RGB information int Red=pSourceScanline[Pixel * 3 + 2]; int Green=pSourceScanline[Pixel * 3 + 1]; int Blue=pSourceScanline[Pixel * 3]; // Now, look up each value in the halftone matrix // using an 8x8 ordered dither. BYTE RedTemp=(BYTE)(aDividedBy51[Red] + (aModulo51[Red]>aHalftone8x8[(Pixel%8)* 8 + Scanline%8])); BYTE GreenTemp=(BYTE)(aDividedBy51[(BYTE)Green] + (aModulo51[Green]>aHalftone8x8[(Pixel%8)*8 + Scanline%8])); BYTE BlueTemp=(BYTE)(aDividedBy51[(BYTE)Blue] + (aModulo51[Blue]>aHalftone8x8[(Pixel%8)*8 + Scanline%8])); // Recombine the halftoned RGB values into a palette index BYTE PaletteIndex=(BYTE)(RedTemp + aTimes6[GreenTemp] + aTimes36[BlueTemp]); if (!bWinGHalfTone) pDestScanline[Pixel]=PaletteIndex; else // And translate through the WinG Halftone Palette // translation vector to give the correct value. pDestScanline[Pixel]=aWinGHalftoneTranslation[PaletteIndex]; } } ::GlobalUnlock((HGLOBAL)m_hDIB); ::GlobalUnlock((HGLOBAL)(pHalfToneDIB->m_hDIB)); Empty(); m_hDIB=pHalfToneDIB->m_hDIB; m_pPalette=pHalfTonePal; // Clean up temporary DIB. First reset his HDIB handle, because we already assigned it to // this COXDib object, otherwise the destructor would free and destroy it. pHalfToneDIB->m_hDIB=NULL; delete pHalfToneDIB; return TRUE; } #endif // NO_DITHER void COXDIB::InitBitmapInfoHeader (PDIB lpBmInfoHdr, DWORD dwWidth, DWORD dwHeight, WORD nBPP) { #ifdef WIN32 memset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER)); #else _fmemset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER)); #endif lpBmInfoHdr->biSize = sizeof (BITMAPINFOHEADER); lpBmInfoHdr->biWidth = dwWidth; lpBmInfoHdr->biHeight = dwHeight; lpBmInfoHdr->biPlanes = 1; lpBmInfoHdr->biCompression =BI_RGB; if (nBPP <= 1) nBPP=1; else if (nBPP <= 4) { nBPP=4; lpBmInfoHdr->biClrUsed=16; } else if (nBPP <= 8) { nBPP=8; lpBmInfoHdr->biClrUsed=256; } else nBPP=24; lpBmInfoHdr->biBitCount =nBPP; lpBmInfoHdr->biSizeImage=WIDTHBYTES (dwWidth * nBPP) * dwHeight; } HDIB COXDIB::BitmapToDIB(HBITMAP hBitmap, CPalette* pPal /*=NULL */) { BITMAP Bitmap; BITMAPINFOHEADER bmInfoHdr; LPBITMAPINFOHEADER lpbmInfoHdr; LPSTR lpBits; HDC hMemDC; CDC* pDC=NULL; CPalette* pOldPal=NULL; // Do some setup -- make sure the Bitmap passed in is valid, // get info on the bitmap (like its height, width, etc.), // then setup a BITMAPINFOHEADER. if (!hBitmap) return NULL; if (!::GetObject (hBitmap, sizeof (Bitmap), (LPSTR) &Bitmap)) return NULL; InitBitmapInfoHeader(&bmInfoHdr, Bitmap.bmWidth, Bitmap.bmHeight, WORD(Bitmap.bmPlanes*Bitmap.bmBitsPixel)); // If DIB was already allocated, dealocate first Empty(); // Now allocate memory for the DIB. Then, set the BITMAPINFOHEADER // into this memory, and find out where the bitmap bits go. m_hDIB=(HDIB)::GlobalAlloc (GHND, sizeof (BITMAPINFOHEADER) + GetPaletteSize((LPSTR) &bmInfoHdr) + bmInfoHdr.biSizeImage); if (!m_hDIB) return NULL; lpbmInfoHdr=(LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) m_hDIB); *lpbmInfoHdr=bmInfoHdr; lpBits =FindDIBBits ((LPSTR) lpbmInfoHdr); // Now, we need a DC to hold our bitmap. If the app passed us // a palette, it should be selected into the DC. hMemDC=GetDC (NULL); pDC=CDC::FromHandle(hMemDC); if (pPal != NULL) { pOldPal=pDC->SelectPalette (pPal, FALSE); pDC->RealizePalette(); } // We're finally ready to get the DIB. Call the driver and let // it party on our bitmap. It will fill in the color table, // and bitmap bits of our global memory block. if (!::GetDIBits (hMemDC,hBitmap,0,Bitmap.bmHeight,lpBits, (LPBITMAPINFO) lpbmInfoHdr,DIB_RGB_COLORS)) { ::GlobalUnlock (m_hDIB); ::GlobalFree (m_hDIB); m_hDIB=NULL; } else ::GlobalUnlock (m_hDIB); // Finally, clean up and return. if (pOldPal != NULL) pDC->SelectPalette (pOldPal, FALSE); // Copy Palette if (pPal != NULL) { SetPaletteUsage(pPal, DIB_RGB_COLORS); LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); InitPalette(lpDIB); ::GlobalUnlock(m_hDIB); } ::ReleaseDC (NULL, hMemDC); return m_hDIB; } #ifdef _WIN32 HDIB COXDIB::IconToDIB(HICON hIcon, CSize sizeIcon, CPalette* pPal /*=NULL */) { // If DIB was already allocated, dealocate first Empty(); CDC SrcDC; VERIFY(SrcDC.CreateDC(_T("DISPLAY"),NULL,NULL,NULL)); CDC memDC; CBitmap bitmap; VERIFY(memDC.CreateCompatibleDC(&SrcDC)); VERIFY(bitmap.CreateCompatibleBitmap(&SrcDC,sizeIcon.cx,sizeIcon.cy)); CBitmap* pOldBitmap=memDC.SelectObject(&bitmap); VERIFY(::DrawIconEx( memDC.GetSafeHdc(),0,0,hIcon,sizeIcon.cx,sizeIcon.cy,0,NULL,DI_NORMAL)); memDC.SelectObject(pOldBitmap); SrcDC.DeleteDC(); memDC.DeleteDC(); return BitmapToDIB((HBITMAP)bitmap,pPal); } #endif BOOL COXDIB::Write(CArchive& ar) { ASSERT_VALID(this); BITMAPFILEHEADER bmfHdr; // Header for Bitmap file LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure DWORD dwDIBSize; if (m_hDIB==NULL) { TRACE(_T("COXDIB::Write: DIB not loaded, cannot save\n")); return FALSE; } // Get a pointer to the DIB memory, the first of which contains // a BITMAPINFO structure lpBI=(LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) m_hDIB); if (lpBI==NULL) { TRACE(_T("COXDIB::Write : Out of memory\n")); return FALSE; } if (!IS_WIN30_DIB(lpBI)) { ::GlobalUnlock((HGLOBAL) m_hDIB); TRACE(_T("COXDIB::Write : DIB is an other-style DIB (save not supported)\n")); return FALSE; } // Fill in the fields of the file header // Fill in file type (first 2 bytes must be "BM" for a bitmap) bmfHdr.bfType=DIB_HEADER_MARKER; // "BM" // Calculating the size of the DIB is a bit tricky (if we want to // do it right). The easiest way to do this is to call GlobalSize() // on our global handle, but since the size of our global memory may have // been padded a few bytes, we may end up writing out a few too // many bytes to the file (which may cause problems with some apps). // // So, instead let's calculate the size manually (if we can) // // First, find size of header plus size of color table. Since the // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains // the size of the structure, let's use this. dwDIBSize=*(LPDWORD)lpBI + GetPaletteSize((LPSTR)lpBI); // Partial Calculation // Now calculate the size of the image if ((lpBI->biCompression==BI_RLE8) || (lpBI->biCompression==BI_RLE4)) { // It's an RLE bitmap, we can't calculate size, so trust the // biSizeImage field dwDIBSize += lpBI->biSizeImage; } else { DWORD dwBmBitsSize; // Size of Bitmap Bits only // It's not RLE, so size is Width (DWORD aligned) * Height dwBmBitsSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight; dwDIBSize += dwBmBitsSize; // Now, since we have calculated the correct size, why don't we // fill in the biSizeImage field (this will fix any .BMP files which // have this field incorrect). lpBI->biSizeImage=dwBmBitsSize; } // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER) bmfHdr.bfSize=dwDIBSize + sizeof(BITMAPFILEHEADER); bmfHdr.bfReserved1=0; bmfHdr.bfReserved2=0; // Now, calculate the offset the actual bitmap bits will be in // the file -- It's the Bitmap file header plus the DIB header, // plus the size of the color table. bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize + GetPaletteSize((LPSTR)lpBI); TRY { // Write the file header ar.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER)); // // Write the DIB header and the bits // WriteHuge(ar, lpBI, dwDIBSize); } CATCH (CFileException, e) { ::GlobalUnlock((HGLOBAL) m_hDIB); THROW_LAST(); } END_CATCH ::GlobalUnlock((HGLOBAL) m_hDIB); return TRUE; } BOOL COXDIB::Write(LPCTSTR pszPath) { CFile file; CFileException fe; if(!file.Open(pszPath, CFile::modeCreate|CFile::modeReadWrite|CFile::shareExclusive,&fe)) { TRACE1("COXDIB::Write : Could not open DIB file : %s\n", pszPath); return FALSE; } if (!Write(&file)) { file.Abort(); // will not throw an exception TRACE1("COXDIB::Write : Error writing file : %s\n", pszPath); return FALSE; } return TRUE; } BOOL COXDIB::Write(CFile* pDIBFile, BOOL bCloseFile/*=TRUE*/) { BOOL bSuccess=FALSE; TRY { CArchive ar(pDIBFile, CArchive::store); bSuccess=Write(ar); ar.Close(); if(bCloseFile) pDIBFile->Close(); } CATCH (CException, eSave) { TRACE(_T("COXDIB::Write : Catching file exception while writing file\n")); return FALSE; } END_CATCH return bSuccess; } // save as JPEG file #ifdef OXDIB_SUPPORTJPEG BOOL COXDIB::WriteJPEG(LPCTSTR pszPath) { DWORD LastError=0; if(IsEmpty()) return FALSE; BOOL bSuccess=FALSE; // mem file for conversion purpose CMemFile tmpBMPFile; CArchive ar(&tmpBMPFile,CArchive::store); bSuccess=Write(ar); ar.Close(); if(!bSuccess) return FALSE; // go to the beginning of the file tmpBMPFile.SeekToBegin(); // create bitmap file COXBMPFile bmpFile(&tmpBMPFile); // create empty JPEG file COXJPEGFile jpgFile(pszPath); LastError=GetLastError(); if(!ConvertDIBtoJPEG(&bmpFile,&jpgFile)) return FALSE; SetLastError(LastError); return TRUE; } BOOL COXDIB::WriteJPEG(CFile* pFile) { ASSERT(pFile!=NULL); DWORD LastError=0; if(IsEmpty()) return FALSE; BOOL bSuccess=FALSE; // mem file for conversion purpose CMemFile tmpBMPFile; CArchive ar(&tmpBMPFile,CArchive::store); bSuccess=Write(ar); ar.Close(); if(!bSuccess) return FALSE; // go to the beginning of the file tmpBMPFile.SeekToBegin(); // create bitmap file COXBMPFile bmpFile(&tmpBMPFile); // create empty JPEG file COXJPEGFile jpgFile(pFile); LastError=GetLastError(); if(!ConvertDIBtoJPEG(&bmpFile,&jpgFile)) return FALSE; SetLastError(LastError); return TRUE; } #endif PDIB COXDIB::ReadBitmapInfo(CArchive& ar) { BITMAPFILEHEADER bmfHeader; PDIB pdibInfo=NULL; // Go read the DIB file header and check if it's valid. if ((ar.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader)) || (bmfHeader.bfType != DIB_HEADER_MARKER)) { TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap header\n")); return NULL; } // Go read the size of the struct that follows the bitmapfileheader DWORD dwSize; if (ar.Read(&dwSize, sizeof(dwSize)) != sizeof(dwSize)) { TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap size\n")); return NULL; } // what type of bitmap info is this? BITMAPCOREHEADER bmCoreHdr; BITMAPINFOHEADER bminfo; switch (dwSize) { default: case sizeof(BITMAPINFOHEADER): { // Go read the DIB bitmap info header BYTE* pByte=(BYTE*)&bminfo; // allready read the size so skip it pByte=pByte + sizeof(DWORD); if (ar.Read(pByte, sizeof(bminfo) - sizeof(DWORD)) != (sizeof(bminfo) - sizeof(DWORD))) { TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap info\n")); return NULL; } bminfo.biSize=dwSize; } break; case sizeof(BITMAPCOREHEADER): { // Go read the DIB bitmap info header BYTE* pByte=(BYTE*)&bmCoreHdr; // allready read the size so skip it pByte=pByte + sizeof(DWORD); if (ar.Read(pByte, sizeof(bmCoreHdr) - sizeof(DWORD)) != (sizeof(bmCoreHdr)-sizeof(DWORD))) { TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap core header\n")); return NULL; } bminfo.biSize =sizeof(BITMAPINFOHEADER); bminfo.biWidth =(DWORD)bmCoreHdr.bcWidth; bminfo.biHeight =(DWORD)bmCoreHdr.bcHeight; bminfo.biPlanes = (WORD)bmCoreHdr.bcPlanes; bminfo.biBitCount = (WORD)bmCoreHdr.bcBitCount; bminfo.biCompression =BI_RGB; bminfo.biSizeImage =0; bminfo.biXPelsPerMeter =0; bminfo.biYPelsPerMeter =0; bminfo.biClrUsed =0; bminfo.biClrImportant =0; } break; } int nNumColors=DibNumColors(&bminfo); FixBitmapInfo(&bminfo); pdibInfo=(PDIB)GlobalAllocPtr(GMEM_MOVEABLE,(LONG)bminfo.biSize + nNumColors * sizeof(RGBQUAD)); if (pdibInfo==NULL) return NULL; // assign contents of bitmap info to dibinfo *pdibInfo=bminfo; RGBQUAD FAR* pRgb; pRgb=DibColors(pdibInfo); if (nNumColors != 0) { if (dwSize==sizeof(BITMAPCOREHEADER)) { /* * convert a old color table (3 byte entries) to a new * color table (4 byte entries) */ if (ar.Read((LPVOID)pRgb, nNumColors * sizeof(RGBTRIPLE)) != (nNumColors * sizeof(RGBTRIPLE))) { TRACE(_T("COXDIB::ReadBitmapInfo : Invalid RGB color table\n")); GlobalFreePtr(pdibInfo); return NULL; } for (int i=nNumColors - 1; i >= 0; i--) { RGBQUAD rgb; rgb.rgbRed =((RGBTRIPLE FAR*)pRgb)[i].rgbtRed; rgb.rgbBlue =((RGBTRIPLE FAR*)pRgb)[i].rgbtBlue; rgb.rgbGreen =((RGBTRIPLE FAR*)pRgb)[i].rgbtGreen; rgb.rgbReserved=(BYTE)0; pRgb[i]=rgb; } } else { if (ar.Read((LPVOID)pRgb, nNumColors * sizeof(RGBQUAD)) != (nNumColors * sizeof(RGBQUAD))) { TRACE(_T("COXDIB::ReadBitmapInfo : Invalid RGB color table\n")); GlobalFreePtr(pdibInfo); return NULL; } } } if (bmfHeader.bfOffBits != 0L) { TRACE(_T("COXDIB::ReadBitmapInfo : BMP with offset bits\n")); } return pdibInfo; } BOOL COXDIB::Read(CArchive& ar) { // If DIB was already allocated, dealocate first Empty(); PDIB pdib=ReadBitmapInfo(ar); if (pdib==NULL) { TRACE(_T("COXDIB::Read : Could not read bitmap info\n")); return FALSE; } // How much memory do we need to hold the DIB DWORD dwBits=pdib->biSizeImage; DWORD dwLen =pdib->biSize + DibPaletteSize(pdib) + dwBits; // Can we get more memory? LPVOID pGlobal=GlobalReAllocPtr(pdib, dwLen, 0); if (pGlobal==NULL) { GlobalFreePtr(pdib); pdib=NULL; } else { pdib=(PDIB)pGlobal; m_hDIB=(HDIB)GlobalPtrHandle(pdib); } if (pdib != NULL) { // Go read the bits. if (ReadHuge(ar, (LPBYTE)pdib + (UINT)pdib->biSize + DibPaletteSize(pdib), dwBits) != dwBits) { GlobalFreePtr(pdib); m_hDIB=NULL; TRACE(_T("COXDIB::Read : Invalid bitmap size\n")); return FALSE; } // Initialize the palette if (!InitPalette((LPSTR)pdib)) return FALSE; GlobalUnlockPtr(pdib); } else { TRACE(_T("COXDIB::Read : Invalid bitmap memory block\n")); Empty(); return FALSE; } ASSERT_VALID(this); return TRUE; } BOOL COXDIB::Read(LPCTSTR pszPath) { CFile file; CFileException fe; if(!file.Open(pszPath,CFile::modeRead|CFile::shareDenyWrite,&fe)) { TRACE1("COXDIB::Read : Could not open DIB file : %s\n", pszPath); return FALSE; } if(!Read(&file)) { file.Abort(); // will not throw an exception TRACE1("COXDIB::Read : Error reading file : %s\n", pszPath); return FALSE; } return TRUE; } BOOL COXDIB::Read(CFile* pDIBFile) { // replace calls to Serialize with Read function BOOL bSuccess=FALSE; TRY { CArchive ar(pDIBFile, CArchive::load); bSuccess=Read(ar); ar.Close(); } CATCH (CFileException, eLoad) { TRACE(_T("COXDIB::Read : Catching file exception while reading file\n")); return FALSE; } END_CATCH return bSuccess; } // load JPEG file #ifdef OXDIB_SUPPORTJPEG BOOL COXDIB::ReadJPEG(LPCTSTR pszPath) { // mem file for conversion purpose CMemFile tmpBMPFile; // create bitmap file COXBMPFile bmpFile(&tmpBMPFile); // create JPEG file object COXJPEGFile jpgFile(pszPath); if(!ConvertJPEGtoDIB(&jpgFile,&bmpFile)) return FALSE; tmpBMPFile.SeekToBegin(); return Read(&tmpBMPFile); } BOOL COXDIB::ReadJPEG(CFile* pFile) { ASSERT(pFile!=NULL); // mem file for conversion purpose CMemFile tmpBMPFile; // create bitmap file COXBMPFile bmpFile(&tmpBMPFile); // create JPEG file object COXJPEGFile jpgFile(pFile); if(!ConvertJPEGtoDIB(&jpgFile,&bmpFile)) return FALSE; tmpBMPFile.SeekToBegin(); return Read(&tmpBMPFile); } #endif // #ifdef OXDIB_SUPPORTJPEG void COXDIB::Serialize(CArchive& ar) { if (ar.IsStoring()) Write(ar); else Read(ar); } // static functions for JPEG/DIB conversions #ifdef OXDIB_SUPPORTJPEG BOOL COXDIB::ConvertDIBtoJPEG(LPCTSTR pszDIBPath, LPCTSTR pszJPEGPath) { COXDIB dib; if(!dib.Read(pszDIBPath)) return FALSE; if(dib.IsEmpty()) return FALSE; return dib.WriteJPEG(pszJPEGPath); } BOOL COXDIB::ConvertDIBtoJPEG(COXBMPFile* pDIBFile, COXJPEGFile* pJPEGFile) { ASSERT(pDIBFile!=NULL); ASSERT(pJPEGFile!=NULL); // object responsible for conversion COXJPEGCompressor JCompr; short nReturn(1); TCHAR ErrorBuffer[SIZE_ERROR_BUF]; TRY { // the only line of code we need to convert bitmap to JPEG nReturn=JCompr.DoCompress(pDIBFile,pJPEGFile); if(nReturn==2) { TRACE(JCompr.GetWarningMessages()); } } CATCH(COXJPEGException, e) { // if something went wrong then notify about it e->GetErrorMessage(ErrorBuffer, SIZE_ERROR_BUF); CString sErrorMessage=_T("COXDIB::ConvertDIBtoJPEG: Exception "); sErrorMessage+=ErrorBuffer; TRACE(sErrorMessage); } END_CATCH return (nReturn==0); } BOOL COXDIB::ConvertJPEGtoDIB(LPCTSTR pszJPEGPath, LPCTSTR pszDIBPath) { COXDIB dib; if(!dib.ReadJPEG(pszJPEGPath)) return FALSE; if(dib.IsEmpty()) return FALSE; return dib.Write(pszDIBPath); } BOOL COXDIB::ConvertJPEGtoDIB(COXJPEGFile* pJPEGFile, COXBMPFile* pDIBFile) { ASSERT(pJPEGFile!=NULL); ASSERT(pDIBFile!=NULL); // object responsible for conversion COXJPEGDecompressor JDecompr; short nReturn(1); TCHAR ErrorBuffer[SIZE_ERROR_BUF]; TRY { // the only line of code that we need to decompress JPEG to bitmap file nReturn=JDecompr.DoDecompress(pJPEGFile,pDIBFile); if(nReturn==2) { TRACE(JDecompr.GetWarningMessages()); } } CATCH(COXJPEGException, e) { // if something went wrong then notify about it e->GetErrorMessage(ErrorBuffer, SIZE_ERROR_BUF); CString sErrorMessage=_T("COXDIB::ConvertJPEGtoDIB: Exception "); sErrorMessage+=ErrorBuffer; TRACE(sErrorMessage); } END_CATCH if(nReturn!=0) return FALSE; return TRUE; } #endif BOOL COXDIB::Rotate(int nAngleDegree, BOOL bFlipHorz/*=FALSE*/, BOOL bFlipVert/*=FALSE*/) { if((nAngleDegree%90)!=0) { TRACE(_T("COXDIB::Rotate: support only 90 degrees rotation step\n")); return FALSE; } if(nAngleDegree<0) { nAngleDegree+=(nAngleDegree/360)*360; nAngleDegree=360-nAngleDegree; } else nAngleDegree-=(nAngleDegree/360)*360; if(IsEmpty()) return FALSE; if(nAngleDegree==0 && !bFlipVert && !bFlipHorz) return TRUE; COXDIB dibCopy=*this; Empty(); LPSTR lpDIBSrc=(LPSTR)::GlobalLock((HGLOBAL)dibCopy.m_hDIB); int nWidthSrc=dibCopy.GetSize().cx; int nHeightSrc=dibCopy.GetSize().cy; WORD nBitsPerPixel=dibCopy.GetNumBitsPerPixel(lpDIBSrc); // calculate resulting size of image int nWidthDest=((nAngleDegree%180)==0 ? nWidthSrc : nHeightSrc); int nHeightDest=((nAngleDegree%180)==0 ? nHeightSrc : nWidthSrc); // recreate DIB if(!CreateEmptyDIB(nBitsPerPixel,nWidthDest,nHeightDest)) { ::GlobalUnlock((HGLOBAL)dibCopy.m_hDIB); *this=dibCopy; TRACE(_T("COXDIB::Rotate: failed to create empty DIB\n")); return FALSE; } LPSTR lpDIBDest=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB); // copy image and rotate pixels // LPSTR lpDIBBitsSrc=dibCopy.FindDIBBits(lpDIBSrc); LPSTR lpDIBBitsDest=FindDIBBits(lpDIBDest); int nWidthBytesSrc=WIDTHBYTES(nWidthSrc*(DWORD)nBitsPerPixel); int nWidthBytesDest=WIDTHBYTES(nWidthDest*(DWORD)nBitsPerPixel); // mask for monochrome DIB BYTE BitMask=0x80; // masks for 16-color DIB BYTE LoMask=0x0F; BYTE HiMask=0xF0; // copy color table for non true-color images if(nBitsPerPixel<=8) { // Copy source DIB's color table to destination DIB RGBQUAD* lpSrcColor=(RGBQUAD*)(lpDIBSrc+(sizeof(BITMAPINFOHEADER))); RGBQUAD* lpDestColor=(RGBQUAD*)(lpDIBDest+(sizeof(BITMAPINFOHEADER))); WORD wNumColors=dibCopy.GetNumColors(lpDIBSrc); for(int nIndex=0; nIndex<(int)wNumColors; nIndex++) *lpDestColor++=*lpSrcColor++; // Initialize the palette of the copy InitPalette(lpDIBSrc); } int nBytesPerPixel=(nBitsPerPixel>=8 ? (nBitsPerPixel>>3) : 1); int nPixelsPerByte=(nBitsPerPixel>=8 ? 1 : 8/nBitsPerPixel); for(int nRow=0; nRow>(nCol%nPixelsPerByte)); switch(nAngleDegree) { case 180: bFlip=!bFlip; case 0: { if(bFlip) { // Shift src bit to dest bit's position srcByte<<=(nCol%nPixelsPerByte); srcByte>>=((nWidthDest-nCol-1)%nPixelsPerByte); // Zero out only the bit we're going to replace destByte&=~(BitMask>>((nWidthDest-nCol-1)% nPixelsPerByte)); } else { // Zero out only the bit we're going to replace destByte&=~(BitMask>>(nCol%nPixelsPerByte)); } break; } case 270: bFlip=!bFlip; case 90: { if(bFlip) { // Shift src bit to dest bit's position srcByte<<=(nCol%nPixelsPerByte); srcByte>>=((nWidthDest-nRow-1)% nPixelsPerByte); // Zero out only the bit we're going to replace destByte&=~(BitMask>>((nWidthDest-nRow-1)% nPixelsPerByte)); } else { // Shift src bit to dest bit's position srcByte<<=(nCol%nPixelsPerByte); srcByte>>=(nRow%nPixelsPerByte); // Zero out only the bit we're going to replace destByte&=~(BitMask>>(nRow%nPixelsPerByte)); } break; } default: ASSERT(FALSE); } // Set the destination bit lpDIBBitsDest[nPositionDest]=(BYTE)(srcByte|destByte); break; } // 16-color bitmap case 4: { // Get the source byte BYTE srcByte=lpDIBBitsSrc[nPositionSrc]; // Get the destination byte BYTE destByte=lpDIBBitsDest[nPositionDest]; if(nCol%2==0) srcByte&=HiMask; else srcByte&=LoMask; switch(nAngleDegree) { case 180: bFlip=!bFlip; case 0: { if(bFlip) { if(nCol%2==0 && (nWidthDest-nCol-1)%2!=0) srcByte>>=nBitsPerPixel; else if(nCol%2!=0 && (nWidthDest-nCol-1)%2==0) srcByte<<=nBitsPerPixel; if((nWidthDest-nCol-1)%2==0) destByte&=LoMask; else destByte&=HiMask; } else { if(nCol%2==0) destByte&=LoMask; else destByte&=HiMask; } break; } case 270: bFlip=!bFlip; case 90: { if(bFlip) { if(nCol%2==0 && (nWidthDest-nRow-1)%2!=0) srcByte>>=nBitsPerPixel; else if(nCol%2!=0 && (nWidthDest-nRow-1)%2==0) srcByte<<=nBitsPerPixel; if((nWidthDest-nRow-1)%2==0) destByte&=LoMask; else destByte&=HiMask; } else { if(nCol%2==0 && nRow%2!=0) srcByte>>=nBitsPerPixel; else if(nCol%2!=0 && nRow%2==0) srcByte<<=nBitsPerPixel; if(nRow%2==0) destByte&=LoMask; else destByte&=HiMask; } break; } default: ASSERT(FALSE); } // Set the destination bit lpDIBBitsDest[nPositionDest]=(BYTE)(srcByte|destByte); break; } // 256-color and true-color bitmaps case 8: case 24: default: { lpDIBBitsDest[nPositionDest]=lpDIBBitsSrc[nPositionSrc]; break; } } } } } // ////////////////////////////////////////// ::GlobalUnlock((HGLOBAL)m_hDIB); ASSERT(m_hDIB!=NULL); ::GlobalUnlock((HGLOBAL)dibCopy.m_hDIB); ASSERT(dibCopy.m_hDIB!=NULL); return TRUE; } COXDIB::~COXDIB() { Empty(); } // Diagnostics -------------------------------------------------------------- #ifdef _DEBUG void COXDIB::AssertValid() const { CObject::AssertValid(); if (m_hDIB != NULL) { // Handle to global memory must be valid #ifdef WIN32 BYTE *lp=(BYTE *) ::GlobalLock((HGLOBAL) m_hDIB); #else BYTE huge* lp=(BYTE huge *) ::GlobalLock((HGLOBAL) m_hDIB); #endif ASSERT(lp != NULL); ::GlobalUnlock((HGLOBAL) m_hDIB); } if (m_pPalette != NULL) { // Palette may only exist together with a DIB ASSERT(m_hDIB != NULL); ASSERT_VALID(m_pPalette); } } void COXDIB::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << TEXT("\nm_hDIB : ") << m_hDIB; dc << TEXT("\nm_pPalette : ") << (const void*)m_pPalette; } #endif //_DEBUG // protected: BOOL COXDIB::InitPalette(LPSTR lpbi) // --- In : // --- Out : // --- Returns : Whether it succeeded or not // --- Effect : This function creates a palette from a DIB by allocating memory for the // logical palette, reading and storing the colors from the DIB's color table // into the logical palette, creating a palette from this logical palette, // and then returning the palette's handle. This allows the DIB to be // displayed using the best possible colors (important for DIBs with 256 or // more colors). { LPLOGPALETTE lpPal; // pointer to a logical palette HANDLE hLogPal; // handle to a logical palette int i; // loop index WORD wNumColors; // number of colors in color table LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0) LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old) BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB BOOL bResult=TRUE; // Initialized with TRUE because when NumColors returns ZERO // ie. when reading a TRUE COLOR DIB, NumColors returns ZERO // and then InitPalette succeedes because there is no need // for a palette. // if handle to DIB is invalid, return FALSE if (lpbi==NULL) { TRACE(_T("COXDIB::InitPalette : DIB not loaded, cannot create palette\n")); return FALSE; } // get pointer to BITMAPINFO (Win 3.0) lpbmi=(LPBITMAPINFO)lpbi; // get pointer to BITMAPCOREINFO (old 1.x) lpbmc=(LPBITMAPCOREINFO)lpbi; // get the number of colors in the DIB wNumColors=GetNumColors(lpbi); if (wNumColors != 0) { // allocate memory block for logical palette hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * wNumColors); // if not enough memory, clean up and return NULL if (hLogPal==0) { TRACE(_T("COXDIB::InitPalette : Not enough memory for logical palette\n")); return FALSE; } lpPal=(LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal); // set version and number of palette entries lpPal->palVersion=PALVERSION; lpPal->palNumEntries=(WORD)wNumColors; // is this a Win 3.0 DIB? bWinStyleDIB=IS_WIN30_DIB(lpbi); for (i=0; i < (int)wNumColors; i++) { if (bWinStyleDIB) { lpPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed; lpPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen; lpPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue; lpPal->palPalEntry[i].peFlags=0; } else { lpPal->palPalEntry[i].peRed=lpbmc->bmciColors[i].rgbtRed; lpPal->palPalEntry[i].peGreen=lpbmc->bmciColors[i].rgbtGreen; lpPal->palPalEntry[i].peBlue=lpbmc->bmciColors[i].rgbtBlue; lpPal->palPalEntry[i].peFlags=0; } } // Cannot initialize the palette twice for the same DIB ASSERT(m_pPalette==NULL); m_pPalette=new CPalette; if (m_pPalette==NULL) { // we must be really low on memory TRACE(_T("COXDIB::InitPalette : Out of memory\n")); Empty(); return FALSE; } // create the palette and get handle to it bResult=m_pPalette->CreatePalette(lpPal); ::GlobalUnlock((HGLOBAL) hLogPal); ::GlobalFree((HGLOBAL) hLogPal); } return bResult; } DWORD COXDIB::ReadHuge(CArchive& ar, void FAR* lpBuffer, DWORD dwCount) // --- In :ar : archive to read from // lpBuffer : pointer to buffer to read // dwCount : Number of bytes to read // --- Out : // --- Returns :Number of bytes read // --- Effect : Helper function to read large bitmaps (see filex.cpp for original) { DWORD dwToRead=dwCount; while (dwToRead>0) { UINT nRead=CalcSize(dwToRead, lpBuffer); UINT nActuallyRead; if ((nActuallyRead=ar.Read(lpBuffer, nRead)) < nRead) return ((dwCount - dwToRead) + nActuallyRead); ASSERT(nActuallyRead==nRead); dwToRead -= nRead; #ifdef WIN32 lpBuffer=((BYTE*)lpBuffer) + nRead; #else lpBuffer=((BYTE _huge*)lpBuffer) + nRead; #endif } return dwCount; } void COXDIB::WriteHuge(CArchive& ar, const void FAR* lpBuffer, DWORD dwCount) // --- In :ar : archive to read from // lpBuffer : pointer to buffer to write // dwCount : Number of bytes to write // --- Out : // --- Returns :Number of bytes read // --- Effect : Helper function to write ead large bitmaps (see filex.cpp for original) { DWORD dwToWrite=dwCount; while (dwToWrite>0) { UINT nWrite=CalcSize(dwToWrite, lpBuffer); ar.Write(lpBuffer, nWrite); dwToWrite -= nWrite; #ifdef WIN32 lpBuffer=((const BYTE*)lpBuffer) + nWrite; #else lpBuffer=((const BYTE _huge*)lpBuffer) + nWrite; #endif } } UINT COXDIB::CalcSize(DWORD cbTotal, const void FAR* lpStart) // --- In : // --- Out : // --- Returns :Number of bytes to read or write // --- Effect : Helper function { // return size to read/write (16K max unless limited by segment bounds) #ifdef WIN32 lpStart; DWORD cb=cbTotal; #else DWORD cb=0x10000L - _AFX_FP_OFF(lpStart); if (cb>cbTotal) cb=cbTotal; #endif return (cb>16384) ? 16384 : (UINT)cb; } HDIB WINAPI COXDIB::CopyHandle(HDIB hDIB, DWORD dwExtraBytes /*=0 */) // --- In : h :Handle to global memory to duplicate. // --- Out : // --- Returns :Returns a handle to the new memory block (NULL on error) // --- Effect : Makes a copy of the given global memory block. { #ifdef WIN32 BYTE *lpCopy; BYTE *lp; HDIB hCopy; DWORD_PTR dwLen; #else BYTE huge *lpCopy; BYTE huge *lp; HDIB hCopy; DWORD dwLen; #endif if (hDIB==NULL) return NULL; dwLen=::GlobalSize((HGLOBAL) hDIB) + dwExtraBytes; if ((hCopy=(HDIB) ::GlobalAlloc(GHND, dwLen)) != NULL) { #ifdef WIN32 lpCopy=(BYTE *) ::GlobalLock((HGLOBAL) hCopy); lp =(BYTE *) ::GlobalLock((HGLOBAL) hDIB); #else lpCopy=(BYTE huge *) ::GlobalLock((HGLOBAL) hCopy); lp =(BYTE huge *) ::GlobalLock((HGLOBAL) hDIB); #endif while (dwLen--) *lpCopy++=*lp++; ::GlobalUnlock((HGLOBAL) hCopy); ::GlobalUnlock((HGLOBAL) hDIB); } else { TRACE1("COXDIB::CopyHandle : Could not GlobalAlloc( ,%i)\n", dwLen); } return hCopy; } DWORD COXDIB::CalcPadding(DWORD dwBitsPerPixel, DWORD dwPixels) { DWORD dwBits=dwBitsPerPixel*dwPixels; DWORD dwPadBits=0; int nBitsInDWORD=sizeof(DWORD)<<3; if((dwBits%nBitsInDWORD)==0) // already DWORD aligned, no padding needed return 0; else dwPadBits=nBitsInDWORD-(dwBits%nBitsInDWORD); return (dwPadBits/8+(((dwPadBits%8)>0) ? 1 : 0)); } // private: // ==========================================================================