STMDIB.CXX

//+--------------------------------------------------------------------------- 
//
// Microsoft Windows
// Copyright 1992 - 1998 Microsoft Corporation.
//
// File: stmdib.cxx
//
// Contents: functions for saving and loading DIBs to OLE streams
//
// Classes:
//
// Functions: WriteDibToStream
// ReadDibFromStream
// ReadDibBitmapInfoFromStream
//
// History: 4-22-94 stevebl Created
//
//----------------------------------------------------------------------------

#include "stmdib.h"
#include "dib.h"
#include <stdlib.h>

//+---------------------------------------------------------------------------
//
// Function: WriteDibToStream
//
// Synopsis: writes a global handle in CF_DIB format to a stream
//
// Arguments: [pstm] - stream
// [hdib] - DIB handle
//
// Returns: S_OK if successful
//
// History: 4-22-94 stevebl Created
//
//----------------------------------------------------------------------------

HRESULT WriteDibToStream (IStream * pstm, HANDLE hdib)
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;
OFSTRUCT of;
HRESULT hr;

if (!hdib)
return FALSE;

lpbi = (LPBITMAPINFOHEADER)GlobalLock (hdib);

/* Fill in the fields of the file header */
hdr.bfType = BFT_BITMAP;
hdr.bfSize = GlobalSize (hdib) + sizeof (BITMAPFILEHEADER);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpbi->biSize +
PaletteSize(lpbi);

/* Write the file header */
if (FAILED(hr = pstm->Write(&hdr, sizeof (BITMAPFILEHEADER), NULL)))
{
return(hr);
}

/* Write the DIB header and the bits */
if (FAILED(hr = pstm->Write(lpbi, GlobalSize (hdib), NULL)))
{
return(hr);
}

GlobalUnlock (hdib);
return S_OK;
}

//+---------------------------------------------------------------------------
//
// Function: ReadDibFromStream
//
// Synopsis: reads a DIB stored in CF_DIB format from a stream
//
// Arguments: [pstm] - pointer to the stream
// [phDib] - pointer to recieve the DIB handle
//
// History: 4-22-94 stevebl Created
//
//----------------------------------------------------------------------------

HRESULT ReadDibFromStream (IStream * pstm, HANDLE * phDib)
{
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen = 0;
DWORD dwBits;
HANDLE hdib;
HANDLE h;
OFSTRUCT of;
HRESULT hr;

*phDib = NULL;

if (FAILED(hr = ReadDibBitmapInfoFromStream(pstm, &hdib)))
{
return(hr);
}
DibInfo(hdib,&bi);

/* Calculate the memory needed to hold the DIB */
dwBits = bi.biSizeImage;
dwLen = bi.biSize + (DWORD)PaletteSize (&bi) + dwBits;

/* Try to increase the size of the bitmap info. buffer to hold the DIB */
h = GlobalReAlloc(hdib, dwLen, GHND);
if (!h)
{
GlobalFree(hdib);
return(E_OUTOFMEMORY);
}
hdib = h;

/* Read in the bits */

lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
if (FAILED(hr = pstm->Read(((LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi)), dwBits, NULL)))
{
return(hr);
}
GlobalUnlock(hdib);

*phDib = hdib;
return(S_OK);
}

//+---------------------------------------------------------------------------
//
// Function: ReadDibBitmapInfoFromStream
//
// Synopsis: reads a file in DIB format and retrieves a global HANDLE to
// its BITMAPINFO.
//
// Arguments: [pstm] - stream
// [phbi] - pointer to receive HANDLE to BITMAPINFO
//
// Returns: S_OK on success
//
// History: 4-22-94 stevebl Created
//
//----------------------------------------------------------------------------

