// dibapi.cpp // // Source file for Device-Independent Bitmap (DIB) API. Provides // the following functions: // // PaintDIB() - Painting routine for a DIB // CreateDIBPalette() - Creates a palette from a DIB // FindDIBBits() - Returns a pointer to the DIB bits // DIBWidth() - Gets the width of the DIB // DIBHeight() - Gets the height of the DIB // PaletteSize() - Gets the size required to store the DIB's palette // DIBNumColors() - Calculates the number of colors // in the DIB's color table // CopyHandle() - Makes a copy of the given global memory block // // This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include "dibapi.h" #include #include #include #include /* * Dib Header Marker - used in writing DIBs to files */ #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B') /************************************************************************* Function: ReadDIBFile (CFile&) Purpose: Reads in the specified DIB file into a global chunk of memory. Returns: A handle to a dib (hDIB) if successful. NULL if an error occurs. Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything from the end of the BITMAPFILEHEADER structure on is returned in the global memory handle. *************************************************************************/ HDIB WINAPI ReadDIBFile(LPCTSTR pszFileName ) { BITMAPFILEHEADER bmfHeader; DWORD dwBitsSize; HDIB hDIB; LPSTR pDIB; HANDLE hFile; DWORD nBytesRead; /* * get length of DIB in bytes for use when reading */ hFile = CreateFile( pszFileName, // pointer to name of the file GENERIC_READ, // access (read-write) mode FILE_SHARE_READ, // share mode NULL, // pointer to security descriptor OPEN_EXISTING, // how to create FILE_ATTRIBUTE_NORMAL, // file attributes NULL // handle to file with attributes to copy ); dwBitsSize = GetFileSize(hFile,NULL); /* * Go read the DIB file header and check if it's valid. */ // attempt an asynchronous read operation if(! ReadFile(hFile, (LPSTR)&bmfHeader, sizeof(bmfHeader), &nBytesRead, NULL)) return NULL; if (bmfHeader.bfType != DIB_HEADER_MARKER) return NULL; /* * Allocate memory for DIB */ hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize); if (hDIB == 0) { return NULL; } pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); /* * Go read the bits. */ if(!ReadFile(hFile, (LPSTR)pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER), &nBytesRead, NULL)) { ::GlobalUnlock((HGLOBAL) hDIB); ::GlobalFree((HGLOBAL) hDIB); return NULL; } ::GlobalUnlock((HGLOBAL) hDIB); CloseHandle(hFile); return hDIB; } /************************************************************************* * * PaintDIB() * * Parameters: * * HDC hDC - DC to do output to * * LPRECT lpDCRect - rectangle on DC to do output to * * HDIB hDIB - handle to global memory with a DIB spec * in it followed by the DIB bits * * LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect * * CPalette* pPal - pointer to CPalette containing DIB's palette * * Return Value: * * BOOL - TRUE if DIB was drawn, FALSE otherwise * * Description: * Painting routine for a DIB. Calls StretchDIBits() or * SetDIBitsToDevice() to paint the DIB. The DIB is * output to the specified DC, at the coordinates given * in lpDCRect. The area of the DIB to be output is * given by lpDIBRect. * ************************************************************************/ BOOL WINAPI PaintDIB(HDC hDC, LPRECT lpDCRect, HDIB hDIB, LPRECT lpDIBRect, HPALETTE hPal) { LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER LPSTR lpDIBBits; // Pointer to DIB bits BOOL bSuccess=FALSE; // Success/fail flag HPALETTE hOldPal=NULL; // Previous palette /* Check for valid DIB handle */ if (hDIB == NULL) return FALSE; /* Lock down the DIB, and get a pointer to the beginning of the bit * buffer */ lpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); lpDIBBits = ::FindDIBBits(lpDIBHdr); // Get the DIB's palette, then select it into DC // Select as background since we have // already realized in forground if needed hOldPal = ::SelectPalette(hDC, hPal, TRUE); /* Make sure to use the stretching mode best for color pictures */ ::SetStretchBltMode(hDC, COLORONCOLOR); /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */ if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) && (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect))) { bSuccess = ::SetDIBitsToDevice(hDC, // hDC lpDCRect->left, // DestX lpDCRect->top, // DestY RECTWIDTH(lpDCRect), // nDestWidth RECTHEIGHT(lpDCRect), // nDestHeight // RECTWIDTH(lpDIBRect), // wSrcWidth // RECTHEIGHT(lpDIBRect), // wSrcHeight lpDIBRect->left, // SrcX (int)DIBHeight(lpDIBHdr) - lpDIBRect->top - RECTHEIGHT(lpDIBRect), // SrcY 0, // nStartScan (WORD)DIBHeight(lpDIBHdr), // nNumScans lpDIBBits, // lpBits (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo DIB_RGB_COLORS); // wUsage } else { bSuccess = ::StretchDIBits(hDC, // hDC lpDCRect->left, // DestX lpDCRect->top, // DestY RECTWIDTH(lpDCRect), // nDestWidth RECTHEIGHT(lpDCRect), // nDestHeight // RECTWIDTH(lpDIBRect), // wSrcWidth // RECTHEIGHT(lpDIBRect), // wSrcHeight lpDIBRect->left, // SrcX lpDIBRect->top, // SrcY RECTWIDTH(lpDIBRect), // wSrcWidth RECTHEIGHT(lpDIBRect), // wSrcHeight lpDIBBits, // lpBits (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo DIB_RGB_COLORS, // wUsage SRCCOPY); // dwROP } ::GlobalUnlock((HGLOBAL) hDIB); /* Reselect old palette */ if (hOldPal != NULL) { ::SelectPalette(hDC, hOldPal, TRUE); } return bSuccess; } /************************************************************************* * * CreateDIBPalette() * * Parameter: * * HDIB hDIB - specifies the DIB * * Return Value: * * HPALETTE - specifies the palette * * Description: * * 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). * ************************************************************************/ BOOL WINAPI CreateDIBPalette(HDIB hDIB, HPALETTE* pPal) { LPLOGPALETTE lpPal; // pointer to a logical palette HANDLE hLogPal; // handle to a logical palette HPALETTE hPal = NULL; // handle to a palette int i; // loop index WORD wNumColors; // number of colors in color table LPSTR lpbi; // pointer to packed-DIB 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 = FALSE; /* if handle to DIB is invalid, return FALSE */ if (hDIB == NULL) return FALSE; lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); /* 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 = ::DIBNumColors(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) { ::GlobalUnlock((HGLOBAL) hDIB); 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; } } /* create the palette and get handle to it */ hPal = (HPALETTE)::CreatePalette((LPLOGPALETTE)lpPal); ::GlobalUnlock((HGLOBAL) hLogPal); ::GlobalFree((HGLOBAL) hLogPal); *pPal = hPal; } ::GlobalUnlock((HGLOBAL) hDIB); return (NULL != pPal); } /************************************************************************* * * FindDIBBits() * * Parameter: * * LPSTR lpbi - pointer to packed-DIB memory block * * Return Value: * * LPSTR - pointer to the DIB bits * * Description: * * This function calculates the address of the DIB's bits and returns a * pointer to the DIB bits. * ************************************************************************/ LPSTR WINAPI FindDIBBits(LPSTR lpbi) { return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi)); } /************************************************************************* * * DIBWidth() * * Parameter: * * LPSTR lpbi - pointer to packed-DIB memory block * * Return Value: * * DWORD - width of the DIB * * Description: * * This function gets the width of the DIB from the BITMAPINFOHEADER * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER * width field if it is an other-style DIB. * ************************************************************************/ DWORD WINAPI DIBWidth(LPSTR lpDIB) { LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB /* point to the header (whether Win 3.0 and old) */ lpbmi = (LPBITMAPINFOHEADER)lpDIB; lpbmc = (LPBITMAPCOREHEADER)lpDIB; /* return the DIB width if it is a Win 3.0 DIB */ if (IS_WIN30_DIB(lpDIB)) return lpbmi->biWidth; else /* it is an other-style DIB, so return its width */ return (DWORD)lpbmc->bcWidth; } /************************************************************************* * * DIBHeight() * * Parameter: * * LPSTR lpbi - pointer to packed-DIB memory block * * Return Value: * * DWORD - height of the DIB * * Description: * * This function gets the height of the DIB from the BITMAPINFOHEADER * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER * height field if it is an other-style DIB. * ************************************************************************/ DWORD WINAPI DIBHeight(LPSTR lpDIB) { LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB /* point to the header (whether old or Win 3.0 */ lpbmi = (LPBITMAPINFOHEADER)lpDIB; lpbmc = (LPBITMAPCOREHEADER)lpDIB; /* return the DIB height if it is a Win 3.0 DIB */ if (IS_WIN30_DIB(lpDIB)) return lpbmi->biHeight; else /* it is an other-style DIB, so return its height */ return (DWORD)lpbmc->bcHeight; } /************************************************************************* * * PaletteSize() * * Parameter: * * LPSTR lpbi - pointer to packed-DIB memory block * * Return Value: * * WORD - size of the color palette of the DIB * * Description: * * This function gets the size required to store the DIB's palette by * multiplying the number of colors by the size of an RGBQUAD (for a * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an other- * style DIB). * ************************************************************************/ WORD WINAPI PaletteSize(LPSTR lpbi) { /* calculate the size required by the palette */ if (IS_WIN30_DIB (lpbi)) return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD)); else return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE)); } /************************************************************************* * * DIBNumColors() * * Parameter: * * LPSTR lpbi - pointer to packed-DIB memory block * * Return Value: * * WORD - number of colors in the color table * * Description: * * This function calculates the number of colors in the DIB's color table * by finding the bits per pixel for the DIB (whether Win3.0 or other-style * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256, * if 24, no colors in color table. * ************************************************************************/ WORD WINAPI DIBNumColors(LPSTR lpbi) { 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) 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; /* 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; } } ////////////////////////////////////////////////////////////////////////// //// Clipboard support //--------------------------------------------------------------------- // // Function: CopyHandle (from SDK DibView sample clipbrd.c) // // Purpose: Makes a copy of the given global memory block. Returns // a handle to the new memory block (NULL on error). // // Routine stolen verbatim out of ShowDIB. // // Parms: h == Handle to global memory to duplicate. // // Returns: Handle to new global memory block. // //--------------------------------------------------------------------- HGLOBAL WINAPI CopyHandle (HGLOBAL h) { if (h == NULL) return NULL; DWORD dwLen = ::GlobalSize((HGLOBAL) h); HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen); if (hCopy != NULL) { void* lpCopy = ::GlobalLock((HGLOBAL) hCopy); void* lp = ::GlobalLock((HGLOBAL) h); memcpy(lpCopy, lp, dwLen); ::GlobalUnlock(hCopy); ::GlobalUnlock(h); } return hCopy; }