⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tga.cpp

📁 《精通 vc++ 图像编程》的源代码
💻 CPP
字号:
// Tga.cpp: implementation of the CTga class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Tga.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTga::CTga()
{
	m_pDib = NULL;
}

CTga::CTga(CDib *pDib)
{
	m_pDib = NULL;
	SetDib(pDib);
}

CTga::~CTga()
{
	if (m_pDib != NULL)
		delete m_pDib;
}

BOOL CTga::Load(LPCTSTR lpstrFileName)
{
	CFile file;
	if (! file.Open(lpstrFileName, CFile::modeRead))
		return FALSE;

	HDIB hDIB = ReadTGAFile(file);

	file.Close();

	// create DIB
	if (m_pDib != NULL)
		delete m_pDib;

	m_pDib = new CDib();
	m_pDib->Attach(hDIB);

	return TRUE;
}

BOOL CTga::Save(LPCTSTR lpstrFileName, CDib* pDib)
{
	if (pDib == NULL)
		pDib = m_pDib;
	if (pDib == NULL)
		return FALSE;

	CDib *pTmpDib = pDib->Clone();

	if (pTmpDib->GetBitCount() != 24)
	{
		pTmpDib->ConvertFormat(24);
	}

	HDIB hDIB = pTmpDib->GetHandle();
	if (hDIB == NULL)
	{
		delete pTmpDib;
		return FALSE;
	}

	CFile file;
	if (! file.Open(lpstrFileName, CFile::modeCreate | CFile::modeWrite))
	{
		delete pTmpDib;
		return FALSE;
	}

	if (! SaveTGAFile(hDIB, file))
	{
		delete pTmpDib;
		return FALSE;
	}

	file.Close();
	delete pTmpDib;

	return TRUE;
}

/*************************************************************************
*
*  Function:  ReadTGAFile (CFile&)
*  
*  Purpose:  Reads in the specified targe file into a global chunk of
* 	  	     memory.
*          
*            Returns:  A handle to a dib (hDIB) if successful.
*            NULL if an error occurs.
*              
**************************************************************************/
          
HDIB CTga::ReadTGAFile(CFile& file)
{
  //Determine if the file is in the original TGA format
  //or the new TGA format i.e. post September 1989
  DWORD dwFileLength = file.GetLength();
  if (dwFileLength == 0)
    return NULL;
  file.Seek(dwFileLength - sizeof(TGA_FILE_FOOTER), CFile::begin);
  TGA_FILE_FOOTER fileFooter;
  file.Read(&fileFooter, sizeof(TGA_FILE_FOOTER));
  BOOL bNewTGAFormat = FALSE;
  if (strcmp(fileFooter.cSignature, "TRUEVISION-XFILE.") == 0)
    bNewTGAFormat = TRUE;

  //Read in the TGA file header
  TGA_FILE_HEADER fileHeader;                  
  file.SeekToBegin();
  file.Read(&fileHeader, sizeof(TGA_FILE_HEADER));

  //We only support 32 and 24 bit color depths
  if ((fileHeader.byPixelDepth != 32) &&
      (fileHeader.byPixelDepth != 24))
  {
    TRACE(_T("Bit depth is %d, which cannot be handled\n"), fileHeader.byPixelDepth);
    return NULL;
  }

  //now read in the image data
  if (fileHeader.byImageType != 2)
  {
    TRACE(_T("Image type is not an uncompressed true-color image, instead it is %d\n"), fileHeader.byImageType);
    return NULL;
  }

  //check that the Color map type is 0
  if (fileHeader.byColorMapType != 0)
  {
    TRACE(_T("Color map type is non zero in the TGA file header for this uncompressed true-color tga file, instead it is %d\n"), fileHeader.byColorMapType);
    return NULL;
  }      

  //Determine the end offset of the "Image Data"
  DWORD dwEndImageData = 0;
  if (bNewTGAFormat)
    dwEndImageData = fileFooter.lExtensionAreaOffset - 1;
  else
    dwEndImageData = dwFileLength;

  //Determine the start offset of the "Image Data" and the pointer to 
  //the color map
  DWORD dwStartImageData = sizeof(TGA_FILE_HEADER) + fileHeader.byIdLength;

  //Read in the image data
  DWORD dwImageSize = dwEndImageData - dwStartImageData;
  BYTE* pImageData = new BYTE[dwImageSize];
  file.Seek(dwStartImageData, CFile::begin);
  file.Read(pImageData, dwImageSize);

  // initializing incapsulated image with correct values
  BITMAPINFO bmi;
  BITMAPINFOHEADER& bih = bmi.bmiHeader;
  ZeroMemory(&bih, sizeof(BITMAPINFOHEADER));
  bih.biSize = sizeof(BITMAPINFOHEADER);
  bih.biWidth = fileHeader.nImageWidth;
  bih.biHeight = fileHeader.nImageHeight;
  bih.biCompression = BI_RGB;
  bih.biPlanes = 1;
  bih.biBitCount = 24;

  //Allocate a buffer to use for the transfer to DIB format
  DWORD imageSize = fileHeader.nImageHeight*(fileHeader.nImageWidth*3+((4-((fileHeader.nImageWidth*3)&3))&3));
  BYTE* pBmp = new BYTE[imageSize];

  //Determine the up/down and left/right ordering of the pixels
  BOOL bTopToBottom = (((fileHeader.byImageDescriptor >> 4) & 1) != 0);
  BOOL bLeftToRight = (((fileHeader.byImageDescriptor >> 5) & 1) != 0);

  //Copy the DIB bits from the user buffer into the DIB
  int nInBytesPerPel = fileHeader.byPixelDepth / 8;

  for (int j=0; j<fileHeader.nImageHeight; j++)
  {
    int nDepthInOffset = 0;
    if (bTopToBottom)
      nDepthInOffset = (fileHeader.nImageHeight - j - 1)*fileHeader.nImageWidth*nInBytesPerPel;
    else
      nDepthInOffset = j*fileHeader.nImageWidth*nInBytesPerPel;

    int nDepthOutOffset = j*WIDTHBYTES(fileHeader.nImageWidth*24);

    for (int i=0; i<fileHeader.nImageWidth; i++)
    {
      int nInOffset = 0;
      if (bTopToBottom)
      {
        if (bLeftToRight)
          nInOffset = nDepthInOffset + (fileHeader.nImageWidth - i - 1)*nInBytesPerPel;
        else
          nInOffset = nDepthInOffset + i*nInBytesPerPel;
      }
      else
      {
        if (bLeftToRight)
          nInOffset = nDepthInOffset + (fileHeader.nImageWidth - i - 1)*nInBytesPerPel;
        else
          nInOffset = nDepthInOffset + i*nInBytesPerPel;
      }

      int nOutOffset = nDepthOutOffset + i*3;

      if (nInBytesPerPel == 3 || nInBytesPerPel == 4)
      {
        pBmp[nOutOffset]   = pImageData[nInOffset];
        pBmp[nOutOffset+1] = pImageData[nInOffset+1];
        pBmp[nOutOffset+2]  = pImageData[nInOffset+2];
      }
      else
      {
        ASSERT(FALSE);
        break;
      }
    }
  }

  //Delete the memory used to load the targe prior to transfering to the DIB
	delete [] pImageData;

  // Allocate memory for DIB
  HDIB hDIB = (HDIB) ::GlobalAlloc(GHND, bih.biSize + imageSize);
  if (hDIB == 0)
  {
	  delete [] pBmp;
    return NULL;
  }
  LPSTR pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  if (pDIB == 0)
  {
	  delete [] pBmp;
    return NULL;
  }

  CopyMemory(pDIB, &bmi.bmiHeader, bih.biSize);
  CopyMemory(pDIB + bih.biSize, pBmp, imageSize);
  delete [] pBmp;

  ::GlobalUnlock((HGLOBAL) hDIB);
  return hDIB;
}