HRESULT ReadDibBitmapInfoFromStream(IStream * pstm, HANDLE * phbi)
{
ULARGE_INTEGER libOff;
LARGE_INTEGER dlibMove;
HANDLE hbi = NULL;
int size;
int i;
WORD nNumColors;

RGBQUAD FAR *pRgb;
BITMAPINFOHEADER bi;
BITMAPCOREHEADER bc;
LPBITMAPINFOHEADER lpbi;
BITMAPFILEHEADER bf;
DWORD dwWidth = 0;
DWORD dwHeight = 0;
WORD wPlanes, wBitCount;
HRESULT hr;

*phbi = NULL;

/* Reset file pointer and read file header */

dlibMove.HighPart = 0;
dlibMove.LowPart = 0;
if (FAILED(hr = pstm->Seek(dlibMove, STREAM_SEEK_CUR, &libOff)))
{
return(hr);
}
if (FAILED(hr = pstm->Read(&bf, sizeof(bf), NULL)))
{
return(hr);
}

/* Do we have a RC HEADER? */
if (!ISDIB (bf.bfType))
{
bf.bfOffBits = 0L;
dlibMove.HighPart = libOff.HighPart;
dlibMove.LowPart = libOff.LowPart;
if (FAILED(hr = pstm->Seek(dlibMove, STREAM_SEEK_SET, NULL)))
{
return(hr);
}
}
if (FAILED(hr = pstm->Read(&bi, sizeof(bi), NULL)))
{
return(hr);
}

nNumColors = DibNumColors (&bi);

/* Check the nature (BITMAPINFO or BITMAPCORE) of the info. block
* and extract the field information accordingly. If a BITMAPCOREHEADER,
* transfer it's field information to a BITMAPINFOHEADER-style block
*/
switch (size = (int)bi.biSize)
{
case sizeof (BITMAPINFOHEADER):
break;

case sizeof (BITMAPCOREHEADER):
bc = *(BITMAPCOREHEADER*)&bi;
dwWidth = (DWORD)bc.bcWidth;
dwHeight = (DWORD)bc.bcHeight;
wPlanes = bc.bcPlanes;
wBitCount = bc.bcBitCount;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = dwWidth;
bi.biHeight = dwHeight;
bi.biPlanes = wPlanes;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = nNumColors;
bi.biClrImportant = nNumColors;
dlibMove.HighPart = 0;
dlibMove.LowPart = sizeof (BITMAPCOREHEADER) - sizeof (BITMAPINFOHEADER);
if (FAILED(hr = pstm->Seek(dlibMove, STREAM_SEEK_CUR, NULL)))
{
return(hr);
}
break;

default:
/* Not a DIB! */
return E_FAIL;
}

/* Fill in some default values if they are zero */
if (bi.biSizeImage == 0)
{
bi.biSizeImage = WIDTHBYTES ((DWORD)bi.biWidth * bi.biBitCount)
* bi.biHeight;
}
if (bi.biClrUsed == 0)
bi.biClrUsed = DibNumColors(&bi);

/* Allocate for the BITMAPINFO structure and the color table. */
hbi = GlobalAlloc (GHND, (LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
if (!hbi)
return NULL;
lpbi = (LPBITMAPINFOHEADER)GlobalLock (hbi);
*lpbi = bi;

/* Get a pointer to the color table */
pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + bi.biSize);
if (nNumColors)
{
if (size == sizeof(BITMAPCOREHEADER))
{
/* Convert a old color table (3 byte RGBTRIPLEs) to a new
* color table (4 byte RGBQUADs)
*/
if (FAILED(hr = pstm->Read(pRgb, nNumColors * sizeof(RGBTRIPLE), NULL)))
{
return(hr);
}

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
{
if (FAILED(hr = pstm->Read(pRgb, nNumColors * sizeof(RGBQUAD), NULL)))
{
return(hr);
}
}
}

if (bf.bfOffBits != 0L)
{
dlibMove.HighPart = libOff.HighPart;
dlibMove.LowPart = libOff.LowPart + bf.bfOffBits;
if (FAILED(hr = pstm->Seek(dlibMove, STREAM_SEEK_SET, NULL)))
{
return(hr);
}
}

GlobalUnlock(hbi);
*phbi = hbi;
return(S_OK);
}