You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
9.1 KiB
C++

// XTPGraphicBitmapPng.cpp : implementation of the CXTPGraphicBitmapPng class.
//
// This file is a part of the XTREME TOOLKITPRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "libpng\png.h"
#include "XTPGraphicBitmapPng.h"
//////////////////////////////////////////////////////////////////////////
// CXTPGraphicBitmapPng
CXTPGraphicBitmapPng::CXTPGraphicBitmapPng()
{
m_bAlpha = FALSE;
}
struct CXTPGraphicBitmapPng::CCallback
{
static void PNGAPI png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
CFile* pFile = (CFile*)png_ptr->io_ptr;
png_size_t sizeRead = (png_size_t)pFile->Read(data, (UINT)length);
if (sizeRead != length)
{
AfxThrowFileException(CFileException::endOfFile);
}
}
static void PNGAPI png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
CFile* pFile = (CFile*)png_ptr->io_ptr;
pFile->Write(data, (UINT)length);
}
static void PNGAPI png_flush(png_structp png_ptr)
{
CFile* pFile = (CFile*)png_ptr->io_ptr;
pFile->Flush();
}
static void PNGAPI png_cexcept_error(png_structp /*png_ptr*/, png_const_charp /*msg*/)
{
AfxThrowFileException(CFileException::badSeek);
}
static BOOL PNGAPI PngLoadImage(CFile* pFile, png_byte **ppbImageData,
png_uint_32 *piWidth, png_uint_32 *piHeight, int *piChannels, png_color *pBkgColor);
};
BOOL CXTPGraphicBitmapPng::CCallback::PngLoadImage(CFile* pFile, png_byte **ppbImageData,
png_uint_32 *piWidth, png_uint_32 *piHeight, int *piChannels, png_color *pBkgColor)
{
png_byte pbSig[8];
int iBitDepth;
int iColorType;
double dGamma;
png_color_16 *pBackground;
png_uint_32 ulChannels;
png_uint_32 ulRowBytes;
png_byte *pbImageData = *ppbImageData;
png_byte **ppbRowPointers = NULL;
png_uint_32 i;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
// open the PNG input file
if (!pFile)
{
*ppbImageData = pbImageData = NULL;
return FALSE;
}
pFile->Read(pbSig, 8);
if (!png_check_sig(pbSig, 8))
{
*ppbImageData = pbImageData = NULL;
return FALSE;
}
// create the two png(-info) structures
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
(png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
if (!png_ptr)
{
*ppbImageData = pbImageData = NULL;
return FALSE;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
*ppbImageData = pbImageData = NULL;
return FALSE;
}
TRY
{
// initialize the png structure
png_set_read_fn(png_ptr, (png_voidp)pFile, png_read_data);
png_set_sig_bytes(png_ptr, 8);
// read all PNG info up to image data
png_read_info(png_ptr, info_ptr);
// get width, height, bit-depth and color-type
png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth,
&iColorType, NULL, NULL, NULL);
// expand images of all color-type and bit-depth to 3x8 bit RGB images
// let the library process things like alpha, transparency, background
if (iBitDepth == 16)
png_set_strip_16(png_ptr);
if (iColorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (iBitDepth < 8)
png_set_expand(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
if (iColorType == PNG_COLOR_TYPE_GRAY ||
iColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
// set the background color to draw transparent and alpha images over.
if (png_get_bKGD(png_ptr, info_ptr, &pBackground))
{
png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
pBkgColor->red = (byte) pBackground->red;
pBkgColor->green = (byte) pBackground->green;
pBkgColor->blue = (byte) pBackground->blue;
}
else
{
pBkgColor = NULL;
}
// if required set gamma conversion
if (png_get_gAMA(png_ptr, info_ptr, &dGamma))
png_set_gamma(png_ptr, (double) 2.2, dGamma);
// after the transformations have been registered update info_ptr data
png_read_update_info(png_ptr, info_ptr);
// get again width, height and the new bit-depth and color-type
png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth,
&iColorType, NULL, NULL, NULL);
// row_bytes is the width x number of channels
ulRowBytes = png_get_rowbytes(png_ptr, info_ptr);
ulChannels = png_get_channels(png_ptr, info_ptr);
*piChannels = ulChannels;
// now we can allocate memory to store the image
if (pbImageData)
{
free (pbImageData);
pbImageData = NULL;
}
pbImageData = (png_byte*)malloc(ulRowBytes * (*piHeight) * sizeof(png_byte));
if (pbImageData == NULL)
{
AfxThrowFileException(CFileException::badSeek);
}
*ppbImageData = pbImageData;
// and allocate memory for an array of row-pointers
ppbRowPointers = (png_bytepp)malloc((*piHeight) * sizeof(png_bytep));
if (ppbRowPointers == NULL)
{
AfxThrowFileException(CFileException::badSeek);
}
// set the individual row-pointers to point at the correct offsets
for (i = 0; i < (*piHeight); i++)
ppbRowPointers[i] = pbImageData + i * ulRowBytes;
// now we can go ahead and just read the whole image
png_read_image(png_ptr, ppbRowPointers);
// read the additional chunks in the PNG file (not really needed)
png_read_end(png_ptr, NULL);
// and we're done
free (ppbRowPointers);
ppbRowPointers = NULL;
// yepp, done
}
CATCH (CFileException, e)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
*ppbImageData = pbImageData = NULL;
if (ppbRowPointers)
free (ppbRowPointers);
return FALSE;
}
END_CATCH
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return TRUE;
}
HBITMAP CXTPGraphicBitmapPng::ConvertToBitmap(BYTE* pbImage, CSize szImage, int cImgChannels) const
{
LONG xImg, yImg;
BYTE *src, *dst;
BYTE r, g, b, a;
BITMAPINFO bmi;
LPBYTE pBits;
HBITMAP hbm;
const int cDIChannels = 4;
UINT wImgRowBytes;
UINT wDIRowBytes;
// Initialize header to 0s.
ZeroMemory(&bmi, sizeof(bmi));
// Fill out the fields you care about.
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = szImage.cx;
bmi.bmiHeader.biHeight = -szImage.cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
hbm = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);
if (!hbm || !pBits)
{
return NULL;
}
wImgRowBytes = cImgChannels * szImage.cx;
wDIRowBytes = cDIChannels * szImage.cx;
// copy image to screen
for (yImg = 0; yImg < szImage.cy; yImg++)
{
src = pbImage + yImg * wImgRowBytes;
dst = pBits + yImg * wDIRowBytes;
for (xImg = 0; xImg < szImage.cx; xImg++)
{
r = *src++;
g = *src++;
b = *src++;
*dst++ = b;
*dst++ = g;
*dst++ = r;
a = 0;
if (cImgChannels == 4)
{
a = *src++;
}
*dst++ = a;
}
}
return hbm;
}
BOOL CXTPGraphicBitmapPng::LoadFromFile(LPCTSTR lpszFileName)
{
m_bAlpha = FALSE;
DeleteObject();
CFile file;
if (!file.Open(lpszFileName, CFile::modeRead))
{
return FALSE;
}
return LoadFromFile(&file);
}
BOOL CXTPGraphicBitmapPng::LoadFromResource(HMODULE hModule, HRSRC hRes)
{
m_bAlpha = FALSE;
DeleteObject();
if (!hRes)
return FALSE;
DWORD nBufferSize = ::SizeofResource(hModule, hRes);
HGLOBAL hMem= ::LoadResource(hModule, hRes);
if (!hMem)
return FALSE;
LPBYTE lpBuffer = (LPBYTE)LockResource(hMem);
if (!lpBuffer || nBufferSize < 10)
return FALSE;
CMemFile file(lpBuffer, nBufferSize);
return LoadFromFile(&file);
}
BOOL CXTPGraphicBitmapPng::LoadFromFile(CFile* pFile)
{
m_bAlpha = FALSE;
DeleteObject();
BYTE* pbImage = NULL;
png_uint_32 cxImgSize, cyImgSize;
int cImgChannels;
png_color bkgColor = {127, 127, 127};
if (!pFile)
return FALSE;
if (!CCallback::PngLoadImage(pFile, &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
{
if (pbImage)
{
free(pbImage);
return FALSE;
}
}
if (!pbImage)
return FALSE;
HBITMAP hBitmap = ConvertToBitmap(pbImage, CSize(cxImgSize, cyImgSize), cImgChannels);
free(pbImage);
if (!hBitmap)
return FALSE;
m_bAlpha = (cImgChannels == 4);
Attach(hBitmap);
return TRUE;
}
_XTP_EXT_CLASS int ZLibCompress( BYTE* dest, ULONG* destLen, const BYTE *source, ULONG sourceLen)
{
return compress( dest, destLen, source, sourceLen);
}
_XTP_EXT_CLASS ULONG ZLibCompressBound(ULONG sourceLen)
{
return compressBound ( sourceLen );
}
_XTP_EXT_CLASS int ZLibUncompress (BYTE* dest, ULONG* destLen, const BYTE* source, ULONG sourceLen)
{
return uncompress ( dest, destLen, source, sourceLen );
}