|
|
// Cdib.cpp
//
#include "stdafx.h"
#include "cdib.h"
#include <windowsx.h>
#include <afxadv.h>
#include <io.h>
#include <errno.h>
#include <math.h>
/////////////////////////////////////////////////////////////////////////////
// CDib
IMPLEMENT_DYNAMIC(CDib, CObject)
/**************************************************************************\
* CDib::CDib() * * Constructor for CDib class * * * Arguments: * * none * * Return Value: * * none * * History: * * 2/14/1999 Original Version * \**************************************************************************/ CDib::CDib() { m_pBMI = NULL; m_pBits = NULL; m_pPalette = NULL; }
/**************************************************************************\
* CDib::~CDib * * Destructor for CDib class * * * Arguments: * * none * * Return Value: * * none * * History: * * 2/14/1999 Original Version * \**************************************************************************/ CDib::~CDib() { Free(); }
/**************************************************************************\
* CDib::Free() * * Cleans the stored DIB from memory * * * Arguments: * * none * * Return Value: * * void * * History: * * 2/14/1999 Original Version * \**************************************************************************/ void CDib::Free() { // Make sure all member data that might have been allocated is freed.
if (m_pBits) { GlobalFreePtr(m_pBits); m_pBits = NULL; } if (m_pBMI) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; } if (m_pPalette) { m_pPalette->DeleteObject(); delete m_pPalette; m_pPalette = NULL; } }
/**************************************************************************\
* CDib::Paint() * * Draws a DIB to the target DC * * * Arguments: * * hDC - Target DC * lpDCRect - DC window rect * lpDIBRect - DIB's rect * * Return Value: * * status * * History: * * 2/14/1999 Original Version * \**************************************************************************/ BOOL CDib::Paint(HDC hDC, LPRECT lpDCRect, LPRECT lpDIBRect) const { float lWidthVal = 1; float lHeightVal = 1;
if (!m_pBMI) return FALSE;
HPALETTE hPal = NULL; // Our DIB's palette
HPALETTE hOldPal = NULL; // Previous palette
// 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(hDC, hPal, TRUE); }
// Make sure to use the stretching mode best for color pictures
::SetStretchBltMode(hDC, COLORONCOLOR);
// Determine whether to call StretchDIBits() or SetDIBitsToDevice()
BOOL bSuccess; 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
lpDIBRect->left, // SrcX
(int)Height() - lpDIBRect->top - RECTHEIGHT(lpDIBRect), // SrcY
0, // nStartScan
(WORD)Height(), // nNumScans
m_pBits, // lpBits
m_pBMI, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
else { //Window width becomes smaller than original image width
if (RECTWIDTH(lpDIBRect) > lpDCRect->right - lpDCRect->left) { lWidthVal = (float)(lpDCRect->right - lpDCRect->left)/RECTWIDTH(lpDIBRect); } //Window height becomes smaller than original image height
if (RECTHEIGHT(lpDIBRect) > lpDCRect->bottom - lpDCRect->top) { lHeightVal = (float)(lpDCRect->bottom - lpDCRect->top)/RECTHEIGHT(lpDIBRect); } long ScaledWidth = (int)(RECTWIDTH(lpDIBRect) * min(lWidthVal,lHeightVal)); long ScaledHeight = (int)(RECTHEIGHT(lpDIBRect) * min(lWidthVal,lHeightVal)); bSuccess = ::StretchDIBits(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
ScaledWidth, // nDestWidth
ScaledHeight, // nDestHeight
lpDIBRect->left, // SrcX
lpDIBRect->top, // SrcY
RECTWIDTH(lpDIBRect), // wSrcWidth
RECTHEIGHT(lpDIBRect), // wSrcHeight
m_pBits, // lpBits
m_pBMI, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
// update outline areas
// Invalidated right side rect
RECT WindowRect; WindowRect.top = lpDCRect->top; WindowRect.left = lpDCRect->left + ScaledWidth; WindowRect.right = lpDCRect->right; WindowRect.bottom = lpDCRect->bottom;
HBRUSH hBrush = CreateSolidBrush(GetBkColor(hDC)); FillRect(hDC,&WindowRect,hBrush);
// Invalidated bottom rect
WindowRect.top = lpDCRect->top + ScaledHeight; WindowRect.left = lpDCRect->left; WindowRect.right = lpDCRect->left + ScaledWidth; WindowRect.bottom = lpDCRect->bottom;
FillRect(hDC,&WindowRect,hBrush); DeleteObject(hBrush); } // Reselect old palette
if (hOldPal != NULL) { ::SelectPalette(hDC, hOldPal, TRUE); } return bSuccess; }
/**************************************************************************\
* CDib::CreatePalette() * * Creates a valid palette using the current DIB data * * * Arguments: * * none * * Return Value: * * status * * History: * * 2/14/1999 Original Version * \**************************************************************************/ BOOL CDib::CreatePalette() { if (!m_pBMI) return FALSE;
//get the number of colors in the DIB
WORD wNumColors = NumColors();
if (wNumColors != 0) { // allocate memory block for logical palette
HANDLE hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*wNumColors);
// if not enough memory, clean up and return NULL
if (hLogPal == 0) return FALSE;
LPLOGPALETTE lpPal = (LPLOGPALETTE)::GlobalLock((HGLOBAL)hLogPal);
// set version and number of palette entries
lpPal->palVersion = PALVERSION; lpPal->palNumEntries = (WORD)wNumColors;
for (int i = 0; i < (int)wNumColors; i++) { lpPal->palPalEntry[i].peRed = m_pBMI->bmiColors[i].rgbRed; lpPal->palPalEntry[i].peGreen = m_pBMI->bmiColors[i].rgbGreen; lpPal->palPalEntry[i].peBlue = m_pBMI->bmiColors[i].rgbBlue; lpPal->palPalEntry[i].peFlags = 0; }
// create the palette and get handle to it
if (m_pPalette) { m_pPalette->DeleteObject(); delete m_pPalette; } m_pPalette = new CPalette; BOOL bResult = m_pPalette->CreatePalette(lpPal); ::GlobalUnlock((HGLOBAL) hLogPal); ::GlobalFree((HGLOBAL) hLogPal); return bResult; }
return TRUE; }
/**************************************************************************\
* CDib::Width * * Returns DIB's width in pixels * * * Arguments: * * none * * Return Value: * * DWORD * * History: * * 2/14/1999 Original Version * \**************************************************************************/ DWORD CDib::Width() const { if (!m_pBMI) return 0; return m_pBMI->bmiHeader.biWidth; }
/**************************************************************************\
* CDib::Height() * * Returns DIB's height in pixels * * * Arguments: * * none * * Return Value: * * DWORD * * History: * * 2/14/1999 Original Version * \**************************************************************************/ DWORD CDib::Height() const { if (!m_pBMI) return 0; return m_pBMI->bmiHeader.biHeight; }
/**************************************************************************\
* CDib::PaletteSize() * * Returns the size of the DIB's palette * * * Arguments: * * none * * Return Value: * * WORD - Palette size in bytes * * History: * * 2/14/1999 Original Version * \**************************************************************************/ WORD CDib::PaletteSize() const { if (!m_pBMI) return 0; return NumColors() * sizeof(RGBQUAD); }
/**************************************************************************\
* CDib::NumColors() * * Returns the number of colors in DIB's palette * * * Arguments: * * none * * Return Value: * * WORD - Number of colors used * * History: * * 2/14/1999 Original Version * \**************************************************************************/ WORD CDib::NumColors() const { if (!m_pBMI) return 0;
WORD wBitCount; // DIB bit count
// 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.
DWORD dwClrUsed;
dwClrUsed = m_pBMI->bmiHeader.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.
wBitCount = m_pBMI->bmiHeader.biBitCount;
// 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; } }
/**************************************************************************\
* CDib::Save() * * Saves the DIB to a file. * note: the CFile must be opened before this call is made! * * * Arguments: * * CFile& - Open CFile * * Return Value: * * DWORD - Number of Bytes saved in the file * * History: * * 2/14/1999 Original Version * \**************************************************************************/ DWORD CDib::Save(CFile& file) const { BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
DWORD dwDIBSize;
if (m_pBMI == NULL) return 0;
// 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)&m_pBMI->bmiHeader + PaletteSize(); // Partial Calculation
// Now calculate the size of the image
if ((m_pBMI->bmiHeader.biCompression == BI_RLE8) || (m_pBMI->bmiHeader.biCompression == BI_RLE4)) { // It's an RLE bitmap, we can't calculate size, so trust the
// biSizeImage field
dwDIBSize += m_pBMI->bmiHeader.biSizeImage; } else { DWORD dwBmBitsSize; // Size of Bitmap Bits only
// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize = WIDTHBYTES((m_pBMI->bmiHeader.biWidth)*((DWORD)m_pBMI->bmiHeader.biBitCount)) * m_pBMI->bmiHeader.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).
m_pBMI->bmiHeader.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) + m_pBMI->bmiHeader.biSize + PaletteSize();
// Write the file header
file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER)); DWORD dwBytesSaved = sizeof(BITMAPFILEHEADER);
// Write the DIB header
UINT nCount = sizeof(BITMAPINFO) + (NumColors()-1)*sizeof(RGBQUAD); dwBytesSaved += nCount; file.Write(m_pBMI, nCount);
// Write the DIB bits
DWORD dwBytes = m_pBMI->bmiHeader.biBitCount * Width(); // Calculate the number of bytes per line
if (dwBytes%32 == 0) dwBytes /= 8; else dwBytes = dwBytes/8 + (32-dwBytes%32)/8 + (((32-dwBytes%32)%8 > 0) ? 1 : 0); nCount = dwBytes * Height(); dwBytesSaved += nCount; file.WriteHuge(m_pBits, nCount); return dwBytesSaved; }
/**************************************************************************\
* CDib::Read() * * Reads from a File into DIB form * Note: the CFile must be opened before this call is made! * * Arguments: * * CFile& - Open CFile * FileType - BMP_IMAGE, TIFF_IMAGE * * Return Value: * * DWORD - Number of bytes read from the CFile * * * History: * * 2/14/1999 Original Version * \**************************************************************************/ DWORD CDib::Read(CFile& file,int FileType) { DWORD dwReadBytes = 0;
// Ensures no memory leaks will occur
Free(); if (FileType == TIFF_IMAGE) { DWORD dwCurrentFileOffset = 0; DWORD dwStripByteCountOffset = 0; DWORD dwStripOffset = 0;
// TIFF variables
TIFFFILEHEADER tfHeader; TIFFTAG tTag; short TagCount = 0;
dwReadBytes = file.Read(&tfHeader,sizeof(TIFFFILEHEADER)); if (dwReadBytes != sizeof(TIFFFILEHEADER)) { AfxMessageBox("Error reading TIFF file header"); return 0; } dwCurrentFileOffset += dwReadBytes;
if (tfHeader.tfType != 42) { AfxMessageBox("Invalid TIFF format"); return 0; }
if (tfHeader.tfByteOrder[0] != 'I' && tfHeader.tfByteOrder[1] != 'I') { AfxMessageBox("Invalid TIFF format not 'II'"); return 0; }
//
// move file pointer to TAG offset
//
dwCurrentFileOffset = file.Seek(tfHeader.tfOffset,CFile::begin);
dwReadBytes = file.Read(&TagCount,sizeof(short)); if (dwReadBytes != sizeof(short)) { AfxMessageBox("Error reading Number of TIFF TAGS"); return 0; } dwCurrentFileOffset += dwReadBytes;
if (TagCount <=0) { AfxMessageBox("Number of TIFF TAGS must be 1 or more.."); return 0; }
TIFFTODIBDATA TiffToDIBData; long tempOffset = 0; int ValueCount = 0;
memset(&TiffToDIBData,0,sizeof(TIFFTODIBDATA)); for (int i = 1;i<=TagCount;i++) { dwReadBytes = file.Read(&tTag,sizeof(TIFFTAG)); if (dwReadBytes != sizeof(TIFFTAG)) { AfxMessageBox("Error reading TIFF TAGS"); return 0; } switch (tTag.ttTag) { case TIFF_NEWSUBFILETYPE: break; case TIFF_IMAGEWIDTH: TiffToDIBData.bmiHeader.biWidth = tTag.ttOffset; break; case TIFF_LENGTH: TiffToDIBData.bmiHeader.biHeight = tTag.ttOffset; break; case TIFF_BITSPERSAMPLE: if (tTag.ttCount == 3) TiffToDIBData.bmiHeader.biBitCount = 24; else TiffToDIBData.bmiHeader.biBitCount = (unsigned short)tTag.ttOffset; break; case TIFF_COMPRESSION: TiffToDIBData.CompressionType = tTag.ttOffset; break; case TIFF_PHOTOINTERP: break; case TIFF_IMAGEDESCRIPTION: tempOffset = dwCurrentFileOffset; file.Seek(tTag.ttOffset,CFile::begin); file.Read(TiffToDIBData.Description,sizeof(tTag.ttCount)); file.Seek(tempOffset,CFile::begin); break; case TIFF_STRIPOFFSETS: TiffToDIBData.StripOffsets = tTag.ttOffset; TiffToDIBData.OffsetCount = tTag.ttCount; TiffToDIBData.pStripOffsets = (long*)GlobalAlloc(GPTR,sizeof(long) * tTag.ttCount); if (tTag.ttCount == 1) { //
// we only have one huge strip
//
TiffToDIBData.pStripOffsets[0] = tTag.ttOffset; } else { //
// we have multiple strips
//
tempOffset = dwCurrentFileOffset; file.Seek(tTag.ttOffset,CFile::begin); file.Read(TiffToDIBData.pStripOffsets,sizeof(long) * tTag.ttCount); file.Seek(tempOffset,CFile::begin); } break; case TIFF_ORIENTATION: break; case TIFF_SAMPLESPERPIXEL: break; case TIFF_ROWSPERSTRIP: TiffToDIBData.RowsPerStrip = tTag.ttOffset; break; case TIFF_STRIPBYTECOUNTS: TiffToDIBData.StripByteCounts = tTag.ttOffset; TiffToDIBData.pStripByteCountsOffsets = (long*)GlobalAlloc(GPTR,sizeof(long) * tTag.ttCount); if (tTag.ttCount == 1) { //
// we only have one huge strip
//
TiffToDIBData.pStripByteCountsOffsets[0] = tTag.ttOffset; } else { //
// we have multiple strips
//
tempOffset = dwCurrentFileOffset; file.Seek(tTag.ttOffset,CFile::begin); file.Read(TiffToDIBData.pStripByteCountsOffsets,sizeof(long) * tTag.ttCount); file.Seek(tempOffset,CFile::begin); } break; case TIFF_XRESOLUTION: tempOffset = dwCurrentFileOffset; file.Seek(tTag.ttOffset,CFile::begin); file.Read(&TiffToDIBData.xResolution,sizeof(TIFFRATIONAL)); file.Seek(tempOffset,CFile::begin); break; case TIFF_YRESOLUTION: tempOffset = dwCurrentFileOffset; file.Seek(tTag.ttOffset,CFile::begin); file.Read(&TiffToDIBData.yResolution,sizeof(TIFFRATIONAL)); file.Seek(tempOffset,CFile::begin); break; case TIFF_RESOLUTIONUNIT: TiffToDIBData.ResolutionUnit = tTag.ttOffset; break; case TIFF_SOFTWARE: tempOffset = dwCurrentFileOffset; file.Seek(tTag.ttOffset,CFile::begin); file.Read(TiffToDIBData.Software,sizeof(tTag.ttCount)); file.Seek(tempOffset,CFile::begin); break; default: break; } dwCurrentFileOffset += dwReadBytes; }
//
// read next Tagcount to see if there are more TAGS
//
dwReadBytes = file.Read(&TagCount,sizeof(short)); if (dwReadBytes != sizeof(short)) { AfxMessageBox("Error reading Number of TIFF TAGS"); return 0; }
//
// if there are more tags exit for now..
//
if (TagCount >0) { //AfxMessageBox("There are more TIFF TAGS in this file");
//return;
}
//
// calculate the rest of the TiffToDIBData
//
int BytesPerPixel = 0; //
// 8-bit DATA
//
if (TiffToDIBData.bmiHeader.biBitCount == 8) { BytesPerPixel = 1; if (TiffToDIBData.ColorsUsed == 0) TiffToDIBData.bmiHeader.biClrUsed = 256; else TiffToDIBData.bmiHeader.biClrUsed = TiffToDIBData.ColorsUsed; } //
// 24-bit DATA
//
else if (TiffToDIBData.bmiHeader.biBitCount == 24) { BytesPerPixel = 3; TiffToDIBData.bmiHeader.biClrUsed = 0; } //
// 4-bit DATA
//
else if (TiffToDIBData.bmiHeader.biBitCount == 4) { BytesPerPixel = 2; TiffToDIBData.bmiHeader.biClrUsed = 256; } //
// 1-bit DATA
//
else { BytesPerPixel = 0; TiffToDIBData.bmiHeader.biClrUsed = 2; } TiffToDIBData.bmiHeader.biSizeImage = WIDTHBYTES((TiffToDIBData.bmiHeader.biWidth)*((DWORD)TiffToDIBData.bmiHeader.biBitCount)) * TiffToDIBData.bmiHeader.biHeight; TiffToDIBData.bmiHeader.biPlanes = 1; TiffToDIBData.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //
// create Palette size if one exists
//
RGBQUAD* pPalette = NULL; long PaletteSize = 0; if (TiffToDIBData.bmiHeader.biClrUsed != 0) { PaletteSize = TiffToDIBData.bmiHeader.biClrUsed * sizeof(RGBQUAD); pPalette = (RGBQUAD*)GlobalAllocPtr(GHND, PaletteSize); if (pPalette == NULL) { AfxMessageBox("Failed to Create Palette"); return 0; } if (TiffToDIBData.bmiHeader.biBitCount == 8) { if (TiffToDIBData.ColorsUsed == 0) { //
// create a grayscale palette
//
for (int i = 0;i<(int)TiffToDIBData.bmiHeader.biClrUsed;i++) { pPalette[i].rgbRed = (BYTE)i; pPalette[i].rgbBlue = (BYTE)i; pPalette[i].rgbGreen = (BYTE)i; pPalette[i].rgbReserved = 0; } } else { //
// create the color palette from colormap
//
TiffToDIBData.bmiHeader.biClrUsed = TiffToDIBData.ColorsUsed; } } if (TiffToDIBData.bmiHeader.biBitCount == 1) { //
// create a black and white palette
//
pPalette[0].rgbRed = 0; pPalette[0].rgbBlue = 0; pPalette[0].rgbGreen = 0; pPalette[0].rgbReserved = 0;
pPalette[1].rgbRed = 255; pPalette[1].rgbBlue = 255; pPalette[1].rgbGreen = 255; pPalette[1].rgbReserved = 255; } }
BITMAPFILEHEADER bmfHeader; memset(&bmfHeader,0,sizeof(BITMAPFILEHEADER)); bmfHeader.bfType = DIB_HEADER_MARKER; bmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + PaletteSize + TiffToDIBData.bmiHeader.biSizeImage; bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+ PaletteSize;
// Allocate memory for DIB info header and possible palette
m_pBMI = (LPBITMAPINFO)GlobalAllocPtr(GHND, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER) + (PaletteSize*2)); if (m_pBMI == 0) return 0;
DWORD dwLength = file.GetLength(); m_pBits = (LPBYTE)GlobalAllocPtr(GHND, TiffToDIBData.bmiHeader.biSizeImage + PaletteSize); if (m_pBits == 0) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; return 0; } BYTE* pData = m_pBits;
//
// set line width (DWORD aligned length)
//
long LineWidth = TiffToDIBData.bmiHeader.biSizeImage/TiffToDIBData.bmiHeader.biHeight;
DWORD ImageByteCount = 0; for (i = 0;i < TiffToDIBData.OffsetCount;i++) { //
// seek to strip
//
file.Seek(TiffToDIBData.pStripOffsets[i],CFile::begin); //
// read strip data (numbytes from pStripBytesCounts.
//
file.ReadHuge(pData,TiffToDIBData.pStripByteCountsOffsets[i]); pData += TiffToDIBData.pStripByteCountsOffsets[i]; ImageByteCount+= TiffToDIBData.pStripByteCountsOffsets[i]; } BYTE ColorValue = 0; int LineCount = 1; pData = m_pBits;
//
// Swap Red and Blue values if the data is 24-BIT
//
if (TiffToDIBData.bmiHeader.biClrUsed == 0) { for (LONG i = 0; i < (LONG)TiffToDIBData.bmiHeader.biSizeImage; i += 3) { BYTE bTemp = pData[i]; pData[i] = pData[i + 2]; pData[i + 2] = bTemp; } }
// Write BITMAPINFOHEADER to member
memmove(m_pBMI,&TiffToDIBData.bmiHeader,sizeof(BITMAPINFOHEADER));
if (TiffToDIBData.bmiHeader.biClrUsed >0) { memmove(m_pBMI->bmiColors,pPalette,PaletteSize); }
if (TiffToDIBData.bmiHeader.biBitCount == 1) LineWidth = (long)ceil((float)TiffToDIBData.bmiHeader.biWidth/8.0f); else LineWidth = TiffToDIBData.bmiHeader.biWidth * BytesPerPixel;
pData = m_pBits; //
// check DWORD alignment of data
//
if ((LineWidth % sizeof(DWORD))) { //
// Pad data
//
int PaddedBytes = sizeof(DWORD) - (LineWidth % sizeof(DWORD)); LineCount = 1; BYTE* pCurrent = NULL; BYTE* pDest = NULL; for (LineCount = TiffToDIBData.bmiHeader.biHeight;LineCount > 1;LineCount--) { pCurrent = pData + (LineWidth*(LineCount - 1)); pDest = pCurrent + (PaddedBytes*(LineCount - 1)); memmove(pDest,pCurrent,(LineWidth + PaddedBytes)); } }
if (pPalette) GlobalFreePtr(pPalette); if (TiffToDIBData.pStripByteCountsOffsets != NULL) GlobalFree(TiffToDIBData.pStripByteCountsOffsets); if (TiffToDIBData.pStripOffsets != NULL) GlobalFree(TiffToDIBData.pStripOffsets); //
// flip the data because we are converting it
// to DIB form
//
Flip(m_pBits); CreatePalette(); } else { BITMAPFILEHEADER bmfHeader;
// Go read the DIB file header and check if it's valid.
if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader)) return 0; if (bmfHeader.bfType != DIB_HEADER_MARKER) return 0; dwReadBytes = sizeof(bmfHeader);
// Allocate memory for DIB info header and possible palette
m_pBMI = (LPBITMAPINFO)GlobalAllocPtr(GHND, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER) + 256*sizeof(RGBQUAD)); if (m_pBMI == 0) return 0;
// Read header.
if (file.Read(m_pBMI, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER)) != (UINT)(bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER))) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; return 0; } dwReadBytes += bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER);
DWORD dwLength = file.GetLength(); // Go read the bits.
m_pBits = (LPBYTE)GlobalAllocPtr(GHND, dwLength - bmfHeader.bfOffBits); if (m_pBits == 0) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; return 0; }
if (file.ReadHuge(m_pBits, dwLength-bmfHeader.bfOffBits) != (dwLength - bmfHeader.bfOffBits)) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; GlobalFreePtr(m_pBits); m_pBits = NULL; return 0; } dwReadBytes += dwLength - bmfHeader.bfOffBits;
CreatePalette(); } return dwReadBytes; }
/**************************************************************************\
* CDib::ReadFromHGLOBAL() * * Reads a global chunk of memory into DIB form * * * Arguments: * * hGlobal - Global block of memory * FileType - BMP_IMAGE, TIFF_IMAGE * * Return Value: * * status * * History: * * 2/14/1999 Original Version * \**************************************************************************/ BOOL CDib::ReadFromHGLOBAL(HGLOBAL hGlobal,int FileType) { Free(); if (hGlobal == NULL) return FALSE; if (FileType == TIFF_IMAGE) { LPBYTE pSrcDib = (LPBYTE)GlobalLock(hGlobal);
TIFFFILEHEADER* ptfHeader = NULL; ptfHeader = (TIFFFILEHEADER*)pSrcDib; LPBYTE pPtr = pSrcDib; LPBYTE ptempPtr = NULL; DWORD dwCurrentFileOffset = 0; DWORD dwStripByteCountOffset = 0; DWORD dwStripOffset = 0;
// TIFF variables
TIFFTAG tTag; short TagCount = 0;
if (ptfHeader->tfType != 42) { AfxMessageBox("Invalid TIFF format"); return 0; }
if (ptfHeader->tfByteOrder[0] != 'I' && ptfHeader->tfByteOrder[1] != 'I') { AfxMessageBox("Invalid TIFF format not 'II'"); return 0; }
//
// move pointer to TAG offset
//
pPtr += ptfHeader->tfOffset;
memmove(&TagCount,pPtr,sizeof(short)); pPtr += sizeof(short);
if (TagCount <=0) { AfxMessageBox("Number of TIFF TAGS must be 1 or more.."); return 0; }
TIFFTODIBDATA TiffToDIBData; long tempOffset = 0; int ValueCount = 0;
memset(&TiffToDIBData,0,sizeof(TIFFTODIBDATA)); for (int i = 1;i<=TagCount;i++) { memmove(&tTag,pPtr,sizeof(TIFFTAG)); pPtr += sizeof(TIFFTAG);
switch (tTag.ttTag) { case TIFF_NEWSUBFILETYPE: break; case TIFF_IMAGEWIDTH: TiffToDIBData.bmiHeader.biWidth = tTag.ttOffset; break; case TIFF_LENGTH: TiffToDIBData.bmiHeader.biHeight = tTag.ttOffset; break; case TIFF_BITSPERSAMPLE: if (tTag.ttCount == 3) TiffToDIBData.bmiHeader.biBitCount = 24; else TiffToDIBData.bmiHeader.biBitCount = (unsigned short)tTag.ttOffset; break; case TIFF_COMPRESSION: TiffToDIBData.CompressionType = tTag.ttOffset; break; case TIFF_PHOTOINTERP: break; case TIFF_IMAGEDESCRIPTION: ptempPtr = pPtr; // save current pointer
pPtr = pSrcDib; // move pointer to start of data
pPtr += tTag.ttOffset; // seek to offset
memmove(TiffToDIBData.Description,pPtr,sizeof(tTag.ttCount)); // read data
pPtr = ptempPtr; // move pointer back to org. position
break; case TIFF_STRIPOFFSETS: TiffToDIBData.StripOffsets = tTag.ttOffset; TiffToDIBData.OffsetCount = tTag.ttCount; TiffToDIBData.pStripOffsets = (long*)GlobalAlloc(GPTR,sizeof(long) * tTag.ttCount); if (tTag.ttCount == 1) { //
// we only have one huge strip
//
TiffToDIBData.pStripOffsets[0] = tTag.ttOffset; } else { //
// we have multiple strips
//
ptempPtr = pPtr; // save current pointer
pPtr = pSrcDib; // move pointer to start of data
pPtr += tTag.ttOffset; // seek to offset
memmove(TiffToDIBData.pStripOffsets,pPtr,sizeof(long) * tTag.ttCount); // read data
pPtr = ptempPtr; // move pointer back to org. position
} break; case TIFF_ORIENTATION: break; case TIFF_SAMPLESPERPIXEL: break; case TIFF_ROWSPERSTRIP: TiffToDIBData.RowsPerStrip = tTag.ttOffset; break; case TIFF_STRIPBYTECOUNTS: TiffToDIBData.StripByteCounts = tTag.ttOffset; TiffToDIBData.pStripByteCountsOffsets = (long*)GlobalAlloc(GPTR,sizeof(long) * tTag.ttCount); if (tTag.ttCount == 1) { //
// we only have one huge strip
//
TiffToDIBData.pStripByteCountsOffsets[0] = tTag.ttOffset; } else { //
// we have multiple strips
//
ptempPtr = pPtr; // save current pointer
pPtr = pSrcDib; // move pointer to start of data
pPtr += tTag.ttOffset; // seek to offset
memmove(TiffToDIBData.pStripByteCountsOffsets,pPtr,sizeof(long) * tTag.ttCount); // read data
pPtr = ptempPtr; // move pointer back to org. position
} break; case TIFF_XRESOLUTION: ptempPtr = pPtr; // save current pointer
pPtr = pSrcDib; // move pointer to start of data
pPtr += tTag.ttOffset; // seek to offset
memmove(&TiffToDIBData.xResolution,pPtr,sizeof(TIFFRATIONAL)); // read data
pPtr = ptempPtr; // move pointer back to org. position
break; case TIFF_YRESOLUTION: ptempPtr = pPtr; // save current pointer
pPtr = pSrcDib; // move pointer to start of data
pPtr += tTag.ttOffset; // seek to offset
memmove(&TiffToDIBData.yResolution,pPtr,sizeof(TIFFRATIONAL)); // read data
pPtr = ptempPtr; // move pointer back to org. position
break; case TIFF_RESOLUTIONUNIT: TiffToDIBData.ResolutionUnit = tTag.ttOffset; break; case TIFF_SOFTWARE: ptempPtr = pPtr; // save current pointer
pPtr = pSrcDib; // move pointer to start of data
pPtr += tTag.ttOffset; // seek to offset
memmove(TiffToDIBData.Software,pPtr,sizeof(tTag.ttCount)); // read data
pPtr = ptempPtr; // move pointer back to org. position
break; default: break; } }
//
// read next Tagcount to see if there are more TAGS
//
//dwReadBytes = file.Read(&TagCount,sizeof(short));
//if(dwReadBytes != sizeof(short))
//{
// AfxMessageBox("Error reading Number of TIFF TAGS");
// return 0;
//}
//
// if there are more tags exit for now..
//
//if(TagCount >0)
//{
//AfxMessageBox("There are more TIFF TAGS in this file");
//return;
//}
//
// calculate the rest of the TiffToDIBData
//
int BytesPerPixel = 0; //
// 8-bit DATA
//
if (TiffToDIBData.bmiHeader.biBitCount == 8) { BytesPerPixel = 1; if (TiffToDIBData.ColorsUsed == 0) TiffToDIBData.bmiHeader.biClrUsed = 256; else TiffToDIBData.bmiHeader.biClrUsed = TiffToDIBData.ColorsUsed; } //
// 24-bit DATA
//
else if (TiffToDIBData.bmiHeader.biBitCount == 24) { BytesPerPixel = 3; TiffToDIBData.bmiHeader.biClrUsed = 0; } //
// 4-bit DATA
//
else if (TiffToDIBData.bmiHeader.biBitCount == 4) { BytesPerPixel = 2; TiffToDIBData.bmiHeader.biClrUsed = 256; } //
// 1-bit DATA
//
else { BytesPerPixel = 0; TiffToDIBData.bmiHeader.biClrUsed = 2; } TiffToDIBData.bmiHeader.biSizeImage = WIDTHBYTES((TiffToDIBData.bmiHeader.biWidth)*((DWORD)TiffToDIBData.bmiHeader.biBitCount)) * TiffToDIBData.bmiHeader.biHeight; TiffToDIBData.bmiHeader.biPlanes = 1; TiffToDIBData.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //
// create Palette size if one exists
//
RGBQUAD* pPalette = NULL; long PaletteSize = 0; if (TiffToDIBData.bmiHeader.biClrUsed != 0) { PaletteSize = TiffToDIBData.bmiHeader.biClrUsed * sizeof(RGBQUAD); pPalette = (RGBQUAD*)GlobalAllocPtr(GHND, PaletteSize); if (pPalette == NULL) { AfxMessageBox("Failed to Create Palette"); return 0; } if (TiffToDIBData.bmiHeader.biBitCount == 8) { if (TiffToDIBData.ColorsUsed == 0) { //
// create a grayscale palette
//
for (int i = 0;i<(int)TiffToDIBData.bmiHeader.biClrUsed;i++) { pPalette[i].rgbRed = (BYTE)i; pPalette[i].rgbBlue = (BYTE)i; pPalette[i].rgbGreen = (BYTE)i; pPalette[i].rgbReserved = 0; } } else { //
// create the color palette from colormap
//
TiffToDIBData.bmiHeader.biClrUsed = TiffToDIBData.ColorsUsed; } } if (TiffToDIBData.bmiHeader.biBitCount == 1) { //
// create a black and white palette
//
pPalette[0].rgbRed = 0; pPalette[0].rgbBlue = 0; pPalette[0].rgbGreen = 0; pPalette[0].rgbReserved = 0;
pPalette[1].rgbRed = 255; pPalette[1].rgbBlue = 255; pPalette[1].rgbGreen = 255; pPalette[1].rgbReserved = 255; } }
BITMAPFILEHEADER bmfHeader; memset(&bmfHeader,0,sizeof(BITMAPFILEHEADER)); bmfHeader.bfType = DIB_HEADER_MARKER; bmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + PaletteSize + TiffToDIBData.bmiHeader.biSizeImage; bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+ PaletteSize;
// Allocate memory for DIB info header and possible palette
m_pBMI = (LPBITMAPINFO)GlobalAllocPtr(GHND, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER) + (PaletteSize*2)); if (m_pBMI == 0) return 0;
m_pBits = (LPBYTE)GlobalAllocPtr(GHND, TiffToDIBData.bmiHeader.biSizeImage + PaletteSize); if (m_pBits == 0) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; return 0; } BYTE* pData = m_pBits;
//
// set line width (DWORD aligned length)
//
long LineWidth = TiffToDIBData.bmiHeader.biSizeImage/TiffToDIBData.bmiHeader.biHeight;
DWORD ImageByteCount = 0; for (i = 0;i < TiffToDIBData.OffsetCount;i++) { //
// seek to strip
//
pPtr = pSrcDib; // move pointer to start of data
pPtr += TiffToDIBData.pStripOffsets[i]; // seek to offset
//
// read strip data (numbytes from pStripBytesCounts.
//
CopyMemory(pData,pPtr,TiffToDIBData.pStripByteCountsOffsets[i]); // read data
pData += TiffToDIBData.pStripByteCountsOffsets[i]; ImageByteCount+= TiffToDIBData.pStripByteCountsOffsets[i]; } BYTE ColorValue = 0; int LineCount = 1; pData = m_pBits;
if (TiffToDIBData.bmiHeader.biClrUsed ==0) { while (LineCount <= TiffToDIBData.bmiHeader.biHeight) { //
// swap red and blue values
// if the data is 24-bit
//
for (int i = 0;i<LineWidth;i+=3) { ColorValue = pData[i]; pData[i] = pData[i+2]; pData[i+2] = ColorValue; }
pData += LineWidth; LineCount++; } }
// Write BITMAPINFOHEADER to member
memmove(m_pBMI,&TiffToDIBData.bmiHeader,sizeof(BITMAPINFOHEADER));
if (TiffToDIBData.bmiHeader.biClrUsed >0) { memmove(m_pBMI->bmiColors,pPalette,PaletteSize); }
if (TiffToDIBData.bmiHeader.biBitCount == 1) LineWidth = (long)ceil((float)TiffToDIBData.bmiHeader.biWidth/8.0f); else LineWidth = TiffToDIBData.bmiHeader.biWidth * BytesPerPixel;
pData = m_pBits; //
// check DWORD alignment of data
//
if ((LineWidth % sizeof(DWORD))) { //
// Pad data
//
int PaddedBytes = sizeof(DWORD) - (LineWidth % sizeof(DWORD)); LineCount = 1; BYTE* pCurrent = NULL; BYTE* pDest = NULL; for (LineCount = TiffToDIBData.bmiHeader.biHeight;LineCount > 1;LineCount--) { pCurrent = pData + (LineWidth*(LineCount - 1)); pDest = pCurrent + (PaddedBytes*(LineCount - 1)); memmove(pDest,pCurrent,(LineWidth + PaddedBytes)); } }
if (pPalette) GlobalFreePtr(pPalette); if (TiffToDIBData.pStripByteCountsOffsets != NULL) GlobalFree(TiffToDIBData.pStripByteCountsOffsets); if (TiffToDIBData.pStripOffsets != NULL) GlobalFree(TiffToDIBData.pStripOffsets); //
// flip the data because we are converting it
// to DIB form
//
Flip(m_pBits); CreatePalette();
} else { BOOL bTopDown = FALSE; LPBYTE pSrcDib = (LPBYTE)GlobalLock(hGlobal); LPBITMAPINFO pbmi = NULL; pbmi = (LPBITMAPINFO)pSrcDib;
// Allocate memory for DIB
m_pBMI = (LPBITMAPINFO)GlobalAllocPtr(GHND, (sizeof(BITMAPINFO) + pbmi->bmiHeader.biClrUsed * sizeof(RGBQUAD))); if (m_pBMI == 0) return 0;
// copy header.
memmove(m_pBMI,pbmi,(sizeof(BITMAPINFO) + pbmi->bmiHeader.biClrUsed * sizeof(RGBQUAD)));
DWORD dwLength = m_pBMI->bmiHeader.biSizeImage;
// if a TOP_DOWN_DIB comes in..adjust it to be displayed
// this is not a normal thing to do here. It is only so that the
// image can be displayed for debug reasons.
if (m_pBMI->bmiHeader.biHeight < 1) { bTopDown = TRUE; m_pBMI->bmiHeader.biHeight = -m_pBMI->bmiHeader.biHeight; }
// Alloc memory for bits
m_pBits = (LPBYTE)GlobalAllocPtr(GHND, dwLength); if (m_pBits == 0) { GlobalFreePtr(m_pBMI); m_pBMI = NULL; return 0; } // move pointer past BITMAPINFOHEADER to bits
pSrcDib+=sizeof(BITMAPINFOHEADER); pSrcDib+=(m_pBMI->bmiHeader.biClrUsed * sizeof(RGBQUAD));
if (bTopDown) { // flip bitmap and copy bits
Flip(pSrcDib); memmove(m_pBits,pSrcDib,dwLength); } else // copy bits
memmove(m_pBits,pSrcDib,dwLength);
CreatePalette(); GlobalUnlock(hGlobal); } return TRUE; }
/**************************************************************************\
* CDib::GotImage() * * Check DIB to see is memory has been allocated and used. * * * Arguments: * * none * * Return Value: * * status * * History: * * 2/14/1999 Original Version * \**************************************************************************/ BOOL CDib::GotImage() { // Make sure all member data that might have been allocated exist.
if (m_pBits) if (m_pBMI) return TRUE; return FALSE; }
/**************************************************************************\
* CDib::ReadFromBMPFile() * * Opens and Reads data from a BMP file into DIB form * * * Arguments: * * LPSTR- filename (Filename to be opened and read) * * Return Value: * * void * * History: * * 2/14/1999 Original Version * \**************************************************************************/
void CDib::ReadFromBMPFile(LPSTR filename) { CFile ImageFile; // open & read image file
ImageFile.Open(filename,CFile::modeRead,NULL); Read(ImageFile,BMP_IMAGE); // close image file
ImageFile.Close(); }
/**************************************************************************\
* CDib::ReadFromBMPFile() * * Opens and Reads data from a BMP file into DIB form * * * Arguments: * * CString- filename (Filename to be opened and read) * * Return Value: * * void * * History: * * 2/14/1999 Original Version * \**************************************************************************/ void CDib::ReadFromBMPFile(CString filename) { CFile ImageFile; // open & read image file
ImageFile.Open(filename,CFile::modeRead,NULL); Read(ImageFile,BMP_IMAGE); // close image file
ImageFile.Close(); } /**************************************************************************\
* CDib::ReadFromTIFFFile() * * Opens and Reads data from a TIFF file into DIB form * * * Arguments: * * CString- filename (Filename to be opened and read) * * Return Value: * * void * * History: * * 4/14/1999 Original Version * \**************************************************************************/ void CDib::ReadFromTIFFFile(CString filename) { CFile ImageFile; // open & read image file
ImageFile.Open(filename,CFile::modeRead,NULL);
Read(ImageFile,TIFF_IMAGE); // close image file
ImageFile.Close(); } /**************************************************************************\
* CDib::Flip() * * Flips a DIB, TOPDOWN to DIB conversion * * * Arguments: * * pSrcData - TOPDOWN DIB to be flipped * * Return Value: * * status * * History: * * 2/14/1999 Original Version * \**************************************************************************/ BOOL CDib::Flip(BYTE* pSrcData) { LONG Width = 0; LONG Height = 0; LONG Linelength = 0; LONG BitCount = 0;
Width = m_pBMI->bmiHeader.biWidth; Height = m_pBMI->bmiHeader.biHeight; BitCount = m_pBMI->bmiHeader.biBitCount;
Linelength = (((Width*BitCount+31)/32)*4);
LONG nLineWidthInBytes = Linelength; PBYTE pLine = new BYTE[nLineWidthInBytes]; for (int i=0;i<Height/2;i++) { PBYTE pSrc = pSrcData + (i * nLineWidthInBytes); PBYTE pDst = pSrcData + ((Height-i-1) * nLineWidthInBytes); CopyMemory( pLine, pSrc, nLineWidthInBytes ); CopyMemory( pSrc, pDst, nLineWidthInBytes ); CopyMemory( pDst, pLine, nLineWidthInBytes ); } delete[] pLine; return TRUE; }
/**************************************************************************\
* CDib::Dump(), CopyToHandle(), ReadFromHandle(), and Serialize() * * Misc. member functions that are not used at this time * * * Arguments: * * - * * Return Value: * * - * * History: * * 2/14/1999 Original Version * \**************************************************************************/
#ifdef _DEBUG
// Dump
void CDib::Dump(CDumpContext& dc) const { CObject::Dump(dc); } #endif
// CopyToHandle
HGLOBAL CDib::CopyToHandle() const { CSharedFile file; try { if (Save(file)==0) return 0; } catch (CFileException* e) { e->Delete(); return 0; }
return file.Detach(); }
// ReadFromHandle
DWORD CDib::ReadFromHandle(HGLOBAL hGlobal) { CSharedFile file; file.SetHandle(hGlobal, FALSE); DWORD dwResult = Read(file,BMP_IMAGE); file.Detach(); return dwResult; }
// Serialize
void CDib::Serialize(CArchive& ar) { CFile* pFile = ar.GetFile(); ASSERT(pFile != NULL); if (ar.IsStoring()) { // storing code
Save(*pFile); } else { // loading code
Read(*pFile,BMP_IMAGE); } }
|