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

935 lines
29 KiB

////////////////////////////////////////////////////////////////////
// Image.cpp
//
// Copyright 2007 cDc@seacave
// Distributed under the Boost Software License, Version 1.0
// (See http://www.boost.org/LICENSE_1_0.txt)
#include "Common.h"
#include "Image.h"
using namespace SEACAVE;
// D E F I N E S ///////////////////////////////////////////////////
// S T R U C T S ///////////////////////////////////////////////////
DEFINE_LOG(CImage, _T("IO "));
// Set the image details;
// if image's data is not NULL, but its size is too small,
// data's buffer is not allocated and _BUFFERSIZE is returned.
HRESULT CImage::Reset(Size width, Size height, PIXELFORMAT pixFormat, Size levels, bool bAllocate)
{
// reinitialize image with given params
const size_t oldDataSize = GetDataSize();
m_dataWidth = m_width = width;
m_dataHeight= m_height = height;
m_format = pixFormat;
m_stride = GetStride(pixFormat);
m_lineWidth = m_width * m_stride;
m_numLevels = levels;
m_level = 0;
if (bAllocate) {
if (m_data != NULL) {
if (oldDataSize < GetDataSize())
return _BUFFERSIZE;
} else {
m_data = new uint8_t[GetDataSize()];
}
}
return _OK;
} // Reset
/*----------------------------------------------------------------*/
HRESULT CImage::Reset(LPCTSTR szFileName, IMCREATE mode)
{
// open the new image stream
m_fileName = szFileName;
// try to directly access the file
File* f;
if (mode == READ) {
f = new File(szFileName, File::READ, File::OPEN);
} else {
Util::ensureFolder(szFileName);
f = new File(szFileName, File::WRITE, File::CREATE | File::TRUNCATE);
}
if (!f->isOpen()) {
delete f;
return _INVALIDFILE;
}
if ((m_pStream = f) == NULL) {
LOG(LT_IMAGE, _T("error: failed opening image '%s'"), szFileName);
return _INVALIDFILE;
}
return _OK;
} // Reset
/*----------------------------------------------------------------*/
HRESULT CImage::Reset(IOSTREAMPTR& pStream)
{
// use the already opened image stream
m_fileName.clear();
m_pStream = pStream;
return _OK;
} // Reset
/*----------------------------------------------------------------*/
void CImage::Close()
{
// close the image stream
m_pStream.Release();
m_data.Release();
} // Close
/*----------------------------------------------------------------*/
HRESULT CImage::ReadHeader()
{
return _OK;
} // ReadHeader
/*----------------------------------------------------------------*/
HRESULT CImage::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
{
// read data
if (dataFormat == m_format && nStride == m_stride) {
// read image directly to the data buffer
if (lineWidth == m_lineWidth) {
const size_t nSize = m_dataHeight*m_lineWidth;
if (nSize != m_pStream->read(pData, nSize))
return _INVALIDFILE;
} else {
for (Size j=0; j<m_dataHeight; ++j, (uint8_t*&)pData+=lineWidth)
if (m_lineWidth != m_pStream->read(pData, m_lineWidth))
return _INVALIDFILE;
}
} else {
// read image to a buffer and convert it
CAutoPtrArr<uint8_t> const buffer(new uint8_t[m_lineWidth]);
for (Size j=0; j<m_dataHeight; ++j, (uint8_t*&)pData+=lineWidth) {
if (m_lineWidth != m_pStream->read(buffer, m_lineWidth))
return _INVALIDFILE;
if (!FilterFormat(pData, dataFormat, nStride, buffer, m_format, m_stride, m_dataWidth))
return _FAIL;
}
}
// prepare next level
if (m_level+1 < m_numLevels)
m_lineWidth = GetDataSizes(++m_level, m_dataWidth, m_dataHeight);
return _OK;
} // ReadData
/*----------------------------------------------------------------*/
HRESULT CImage::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels)
{
// write header
m_numLevels = numLevels;
m_level = 0;
m_format = imageFormat;
m_stride = GetStride(m_format);
m_width = width;
m_height = height;
m_lineWidth = GetDataSizes(0, m_dataWidth, m_dataHeight);
return _OK;
} // WriteHeader
/*----------------------------------------------------------------*/
HRESULT CImage::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
{
// write data
if (dataFormat == m_format && nStride == m_stride) {
// write data buffer directly to the image
if (lineWidth == m_lineWidth) {
const size_t nSize = m_dataHeight*m_lineWidth;
if (nSize != m_pStream->write(pData, nSize))
return _INVALIDFILE;
} else {
for (Size j=0; j<m_dataHeight; ++j, (uint8_t*&)pData+=lineWidth)
if (m_lineWidth != m_pStream->write(pData, m_lineWidth))
return _INVALIDFILE;
}
} else {
// convert data to a buffer and write it
CAutoPtrArr<uint8_t> const buffer(new uint8_t[m_lineWidth]);
for (Size j=0; j<m_dataHeight; ++j, (uint8_t*&)pData+=lineWidth) {
if (!FilterFormat(buffer, m_format, m_stride, pData, dataFormat, nStride, m_dataWidth))
return _FAIL;
if (m_lineWidth != m_pStream->write(buffer, m_lineWidth))
return _INVALIDFILE;
}
}
// prepare next level
if (m_level+1 < m_numLevels)
m_lineWidth = GetDataSizes(++m_level, m_dataWidth, m_dataHeight);
return _OK;
} // WriteData
/*----------------------------------------------------------------*/
CImage::Size CImage::GetDataSizes(Size mipLevel, Size& width, Size& height) const
{
// Bump by the mip level.
height = MAXF((Size)1, m_height >> mipLevel);
width = MAXF((Size)1, m_width >> mipLevel);
// if compressed, divide dims by 4
if (m_format >= PF_DXT1)
{
width = (width+3)>>2;
height = (height+3)>>2;
}
return width * m_stride;
} // GetDataSizes
/*----------------------------------------------------------------*/
CImage::Size CImage::GetStride(PIXELFORMAT pixFormat)
{
switch (pixFormat)
{
case PF_A8:
case PF_GRAY8:
return 1;
case PF_R5G6B5:
return 2;
case PF_B8G8R8:
case PF_R8G8B8:
return 3;
case PF_R8G8B8A8:
case PF_A8R8G8B8:
case PF_B8G8R8A8:
case PF_A8B8G8R8:
return 4;
case PF_DXT1:
return 8;
case PF_DXT2:
case PF_DXT3:
case PF_DXT4:
case PF_DXT5:
case PF_3DC:
return 16;
default:
LOG(LT_IMAGE, "error: unsupported SCI pixel format");
}
return 0;
} // GetStride
/*----------------------------------------------------------------*/
// If the given image format has alpha channel, returns true.
bool CImage::FormatHasAlpha(PIXELFORMAT format)
{
switch (format)
{
case PF_A8:
case PF_R8G8B8A8:
case PF_A8R8G8B8:
case PF_B8G8R8A8:
case PF_A8B8G8R8:
case PF_DXT2:
case PF_DXT3:
case PF_DXT4:
case PF_DXT5:
return true;
case PF_GRAY8:
case PF_R5G6B5:
case PF_B8G8R8:
case PF_R8G8B8:
case PF_DXT1:
case PF_3DC:
return false;
default:
ASSERT("Unknown format" == NULL);
}
return false;
} // FormatHasAlpha
/*----------------------------------------------------------------*/
// Convert from one format to another.
// nSzize is the number of pixels to process.
bool CImage::FilterFormat(void* pDst, PIXELFORMAT formatDst, Size strideDst, const void* pSrc, PIXELFORMAT formatSrc, Size strideSrc, Size nSzize)
{
//ASSERT(formatDst != formatSrc || strideDst != strideSrc)
switch (formatDst)
{
case PF_A8:
case PF_GRAY8:
switch (formatSrc)
{
case PF_R8G8B8A8:
case PF_A8R8G8B8:
case PF_B8G8R8A8:
case PF_A8B8G8R8:
// from PF_R8G8B8A8 to PF_A8 (just copy the alpha channel)
(uint8_t*&)pSrc += 3; //skip the first RGB values
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_A8 (just copy)
ASSERT(strideDst != strideSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[0];
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_A8 (16bits to gray)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = RGB24TO8(RGB16TOR(clr), RGB16TOG(clr), RGB16TOB(clr));
}
return true;
case PF_B8G8R8:
case PF_R8G8B8:
// from PF_R8G8B8 to PF_A8 (24bits to gray)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint8_t*)pDst)[0] = RGB24TO8(((uint8_t*)pSrc)[2], ((uint8_t*)pSrc)[1], ((uint8_t*)pSrc)[0]);
return true;
}
break;
case PF_R5G6B5:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_R5G6B5 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = RGB24TO16(((uint8_t*)pSrc)[0], ((uint8_t*)pSrc)[0], ((uint8_t*)pSrc)[0]);
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_R5G6B5 (just copy)
ASSERT(strideDst != strideSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = *((uint16_t*)pSrc);
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_R5G6B5 (24bits to 16bits)
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_R5G6B5 (24bits to 16bits)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = RGB24TO16(((uint8_t*)pSrc)[2], ((uint8_t*)pSrc)[1], ((uint8_t*)pSrc)[0]);
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_R5G6B5 (24bits to 16bits)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = RGB24TO16(((uint8_t*)pSrc)[3], ((uint8_t*)pSrc)[2], ((uint8_t*)pSrc)[1]);
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_R5G6B5 (24bits to 16bits)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = RGB24TO16(((uint8_t*)pSrc)[0], ((uint8_t*)pSrc)[1], ((uint8_t*)pSrc)[2]);
return true;
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_R5G6B5 (24bits to 16bits)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = RGB24TO16(((uint8_t*)pSrc)[0], ((uint8_t*)pSrc)[1], ((uint8_t*)pSrc)[2]);
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_R5G6B5 (24bits to 16bits)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
*((uint16_t*)pDst) = RGB24TO16(((uint8_t*)pSrc)[1], ((uint8_t*)pSrc)[2], ((uint8_t*)pSrc)[3]);
return true;
}
break;
case PF_R8G8B8:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_R8G8B8 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint8_t*)pDst)[0] = ((uint8_t*)pDst)[1] = ((uint8_t*)pDst)[2] = *((uint8_t*)pSrc);
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_R8G8B8 (16bits to 24bits))
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = RGB16TOB(clr);
((uint8_t*)pDst)[1] = RGB16TOG(clr);
((uint8_t*)pDst)[2] = RGB16TOR(clr);
}
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_R8G8B8 (just copy)
ASSERT(strideDst != strideSrc);
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_R8G8B8 (just copy)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint16_t*)pDst)[0] = ((uint16_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[2];
}
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_R8G8B8 (just copy)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[3];
}
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_R8G8B8 (flip)
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_R8G8B8 (flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_R8G8B8 (flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
}
return true;
}
break;
case PF_R8G8B8A8:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_R8G8B8A8 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pDst)[1] = ((uint8_t*)pDst)[2] = *((uint8_t*)pSrc);
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_R8G8B8A8 (16bits to 24bits))
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = RGB16TOB(clr);
((uint8_t*)pDst)[1] = RGB16TOG(clr);
((uint8_t*)pDst)[2] = RGB16TOR(clr);
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_R8G8B8A8 (just copy the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint16_t*)pDst)[0] = ((uint16_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_R8G8B8A8 (just copy)
ASSERT(strideDst != strideSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint32_t*)pDst)[0] = ((uint32_t*)pSrc)[0];
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_R8G8B8A8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_R8G8B8A8 (copy and flip the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_R8G8B8A8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[3];
}
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_R8G8B8A8 (flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
}
break;
case PF_A8R8G8B8:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_A8R8G8B8 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = ((uint8_t*)pDst)[2] = ((uint8_t*)pDst)[3] = *((uint8_t*)pSrc);
}
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_A8R8G8B8 (16bits to 24bits))
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = RGB16TOB(clr);
((uint8_t*)pDst)[2] = RGB16TOG(clr);
((uint8_t*)pDst)[3] = RGB16TOR(clr);
}
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_A8R8G8B8 (just copy the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[2];
}
return true;
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_A8R8G8B8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[2];
}
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_A8R8G8B8 (just copy)
ASSERT(strideDst != strideSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint32_t*)pDst)[0] = ((uint32_t*)pSrc)[0];
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_A8R8G8B8 (copy and flip the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_A8R8G8B8 (flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_A8R8G8B8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[1];
}
return true;
}
break;
case PF_B8G8R8:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_B8G8R8 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint8_t*)pDst)[0] = ((uint8_t*)pDst)[1] = ((uint8_t*)pDst)[2] = *((uint8_t*)pSrc);
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_B8G8R8 (16bits to 24bits))
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = RGB16TOR(clr);
((uint8_t*)pDst)[1] = RGB16TOG(clr);
((uint8_t*)pDst)[2] = RGB16TOB(clr);
}
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_B8G8R8 (flip)
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_B8G8R8 (flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_B8G8R8 (flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
}
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_B8G8R8 (just copy)
ASSERT(strideDst != strideSrc);
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_B8G8R8 (just copy)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint16_t*)pDst)[0] = ((uint16_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[2];
}
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_B8G8R8 (just copy)
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[3];
}
return true;
}
break;
case PF_B8G8R8A8:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_B8G8R8A8 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pDst)[1] = ((uint8_t*)pDst)[2] = *((uint8_t*)pSrc);
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_B8G8R8A8 (16bits to 24bits))
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = RGB16TOR(clr);
((uint8_t*)pDst)[1] = RGB16TOG(clr);
((uint8_t*)pDst)[2] = RGB16TOB(clr);
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_B8G8R8A8 (copy and flip the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_B8G8R8A8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[3];
}
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_B8G8R8A8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_B8G8R8A8 (just copy the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint16_t*)pDst)[0] = ((uint16_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[3] = 0xFF;
}
return true;
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_B8G8R8A8 (just copy)
ASSERT(strideDst != strideSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint32_t*)pDst)[0] = ((uint32_t*)pSrc)[0];
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_B8G8R8A8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
}
break;
case PF_A8B8G8R8:
switch (formatSrc)
{
case PF_A8:
case PF_GRAY8:
// from PF_A8 to PF_A8B8G8R8 (doesn't make sense)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = ((uint8_t*)pDst)[2] = ((uint8_t*)pDst)[3] = *((uint8_t*)pSrc);
}
return true;
case PF_R5G6B5:
// from PF_R5G6B5 to PF_A8B8G8R8 (16bits to 24bits))
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
const uint16_t clr = *((uint16_t*)pSrc);
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = RGB16TOR(clr);
((uint8_t*)pDst)[2] = RGB16TOG(clr);
((uint8_t*)pDst)[3] = RGB16TOB(clr);
}
return true;
case PF_R8G8B8:
// from PF_R8G8B8 to PF_A8B8G8R8 (copy and flip the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_R8G8B8A8:
// from PF_R8G8B8A8 to PF_A8B8G8R8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_A8R8G8B8:
// from PF_A8R8G8B8 to PF_A8B8G8R8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[2];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[0];
}
return true;
case PF_B8G8R8:
// from PF_B8G8R8 to PF_A8B8G8R8 (just copy the RGB and set A to 255)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = 0xFF;
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[2];
}
return true;
case PF_B8G8R8A8:
// from PF_B8G8R8A8 to PF_A8B8G8R8 (copy and flip)
ASSERT(pDst != pSrc);
for (Size i=0; i<nSzize; ++i, (uint8_t*&)pDst+=strideDst, (uint8_t*&)pSrc+=strideSrc) {
((uint8_t*)pDst)[0] = ((uint8_t*)pSrc)[3];
((uint8_t*)pDst)[1] = ((uint8_t*)pSrc)[0];
((uint8_t*)pDst)[2] = ((uint8_t*)pSrc)[1];
((uint8_t*)pDst)[3] = ((uint8_t*)pSrc)[2];
}
return true;
case PF_A8B8G8R8:
// from PF_A8B8G8R8 to PF_A8B8G8R8 (just copy)
ASSERT(strideDst != strideSrc);
for (Size i=0; i<nSzize; ++i,(uint8_t*&)pDst+=strideDst,(uint8_t*&)pSrc+=strideSrc)
((uint32_t*)pDst)[0] = ((uint32_t*)pSrc)[0];
return true;
}
break;
}
return false;
} // FilterFormat
/*----------------------------------------------------------------*/
// Flip R and B in a 24bit pixel color.
// size is the number of pixels to process.
// stride is the number of bytes used for one pixel.
void CImage::FlipRB24(uint8_t* data, Size size, Size stride)
{
for (Size i=0; i<size; ++i, data+=stride)
{
const uint8_t tmp = data[0];
data[0] = data[2];
data[2] = tmp;
}
} // FlipRB24
/*----------------------------------------------------------------*/
// Copy and flip R and B in a 24bit pixel color.
// size is the number of pixels to process.
// stride is the number of bytes used for one pixel for dest and source respectively.
void CImage::CopyFlipRB24(uint8_t* pDst, const uint8_t* pSrc, Size size, Size strideDst, Size strideSrc)
{
for (Size i=0; i<size; ++i, pDst+=strideDst, pSrc+=strideSrc)
{
pDst[0] = pSrc[2];
pDst[1] = pSrc[1];
pDst[2] = pSrc[0];
}
} // CopyFlipRB24
/*----------------------------------------------------------------*/
CImage* CImage::Create(LPCTSTR szName, IMCREATE mode)
{
// check image file type
CImage* pImage;
LPCTSTR const fext = _tcsrchr(szName, '.');
if (fext == NULL)
goto UNKNOWN_FORMAT;
if (_tcsncicmp(fext, _T(".sci"), 4) == 0)
pImage = new CImageSCI();
#ifdef _IMAGE_BMP
else if (_tcsncicmp(fext, _T(".bmp"), 4) == 0)
pImage = new CImageBMP();
#endif
#ifdef _IMAGE_TGA
else if (_tcsncicmp(fext, _T(".tga"), 4) == 0)
pImage = new CImageTGA();
#endif
#ifdef _IMAGE_DDS
else if (_tcsncicmp(fext, _T(".dds"), 4) == 0)
pImage = new CImageDDS();
#endif
#ifdef _IMAGE_PNG
else if (_tcsncicmp(fext, _T(".png"), 4) == 0)
pImage = new CImagePNG();
#endif
#ifdef _IMAGE_JPG
else if (_tcsncicmp(fext, _T(".jpg"), 4) == 0 || _tcsncicmp(fext, _T(".jpeg"), 5) == 0)
pImage = new CImageJPG();
#endif
#ifdef _IMAGE_TIFF
else if (_tcsncicmp(fext, _T(".tif"), 4) == 0 || _tcsncicmp(fext, _T(".tiff"), 5) == 0)
pImage = new CImageTIFF();
#endif
else
goto UNKNOWN_FORMAT;
// open the image stream
if (FAILED(pImage->Reset(szName, mode))) {
delete pImage;
return NULL;
}
return pImage;
UNKNOWN_FORMAT:
// Unknown format
LOG(LT_IMAGE, "error: unknown image format '%s'", szName);
return NULL;
} // Create
/*----------------------------------------------------------------*/
#ifndef _RELEASE
// Save image as raw data.
void CImage::Dump(LPCTSTR szFileName)
{
const String strName = Util::getFileName(szFileName)+String::ToString(m_width)+_T("x")+String::ToString(m_height)+_T("x")+String::ToString(m_stride)+Util::getFileExt(szFileName);
File f(strName, File::WRITE, File::CREATE | File::TRUNCATE);
if (!f.isOpen())
return;
f.write(GetData(), GetDataSize());
} // FlipRB24
/*----------------------------------------------------------------*/
#endif