/*************************************************************************
*
* SaveTGAFile()
*
* Saves the specified DIB as a Targa into the specified CFile.  The CFile
* is opened and closed by the caller.
*
* Parameters:
*
* HDIB hDib - Handle to the dib to save
*
* CFile& file - open CFile used to save as Targa
*
* Return value: TRUE if successful, else FALSE or CFileException
*
*************************************************************************/

BOOL CTga::SaveTGAFile(HDIB hDib, CFile& file)
{
  BOOL bSuccess = TRUE;

  //No bitmap, then cannot save
  if (hDib == NULL)
    return FALSE;

  // Get a pointer to the DIB memory, the first of which contains
  // a BITMAPINFO structure
  LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
  if (lpBI == NULL)
    return FALSE;
   
  if (!IS_WIN30_DIB(lpBI))
  {
    TRACE(_T("Only Windows 3.0 DIB images can be saved as Targa!\n"));
    ::GlobalUnlock((HGLOBAL) hDib);
    return FALSE;  // It's an other-style DIB (save not supported)
  }

  if (lpBI->biBitCount != 24)
  {
    TRACE(_T("Only 16 million colors (24 bit) images can be saved as Targa!\n"));
    ::GlobalUnlock((HGLOBAL) hDib);
    return FALSE;
  }

  if (lpBI->biCompression != BI_RGB)
  {
    TRACE(_T("RLE-compressed images can't be saved as Targa!\n"));
    ::GlobalUnlock((HGLOBAL) hDib);
    return FALSE;
  }

  DWORD dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);  // Partial Calculation

  // Now calculate the size of the image

  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;

  TRY
  {
    //First write out the header
    TGA_FILE_HEADER fileHeader;                  
    ZeroMemory(&fileHeader, sizeof(TGA_FILE_HEADER));
    fileHeader.byImageType = 2;
    fileHeader.nImageWidth = (short) lpBI->biWidth;
    fileHeader.nImageHeight = (short) lpBI->biHeight;
    fileHeader.byPixelDepth = 24;
    file.SeekToBegin();
    file.Write(&fileHeader, sizeof(TGA_FILE_HEADER));

    //Allocate some memory to save the Dib bits into 
    BYTE* pImageData = (BYTE*)lpBI + lpBI->biSize;
    DWORD dwImageDataSize = lpBI->biWidth*lpBI->biHeight*3;
    BYTE* pBmp = new BYTE[dwImageDataSize];

    //Copy the Dib bits into the buffer we just allocated
    for (int j=0; j<lpBI->biHeight; j++)
    {
      int nDepthOffset = j*WIDTHBYTES(lpBI->biWidth*24);
      for (int i=0; i<lpBI->biWidth; i++)
      {
        int nOutputOffset = j*lpBI->biWidth*3 + i*3;
        int nInputOffset = nDepthOffset + i*3;
	      pBmp[nOutputOffset]	    = pImageData[nInputOffset];
	      pBmp[nOutputOffset+1]	= pImageData[nInputOffset+1];
	      pBmp[nOutputOffset+2]	= pImageData[nInputOffset+2];
      }
    }

    ::GlobalUnlock((HGLOBAL)hDib);

    //Write the image data to disk
    file.Write(pBmp, dwImageDataSize);

    //Free up the memory we used
    delete [] pBmp;
  }
  CATCH_ALL(e)
  {
    bSuccess = FALSE;
    TRACE(_T("Error storing TGA file!\n"));
  }
  END_CATCH_ALL

  return bSuccess;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -