www.pudn.com > Cimage.zip > DIBUTILS.CPP


/************************************************************************** 
 
	 UTILS.C - useful functions for WinG Sample Apps 
 
 **************************************************************************/ 
/************************************************************************** 
 
	 (C) Copyright 1994 Microsoft Corp.  All rights reserved. 
 
    You have a royalty-free right to use, modify, reproduce and  
    distribute the Sample Files (and/or any modified version) in  
    any way you find useful, provided that you agree that  
	 Microsoft has no warranty obligations or liability for any 
    Sample Application Files which are modified.  
 
 **************************************************************************/ 
 
/*----------------------------------------------------------------------------*\ 
|   Functions for handling Device Independent Bitmaps and clearing the         | 
|   System Palette.                                                            | 
\*----------------------------------------------------------------------------*/ 
 
#include "stdafx.h" 
 
#include  
#include  
#include  
#include "dibutils.h" 
 
#if defined(WIN32) || defined(_WIN32) 
    #include              // for _fmemcpy() 
	 #define _huge 
#ifndef hmemcpy 
    #define hmemcpy memcpy 
#endif 
#endif 
 
#define BFT_ICON   0x4349   /* 'IC' */ 
#define BFT_BITMAP 0x4d42   /* 'BM' */ 
#define BFT_CURSOR 0x5450   /* 'PT' */ 
 
/* flags for _lseek */ 
#define  SEEK_CUR 1 
#define  SEEK_END 2 
#define  SEEK_SET 0 
 
 
/* 
 *  Clear the System Palette so that we can ensure an identity palette  
 *  mapping for fast performance. 
 */ 
 
void ClearSystemPalette(void) 
{ 
  //*** 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; 
} 
 
 
/* 
 *   Open a DIB file and return a MEMORY DIB, a memory handle containing.. 
 * 
 *   BITMAP INFO    bi 
 *   palette data 
 *   bits.... 
 */ 
 
int DibWriteFile(LPSTR szFile, LPBITMAPINFOHEADER lpbi) 
{ 
	 HFILE               fh; 
	 OFSTRUCT            of; 
 
	 fh = OpenFile(szFile, &of, OF_WRITE | OF_CREATE); 
 
  if (!fh) { 
//	 printf("la regamos0"); 
	 return 0; 
  } 
 
  long size = DibSize(lpbi); 
 
  // write file header 
  BITMAPFILEHEADER bmf; 
  bmf.bfType = 'BM'; 
  bmf.bfSize = sizeof(bmf) + size; 
  bmf.bfReserved1 = 0; 
  bmf.bfReserved2 = 0; 
  bmf.bfOffBits = sizeof(bmf) + (char far*)(DibPtr(lpbi)) - (char far*)lpbi; 
#if defined( __WATCOMC__) || defined(_MSC_VER) 
  if (_hwrite(fh, (LPCSTR)(&bmf), sizeof(bmf))<0 || 
	_hwrite(fh, (LPCSTR)lpbi, size)<0) { 
	  _lclose(fh); 
//	 printf("la regamos1"); 
	  return 0; 
  } 
#else 
  if (_hwrite(fh, (LPBYTE)(&bmf), sizeof(bmf))<0 || 
	_hwrite(fh, (LPBYTE)lpbi, size)<0) { 
	  _lclose(fh); 
//	 printf("la regamos1"); 
	  return 0; 
  } 
#endif 
 
  _lclose(fh); 
  return 1; 
} 
 
// The following is an alternative implementation of DIB writing, since 
// the above doesn't appear to work. 
 
/**************************************************************************** 
 *									    * 
 *  FUNCTION   :  PaletteSize(VOID FAR * pv)				    * 
 *									    * 
 *  PURPOSE    :  Calculates the palette size in bytes. If the info. block  * 
 *		  is of the BITMAPCOREHEADER type, the number of colors is  * 
 *		  multiplied by 3 to give the palette size, otherwise the   * 
 *		  number of colors is multiplied by 4.								* 
 *									    * 
 *  RETURNS    :  Palette size in number of bytes.			    * 
 *									    * 
 ****************************************************************************/ 
 
WORD PaletteSize(VOID FAR * pv) 
{ 
	LPBITMAPINFOHEADER lpbi; 
	WORD	       NumColors; 
 
	lpbi = (LPBITMAPINFOHEADER) pv; 
	NumColors = DibNumColors(lpbi); 
 
	if (lpbi->biSize == sizeof(BITMAPCOREHEADER)) 
		return NumColors * sizeof(RGBTRIPLE); 
	else  
		return NumColors * sizeof(RGBQUAD); 
} 
 
/**************************************************************************** 
 *									    * 
 *  FUNCTION   : lwrite(int fh, VOID FAR *pv, DWORD ul) 		    * 
 *									    * 
 *  PURPOSE    : Writes data in steps of 32k till all the data is written.  * 
 *									    * 
 *  RETURNS    : 0 - If write did not proceed correctly.		    * 
 *		 number of bytes written otherwise.			    * 
 *									    * 
 ****************************************************************************/ 
 
#define MAXREAD  32768				 /* Number of bytes to be read during */ 
						 /* each read operation.			 */ 
 
DWORD PASCAL lwrite(int fh, VOID FAR *pv, DWORD ul) 
{ 
	DWORD     ulT = ul; 
#if defined(WINNT) || defined(WIN32) || defined(__WIN32__) 
	BYTE *hp = (BYTE *) pv; 
#else 
	BYTE huge *hp = (BYTE huge *) pv; 
#endif 
	while (ul > MAXREAD) { 
		if (_lwrite(fh, (LPSTR) hp, (WORD) MAXREAD) != MAXREAD) 
			return 0; 
		ul -= MAXREAD; 
		hp += MAXREAD; 
		} 
	if (_lwrite(fh, (LPSTR) hp, (WORD) ul) != (WORD) ul) 
		return 0; 
	return ulT; 
} 
 
/**************************************************************************** 
 *									    * 
 *  FUNCTION   : WriteDIB(LPSTR szFile,HANDLE hdib)			    * 
 *									    * 
 *  PURPOSE    : Write a global handle in CF_DIB format to a file.	    * 
 *									    * 
 *  RETURNS    : TRUE  - if successful. 				    * 
 *		 FALSE - otherwise					    * 
 *									    * 
 ****************************************************************************/ 
 
BOOL WriteDIB(const char *szFile, LPBITMAPINFOHEADER  lpbi) 
{ 
	BITMAPFILEHEADER	hdr; 
	int                 fh; 
	OFSTRUCT            of; 
 
	if (!lpbi) 
		return FALSE; 
 
	fh = OpenFile(szFile, &of, OF_CREATE | OF_READWRITE); 
	if (fh == -1) 
		return FALSE; 
 
    /* Fill in the fields of the file header */ 
	hdr.bfType = BFT_BITMAP; 
	hdr.bfSize = DibSize(lpbi) + sizeof(BITMAPFILEHEADER); 
	hdr.bfReserved1 = 0; 
	hdr.bfReserved2 = 0; 
	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + lpbi->biSize +  
		 PaletteSize(lpbi); 
 
    /* Write the file header */ 
	_lwrite(fh, (LPSTR) &hdr, sizeof(BITMAPFILEHEADER)); 
 
    /* Write the DIB header and the bits */ 
	lwrite(fh, (LPSTR) lpbi, DibSize(lpbi)); 
 
	_lclose(fh); 
	return TRUE; 
} 
 
PDIB DibOpenFile(LPSTR szFile) 
{ 
	 HFILE               fh; 
	 DWORD               dwLen; 
	 DWORD               dwBits; 
	 PDIB                pdib; 
	 LPVOID              p; 
	 OFSTRUCT            of; 
 
#if defined(WIN32) || defined(_WIN32) 
	 #define GetCurrentInstance()    GetModuleHandle(NULL) 
#else 
	 #define GetCurrentInstance()    (HINSTANCE)SELECTOROF((LPVOID)&of) 
#endif 
 
	 fh = OpenFile(szFile, &of, OF_READ); 
 
#if 0 
	 if (fh == -1) 
	 { 
		  HRSRC h; 
 
		  h = FindResource(GetCurrentInstance(), szFile, RT_BITMAP); 
 
#if defined(WIN32) || defined(_WIN32) 
		  //!!! can we call GlobalFree() on this? is it the right format. 
		  //!!! can we write to this resource? 
		  if (h) 
				return (PDIB)LockResource(LoadResource(GetCurrentInstance(), h)); 
#else 
		  if (h) 
				fh = AccessResource(GetCurrentInstance(), h); 
#endif 
	 } 
#endif 
 
	 if (fh == -1) 
		  return NULL; 
 
	 pdib = DibReadBitmapInfo(fh); 
 
	 if (!pdib) 
		  return NULL; 
 
    /* How much memory do we need to hold the DIB */ 
 
    dwBits = pdib->biSizeImage; 
    dwLen  = pdib->biSize + DibPaletteSize(pdib) + dwBits; 
 
    /* Can we get more memory? */ 
 
	 p = GlobalReAllocPtr(pdib,dwLen,0); 
 
    if (!p) 
    { 
		  GlobalFreePtr(pdib); 
        pdib = NULL; 
    } 
    else 
    { 
        pdib = (PDIB)p; 
    } 
 
    if (pdib) 
    { 
		  /* read in the bits */ 
		  _hread(fh, (LPBYTE)pdib + (UINT)pdib->biSize + DibPaletteSize(pdib), dwBits); 
    } 
 
    _lclose(fh); 
 
    return pdib; 
} 
 
 
/* 
 *  ReadDibBitmapInfo() 
 * 
 *  Will read a file in DIB format and return a global HANDLE to its 
 *  BITMAPINFO.  This function will work with both "old" and "new" 
 *  bitmap formats, but will always return a "new" BITMAPINFO. 
 */ 
 
PDIB DibReadBitmapInfo(HFILE fh) 
{ 
    DWORD     off; 
    HANDLE    hbi = NULL; 
    int       size; 
    int       i; 
    int       nNumColors; 
 
    RGBQUAD FAR       *pRgb; 
    BITMAPINFOHEADER   bi; 
    BITMAPCOREHEADER   bc; 
    BITMAPFILEHEADER   bf; 
    PDIB               pdib; 
 
    if (fh == -1) 
        return NULL; 
 
    off = _llseek(fh,0L,SEEK_CUR); 
 
    if (sizeof(bf) != _lread(fh,(LPSTR)&bf,sizeof(bf))) 
        return FALSE; 
 
    /* 
     *  do we have a RC HEADER? 
     */ 
    if (bf.bfType != BFT_BITMAP) 
    { 
        bf.bfOffBits = 0L; 
        _llseek(fh,off,SEEK_SET); 
    } 
 
    if (sizeof(bi) != _lread(fh,(LPSTR)&bi,sizeof(bi))) 
        return FALSE; 
 
    /* 
     *  what type of bitmap info is this? 
     */ 
    switch (size = (int)bi.biSize) 
    { 
        default: 
        case sizeof(BITMAPINFOHEADER): 
            break; 
 
        case sizeof(BITMAPCOREHEADER): 
            bc = *(BITMAPCOREHEADER*)&bi; 
            bi.biSize               = sizeof(BITMAPINFOHEADER); 
            bi.biWidth              = (DWORD)bc.bcWidth; 
            bi.biHeight             = (DWORD)bc.bcHeight; 
            bi.biPlanes             =  (UINT)bc.bcPlanes; 
            bi.biBitCount           =  (UINT)bc.bcBitCount; 
            bi.biCompression        = BI_RGB; 
            bi.biSizeImage          = 0; 
            bi.biXPelsPerMeter      = 0; 
            bi.biYPelsPerMeter      = 0; 
            bi.biClrUsed            = 0; 
            bi.biClrImportant       = 0; 
 
            _llseek(fh,(LONG)sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER),SEEK_CUR); 
 
            break; 
    } 
 
    nNumColors = DibNumColors(&bi); 
 
#if 0 
    if (bi.biSizeImage == 0) 
        bi.biSizeImage = DibSizeImage(&bi); 
 
    if (bi.biClrUsed == 0) 
        bi.biClrUsed = DibNumColors(&bi); 
#else 
    FixBitmapInfo(&bi); 
#endif 
 
    pdib = (PDIB)GlobalAllocPtr(GMEM_MOVEABLE,(LONG)bi.biSize + nNumColors * sizeof(RGBQUAD)); 
 
    if (!pdib) 
        return NULL; 
 
    *pdib = bi; 
 
    pRgb = DibColors(pdib); 
 
    if (nNumColors) 
    { 
        if (size == sizeof(BITMAPCOREHEADER)) 
        { 
            /* 
             * convert a old color table (3 byte entries) to a new 
             * color table (4 byte entries) 
             */ 
            _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBTRIPLE)); 
 
            for (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 
        { 
            _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBQUAD)); 
        } 
    } 
 
    if (bf.bfOffBits != 0L) 
        _llseek(fh,off + bf.bfOffBits,SEEK_SET); 
 
    return pdib; 
} 
 
/* 
 *  DibSetUsage(hdib,hpal,wUsage) 
 * 
 *  Modifies the color table of the passed DIB for use with the wUsage 
 *  parameter specifed. 
 * 
 *  if wUsage is DIB_PAL_COLORS the DIB color table is set to 0-256 
 *  if wUsage is DIB_RGB_COLORS the DIB color table is set to the RGB values 
 *      in the passed palette 
 */ 
 
BOOL DibSetUsage(PDIB pdib, HPALETTE hpal,UINT wUsage) 
{ 
    PALETTEENTRY       ape[256]; 
    RGBQUAD FAR *      pRgb; 
    WORD FAR *         pw; 
    int                nColors; 
    int                n; 
 
    if (hpal == NULL) 
        hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE); 
 
    if (!pdib) 
        return FALSE; 
 
    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; nbiSize            = sizeof(BITMAPINFOHEADER) ; 
    lpbi->biWidth           = dx; 
    lpbi->biHeight          = dy; 
    lpbi->biPlanes          = 1; 
    lpbi->biBitCount        = bits ; 
    lpbi->biCompression     = BI_RGB ; 
    lpbi->biSizeImage       = dwSizeImage; 
    lpbi->biXPelsPerMeter   = 0 ; 
    lpbi->biYPelsPerMeter   = 0 ; 
    lpbi->biClrUsed         = 0 ; 
    lpbi->biClrImportant    = 0 ; 
 
    if (bits == 4) 
        lpbi->biClrUsed = 16; 
 
    else if (bits == 8) 
        lpbi->biClrUsed = 256; 
 
    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 
    } 
 
    return (PDIB)lpbi; 
} 
 
static void xlatClut8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat) 
{ 
    DWORD dw; 
 
#ifdef __cplusplus 
    for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++) 
#else 
    for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++) 
#endif 
        *pb = xlat[*pb]; 
} 
 
static void xlatClut4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat) 
{ 
    DWORD dw; 
 
#ifdef __cplusplus 
    for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++) 
#else 
    for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++) 
#endif 
        *pb = (BYTE)(xlat[*pb & 0x0F] | (xlat[(*pb >> 4) & 0x0F] << 4)); 
} 
 
#define RLE_ESCAPE  0 
#define RLE_EOL     0 
#define RLE_EOF     1 
#define RLE_JMP     2 
 
static void xlatRle8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat) 
{ 
    BYTE    cnt; 
    BYTE    b; 
    BYTE _huge *prle = pb; 
 
    for(;;) 
    { 
        cnt = *prle++; 
        b   = *prle; 
 
        if (cnt == RLE_ESCAPE) 
        { 
            prle++; 
 
            switch (b) 
            { 
                case RLE_EOF: 
                    return; 
 
                case RLE_EOL: 
                    break; 
 
                case RLE_JMP: 
                    prle++;     // skip dX 
                    prle++;     // skip dY 
                    break; 
 
                default: 
                    cnt = b; 
                    for (b=0; bbiSizeImage) == 0) 
		  SizeImage = DibSizeImage(lpbi); 
 
	 // 
	 //  build a xlat table. from the current DIB colors to the given 
	 //  palette. 
	 // 
	 for (n=0; nbiClrUsed = nPalColors; 
 
	 // 
	 // re-size the DIB 
	 // 
	 if (nPalColors > nDibColors) 
	 { 
		  GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0); 
		  hmemmove((BYTE _huge *)DibPtr(lpbi), (BYTE _huge *)lpBits, SizeImage); 
		  lpBits = (LPBYTE)DibPtr(lpbi); 
	 } 
	 else if (nPalColors < nDibColors) 
	 { 
		  hmemcpy(DibPtr(lpbi), lpBits, SizeImage); 
		  GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0); 
		  lpBits = (LPBYTE)DibPtr(lpbi); 
	 } 
 
	 // 
	 // translate the DIB bits 
	 // 
	 switch (lpbi->biCompression) 
	 { 
		  case BI_RLE8: 
				xlatRle8(lpBits, SizeImage, xlat); 
				break; 
 
		  case BI_RLE4: 
				xlatRle4(lpBits, SizeImage, xlat); 
				break; 
 
        case BI_RGB: 
				if (lpbi->biBitCount == 8) 
                xlatClut8(lpBits, SizeImage, xlat); 
            else 
                xlatClut4(lpBits, SizeImage, xlat); 
            break; 
    } 
 
    // 
    //  Now copy the RGBs in the logical palette to the dib color table 
    // 
    for (n=0; nbmiColors; 
 
  WORD nColors = Info->bmiHeader.biClrUsed; 
  if (nColors) { 
	 LOGPALETTE* logPal = (LOGPALETTE*) 
		 new BYTE[sizeof(LOGPALETTE) + (nColors-1)*sizeof(PALETTEENTRY)]; 
 
	 logPal->palVersion  = 0x300; // Windows 3.0 version 
	 logPal->palNumEntries = nColors; 
	 for (short n = 0; n < nColors; n++) { 
		logPal->palPalEntry[n].peRed   = rgb[n].rgbRed; 
		logPal->palPalEntry[n].peGreen = rgb[n].rgbGreen; 
		logPal->palPalEntry[n].peBlue  = rgb[n].rgbBlue; 
		logPal->palPalEntry[n].peFlags = (BYTE)flags; 
	 } 
	 hPalette = ::CreatePalette(logPal); 
	 delete logPal; 
  } else 
	 hPalette = 0; 
 
  return hPalette; 
}