提交scripts
This commit is contained in:
1 parent
82caf72036
commit
07dabbd186
224 files changed
+130146
No files matched your search
@@ -0,0 +1,51 @@
|
||||
# Find required packages
|
||||
FIND_PACKAGE(PNG QUIET)
|
||||
if(PNG_FOUND)
|
||||
INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIRS})
|
||||
ADD_DEFINITIONS(${PNG_DEFINITIONS})
|
||||
SET(_USE_PNG TRUE CACHE INTERNAL "")
|
||||
else()
|
||||
SET(PNG_LIBRARIES "")
|
||||
endif()
|
||||
FIND_PACKAGE(JPEG QUIET)
|
||||
if(JPEG_FOUND)
|
||||
INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})
|
||||
ADD_DEFINITIONS(${JPEG_DEFINITIONS})
|
||||
SET(_USE_JPG TRUE CACHE INTERNAL "")
|
||||
else()
|
||||
SET(JPEG_LIBRARIES "")
|
||||
endif()
|
||||
FIND_PACKAGE(TIFF QUIET)
|
||||
if(TIFF_FOUND)
|
||||
INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
|
||||
ADD_DEFINITIONS(${TIFF_DEFINITIONS})
|
||||
SET(_USE_TIFF TRUE CACHE INTERNAL "")
|
||||
else()
|
||||
SET(TIFF_LIBRARIES "")
|
||||
endif()
|
||||
|
||||
# List sources files
|
||||
FILE(GLOB LIBRARY_FILES_C "*.cpp")
|
||||
FILE(GLOB LIBRARY_FILES_H "*.h" "*.inl")
|
||||
|
||||
cxx_library_with_type(IO "Libs" "" "${cxx_default}"
|
||||
${LIBRARY_FILES_C} ${LIBRARY_FILES_H}
|
||||
)
|
||||
|
||||
# Manually set Common.h as the precompiled header
|
||||
IF(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16.0)
|
||||
TARGET_PRECOMPILE_HEADERS(IO PRIVATE "Common.h")
|
||||
endif()
|
||||
|
||||
# Link its dependencies
|
||||
TARGET_LINK_LIBRARIES(IO Common ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARIES} ${EXIV2_LIBS})
|
||||
|
||||
# Install
|
||||
SET_TARGET_PROPERTIES(IO PROPERTIES
|
||||
PUBLIC_HEADER "${LIBRARY_FILES_H}")
|
||||
INSTALL(TARGETS IO
|
||||
EXPORT OpenMVSTargets
|
||||
LIBRARY DESTINATION "${INSTALL_LIB_DIR}"
|
||||
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
|
||||
RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
|
||||
PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}/IO")
|
||||
@@ -0,0 +1,12 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Common.cpp
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Source file that includes just the standard includes
|
||||
// Common.pch will be the pre-compiled header
|
||||
// Common.obj will contain the pre-compiled type information
|
||||
|
||||
#include "Common.h"
|
||||
@@ -0,0 +1,63 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Common.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __IO_COMMON_H__
|
||||
#define __IO_COMMON_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#if defined(IO_EXPORTS) && !defined(Common_EXPORTS)
|
||||
#define Common_EXPORTS
|
||||
#endif
|
||||
|
||||
#include "../Common/Common.h"
|
||||
|
||||
#ifndef IO_API
|
||||
#define IO_API GENERAL_API
|
||||
#endif
|
||||
#ifndef IO_TPL
|
||||
#define IO_TPL GENERAL_TPL
|
||||
#endif
|
||||
|
||||
#define _IMAGE_BMP // add BMP support
|
||||
#define _IMAGE_TGA // add TGA support
|
||||
#define _IMAGE_DDS // add DDS support
|
||||
#ifdef _USE_PNG
|
||||
#define _IMAGE_PNG // add PNG support
|
||||
#endif
|
||||
#ifdef _USE_JPG
|
||||
#define _IMAGE_JPG // add JPG support
|
||||
#endif
|
||||
#ifdef _USE_TIFF
|
||||
#define _IMAGE_TIFF // add TIFF support
|
||||
#endif
|
||||
|
||||
#include "ImageSCI.h"
|
||||
#ifdef _IMAGE_BMP
|
||||
#include "ImageBMP.h"
|
||||
#endif
|
||||
#ifdef _IMAGE_TGA
|
||||
#include "ImageTGA.h"
|
||||
#endif
|
||||
#ifdef _IMAGE_DDS
|
||||
#include "ImageDDS.h"
|
||||
#endif
|
||||
#ifdef _IMAGE_PNG
|
||||
#include "ImagePNG.h"
|
||||
#endif
|
||||
#ifdef _IMAGE_JPG
|
||||
#include "ImageJPG.h"
|
||||
#endif
|
||||
#ifdef _IMAGE_TIFF
|
||||
#include "ImageTIFF.h"
|
||||
#endif
|
||||
#include "PLY.h"
|
||||
#include "OBJ.h"
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // __IO_COMMON_H__
|
||||
@@ -0,0 +1,935 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Image.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGE_H__
|
||||
#define __SEACAVE_IMAGE_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
#define LT_IMAGE CImage::ms_nLogType
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
// All formats are listed from left to right, most-significant bit to least-significant bit.
|
||||
// For example, PF_A8R8G8B8 is ordered from the most-significant bit channel A (alpha),
|
||||
// to the least-significant bit channel B (blue). When traversing image data, the data is
|
||||
// stored in memory on a little-endian machine from least-significant bit to most-significant bit,
|
||||
// which means that the channel order in memory is from least-significant bit (blue) to
|
||||
// most-significant bit (alpha).
|
||||
typedef enum PIXELFORMAT_TYPE {
|
||||
PF_UNKNOWN = 0,
|
||||
// gray
|
||||
PF_A8,
|
||||
PF_GRAY8,
|
||||
// uncompressed RGB
|
||||
PF_R5G6B5,
|
||||
PF_R8G8B8,
|
||||
PF_R8G8B8A8,
|
||||
PF_A8R8G8B8,
|
||||
// uncompressed BGR
|
||||
PF_B8G8R8,
|
||||
PF_B8G8R8A8,
|
||||
PF_A8B8G8R8,
|
||||
// compressed
|
||||
PF_DXT1 = 128,
|
||||
PF_DXT2,
|
||||
PF_DXT3,
|
||||
PF_DXT4,
|
||||
PF_DXT5,
|
||||
PF_3DC,
|
||||
} PIXELFORMAT;
|
||||
|
||||
class IO_API CImage
|
||||
{
|
||||
DECLARE_LOG();
|
||||
|
||||
public:
|
||||
enum IMCREATE {
|
||||
READ,
|
||||
WRITE
|
||||
};
|
||||
typedef uint32_t Size;
|
||||
|
||||
CImage() {}
|
||||
virtual ~CImage() {}
|
||||
|
||||
virtual HRESULT Reset(Size width, Size height, PIXELFORMAT pixFormat, Size levels = 1, bool bAllocate = false);
|
||||
virtual HRESULT Reset(LPCTSTR szFileName, IMCREATE mode);
|
||||
virtual HRESULT Reset(IOSTREAMPTR& pStream);
|
||||
virtual void Close();
|
||||
|
||||
virtual HRESULT ReadHeader();
|
||||
virtual HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
|
||||
virtual HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
virtual HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
|
||||
const IOSTREAMPTR& GetStream() const { return m_pStream; }
|
||||
IOSTREAMPTR& GetStream() { return m_pStream; }
|
||||
BYTE* GetData() const { return m_data; }
|
||||
BYTE*& GetData() { return m_data; }
|
||||
size_t GetDataSize() const { return m_lineWidth * m_dataHeight; }
|
||||
Size GetWidth() const { return m_width; }
|
||||
Size GetHeight() const { return m_height; }
|
||||
Size GetDataWidth() const { return m_dataWidth; }
|
||||
Size GetDataHeight() const { return m_dataHeight; }
|
||||
Size GetStride() const { return m_stride; }
|
||||
Size GetLineWidth() const { return m_lineWidth; }
|
||||
BYTE GetNumLevels() const { return m_numLevels; }
|
||||
PIXELFORMAT GetFormat() const { return m_format; }
|
||||
bool FormatHasAlpha() const { return FormatHasAlpha(m_format); }
|
||||
const String& GetFileName() const { return m_fileName; }
|
||||
String& GetFileName() { return m_fileName; }
|
||||
|
||||
Size GetDataSizes(Size mipLevel, Size& width, Size& height) const;
|
||||
|
||||
static Size GetStride(PIXELFORMAT); //in bits
|
||||
static bool FormatHasAlpha(PIXELFORMAT);
|
||||
static bool FilterFormat(void*, PIXELFORMAT, Size, const void*, PIXELFORMAT, Size, Size nSzize);
|
||||
static void FlipRB24(uint8_t* data, Size size, Size stride);
|
||||
static void CopyFlipRB24(uint8_t* pDst, const uint8_t* pSrc, Size size, Size strideDst, Size strideSrc);
|
||||
|
||||
static CImage* Create(LPCTSTR szName, IMCREATE mode);
|
||||
|
||||
#ifndef _RELEASE
|
||||
void Dump(LPCTSTR szFileName);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
IOSTREAMPTR m_pStream; // stream used to read/write the image data
|
||||
CAutoPtrArr<BYTE> m_data; // image's data buffer
|
||||
Size m_width; // image width in pixels
|
||||
Size m_height; // image height in pixels
|
||||
Size m_dataWidth; // image's data width including mipmaps
|
||||
Size m_dataHeight; // image's data height
|
||||
Size m_stride; // bytes per pixel
|
||||
Size m_lineWidth; // image canvas width in bytes
|
||||
PIXELFORMAT m_format; // image format (pixel type)
|
||||
BYTE m_numLevels; // number of mipmap levels (0 = auto-generate)
|
||||
BYTE m_level; // index of the mipmap level currently reading
|
||||
String m_fileName; // image's file name
|
||||
}; // class CImage
|
||||
typedef CSharedPtr<CImage> IMAGEPTR;
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGE_H__
|
||||
@@ -0,0 +1,261 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageBMP.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"
|
||||
|
||||
#ifdef _IMAGE_BMP
|
||||
#include "ImageBMP.h"
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER
|
||||
typedef long LONG;
|
||||
typedef struct tagBITMAPFILEHEADER {
|
||||
WORD bfType;
|
||||
DWORD bfSize;
|
||||
WORD bfReserved1;
|
||||
WORD bfReserved2;
|
||||
DWORD bfOffBits;
|
||||
} BITMAPFILEHEADER;
|
||||
typedef struct tagBITMAPINFOHEADER {
|
||||
DWORD biSize;
|
||||
LONG biWidth;
|
||||
LONG biHeight;
|
||||
WORD biPlanes;
|
||||
WORD biBitCount;
|
||||
DWORD biCompression;
|
||||
DWORD biSizeImage;
|
||||
LONG biXPelsPerMeter;
|
||||
LONG biYPelsPerMeter;
|
||||
DWORD biClrUsed;
|
||||
DWORD biClrImportant;
|
||||
} BITMAPINFOHEADER;
|
||||
/* constants for the biCompression field */
|
||||
#define BI_RGB 0L
|
||||
#define BI_RLE8 1L
|
||||
#define BI_RLE4 2L
|
||||
#define BI_BITFIELDS 3L
|
||||
#define BI_JPEG 4L
|
||||
#define BI_PNG 5L
|
||||
#endif
|
||||
|
||||
|
||||
CImageBMP::CImageBMP()
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImageBMP::~CImageBMP()
|
||||
{
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageBMP::ReadHeader()
|
||||
{
|
||||
// Jump to the beginning of the file
|
||||
((ISTREAM*)m_pStream)->setPos(0);
|
||||
|
||||
// Read the BITMAPFILEHEADER
|
||||
// and check the type field to make sure we have a .bmp file
|
||||
// bfType should contain the letters "BM"
|
||||
BITMAPFILEHEADER bmp_fileheader;
|
||||
if (sizeof(BITMAPFILEHEADER) != m_pStream->read(&bmp_fileheader, sizeof(BITMAPFILEHEADER)) ||
|
||||
memcmp(&bmp_fileheader.bfType, "BM", 2))
|
||||
{
|
||||
LOG(LT_IMAGE, _T("error: invalid BMP image"));
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
// Read the BITMAPINFOHEADER.
|
||||
// and double Check to make sure we got a correct BITMAPINFOHEADER
|
||||
BITMAPINFOHEADER bmp_infoheader;
|
||||
if (sizeof(BITMAPINFOHEADER) != m_pStream->read(&bmp_infoheader, sizeof(BITMAPINFOHEADER)) ||
|
||||
bmp_infoheader.biSize != sizeof(bmp_infoheader))
|
||||
{
|
||||
LOG(LT_IMAGE, _T("error: invalid BMP image"));
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
// Check for unsupported format: biPlanes MUST equal 1
|
||||
// and we can only handle uncompressed .bmps
|
||||
if (bmp_infoheader.biPlanes != 1 ||
|
||||
(bmp_infoheader.biCompression != BI_RGB && bmp_infoheader.biCompression != BI_BITFIELDS))
|
||||
{
|
||||
LOG(LT_IMAGE, "error: unsupported BMP image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
// Initililize our width, height and format as the .bmp we are loading
|
||||
m_dataWidth = m_width = bmp_infoheader.biWidth;
|
||||
m_dataHeight= m_height = bmp_infoheader.biHeight;
|
||||
m_numLevels = 0;
|
||||
m_level = 0;
|
||||
m_lineWidth = (bmp_fileheader.bfSize-bmp_fileheader.bfOffBits)/bmp_infoheader.biHeight; //bmp_infoheader.biSizeImage may be set to zero for BI_RGB bitmaps
|
||||
m_stride = bmp_infoheader.biBitCount>>3;
|
||||
switch (m_stride)
|
||||
{
|
||||
case 1:
|
||||
m_format = PF_GRAY8;
|
||||
break;
|
||||
case 2:
|
||||
m_format = PF_R5G6B5;
|
||||
break;
|
||||
case 3:
|
||||
m_format = PF_R8G8B8;
|
||||
break;
|
||||
case 4:
|
||||
m_format = PF_R8G8B8A8;
|
||||
break;
|
||||
default:
|
||||
LOG(LT_IMAGE, "error: unsupported BMP image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
// Ensure m_lineWidth is DWORD aligned
|
||||
while ((m_lineWidth%4) != 0) ++m_lineWidth;
|
||||
|
||||
// Jump to the location where the bitmap data is stored
|
||||
((ISTREAM*)m_pStream)->setPos(bmp_fileheader.bfOffBits);
|
||||
|
||||
return _OK;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageBMP::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
// read data
|
||||
const size_t nSize = m_width*m_stride;
|
||||
const size_t nPad = m_lineWidth-nSize;
|
||||
CAutoPtrArr<uint8_t> const bufferPad(nPad ? new uint8_t[nPad] : NULL);
|
||||
if (dataFormat == m_format && nStride == m_stride) {
|
||||
// read image directly to the data buffer
|
||||
(BYTE*&)pData += (m_height-1)*lineWidth;
|
||||
for (Size j=0; j<m_height; ++j,(uint8_t*&)pData-=lineWidth)
|
||||
if (nSize != m_pStream->read(pData, nSize) ||
|
||||
(nPad && nPad != m_pStream->read(bufferPad, nPad)))
|
||||
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_height; ++j) {
|
||||
if (m_lineWidth != m_pStream->read(buffer, m_lineWidth))
|
||||
return _INVALIDFILE;
|
||||
if (!FilterFormat((uint8_t*)pData+(m_height-j-1)*lineWidth, dataFormat, nStride, buffer, m_format, m_stride, m_width))
|
||||
return _FAIL;
|
||||
}
|
||||
}
|
||||
return _OK;
|
||||
} // ReadData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageBMP::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE /*numLevels*/)
|
||||
{
|
||||
// write header
|
||||
m_numLevels = 0;
|
||||
m_level = 0;
|
||||
DWORD dwCompression;
|
||||
switch (imageFormat)
|
||||
{
|
||||
case PF_A8:
|
||||
case PF_GRAY8:
|
||||
m_stride = 1;
|
||||
dwCompression = BI_RGB;
|
||||
m_format = PF_GRAY8;
|
||||
break;
|
||||
case PF_R5G6B5:
|
||||
m_stride = 2;
|
||||
dwCompression = BI_BITFIELDS;
|
||||
m_format = PF_R5G6B5;
|
||||
break;
|
||||
case PF_B8G8R8:
|
||||
case PF_R8G8B8:
|
||||
m_stride = 3;
|
||||
dwCompression = BI_RGB;
|
||||
m_format = PF_R8G8B8;
|
||||
break;
|
||||
case PF_R8G8B8A8:
|
||||
case PF_A8R8G8B8:
|
||||
case PF_B8G8R8A8:
|
||||
case PF_A8B8G8R8:
|
||||
m_stride = 4;
|
||||
dwCompression = BI_BITFIELDS;
|
||||
m_format = PF_R8G8B8A8;
|
||||
break;
|
||||
default:
|
||||
LOG(LT_IMAGE, "error: unsupported BMP image format");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
m_dataWidth = m_width = width;
|
||||
m_dataHeight= m_height = height;
|
||||
m_lineWidth = m_width*m_stride;
|
||||
// Ensure m_lineWidth is DWORD aligned
|
||||
while ((m_lineWidth%4) != 0) ++m_lineWidth;
|
||||
((OSTREAM*)m_pStream)->setPos(0);
|
||||
// Write the BITMAPFILEHEADER and the BITMAPINFOHEADER.
|
||||
const BITMAPFILEHEADER bmp_fileheader = {
|
||||
0x4d42, //BM
|
||||
(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+m_lineWidth*m_height, //total file size
|
||||
0, 0, //reserved
|
||||
(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER) //offset to the bitmap bits
|
||||
};
|
||||
const BITMAPINFOHEADER bmp_infoheader = {
|
||||
(DWORD)sizeof(BITMAPINFOHEADER), //size of this structure
|
||||
(LONG)m_width, (LONG)m_height, //dim
|
||||
(WORD)1, //number of color planes being used (must be set to 1)
|
||||
(WORD)(m_stride<<3), //number of bits per pixel
|
||||
dwCompression, //compression method being used
|
||||
m_lineWidth*m_height, //raw image size
|
||||
0, 0, //pixels-per-meter
|
||||
0, //number of colors in the color palette
|
||||
0 //number of important colors used
|
||||
};
|
||||
if (sizeof(BITMAPFILEHEADER) != m_pStream->write(&bmp_fileheader, sizeof(BITMAPFILEHEADER)) ||
|
||||
sizeof(BITMAPINFOHEADER) != m_pStream->write(&bmp_infoheader, sizeof(BITMAPINFOHEADER)))
|
||||
{
|
||||
LOG(LT_IMAGE, "error: failed writing the BMP image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
return _OK;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageBMP::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
// write data
|
||||
const size_t nSize = m_width*m_stride;
|
||||
const size_t nPad = m_lineWidth-nSize;
|
||||
CAutoPtrArr<uint8_t> const bufferPad(nPad ? new uint8_t[nPad] : NULL);
|
||||
if (nPad) memset(bufferPad, 0, nPad);
|
||||
if (dataFormat == m_format && nStride == m_stride) {
|
||||
// write data buffer directly to the image
|
||||
for (Size j=0; j<m_height; ++j)
|
||||
if (nSize != m_pStream->write((uint8_t*)pData+(m_height-j-1)*lineWidth, nSize) ||
|
||||
(nPad && nPad != m_pStream->write(bufferPad, nPad)))
|
||||
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_height; ++j) {
|
||||
if (!FilterFormat(buffer, m_format, m_stride, (uint8_t*)pData+(m_height-j-1)*lineWidth, dataFormat, nStride, m_width))
|
||||
return _FAIL;
|
||||
if (m_lineWidth != m_pStream->write(buffer, m_lineWidth))
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
}
|
||||
return _OK;
|
||||
} // WriteData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // _IMAGE_BMP
|
||||
@@ -0,0 +1,36 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageBMP.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGEBMP_H__
|
||||
#define __SEACAVE_IMAGEBMP_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImageBMP : public CImage
|
||||
{
|
||||
public:
|
||||
CImageBMP();
|
||||
virtual ~CImageBMP();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
}; // class CImageBMP
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGEBMP_H__
|
||||
@@ -0,0 +1,341 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageDDS.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"
|
||||
|
||||
#ifdef _IMAGE_DDS
|
||||
#include "ImageDDS.h"
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
// These were copied from the DX9 docs. The names are changed
|
||||
// from the "real" defines since not all platforms have them.
|
||||
|
||||
#ifndef MakeFourCC
|
||||
#define MakeFourCC(ch0, ch1, ch2, ch3) \
|
||||
((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \
|
||||
((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 ))
|
||||
#endif
|
||||
|
||||
#define IMAGE_DDS_TYPE MakeFourCC('D','D','S',' ') //"DDS " = 4 bytes
|
||||
|
||||
#define FOURCC_DXT1 MakeFourCC('D','X','T','1')
|
||||
#define FOURCC_DXT2 MakeFourCC('D','X','T','2')
|
||||
#define FOURCC_DXT3 MakeFourCC('D','X','T','3')
|
||||
#define FOURCC_DXT4 MakeFourCC('D','X','T','4')
|
||||
#define FOURCC_DXT5 MakeFourCC('D','X','T','5')
|
||||
#define FOURCC_3DC MakeFourCC('A','T','I','2')
|
||||
|
||||
enum DDSSurfaceDescFlags
|
||||
{
|
||||
DDSDCaps = 0x00000001l,
|
||||
DDSDHeight = 0x00000002l,
|
||||
DDSDWidth = 0x00000004l,
|
||||
DDSDPitch = 0x00000008l,
|
||||
DDSDPixelFormat = 0x00001000l,
|
||||
DDSDMipMapCount = 0x00020000l,
|
||||
DDSDLinearSize = 0x00080000l,
|
||||
DDSDDepth = 0x00800000l,
|
||||
};
|
||||
|
||||
enum DDSPixelFormatFlags
|
||||
{
|
||||
DDPFAlphaPixels = 0x00000001,
|
||||
DDPFFourCC = 0x00000004,
|
||||
DDPFRGB = 0x00000040,
|
||||
};
|
||||
|
||||
enum DDSCapFlags
|
||||
{
|
||||
DDSCAPSComplex = 0x00000008,
|
||||
DDSCAPSTexture = 0x00001000,
|
||||
DDSCAPSMipMap = 0x00400000,
|
||||
|
||||
DDSCAPS2Cubemap = 0x00000200,
|
||||
DDSCAPS2Cubemap_POSITIVEX = 0x00000400,
|
||||
DDSCAPS2Cubemap_NEGATIVEX = 0x00000800,
|
||||
DDSCAPS2Cubemap_POSITIVEY = 0x00001000,
|
||||
DDSCAPS2Cubemap_NEGATIVEY = 0x00002000,
|
||||
DDSCAPS2Cubemap_POSITIVEZ = 0x00004000,
|
||||
DDSCAPS2Cubemap_NEGATIVEZ = 0x00008000,
|
||||
DDSCAPS2Volume = 0x00200000,
|
||||
};
|
||||
|
||||
typedef struct DDPIXELFORMAT_TYPE
|
||||
{
|
||||
DWORD dwSize; // size of structure
|
||||
DWORD dwFlags; // pixel format flags
|
||||
DWORD dwFourCC; // (FOURCC code)
|
||||
union
|
||||
{
|
||||
DWORD dwRGBBitCount; // how many bits per pixel
|
||||
DWORD dwYUVBitCount; // how many bits per pixel
|
||||
DWORD dwZBufferBitDepth; // how many total bits/pixel in z buffer (including any stencil bits)
|
||||
DWORD dwAlphaBitDepth; // how many bits for alpha channels
|
||||
DWORD dwLuminanceBitCount; // how many bits per pixel
|
||||
DWORD dwBumpBitCount; // how many bits per "buxel", total
|
||||
DWORD dwPrivateFormatBitCount;// Bits per pixel of private driver formats. Only valid in texture
|
||||
// format list and if DDPF_D3DFORMAT is set
|
||||
};
|
||||
union
|
||||
{
|
||||
DWORD dwRBitMask; // mask for red bit
|
||||
DWORD dwYBitMask; // mask for Y bits
|
||||
DWORD dwStencilBitDepth; // how many stencil bits (note: dwZBufferBitDepth-dwStencilBitDepth is total Z-only bits)
|
||||
DWORD dwLuminanceBitMask; // mask for luminance bits
|
||||
DWORD dwBumpDuBitMask; // mask for bump map U delta bits
|
||||
DWORD dwOperations; // DDPF_D3DFORMAT Operations
|
||||
};
|
||||
union
|
||||
{
|
||||
DWORD dwGBitMask; // mask for green bits
|
||||
DWORD dwUBitMask; // mask for U bits
|
||||
DWORD dwZBitMask; // mask for Z bits
|
||||
DWORD dwBumpDvBitMask; // mask for bump map V delta bits
|
||||
struct
|
||||
{
|
||||
WORD wFlipMSTypes; // Multisample methods supported via flip for this D3DFORMAT
|
||||
WORD wBltMSTypes; // Multisample methods supported via blt for this D3DFORMAT
|
||||
};
|
||||
|
||||
};
|
||||
union
|
||||
{
|
||||
DWORD dwBBitMask; // mask for blue bits
|
||||
DWORD dwVBitMask; // mask for V bits
|
||||
DWORD dwStencilBitMask; // mask for stencil bits
|
||||
DWORD dwBumpLuminanceBitMask; // mask for luminance in bump map
|
||||
};
|
||||
union
|
||||
{
|
||||
DWORD dwRGBAlphaBitMask; // mask for alpha channel
|
||||
DWORD dwYUVAlphaBitMask; // mask for alpha channel
|
||||
DWORD dwLuminanceAlphaBitMask;// mask for alpha channel
|
||||
DWORD dwRGBZBitMask; // mask for Z channel
|
||||
DWORD dwYUVZBitMask; // mask for Z channel
|
||||
};
|
||||
} DDSPF;
|
||||
|
||||
typedef struct DDSCAPS_TYPE
|
||||
{
|
||||
DWORD dwCaps; // capabilities of surface wanted
|
||||
DWORD dwCaps2;
|
||||
DWORD dwCaps3;
|
||||
union
|
||||
{
|
||||
DWORD dwCaps4;
|
||||
DWORD dwVolumeDepth;
|
||||
};
|
||||
} DDSCAPS;
|
||||
|
||||
typedef struct DDSINFOHEADER_TYPE {
|
||||
DWORD dwHeader; // magic number "DDS "
|
||||
DWORD dwSize; // size of the DDSURFACEDESC structure
|
||||
DWORD dwFlags; // determines what fields are valid
|
||||
DWORD dwHeight; // height of surface to be created
|
||||
DWORD dwWidth; // width of input surface
|
||||
DWORD dwPitchOrLinearSize; // distance to start of next line or formless late-allocated optimized surface size
|
||||
DWORD dwDepth; // the depth if this is a volume texture
|
||||
DWORD dwMipMapCount; // number of mip-map levels requestde
|
||||
DWORD dwReserved1[11];
|
||||
DDSPF ddsPixelFormat; // pixel format description of the surface
|
||||
DDSCAPS ddsCaps; // direct draw surface capabilities
|
||||
DWORD dwReserved2;
|
||||
} DDSINFOHEADER;
|
||||
|
||||
#define IMAGE_DDS_DDSINFOHEADERSIZE (sizeof(DDSINFOHEADER)-sizeof(DWORD)/*dwHeader*/) // should be 124
|
||||
|
||||
#define ISBITMASK(r,g,b,a) (ddsInfo.ddsPixelFormat.dwRBitMask == r && ddsInfo.ddsPixelFormat.dwGBitMask == g && ddsInfo.ddsPixelFormat.dwBBitMask == b && ddsInfo.ddsPixelFormat.dwRGBAlphaBitMask == a )
|
||||
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
CImageDDS::CImageDDS()
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImageDDS::~CImageDDS()
|
||||
{
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageDDS::ReadHeader()
|
||||
{
|
||||
// read header
|
||||
((ISTREAM*)m_pStream)->setPos(0);
|
||||
DDSINFOHEADER ddsInfo;
|
||||
m_pStream->read(&ddsInfo, sizeof(DDSINFOHEADER));
|
||||
if (ddsInfo.dwHeader != IMAGE_DDS_TYPE &&
|
||||
ddsInfo.dwSize != IMAGE_DDS_DDSINFOHEADERSIZE &&
|
||||
!(ddsInfo.dwFlags & (DDSDCaps | DDSDPixelFormat | DDSDWidth | DDSDHeight))) { // always include DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT
|
||||
LOG(LT_IMAGE, "error: invalid DDS image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
m_width = ddsInfo.dwWidth;
|
||||
m_height = ddsInfo.dwHeight;
|
||||
m_numLevels = ddsInfo.dwFlags & DDSDMipMapCount ? (BYTE)ddsInfo.dwMipMapCount : 0;
|
||||
m_level = 0;
|
||||
|
||||
// get the format
|
||||
m_stride = ddsInfo.ddsPixelFormat.dwRGBBitCount>>3;
|
||||
m_format = PF_UNKNOWN;
|
||||
if (ddsInfo.ddsPixelFormat.dwFlags & DDPFFourCC)
|
||||
{
|
||||
switch (ddsInfo.ddsPixelFormat.dwFourCC)
|
||||
{
|
||||
case FOURCC_DXT1:
|
||||
m_format = PF_DXT1;
|
||||
m_stride = 8;
|
||||
break;
|
||||
case FOURCC_DXT2:
|
||||
m_format = PF_DXT2;
|
||||
m_stride = 16;
|
||||
break;
|
||||
case FOURCC_DXT3:
|
||||
m_format = PF_DXT3;
|
||||
m_stride = 16;
|
||||
break;
|
||||
case FOURCC_DXT4:
|
||||
m_format = PF_DXT4;
|
||||
m_stride = 16;
|
||||
break;
|
||||
case FOURCC_DXT5:
|
||||
m_format = PF_DXT5;
|
||||
m_stride = 16;
|
||||
break;
|
||||
case FOURCC_3DC:
|
||||
m_format = PF_3DC;
|
||||
m_stride = 16;
|
||||
break;
|
||||
//case 0x74:
|
||||
// m_format=FORMAT_R32G32B32A32F;
|
||||
// break;
|
||||
//case 0x71:
|
||||
// m_format=FORMAT_R16G16B16A16F;
|
||||
// break;
|
||||
//case 0x70:
|
||||
// m_format=FORMAT_G16R16F;
|
||||
// break;
|
||||
//case 0x73:
|
||||
// m_format=FORMAT_G32R32F;
|
||||
// break;
|
||||
//case 0x6F:
|
||||
// m_format=FORMAT_R16F;
|
||||
// break;
|
||||
//case 0x72:
|
||||
// m_format=FORMAT_R32F;
|
||||
// break;
|
||||
}
|
||||
}
|
||||
else if (ddsInfo.ddsPixelFormat.dwFlags & DDPFRGB)
|
||||
{
|
||||
if (ddsInfo.ddsPixelFormat.dwFlags & DDPFAlphaPixels)
|
||||
{
|
||||
if (ISBITMASK(0xff, 0xff00, 0xff0000, 0xff000000))
|
||||
m_format = PF_B8G8R8A8;
|
||||
else if (ISBITMASK(0xff0000, 0xff00, 0xff, 0xff000000))
|
||||
m_format = PF_R8G8B8A8;
|
||||
//else if (ISBITMASK(0xff000000, 0xff0000, 0xff00, 0xff))
|
||||
// m_format = FORMAT_ABGR;
|
||||
//else if (ISBITMASK(0x7C00, 0x3E0, 0x1F, 0x8000))
|
||||
// m_format = FORMAT_A1R5G5B5;
|
||||
}
|
||||
else //no DDPFAlphaPixels
|
||||
{
|
||||
if (ISBITMASK(0xff, 0xff00, 0xff0000, 0x00))
|
||||
m_format = PF_B8G8R8;
|
||||
else if (ISBITMASK(0xff0000, 0xff00, 0xff, 0x00))
|
||||
m_format = PF_R8G8B8;
|
||||
else if (ISBITMASK(0xF800, 0x7E0, 0x1F, 0x00))
|
||||
m_format = PF_R5G6B5;
|
||||
//else if (ISBITMASK(0xffFF, 0xffFF0000, 0x00, 0x00))
|
||||
// m_format = FORMAT_G16R16;
|
||||
//else if (ISBITMASK(0x7C00, 0x3E0, 0x1F, 0x00))
|
||||
// m_format = FORMAT_X1R5G5B5;
|
||||
}
|
||||
}
|
||||
else //no DDPFRGB
|
||||
{
|
||||
if (ISBITMASK(0x00, 0x00, 0x00, 0xff))
|
||||
m_format = PF_A8;
|
||||
else if (ISBITMASK(0xff, 0x00, 0x00, 0x00))
|
||||
m_format = PF_GRAY8;
|
||||
//else if (ISBITMASK(0xffff, 0x00, 0x00, 0x00))
|
||||
// m_format = FORMAT_L16;
|
||||
//else if (ISBITMASK(0xff, 0x00, 0x00, 0xff00))
|
||||
// m_format = FORMAT_A8L8;
|
||||
//else if (ISBITMASK(0xff, 0xff00, 0x00, 0x00))
|
||||
// m_format = FORMAT_V8U8;
|
||||
//else if (ISBITMASK(0xFF, 0xFF00, 0xFF0000, 0xFF000000))
|
||||
// m_format = FORMAT_Q8W8V8U8;
|
||||
//else if (ISBITMASK(0xFFFF, 0xFFFF0000, 0x00, 0x00))
|
||||
// m_format = FORMAT_V16U16;
|
||||
}
|
||||
ASSERT(m_format != PF_UNKNOWN);
|
||||
if (m_format == PF_UNKNOWN)
|
||||
{
|
||||
LOG(LT_IMAGE, "error: unsupported DDS image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
m_lineWidth = GetDataSizes(0, m_dataWidth, m_dataHeight);
|
||||
return _OK;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageDDS::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
|
||||
m_lineWidth = GetDataSizes(++m_level, m_dataWidth, m_dataHeight);
|
||||
return _OK;
|
||||
} // ReadData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageDDS::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels)
|
||||
{
|
||||
return _FAIL;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageDDS::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
return _FAIL;
|
||||
} // WriteData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // _IMAGE_DDS
|
||||
@@ -0,0 +1,36 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageDDS.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGEDDS_H__
|
||||
#define __SEACAVE_IMAGEDDS_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImageDDS : public CImage
|
||||
{
|
||||
public:
|
||||
CImageDDS();
|
||||
virtual ~CImageDDS();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
}; // class CImageDDS
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGEDDS_H__
|
||||
@@ -0,0 +1,281 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageJPG.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"
|
||||
|
||||
#ifdef _IMAGE_JPG
|
||||
#include "ImageJPG.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define XMD_H // prevent redefinition of INT32
|
||||
#undef FAR // prevent FAR redefinition
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <jpeglib.h>
|
||||
}
|
||||
#include <setjmp.h>
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
#define JPG_BUFFER_SIZE (16*1024)
|
||||
|
||||
struct JpegErrorMgr
|
||||
{
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
|
||||
struct JpegSource
|
||||
{
|
||||
struct jpeg_source_mgr pub;
|
||||
ISTREAM* pStream;
|
||||
JOCTET* buffer;
|
||||
};
|
||||
|
||||
struct JpegState
|
||||
{
|
||||
jpeg_decompress_struct cinfo; // IJG JPEG codec structure
|
||||
JpegErrorMgr jerr;// error processing manager state
|
||||
JpegSource source;// memory buffer source
|
||||
};
|
||||
|
||||
|
||||
// F U N C T I O N S ///////////////////////////////////////////////
|
||||
|
||||
METHODDEF(void)
|
||||
stub(j_decompress_ptr cinfo)
|
||||
{
|
||||
JpegSource* source = (JpegSource*)cinfo->src;
|
||||
source->pStream->setPos(0);
|
||||
}
|
||||
|
||||
METHODDEF(boolean)
|
||||
fill_input_buffer(j_decompress_ptr cinfo)
|
||||
{
|
||||
JpegSource* source = (JpegSource*)cinfo->src;
|
||||
const size_t size = source->pStream->read(source->buffer, JPG_BUFFER_SIZE);
|
||||
if (size == STREAM_ERROR || size == 0)
|
||||
return FALSE;
|
||||
source->pub.next_input_byte = source->buffer;
|
||||
source->pub.bytes_in_buffer = size;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
skip_input_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
JpegSource* source = (JpegSource*)cinfo->src;
|
||||
|
||||
if (num_bytes > (long)source->pub.bytes_in_buffer)
|
||||
{
|
||||
// We need to skip more data than we have in the buffer.
|
||||
source->pStream->setPos(source->pStream->getPos() + (num_bytes - source->pub.bytes_in_buffer));
|
||||
source->pub.next_input_byte += source->pub.bytes_in_buffer;
|
||||
source->pub.bytes_in_buffer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip portion of the buffer
|
||||
source->pub.bytes_in_buffer -= num_bytes;
|
||||
source->pub.next_input_byte += num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
error_exit(j_common_ptr cinfo)
|
||||
{
|
||||
JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err);
|
||||
|
||||
/* Return control to the setjmp point */
|
||||
longjmp( err_mgr->setjmp_buffer, 1 );
|
||||
}
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
CImageJPG::CImageJPG() : m_state(NULL)
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImageJPG::~CImageJPG()
|
||||
{
|
||||
//clean up
|
||||
Close();
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void CImageJPG::Close()
|
||||
{
|
||||
if (m_state)
|
||||
{
|
||||
JpegState* state = (JpegState*)m_state;
|
||||
jpeg_destroy_decompress( &state->cinfo );
|
||||
delete state;
|
||||
m_state = NULL;
|
||||
}
|
||||
m_width = m_height = 0;
|
||||
CImage::Close();
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageJPG::ReadHeader()
|
||||
{
|
||||
JpegState* state = new JpegState;
|
||||
m_state = state;
|
||||
state->cinfo.err = jpeg_std_error(&state->jerr.pub);
|
||||
state->jerr.pub.error_exit = error_exit;
|
||||
|
||||
if (setjmp(state->jerr.setjmp_buffer ) == 0)
|
||||
{
|
||||
jpeg_create_decompress( &state->cinfo );
|
||||
|
||||
// Prepare for suspending reader
|
||||
state->source.pub.init_source = stub;
|
||||
state->source.pub.fill_input_buffer = fill_input_buffer;
|
||||
state->source.pub.skip_input_data = skip_input_data;
|
||||
state->source.pub.resync_to_restart = jpeg_resync_to_restart;
|
||||
state->source.pub.term_source = stub;
|
||||
state->source.pub.bytes_in_buffer = 0;// forces fill_input_buffer on first read
|
||||
state->source.pub.next_input_byte = NULL;
|
||||
state->source.pStream = (IOSTREAM*)m_pStream;
|
||||
state->source.buffer = (JOCTET*)(*state->cinfo.mem->alloc_small)((j_common_ptr)&state->cinfo, JPOOL_PERMANENT, JPG_BUFFER_SIZE * sizeof(JOCTET));
|
||||
state->cinfo.src = &state->source.pub;
|
||||
|
||||
jpeg_read_header(&state->cinfo, TRUE);
|
||||
|
||||
m_dataWidth = m_width = state->cinfo.image_width;
|
||||
m_dataHeight= m_height = state->cinfo.image_height;
|
||||
m_numLevels = 0;
|
||||
m_level = 0;
|
||||
m_stride = state->cinfo.num_components;
|
||||
m_lineWidth = m_width * m_stride;
|
||||
switch (m_stride)
|
||||
{
|
||||
case 1:
|
||||
m_format = PF_GRAY8;
|
||||
state->cinfo.out_color_space = JCS_GRAYSCALE;
|
||||
state->cinfo.out_color_components = 1;
|
||||
break;
|
||||
case 3:
|
||||
m_format = PF_B8G8R8;
|
||||
state->cinfo.out_color_space = JCS_RGB;
|
||||
state->cinfo.out_color_components = 3;
|
||||
break;
|
||||
default:
|
||||
LOG(LT_IMAGE, "error: unsupported JPG image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
return _OK;
|
||||
}
|
||||
|
||||
Close();
|
||||
return _FAIL;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageJPG::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
JpegState* state = (JpegState*)m_state;
|
||||
|
||||
if (state && m_width && m_height)
|
||||
{
|
||||
jpeg_decompress_struct* cinfo = &state->cinfo;
|
||||
JpegErrorMgr* jerr = &state->jerr;
|
||||
|
||||
if (setjmp(jerr->setjmp_buffer) == 0)
|
||||
{
|
||||
jpeg_start_decompress(cinfo);
|
||||
|
||||
// read data
|
||||
if (dataFormat == m_format && nStride == m_stride) {
|
||||
// read image directly to the data buffer
|
||||
JSAMPLE* buffer[1] = {(JSAMPLE*)pData};
|
||||
uint8_t*& data = (uint8_t*&)buffer[0];
|
||||
for (Size j=0; j<m_height; ++j, data+=lineWidth)
|
||||
jpeg_read_scanlines(cinfo, buffer, 1);
|
||||
} else {
|
||||
// read image to a buffer and convert it
|
||||
JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo, JPOOL_IMAGE, m_lineWidth, 1);
|
||||
uint8_t* dst = (uint8_t*)pData;
|
||||
uint8_t* src = (uint8_t*)buffer[0];
|
||||
for (Size j=0; j<m_height; ++j, dst+=lineWidth) {
|
||||
jpeg_read_scanlines(cinfo, buffer, 1);
|
||||
if (!FilterFormat(dst, dataFormat, nStride, src, m_format, m_stride, m_width))
|
||||
return _FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
jpeg_finish_decompress(cinfo);
|
||||
return _OK;
|
||||
}
|
||||
}
|
||||
|
||||
Close();
|
||||
return _FAIL;
|
||||
} // Read
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageJPG::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels)
|
||||
{
|
||||
//TODO: to implement the JPG encoder
|
||||
return _OK;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageJPG::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
//TODO: to implement the JPG encoder
|
||||
//const int quality = 100;
|
||||
//struct jpeg_compress_struct cinfo;
|
||||
//struct jpeg_error_mgr jerr;
|
||||
///* More stuff */
|
||||
//FILE * outfile; /* target file */
|
||||
//JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
|
||||
//int row_stride; /* physical row width in image buffer */
|
||||
|
||||
//cinfo.err = jpeg_std_error(&jerr);
|
||||
//jpeg_create_compress(&cinfo);
|
||||
|
||||
//if ((outfile = fopen(filename.c_str(), "wb")) == NULL) {
|
||||
// fprintf(stderr, "can't open %s\n", filename.c_str());
|
||||
// exit(1);
|
||||
//}
|
||||
//jpeg_stdio_dest(&cinfo, outfile);
|
||||
|
||||
//cinfo.image_width = width;
|
||||
//cinfo.image_height = height;
|
||||
//cinfo.input_components = 3;
|
||||
//cinfo.in_color_space = JCS_RGB;
|
||||
//jpeg_set_defaults(&cinfo);
|
||||
//jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
|
||||
|
||||
//jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
//row_stride = width * 3; /* JSAMPLEs per row in image_buffer */
|
||||
|
||||
//while (cinfo.next_scanline < cinfo.image_height) {
|
||||
// if (flip)
|
||||
// row_pointer[0] = (JSAMPROW)& buffer[(cinfo.image_height - 1 - cinfo.next_scanline) * row_stride];
|
||||
// else
|
||||
// row_pointer[0] = (JSAMPROW)& buffer[cinfo.next_scanline * row_stride];
|
||||
// (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
|
||||
//}
|
||||
|
||||
//jpeg_finish_compress(&cinfo);
|
||||
//fclose(outfile);
|
||||
|
||||
//jpeg_destroy_compress(&cinfo);
|
||||
return _OK;
|
||||
} // WriteData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // _IMAGE_JPG
|
||||
@@ -0,0 +1,44 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageJPG.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGEJPG_H__
|
||||
#define __SEACAVE_IMAGEJPG_H__
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImageJPG : public CImage
|
||||
{
|
||||
public:
|
||||
CImageJPG();
|
||||
virtual ~CImageJPG();
|
||||
|
||||
void Close();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
|
||||
protected:
|
||||
void* m_state;
|
||||
}; // class CImageJPG
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGEJPG_H__
|
||||
@@ -0,0 +1,307 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImagePNG.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"
|
||||
|
||||
#ifdef _IMAGE_PNG
|
||||
#include "ImagePNG.h"
|
||||
#include <png.h>
|
||||
#include <zlib.h>
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
|
||||
// F U N C T I O N S ///////////////////////////////////////////////
|
||||
|
||||
void custom_png_read_file(png_structp png_ptr, png_bytep buffer, png_size_t size)
|
||||
{
|
||||
png_voidp const ptrIO = png_get_io_ptr(png_ptr);
|
||||
((InputStream*)ptrIO)->read(buffer, size);
|
||||
}
|
||||
|
||||
void custom_png_write_file(png_structp png_ptr, png_bytep buffer, png_size_t size)
|
||||
{
|
||||
png_voidp const ptrIO = png_get_io_ptr(png_ptr);
|
||||
((IOStream*)ptrIO)->write(buffer, size);
|
||||
}
|
||||
|
||||
void custom_png_flush_file(png_structp png_ptr)
|
||||
{
|
||||
png_voidp const ptrIO = png_get_io_ptr(png_ptr);
|
||||
((IOStream*)ptrIO)->flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
CImagePNG::CImagePNG() : m_png_ptr(NULL), m_info_ptr(NULL)
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImagePNG::~CImagePNG()
|
||||
{
|
||||
Close();
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void CImagePNG::Close()
|
||||
{
|
||||
if (m_png_ptr) {
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
png_infop info_ptr = (png_infop)m_info_ptr;
|
||||
if (bRead)
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
else
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
m_png_ptr = m_info_ptr = NULL;
|
||||
}
|
||||
CImage::Close();
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImagePNG::ReadHeader()
|
||||
{
|
||||
// initialize stuff
|
||||
ASSERT(m_png_ptr == NULL);
|
||||
m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!m_png_ptr) {
|
||||
LOG(LT_IMAGE, "error: invalid PNG image (png_create_read_struct)");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
bRead = true;
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
|
||||
m_info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!m_info_ptr) {
|
||||
LOG(LT_IMAGE, "error: invalid PNG image (png_create_info_struct)");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
png_infop info_ptr = (png_infop)m_info_ptr;
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
return _INVALIDFILE;
|
||||
|
||||
((ISTREAM*)m_pStream)->setPos(0);
|
||||
png_set_read_fn(png_ptr, m_pStream, custom_png_read_file);
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 width, height; int bitdepth, colortype;
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitdepth, &colortype, NULL, NULL, NULL);
|
||||
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
colortype = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// if it doesn't have a file gamma, don't do any correction ("do no harm")
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
|
||||
double gamma = 0;
|
||||
const double screen_gamma = 2.2;
|
||||
if (png_get_gAMA(png_ptr, info_ptr, &gamma))
|
||||
png_set_gamma(png_ptr, screen_gamma, gamma);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (colortype)
|
||||
{
|
||||
case PNG_COLOR_TYPE_GRAY:
|
||||
if (bitdepth < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
||||
m_format = PF_GRAY8;
|
||||
m_stride = 1;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
m_format = PF_B8G8R8;
|
||||
m_stride = 3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
m_format = PF_B8G8R8;
|
||||
m_stride = 3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
m_format = PF_B8G8R8;
|
||||
m_stride = 3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
m_format = PF_B8G8R8A8;
|
||||
m_stride = 4;
|
||||
break;
|
||||
default:
|
||||
LOG(LT_IMAGE, "error: unsupported PNG image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
if (bitdepth == 16)
|
||||
png_set_strip_16(png_ptr);
|
||||
|
||||
png_set_interlace_handling(png_ptr);
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
m_dataWidth = m_width = (Size)width;
|
||||
m_dataHeight= m_height = (Size)height;
|
||||
m_numLevels = 0;
|
||||
m_level = 0;
|
||||
m_lineWidth = (Size)png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
return _OK;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImagePNG::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
|
||||
// read data
|
||||
if (nStride == m_stride && (m_format != PF_B8G8R8A8 || (dataFormat != PF_A8R8G8B8 && dataFormat != PF_A8B8G8R8))) {
|
||||
if ((m_format == PF_B8G8R8 && dataFormat == PF_R8G8B8) ||
|
||||
(m_format == PF_B8G8R8A8 && dataFormat == PF_R8G8B8A8)) {
|
||||
// flip R and B from the PNG library
|
||||
png_set_bgr(png_ptr);
|
||||
} else {
|
||||
ASSERT(m_format == dataFormat);
|
||||
}
|
||||
// read image directly to the data buffer
|
||||
for (Size j=0; j<m_height; ++j, (BYTE*&)pData+=lineWidth)
|
||||
png_read_row(png_ptr, (png_bytep)pData, NULL);
|
||||
} else {
|
||||
// read image to a buffer and convert it
|
||||
CAutoPtrArr<png_byte> const buffer(new png_byte[m_lineWidth]);
|
||||
for (Size j=0; j<m_height; ++j, pData=(uint8_t*)pData+lineWidth) {
|
||||
png_read_row(png_ptr, buffer, NULL);
|
||||
if (!FilterFormat(pData, dataFormat, nStride, buffer, m_format, m_stride, m_width))
|
||||
return _FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return _OK;
|
||||
} // Read
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImagePNG::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE /*numLevels*/)
|
||||
{
|
||||
// initialize stuff
|
||||
ASSERT(m_png_ptr == NULL);
|
||||
m_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!m_png_ptr) {
|
||||
LOG(LT_IMAGE, "error: can not create PNG image (png_create_write_struct)");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
bRead = false;
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
|
||||
m_info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!m_info_ptr) {
|
||||
LOG(LT_IMAGE, "error: invalid PNG image (png_create_info_struct)");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
png_infop info_ptr = (png_infop)m_info_ptr;
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
return _INVALIDFILE;
|
||||
|
||||
// write header
|
||||
switch (imageFormat)
|
||||
{
|
||||
case PF_A8:
|
||||
case PF_GRAY8:
|
||||
m_stride = 1;
|
||||
m_format = PF_GRAY8;
|
||||
break;
|
||||
case PF_B8G8R8:
|
||||
case PF_R8G8B8:
|
||||
m_stride = 3;
|
||||
m_format = PF_B8G8R8;
|
||||
break;
|
||||
case PF_R8G8B8A8:
|
||||
case PF_A8R8G8B8:
|
||||
case PF_B8G8R8A8:
|
||||
case PF_A8B8G8R8:
|
||||
m_stride = 4;
|
||||
m_format = PF_B8G8R8A8;
|
||||
break;
|
||||
default:
|
||||
LOG(LT_IMAGE, "error: unsupported PNG image format");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
m_numLevels = 1;
|
||||
m_level = 0;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_lineWidth = GetDataSizes(0, m_dataWidth, m_dataHeight);
|
||||
|
||||
png_set_write_fn(png_ptr, m_pStream, custom_png_write_file, custom_png_flush_file);
|
||||
|
||||
int compression_level = 0;
|
||||
int compression_strategy = Z_RLE;
|
||||
|
||||
if (compression_level > 0) {
|
||||
png_set_compression_mem_level(png_ptr, compression_level);
|
||||
}
|
||||
else {
|
||||
// tune parameters for speed
|
||||
// (see http://wiki.linuxquestions.org/wiki/Libpng)
|
||||
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
|
||||
png_set_compression_level(png_ptr, Z_BEST_SPEED);
|
||||
}
|
||||
png_set_compression_strategy(png_ptr, compression_strategy);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8/*depth*/,
|
||||
m_stride == 1 ? PNG_COLOR_TYPE_GRAY :
|
||||
m_stride == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
return _OK;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImagePNG::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
|
||||
// write data
|
||||
if (nStride == m_stride && (m_format != PF_B8G8R8A8 || (dataFormat != PF_A8R8G8B8 && dataFormat != PF_A8B8G8R8))) {
|
||||
if ((m_format == PF_B8G8R8 && dataFormat == PF_R8G8B8) ||
|
||||
(m_format == PF_B8G8R8A8 && dataFormat == PF_R8G8B8A8)) {
|
||||
// flip R and B from the PNG library
|
||||
png_set_bgr(png_ptr);
|
||||
} else {
|
||||
ASSERT(m_format == dataFormat);
|
||||
}
|
||||
// write image directly to the data buffer
|
||||
for (Size j=0; j<m_height; ++j, (BYTE*&)pData+=lineWidth)
|
||||
png_write_row(png_ptr, (png_bytep)pData);
|
||||
} else {
|
||||
// read image to a buffer and convert it
|
||||
CAutoPtrArr<png_byte> const buffer(new png_byte[m_lineWidth]);
|
||||
for (Size j=0; j<m_height; ++j, pData=(uint8_t*)pData+lineWidth) {
|
||||
if (!FilterFormat(buffer, m_format, m_stride, pData, dataFormat, nStride, m_width))
|
||||
return _FAIL;
|
||||
png_write_row(png_ptr, buffer);
|
||||
}
|
||||
}
|
||||
png_write_end(png_ptr, NULL);
|
||||
|
||||
return _OK;
|
||||
} // WriteData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // _IMAGE_PNG
|
||||
@@ -0,0 +1,46 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImagePNG.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGEPNG_H__
|
||||
#define __SEACAVE_IMAGEPNG_H__
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImagePNG : public CImage
|
||||
{
|
||||
public:
|
||||
CImagePNG();
|
||||
virtual ~CImagePNG();
|
||||
|
||||
void Close();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
|
||||
protected:
|
||||
void* m_png_ptr;
|
||||
void* m_info_ptr;
|
||||
bool bRead;
|
||||
}; // class CImagePNG
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGEPNG_H__
|
||||
@@ -0,0 +1,78 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageSCI.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 "ImageSCI.h"
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
#define IMAGE_SCI_TYPE 0x494353 //"SCI" = 3 bytes
|
||||
#define IMAGE_SCI_VERSION 1 //1 byte
|
||||
#define IMAGE_SCI_HEADER ((DWORD)((((DWORD)IMAGE_SCI_VERSION)<<24)|(DWORD)IMAGE_SCI_TYPE)) //"SCI"+ver = 4 bytes
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
typedef struct SCIINFOHEADER_TYPE {
|
||||
uint32_t dwHeader;
|
||||
uint16_t shWidth;
|
||||
uint16_t shHeight;
|
||||
uint8_t byFormat;
|
||||
uint8_t byLevels;
|
||||
uint8_t byReserved1;
|
||||
uint8_t byReserved2;
|
||||
} SCIINFOHEADER;
|
||||
|
||||
|
||||
CImageSCI::CImageSCI()
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImageSCI::~CImageSCI()
|
||||
{
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageSCI::ReadHeader()
|
||||
{
|
||||
// read header
|
||||
((ISTREAM*)m_pStream)->setPos(0);
|
||||
SCIINFOHEADER sciInfo;
|
||||
m_pStream->read(&sciInfo, sizeof(SCIINFOHEADER));
|
||||
if (sciInfo.dwHeader != IMAGE_SCI_HEADER) {
|
||||
LOG(LT_IMAGE, "error: invalid SCI image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
m_width = sciInfo.shWidth;
|
||||
m_height = sciInfo.shHeight;
|
||||
m_numLevels = sciInfo.byLevels;
|
||||
m_level = 0;
|
||||
m_format = (PIXELFORMAT)sciInfo.byFormat;
|
||||
m_stride = GetStride(m_format);
|
||||
m_lineWidth = GetDataSizes(0, m_dataWidth, m_dataHeight);
|
||||
return _OK;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageSCI::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels)
|
||||
{
|
||||
// write header
|
||||
CImage::WriteHeader(imageFormat, width, height, numLevels);
|
||||
((OSTREAM*)m_pStream)->setPos(0);
|
||||
const SCIINFOHEADER sciInfo = {IMAGE_SCI_HEADER, (uint16_t)m_width, (uint16_t)m_height, (uint8_t)m_format, m_numLevels, 0, 0};
|
||||
if (sizeof(SCIINFOHEADER) != m_pStream->write(&sciInfo, sizeof(SCIINFOHEADER))) {
|
||||
LOG(LT_IMAGE, "error: failed writing the SCI image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
return _OK;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
@@ -0,0 +1,34 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageSCI.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGESCI_H__
|
||||
#define __SEACAVE_IMAGESCI_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImageSCI : public CImage
|
||||
{
|
||||
public:
|
||||
CImageSCI();
|
||||
virtual ~CImageSCI();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
}; // class CImageSCI
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGESCI_H__
|
||||
@@ -0,0 +1,146 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageTGA.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"
|
||||
|
||||
#ifdef _IMAGE_TGA
|
||||
#include "ImageTGA.h"
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct TGAINFOHEADER_TYPE {
|
||||
BYTE byIDLength; // ID length
|
||||
BYTE byCMType; // Color map type
|
||||
BYTE byType; // Image type
|
||||
struct { // Color map specifications
|
||||
uint16_t shCMIdx; // First entry index, offset into the color map table
|
||||
uint16_t shCMLength; // Color map length, number of entries
|
||||
BYTE byCMBPP; // Color map entry size, number of bits per pixel
|
||||
};
|
||||
struct { // Image specifications
|
||||
uint16_t shXOrigin; // X-origin, absolute coordinate of lower-left corner for displays where origin is at the lower left
|
||||
uint16_t shYOrigin; // Y-origin, as for X-origin
|
||||
uint16_t shWidth; // Image width, width in pixels
|
||||
uint16_t shHeight; // Image height, width in pixels
|
||||
BYTE byBPP; // Pixel depth, bits per pixel
|
||||
union {
|
||||
BYTE byAlphaInfo; // Image descriptor, bits 3-0 give the alpha channel depth, bits 4-5 give direction
|
||||
struct {
|
||||
BYTE byAlphaBPP : 3;// alpha channel depth
|
||||
BYTE bMirrored : 1;// alpha channel depth
|
||||
BYTE bFlipped : 1;// alpha channel depth
|
||||
BYTE : 0;// Force alignment to next boundary.
|
||||
};
|
||||
};
|
||||
};
|
||||
} TGAINFOHEADER;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
CImageTGA::CImageTGA()
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImageTGA::~CImageTGA()
|
||||
{
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageTGA::ReadHeader()
|
||||
{
|
||||
// read header
|
||||
((ISTREAM*)m_pStream)->setPos(0);
|
||||
TGAINFOHEADER tgaInfo;
|
||||
m_pStream->read(&tgaInfo, sizeof(TGAINFOHEADER));
|
||||
if (tgaInfo.byCMType != 0) { // paletted images not supported
|
||||
LOG(LT_IMAGE, "error: invalid TGA image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
m_dataWidth = m_width = tgaInfo.shWidth;
|
||||
m_dataHeight = m_height = tgaInfo.shHeight;
|
||||
m_numLevels = 0;
|
||||
m_level = 0;
|
||||
|
||||
// get the format
|
||||
m_stride = (tgaInfo.byBPP>>3);
|
||||
switch (tgaInfo.byType)
|
||||
{
|
||||
case 2: //uncompressed, true-color image
|
||||
case 3: //uncompressed, black-and-white image
|
||||
m_format = (m_stride == 3 ? PF_R8G8B8 : PF_R8G8B8A8);
|
||||
m_bRLE = false;
|
||||
break;
|
||||
//case 10://run-length encoded, true-color image and
|
||||
// m_format = IF_3DC;
|
||||
// m_bRLE = true;
|
||||
// break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
LOG(LT_IMAGE, "error: unsupported TGA image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
m_lineWidth = m_width * m_stride;
|
||||
|
||||
// read the id stuff, not using seeking to be able to use non seekable sources
|
||||
if (tgaInfo.byIDLength) {
|
||||
CAutoPtrArr<uint8_t> const buffer(new uint8_t[tgaInfo.byIDLength]);
|
||||
m_pStream->read(buffer, tgaInfo.byIDLength);
|
||||
}
|
||||
|
||||
return _OK;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageTGA::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
|
||||
(BYTE*&)pData += (m_height-1)*lineWidth;
|
||||
for (Size j=0; j<m_height; ++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_height; ++j) {
|
||||
if (m_lineWidth != m_pStream->read(buffer, m_lineWidth))
|
||||
return _INVALIDFILE;
|
||||
if (!FilterFormat((BYTE*)pData+(m_height-j-1)*lineWidth, dataFormat, nStride, buffer, m_format, m_stride, m_width))
|
||||
return _FAIL;
|
||||
}
|
||||
}
|
||||
return _OK;
|
||||
} // ReadData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageTGA::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels)
|
||||
{
|
||||
return _FAIL;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
HRESULT CImageTGA::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
return _FAIL;
|
||||
} // WriteData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // _IMAGE_TGA
|
||||
@@ -0,0 +1,39 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageTGA.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGETGA_H__
|
||||
#define __SEACAVE_IMAGETGA_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImageTGA : public CImage
|
||||
{
|
||||
public:
|
||||
CImageTGA();
|
||||
virtual ~CImageTGA();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
|
||||
protected:
|
||||
bool m_bRLE;
|
||||
}; // class CImageTGA
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGETGA_H__
|
||||
@@ -0,0 +1,567 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageTIFF.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"
|
||||
|
||||
#ifdef _IMAGE_TIFF
|
||||
#include "ImageTIFF.h"
|
||||
|
||||
extern "C" {
|
||||
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
|
||||
#include <tiffconf.h>
|
||||
#undef TIFF_INT64_T
|
||||
#define TIFF_INT64_T int64_t
|
||||
#undef TIFF_UINT64_T
|
||||
#define TIFF_UINT64_T uint64_t
|
||||
#endif
|
||||
#include <tiffio.h>
|
||||
}
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
ISO C++ uses a 'std::streamsize' type to define counts. This makes
|
||||
it similar to, (but perhaps not the same as) size_t.
|
||||
|
||||
The std::ios::pos_type is used to represent stream positions as used
|
||||
by tellg(), tellp(), seekg(), and seekp(). This makes it similar to
|
||||
(but perhaps not the same as) 'off_t'. The std::ios::streampos type
|
||||
is used for character streams, but is documented to not be an
|
||||
integral type anymore, so it should *not* be assigned to an integral
|
||||
type.
|
||||
|
||||
The std::ios::off_type is used to specify relative offsets needed by
|
||||
the variants of seekg() and seekp() which accept a relative offset
|
||||
argument.
|
||||
|
||||
Useful prototype knowledge:
|
||||
|
||||
Obtain read position
|
||||
ios::pos_type basic_istream::tellg()
|
||||
|
||||
Set read position
|
||||
basic_istream& basic_istream::seekg(ios::pos_type)
|
||||
basic_istream& basic_istream::seekg(ios::off_type, ios_base::seekdir)
|
||||
|
||||
Read data
|
||||
basic_istream& istream::read(char *str, streamsize count)
|
||||
|
||||
Number of characters read in last unformatted read
|
||||
streamsize istream::gcount();
|
||||
|
||||
Obtain write position
|
||||
ios::pos_type basic_ostream::tellp()
|
||||
|
||||
Set write position
|
||||
basic_ostream& basic_ostream::seekp(ios::pos_type)
|
||||
basic_ostream& basic_ostream::seekp(ios::off_type, ios_base::seekdir)
|
||||
|
||||
Write data
|
||||
basic_ostream& ostream::write(const char *str, streamsize count)
|
||||
*/
|
||||
|
||||
struct tiffis_data;
|
||||
struct tiffos_data;
|
||||
|
||||
extern "C" {
|
||||
|
||||
static tmsize_t _tiffosReadProc(thandle_t, void*, tmsize_t);
|
||||
static tmsize_t _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size);
|
||||
static tmsize_t _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size);
|
||||
static tmsize_t _tiffisWriteProc(thandle_t, void*, tmsize_t);
|
||||
static uint64_t _tiffosSeekProc(thandle_t fd, uint64_t off, int whence);
|
||||
static uint64_t _tiffisSeekProc(thandle_t fd, uint64_t off, int whence);
|
||||
static uint64_t _tiffosSizeProc(thandle_t fd);
|
||||
static uint64_t _tiffisSizeProc(thandle_t fd);
|
||||
static int _tiffosCloseProc(thandle_t fd);
|
||||
static int _tiffisCloseProc(thandle_t fd);
|
||||
static int _tiffDummyMapProc(thandle_t, void** base, toff_t* size);
|
||||
static void _tiffDummyUnmapProc(thandle_t, void* base, toff_t size);
|
||||
static TIFF* _tiffStreamOpen(const char* name, const char* mode, void *fd);
|
||||
|
||||
struct tiffis_data
|
||||
{
|
||||
ISTREAM* stream;
|
||||
size_f_t start_pos;
|
||||
};
|
||||
|
||||
struct tiffos_data
|
||||
{
|
||||
OSTREAM* stream;
|
||||
size_f_t start_pos;
|
||||
};
|
||||
|
||||
static tmsize_t _tiffosReadProc(thandle_t, void*, tmsize_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static tmsize_t _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size)
|
||||
{
|
||||
tiffis_data *data = reinterpret_cast<tiffis_data *>(fd);
|
||||
|
||||
// Verify that type does not overflow.
|
||||
size_t request_size = size;
|
||||
if (static_cast<tmsize_t>(request_size) != size)
|
||||
return static_cast<tmsize_t>(-1);
|
||||
|
||||
return static_cast<tmsize_t>(data->stream->read(buf, request_size));
|
||||
}
|
||||
|
||||
static tmsize_t _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size)
|
||||
{
|
||||
tiffos_data *data = reinterpret_cast<tiffos_data *>(fd);
|
||||
|
||||
// Verify that type does not overflow.
|
||||
size_t request_size = size;
|
||||
if (static_cast<tmsize_t>(request_size) != size)
|
||||
return static_cast<tmsize_t>(-1);
|
||||
|
||||
return static_cast<tmsize_t>(data->stream->write(buf, request_size));
|
||||
}
|
||||
|
||||
static tmsize_t _tiffisWriteProc(thandle_t, void*, tmsize_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t _tiffosSeekProc(thandle_t fd, uint64_t off, int whence)
|
||||
{
|
||||
tiffos_data *data = reinterpret_cast<tiffos_data *>(fd);
|
||||
OSTREAM* os = data->stream;
|
||||
|
||||
// if the stream has already failed, don't do anything
|
||||
if (os == NULL)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
bool bSucceeded(true);
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
{
|
||||
// Compute 64-bit offset
|
||||
uint64_t new_offset = static_cast<uint64_t>(data->start_pos) + off;
|
||||
|
||||
// Verify that value does not overflow
|
||||
size_f_t offset = static_cast<size_f_t>(new_offset);
|
||||
if (static_cast<uint64_t>(offset) != new_offset)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
bSucceeded = os->setPos(offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_CUR:
|
||||
{
|
||||
// Verify that value does not overflow
|
||||
size_f_t offset = static_cast<size_f_t>(off);
|
||||
if (static_cast<uint64_t>(offset) != off)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
bSucceeded = os->setPos(os->getPos()+offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
// Verify that value does not overflow
|
||||
size_f_t offset = static_cast<size_f_t>(off);
|
||||
if (static_cast<uint64_t>(offset) != off)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
bSucceeded = os->setPos(os->getSize()-offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to workaround problems with seeking past the end of the
|
||||
// stream. ofstream doesn't have a problem with this but
|
||||
// ostrstream/ostringstream does. In that situation, add intermediate
|
||||
// '\0' characters.
|
||||
if (!bSucceeded) {
|
||||
size_f_t origin;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
default:
|
||||
origin = data->start_pos;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
origin = os->getPos();
|
||||
break;
|
||||
case SEEK_END:
|
||||
os->setPos(os->getSize());
|
||||
origin = os->getPos();
|
||||
break;
|
||||
}
|
||||
|
||||
// only do something if desired seek position is valid
|
||||
if ((static_cast<uint64_t>(origin) + off) > static_cast<uint64_t>(data->start_pos)) {
|
||||
uint64_t num_fill;
|
||||
// extend the stream to the expected size
|
||||
os->setPos(os->getSize());
|
||||
num_fill = (static_cast<uint64_t>(origin)) + off - os->getPos();
|
||||
const char dummy = '\0';
|
||||
for (uint64_t i = 0; i < num_fill; i++)
|
||||
os->write(&dummy, 1);
|
||||
// retry the seek
|
||||
os->setPos(static_cast<size_f_t>(static_cast<uint64_t>(origin) + off));
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<uint64_t>(os->getPos());
|
||||
}
|
||||
|
||||
static uint64_t _tiffisSeekProc(thandle_t fd, uint64_t off, int whence)
|
||||
{
|
||||
tiffis_data *data = reinterpret_cast<tiffis_data *>(fd);
|
||||
ISTREAM* is = data->stream;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
{
|
||||
// Compute 64-bit offset
|
||||
uint64_t new_offset = static_cast<uint64_t>(data->start_pos) + off;
|
||||
|
||||
// Verify that value does not overflow
|
||||
size_f_t offset = static_cast<size_f_t>(new_offset);
|
||||
if (static_cast<uint64_t>(offset) != new_offset)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
is->setPos(offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_CUR:
|
||||
{
|
||||
// Verify that value does not overflow
|
||||
size_f_t offset = static_cast<size_f_t>(off);
|
||||
if (static_cast<uint64_t>(offset) != off)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
is->setPos(is->getPos()+offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
// Verify that value does not overflow
|
||||
size_f_t offset = static_cast<size_f_t>(off);
|
||||
if (static_cast<uint64_t>(offset) != off)
|
||||
return static_cast<uint64_t>(-1);
|
||||
|
||||
is->setPos(is->getSize()-offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint64_t)(is->getPos() - data->start_pos);
|
||||
}
|
||||
|
||||
static uint64_t _tiffosSizeProc(thandle_t fd)
|
||||
{
|
||||
tiffos_data *data = reinterpret_cast<tiffos_data *>(fd);
|
||||
return (uint64_t)data->stream->getSize();
|
||||
}
|
||||
|
||||
static uint64_t _tiffisSizeProc(thandle_t fd)
|
||||
{
|
||||
tiffis_data *data = reinterpret_cast<tiffis_data *>(fd);
|
||||
return (uint64_t)data->stream->getSize();
|
||||
}
|
||||
|
||||
static int _tiffosCloseProc(thandle_t fd)
|
||||
{
|
||||
// Our stream was not allocated by us, so it shouldn't be closed by us.
|
||||
delete reinterpret_cast<tiffos_data *>(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _tiffisCloseProc(thandle_t fd)
|
||||
{
|
||||
// Our stream was not allocated by us, so it shouldn't be closed by us.
|
||||
delete reinterpret_cast<tiffis_data *>(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _tiffDummyMapProc(thandle_t, void** /*base*/, toff_t* /*size*/)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void _tiffDummyUnmapProc(thandle_t, void* /*base*/, toff_t /*size*/)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a TIFF file descriptor for read/writing.
|
||||
*/
|
||||
static TIFF* _tiffStreamOpen(const char* name, const char* mode, void *fd)
|
||||
{
|
||||
TIFF* tif;
|
||||
|
||||
if (strchr(mode, 'w')) {
|
||||
tiffos_data *data = new tiffos_data;
|
||||
data->stream = reinterpret_cast<OSTREAM*>(fd);
|
||||
data->start_pos = data->stream->getPos();
|
||||
|
||||
// Open for writing.
|
||||
tif = TIFFClientOpen(name, mode,
|
||||
reinterpret_cast<thandle_t>(data),
|
||||
_tiffosReadProc,
|
||||
_tiffosWriteProc,
|
||||
_tiffosSeekProc,
|
||||
_tiffosCloseProc,
|
||||
_tiffosSizeProc,
|
||||
_tiffDummyMapProc,
|
||||
_tiffDummyUnmapProc);
|
||||
} else {
|
||||
tiffis_data *data = new tiffis_data;
|
||||
data->stream = reinterpret_cast<ISTREAM*>(fd);
|
||||
data->start_pos = data->stream->getPos();
|
||||
// Open for reading.
|
||||
tif = TIFFClientOpen(name, mode,
|
||||
reinterpret_cast<thandle_t>(data),
|
||||
_tiffisReadProc,
|
||||
_tiffisWriteProc,
|
||||
_tiffisSeekProc,
|
||||
_tiffisCloseProc,
|
||||
_tiffisSizeProc,
|
||||
_tiffDummyMapProc,
|
||||
_tiffDummyUnmapProc);
|
||||
}
|
||||
|
||||
return (tif);
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
// TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.
|
||||
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
|
||||
// NB: We don't support mapped files with streams so add 'm'
|
||||
TIFF* TIFFStreamOpen(const char* name, OSTREAM* os)
|
||||
{
|
||||
return _tiffStreamOpen(name, "wm", os);
|
||||
}
|
||||
TIFF* TIFFStreamOpen(const char* name, ISTREAM* is)
|
||||
{
|
||||
return _tiffStreamOpen(name, "rm", is);
|
||||
}
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
CImageTIFF::CImageTIFF() : m_state(NULL)
|
||||
{
|
||||
} // Constructor
|
||||
|
||||
CImageTIFF::~CImageTIFF()
|
||||
{
|
||||
//clean up
|
||||
Close();
|
||||
} // Destructor
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void CImageTIFF::Close()
|
||||
{
|
||||
if (m_state)
|
||||
{
|
||||
TIFF* tif = static_cast<TIFF*>(m_state);
|
||||
TIFFClose(tif);
|
||||
m_state = NULL;
|
||||
}
|
||||
m_width = m_height = 0;
|
||||
CImage::Close();
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageTIFF::ReadHeader()
|
||||
{
|
||||
TIFF* tif = static_cast<TIFF*>(m_state);
|
||||
if (!tif) {
|
||||
tif = TIFFStreamOpen("ReadTIFF", (ISTREAM*)m_pStream);
|
||||
if (!tif) {
|
||||
LOG(LT_IMAGE, "error: unsupported TIFF image");
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
}
|
||||
m_state = tif;
|
||||
|
||||
uint16 photometric = 0;
|
||||
if (TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &m_width) &&
|
||||
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &m_height) &&
|
||||
TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric))
|
||||
{
|
||||
uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
|
||||
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp);
|
||||
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn);
|
||||
|
||||
m_dataWidth = m_width;
|
||||
m_dataHeight= m_height;
|
||||
m_numLevels = 0;
|
||||
m_level = 0;
|
||||
|
||||
if ((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV) {
|
||||
// this is HDR format with 3 floats per pixel
|
||||
//TODO: implement
|
||||
ASSERT("error: not implemented" == NULL);
|
||||
Close();
|
||||
return _FAIL;
|
||||
}
|
||||
if (bpp > 8 &&
|
||||
((photometric != 2 && photometric != 1) ||
|
||||
(ncn != 1 && ncn != 3 && ncn != 4)))
|
||||
bpp = 8;
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
m_stride = 4;
|
||||
m_format = PF_B8G8R8A8;
|
||||
break;
|
||||
//case 16:
|
||||
// m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? 3 : 1);
|
||||
// break;
|
||||
//case 32:
|
||||
// m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
|
||||
// break;
|
||||
//case 64:
|
||||
// m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
|
||||
// break;
|
||||
default:
|
||||
//TODO: implement
|
||||
ASSERT("error: not implemented" == NULL);
|
||||
LOG(LT_IMAGE, "error: unsupported TIFF image");
|
||||
Close();
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
m_lineWidth = m_width * m_stride;
|
||||
|
||||
return _OK;
|
||||
}
|
||||
|
||||
Close();
|
||||
return _FAIL;
|
||||
} // ReadHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageTIFF::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
if (m_state && m_width && m_height) {
|
||||
TIFF* tif = (TIFF*)m_state;
|
||||
uint32_t tile_width0 = m_width, tile_height0 = 0;
|
||||
int is_tiled = TIFFIsTiled(tif);
|
||||
uint16 photometric;
|
||||
TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
|
||||
uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
|
||||
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp);
|
||||
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn);
|
||||
const int bitsPerByte = 8;
|
||||
int dst_bpp = (int)(1 * bitsPerByte);
|
||||
if (dst_bpp == 8) {
|
||||
char errmsg[1024];
|
||||
if (!TIFFRGBAImageOK(tif, errmsg)) {
|
||||
Close();
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!is_tiled) ||
|
||||
(is_tiled &&
|
||||
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width0) &&
|
||||
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height0)))
|
||||
{
|
||||
if (!is_tiled)
|
||||
TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &tile_height0);
|
||||
|
||||
if (tile_width0 <= 0)
|
||||
tile_width0 = m_width;
|
||||
|
||||
if (tile_height0 <= 0 ||
|
||||
(!is_tiled && tile_height0 == std::numeric_limits<uint32_t>::max()))
|
||||
tile_height0 = m_height;
|
||||
|
||||
uint8_t* data = (uint8_t*)pData;
|
||||
if (!is_tiled && tile_height0 == 1 && dataFormat == m_format && nStride == m_stride) {
|
||||
// read image directly to the data buffer
|
||||
for (Size j=0; j<m_height; ++j, data+=lineWidth)
|
||||
if (!TIFFReadRGBAStrip(tif, j, (uint32_t*)data)) {
|
||||
Close();
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
} else {
|
||||
// read image to a buffer and convert it
|
||||
const size_t buffer_size = 4 * tile_height0 * tile_width0;
|
||||
CLISTDEF0(uint8_t) _buffer(buffer_size);
|
||||
uint8_t* buffer = _buffer.Begin();
|
||||
|
||||
for (uint32_t y = 0; y < m_height; y += tile_height0, data += lineWidth*tile_height0) {
|
||||
uint32_t tile_height = tile_height0;
|
||||
if (y + tile_height > m_height)
|
||||
tile_height = m_height - y;
|
||||
|
||||
for (uint32_t x = 0; x < m_width; x += tile_width0) {
|
||||
uint32_t tile_width = tile_width0;
|
||||
if (x + tile_width > m_width)
|
||||
tile_width = m_width - x;
|
||||
|
||||
int ok;
|
||||
switch (dst_bpp) {
|
||||
case 8:
|
||||
{
|
||||
uint8_t* bstart = buffer;
|
||||
if (!is_tiled)
|
||||
ok = TIFFReadRGBAStrip(tif, y, (uint32_t*)buffer);
|
||||
else {
|
||||
ok = TIFFReadRGBATile(tif, x, y, (uint32_t*)buffer);
|
||||
//Tiles fill the buffer from the bottom up
|
||||
bstart += (tile_height0 - tile_height) * tile_width0 * 4;
|
||||
}
|
||||
if (!ok) {
|
||||
Close();
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < tile_height; ++i) {
|
||||
uint8_t* dst = data + x*3 + lineWidth*(tile_height - i - 1);
|
||||
uint8_t* src = bstart + i*tile_width0*4;
|
||||
if (!FilterFormat(dst, dataFormat, nStride, src, m_format, m_stride, tile_width)) {
|
||||
Close();
|
||||
return _FAIL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Close();
|
||||
return _INVALIDFILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _OK;
|
||||
}
|
||||
}
|
||||
|
||||
Close();
|
||||
return _FAIL;
|
||||
} // Read
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageTIFF::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels)
|
||||
{
|
||||
//TODO: to implement the TIFF encoder
|
||||
return _OK;
|
||||
} // WriteHeader
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
HRESULT CImageTIFF::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth)
|
||||
{
|
||||
//TODO: to implement the TIFF encoder
|
||||
return _OK;
|
||||
} // WriteData
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif // _IMAGE_TIFF
|
||||
@@ -0,0 +1,44 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// ImageTIFF.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_IMAGETIFF_H__
|
||||
#define __SEACAVE_IMAGETIFF_H__
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API CImageTIFF : public CImage
|
||||
{
|
||||
public:
|
||||
CImageTIFF();
|
||||
virtual ~CImageTIFF();
|
||||
|
||||
void Close();
|
||||
|
||||
HRESULT ReadHeader();
|
||||
HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels);
|
||||
HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth);
|
||||
|
||||
protected:
|
||||
void* m_state;
|
||||
}; // class CImageTIFF
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_IMAGETIFF_H__
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// OBJ.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 "OBJ.h"
|
||||
|
||||
using namespace SEACAVE;
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
// uncomment to enable multi-threading based on OpenMP
|
||||
#ifdef _USE_OPENMP
|
||||
#define OBJ_USE_OPENMP
|
||||
#endif
|
||||
|
||||
#define OBJ_INDEX_OFFSET 1
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
ObjModel::MaterialLib::Material::Material(const Image8U3& _diffuse_map, const Color& _Kd)
|
||||
:
|
||||
diffuse_map(_diffuse_map),
|
||||
Kd(_Kd)
|
||||
{
|
||||
}
|
||||
|
||||
bool ObjModel::MaterialLib::Material::LoadDiffuseMap()
|
||||
{
|
||||
if (diffuse_map.empty())
|
||||
return diffuse_map.Load(diffuse_name);
|
||||
return true;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
ObjModel::MaterialLib::MaterialLib()
|
||||
{
|
||||
}
|
||||
|
||||
bool ObjModel::MaterialLib::Save(const String& prefix, bool texLossless) const
|
||||
{
|
||||
std::ofstream out((prefix+".mtl").c_str());
|
||||
if (!out.good())
|
||||
return false;
|
||||
|
||||
const String pathName(Util::getFilePath(prefix));
|
||||
const String name(Util::getFileNameExt(prefix));
|
||||
#ifdef OBJ_USE_OPENMP
|
||||
bool bSuccess(true);
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int_t i = 0; i < (int_t)materials.size(); ++i) {
|
||||
const Material& mat = materials[i];
|
||||
// save material description
|
||||
std::stringstream ss;
|
||||
ss << "newmtl " << mat.name << "\n"
|
||||
<< "Ka 1.000000 1.000000 1.000000" << "\n"
|
||||
<< "Kd " << mat.Kd.r << " " << mat.Kd.g << " " << mat.Kd.b << "\n"
|
||||
<< "Ks 0.000000 0.000000 0.000000" << "\n"
|
||||
<< "Tr 1.000000" << "\n"
|
||||
<< "illum 1" << "\n"
|
||||
<< "Ns 1.000000" << "\n";
|
||||
// save material maps
|
||||
if (mat.diffuse_map.empty()) {
|
||||
#ifdef OBJ_USE_OPENMP
|
||||
#pragma omp critical
|
||||
#endif
|
||||
out << ss.str();
|
||||
continue;
|
||||
}
|
||||
if (mat.diffuse_name.IsEmpty())
|
||||
const_cast<String&>(mat.diffuse_name) = name+"_"+mat.name+"_map_Kd."+(texLossless?"png":"jpg");
|
||||
ss << "map_Kd " << mat.diffuse_name << "\n";
|
||||
#ifdef OBJ_USE_OPENMP
|
||||
#pragma omp critical
|
||||
#endif
|
||||
out << ss.str();
|
||||
const bool bRet(mat.diffuse_map.Save(pathName+mat.diffuse_name));
|
||||
#ifdef OBJ_USE_OPENMP
|
||||
#pragma omp critical
|
||||
if (!bRet)
|
||||
bSuccess = false;
|
||||
#else
|
||||
if (!bRet)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#ifdef OBJ_USE_OPENMP
|
||||
return bSuccess;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ObjModel::MaterialLib::Load(const String& fileName)
|
||||
{
|
||||
const size_t numMaterials(materials.size());
|
||||
std::ifstream in(fileName.c_str());
|
||||
String keyword;
|
||||
while (in.good() && in >> keyword) {
|
||||
if (keyword == "newmtl") {
|
||||
in >> keyword;
|
||||
materials.push_back(Material(keyword));
|
||||
} else if (keyword == "Kd") {
|
||||
ASSERT(numMaterials < materials.size());
|
||||
Color c;
|
||||
in >> c.r >> c.g >> c.b;
|
||||
materials.back().Kd = c;
|
||||
} else if (keyword == "map_Kd") {
|
||||
ASSERT(numMaterials < materials.size());
|
||||
String& diffuse_name = materials.back().diffuse_name;
|
||||
in >> diffuse_name;
|
||||
diffuse_name = Util::getFilePath(fileName) + diffuse_name;
|
||||
}
|
||||
}
|
||||
return numMaterials < materials.size();
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless) const
|
||||
{
|
||||
if (vertices.empty())
|
||||
return false;
|
||||
const String prefix(Util::getFileFullName(fileName));
|
||||
const String name(Util::getFileNameExt(prefix));
|
||||
|
||||
if (!material_lib.Save(prefix, texLossless))
|
||||
return false;
|
||||
|
||||
std::ofstream out((prefix + ".obj").c_str());
|
||||
if (!out.good())
|
||||
return false;
|
||||
|
||||
out << "mtllib " << name << ".mtl" << "\n";
|
||||
|
||||
out << std::fixed << std::setprecision(precision);
|
||||
for (size_t i = 0; i < vertices.size(); ++i) {
|
||||
out << "v "
|
||||
<< vertices[i][0] << " "
|
||||
<< vertices[i][1] << " "
|
||||
<< vertices[i][2] << "\n";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < texcoords.size(); ++i) {
|
||||
out << "vt "
|
||||
<< texcoords[i][0] << " "
|
||||
<< texcoords[i][1] << "\n";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < normals.size(); ++i) {
|
||||
out << "vn "
|
||||
<< normals[i][0] << " "
|
||||
<< normals[i][1] << " "
|
||||
<< normals[i][2] << "\n";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < groups.size(); ++i) {
|
||||
out << "usemtl " << groups[i].material_name << "\n";
|
||||
for (size_t j = 0; j < groups[i].faces.size(); ++j) {
|
||||
const Face& face = groups[i].faces[j];
|
||||
out << "f";
|
||||
for (size_t k = 0; k < 3; ++k) {
|
||||
out << " " << face.vertices[k] + OBJ_INDEX_OFFSET;
|
||||
if (!texcoords.empty()) {
|
||||
out << "/" << face.texcoords[k] + OBJ_INDEX_OFFSET;
|
||||
if (!normals.empty())
|
||||
out << "/" << face.normals[k] + OBJ_INDEX_OFFSET;
|
||||
} else
|
||||
if (!normals.empty())
|
||||
out << "//" << face.normals[k] + OBJ_INDEX_OFFSET;
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjModel::Load(const String& fileName)
|
||||
{
|
||||
ASSERT(vertices.empty() && groups.empty() && material_lib.materials.empty());
|
||||
std::ifstream fin(fileName.c_str());
|
||||
String line, keyword;
|
||||
std::istringstream in;
|
||||
while (fin.good()) {
|
||||
std::getline(fin, line);
|
||||
if (line.empty() || line[0u] == '#')
|
||||
continue;
|
||||
in.str(line);
|
||||
in >> keyword;
|
||||
if (keyword == "v") {
|
||||
Vertex v;
|
||||
in >> v[0] >> v[1] >> v[2];
|
||||
if (in.fail())
|
||||
return false;
|
||||
vertices.push_back(v);
|
||||
} else
|
||||
if (keyword == "vt") {
|
||||
TexCoord vt;
|
||||
in >> vt[0] >> vt[1];
|
||||
if (in.fail())
|
||||
return false;
|
||||
texcoords.push_back(vt);
|
||||
} else
|
||||
if (keyword == "vn") {
|
||||
Normal vn;
|
||||
in >> vn[0] >> vn[1] >> vn[2];
|
||||
if (in.fail())
|
||||
return false;
|
||||
normals.push_back(vn);
|
||||
} else
|
||||
if (keyword == "f") {
|
||||
Face f;
|
||||
memset(&f, 0xFF, sizeof(Face));
|
||||
for (size_t k = 0; k < 3; ++k) {
|
||||
in >> keyword;
|
||||
switch (sscanf(keyword, "%u/%u/%u", f.vertices+k, f.texcoords+k, f.normals+k)) {
|
||||
case 1:
|
||||
f.vertices[k] -= OBJ_INDEX_OFFSET;
|
||||
break;
|
||||
case 2:
|
||||
f.vertices[k] -= OBJ_INDEX_OFFSET;
|
||||
if (f.texcoords[k] != NO_ID)
|
||||
f.texcoords[k] -= OBJ_INDEX_OFFSET;
|
||||
if (f.normals[k] != NO_ID)
|
||||
f.normals[k] -= OBJ_INDEX_OFFSET;
|
||||
break;
|
||||
case 3:
|
||||
f.vertices[k] -= OBJ_INDEX_OFFSET;
|
||||
f.texcoords[k] -= OBJ_INDEX_OFFSET;
|
||||
f.normals[k] -= OBJ_INDEX_OFFSET;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (in.fail())
|
||||
return false;
|
||||
if (groups.empty())
|
||||
AddGroup("");
|
||||
groups.back().faces.push_back(f);
|
||||
} else
|
||||
if (keyword == "mtllib") {
|
||||
in >> keyword;
|
||||
if (!material_lib.Load(keyword))
|
||||
return false;
|
||||
} else
|
||||
if (keyword == "usemtl") {
|
||||
Group group;
|
||||
in >> group.material_name;
|
||||
if (in.fail())
|
||||
return false;
|
||||
groups.push_back(group);
|
||||
}
|
||||
in.clear();
|
||||
}
|
||||
return !vertices.empty();
|
||||
}
|
||||
|
||||
|
||||
ObjModel::Group& ObjModel::AddGroup(const String& material_name)
|
||||
{
|
||||
groups.push_back(Group());
|
||||
Group& group = groups.back();
|
||||
group.material_name = material_name;
|
||||
if (!GetMaterial(material_name))
|
||||
material_lib.materials.push_back(MaterialLib::Material(material_name));
|
||||
return group;
|
||||
}
|
||||
|
||||
ObjModel::MaterialLib::Material* ObjModel::GetMaterial(const String& name)
|
||||
{
|
||||
MaterialLib::Materials::iterator it(std::find_if(material_lib.materials.begin(), material_lib.materials.end(), [&name](const MaterialLib::Material& mat) { return mat.name == name; }));
|
||||
if (it == material_lib.materials.end())
|
||||
return NULL;
|
||||
return &(*it);
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// OBJ.h
|
||||
//
|
||||
// Copyright 2007 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef __SEACAVE_OBJ_H__
|
||||
#define __SEACAVE_OBJ_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
|
||||
namespace SEACAVE {
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
// OBJ model files parser.
|
||||
//
|
||||
// The OBJ file format is a simple data-format that represents 3D geometry alone —
|
||||
// namely, the position of each vertex, the UV position of each texture coordinate
|
||||
// vertex, vertex normals, and the faces that make each polygon defined as a list of
|
||||
// vertices, and texture vertices. Vertices are stored in a counter-clockwise order
|
||||
// by default, making explicit declaration of face normals unnecessary.
|
||||
|
||||
class IO_API ObjModel {
|
||||
public:
|
||||
typedef Pixel32F Color;
|
||||
|
||||
// represents a material lib of an OBJ model
|
||||
struct MaterialLib {
|
||||
// represents a Lambertian material
|
||||
struct Material {
|
||||
String name;
|
||||
String diffuse_name;
|
||||
Image8U3 diffuse_map;
|
||||
Color Kd;
|
||||
|
||||
Material() : Kd(Color::WHITE) {}
|
||||
Material(const String& _name) : name(_name), Kd(Color::WHITE) {}
|
||||
Material(const Image8U3& _diffuse_map, const Color& _Kd=Color::WHITE);
|
||||
|
||||
// Makes sure the image is loaded for the diffuse map
|
||||
bool LoadDiffuseMap();
|
||||
};
|
||||
|
||||
typedef std::vector<Material> Materials;
|
||||
|
||||
Materials materials;
|
||||
|
||||
MaterialLib();
|
||||
|
||||
// Saves the material lib to a .mtl file and all textures of its materials with the given prefix name
|
||||
bool Save(const String& prefix, bool texLossless=false) const;
|
||||
// Loads the material lib from a .mtl file and all textures of its materials with the given file name
|
||||
bool Load(const String& fileName);
|
||||
};
|
||||
|
||||
typedef Point3f Vertex;
|
||||
typedef Point2f TexCoord;
|
||||
typedef Point3f Normal;
|
||||
|
||||
typedef uint32_t Index;
|
||||
|
||||
struct Face {
|
||||
Index vertices[3];
|
||||
Index texcoords[3];
|
||||
Index normals[3];
|
||||
};
|
||||
|
||||
struct Group {
|
||||
String material_name;
|
||||
std::vector<Face> faces;
|
||||
};
|
||||
|
||||
typedef std::vector<Vertex> Vertices;
|
||||
typedef std::vector<TexCoord> TexCoords;
|
||||
typedef std::vector<Normal> Normals;
|
||||
typedef std::vector<Group> Groups;
|
||||
|
||||
protected:
|
||||
Vertices vertices;
|
||||
TexCoords texcoords;
|
||||
Normals normals;
|
||||
Groups groups;
|
||||
MaterialLib material_lib;
|
||||
|
||||
public:
|
||||
ObjModel() {}
|
||||
|
||||
// Saves the obj model to an .obj file, its material lib and the materials with the given file name
|
||||
bool Save(const String& fileName, unsigned precision=6, bool texLossless=false) const;
|
||||
// Loads the obj model from an .obj file, its material lib and the materials with the given file name
|
||||
bool Load(const String& fileName);
|
||||
|
||||
// Creates a new group with the given material name
|
||||
Group& AddGroup(const String& material_name);
|
||||
// Retrieves a material from the library based on its name
|
||||
MaterialLib::Material* GetMaterial(const String& name);
|
||||
|
||||
MaterialLib& get_material_lib() { return material_lib; }
|
||||
Vertices& get_vertices() { return vertices; }
|
||||
TexCoords& get_texcoords() { return texcoords; }
|
||||
Normals& get_normals() { return normals; }
|
||||
Groups& get_groups() { return groups; }
|
||||
};
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
} // namespace SEACAVE
|
||||
|
||||
#endif // __SEACAVE_OBJ_H__
|
||||
+2386
File diff suppressed because it is too large.
Load diff
+315
@@ -0,0 +1,315 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// PLY.h
|
||||
//
|
||||
// Copyright 2023 cDc@seacave
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// PLY polygon files parser.
|
||||
// (originally by Greg Turk, heavily modified by cDc@seacave)
|
||||
//
|
||||
// A PLY file contains a single polygonal _object_.
|
||||
//
|
||||
// An object is composed of lists of _elements_. Typical elements are
|
||||
// vertices, faces, edges and materials.
|
||||
//
|
||||
// Each type of element for a given object has one or more _properties_
|
||||
// associated with the element type. For instance, a vertex element may
|
||||
// have as properties three floating-point values x,y,z and three unsigned
|
||||
// chars for red, green and blue.
|
||||
|
||||
|
||||
#ifndef __SEACAVE_PLY_H__
|
||||
#define __SEACAVE_PLY_H__
|
||||
|
||||
|
||||
// I N C L U D E S /////////////////////////////////////////////////
|
||||
|
||||
|
||||
// D E F I N E S ///////////////////////////////////////////////////
|
||||
|
||||
#define PLY_OKAY 0 // ply routine worked okay
|
||||
#define PLY_ERROR -1 // error in ply routine
|
||||
|
||||
|
||||
// S T R U C T S ///////////////////////////////////////////////////
|
||||
|
||||
class IO_API PLY
|
||||
{
|
||||
public:
|
||||
// scalar data types supported by PLY format
|
||||
enum FileType {
|
||||
ASCII = 1, // ascii PLY file
|
||||
BINARY_BE = 2, // binary PLY file, big endian
|
||||
BINARY_LE = 3, // binary PLY file, little endian
|
||||
};
|
||||
enum DataType {
|
||||
StartType = 0,
|
||||
Int8 = 1,
|
||||
Int16 = 2,
|
||||
Int32 = 3,
|
||||
Uint8 = 4,
|
||||
Uint16 = 5,
|
||||
Uint32 = 6,
|
||||
Float32 = 7,
|
||||
Float64 = 8,
|
||||
EndType = 9,
|
||||
};
|
||||
enum ListType {
|
||||
SCALAR = 0,
|
||||
LIST = 1,
|
||||
STRING = 2,
|
||||
};
|
||||
enum RuleType {
|
||||
AVERAGE_RULE = 1,
|
||||
MAJORITY_RULE = 2,
|
||||
MINIMUM_RULE = 3,
|
||||
MAXIMUM_RULE = 4,
|
||||
SAME_RULE = 5,
|
||||
RANDOM_RULE = 6,
|
||||
};
|
||||
|
||||
// description of a property
|
||||
struct PlyProperty {
|
||||
std::string name; // property name
|
||||
int external_type; // file's data type
|
||||
int internal_type; // program's data type
|
||||
int offset; // offset bytes of prop in a struct
|
||||
|
||||
int is_list; // 0 = scalar, 1 = list, 2 = char string
|
||||
int count_external; // file's count type
|
||||
int count_internal; // program's count type
|
||||
int count_offset; // offset byte for list count
|
||||
};
|
||||
|
||||
// description of an element
|
||||
struct PlyElement {
|
||||
std::string name; // element name
|
||||
int num; // number of elements in this object
|
||||
int size; // size of element (bytes) or -1 if variable
|
||||
std::vector<PlyProperty*> props;// list of properties in the file
|
||||
std::vector<char> store_prop; // flags: property wanted by user?
|
||||
int other_offset; // offset to un-asked-for props, or -1 if none
|
||||
int other_size; // size of other_props structure
|
||||
};
|
||||
|
||||
// describes other properties in an element
|
||||
struct PlyOtherProp {
|
||||
std::string name; // element name
|
||||
int size; // size of other_props
|
||||
std::vector<PlyProperty*> props;// list of properties in other_props
|
||||
};
|
||||
|
||||
// for storing other_props for an other element
|
||||
struct OtherData {
|
||||
void* other_props;
|
||||
};
|
||||
|
||||
// data for one "other" element
|
||||
struct OtherElem {
|
||||
std::string elem_name; // names of other elements
|
||||
int elem_count; // count of instances of each element
|
||||
OtherData** other_data; // actual property data for the elements
|
||||
PlyOtherProp* other_props; // description of the property data
|
||||
};
|
||||
|
||||
// "other" elements, not interpreted by user
|
||||
struct PlyOtherElems {
|
||||
std::vector<OtherElem> other_list;// list of data for other elements
|
||||
};
|
||||
|
||||
// rules for combining "other" properties
|
||||
struct PlyPropRules {
|
||||
PlyElement* elem; // element whose rules we are making
|
||||
int* rule_list; // types of rules (AVERAGE_PLY, MAJORITY_PLY, etc.)
|
||||
uint32_t max_props; // maximum number of properties we have room for now
|
||||
std::vector<void*> props; // list of properties we're combining
|
||||
std::vector<float> weights; // list of weights of the properties
|
||||
};
|
||||
|
||||
struct PlyRuleList {
|
||||
LPCSTR name; // name of the rule
|
||||
char* element; // name of element that rule applies to
|
||||
char* property; // name of property that rule applies to
|
||||
struct PlyRuleList* next; // pointer for linked list of rules
|
||||
};
|
||||
|
||||
// property propagation rules
|
||||
struct RuleName {
|
||||
int code;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
protected:
|
||||
struct ValueType {
|
||||
union {
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
float f;
|
||||
double d;
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
PLY();
|
||||
~PLY();
|
||||
|
||||
bool read(LPCSTR);
|
||||
bool read(SEACAVE::ISTREAM*);
|
||||
bool write(LPCSTR, int, LPCSTR*, int, size_t memBufferSize=0);
|
||||
bool write(SEACAVE::OSTREAM*, int, LPCSTR*, int, size_t memBufferSize=0);
|
||||
void release();
|
||||
|
||||
void set_legacy_type_names();
|
||||
|
||||
void get_info(float*, int*);
|
||||
|
||||
void append_comment(const char*);
|
||||
void append_obj_info(const char*);
|
||||
void copy_comments(const PLY&);
|
||||
void copy_obj_info(const PLY&);
|
||||
std::vector<std::string>& get_comments();
|
||||
std::vector<std::string>& get_obj_info();
|
||||
|
||||
void describe_property(const char*, const PlyProperty&);
|
||||
void describe_property(const char*, int nprops, const PlyProperty*);
|
||||
void get_property(const char*, PlyProperty*);
|
||||
void get_element(void*);
|
||||
|
||||
PlyOtherElems* get_other_element();
|
||||
|
||||
int get_element_list(std::vector<std::string>&) const;
|
||||
void setup_property(const PlyProperty&);
|
||||
LPCSTR setup_element_read(int, int*);
|
||||
PlyOtherProp* get_other_properties(int);
|
||||
|
||||
int get_elements_count() const { return (int)elems.size(); }
|
||||
int get_current_element_count() const { return which_elem->num; }
|
||||
void element_count(const char*, int);
|
||||
void describe_element(const char*, int);
|
||||
void describe_property(const PlyProperty&);
|
||||
void describe_other_properties(PlyOtherProp*, int);
|
||||
void describe_other_elements( PlyOtherElems*);
|
||||
void get_element_setup(const char*, int, PlyProperty*);
|
||||
int get_element_description(const char*, std::vector<PlyProperty*>&) const;
|
||||
void element_layout(const char*, int, int, PlyProperty*);
|
||||
|
||||
bool header_complete();
|
||||
void put_element_setup(const char*);
|
||||
void put_element(const void*);
|
||||
void put_other_elements();
|
||||
|
||||
PlyPropRules* init_rule(const char*);
|
||||
void modify_rule(PlyPropRules*, const char*, int);
|
||||
void start_props(PlyPropRules*);
|
||||
void weight_props(float, void*);
|
||||
void* get_new_props();
|
||||
void set_prop_rules(PlyRuleList*);
|
||||
PlyRuleList* append_prop_rule(PlyRuleList*, const char*, const char*);
|
||||
|
||||
// find an element in a ply's list
|
||||
PlyElement* find_element(const char*) const;
|
||||
// find a property in an element's list
|
||||
int find_property(PlyElement*, const char*) const;
|
||||
|
||||
static inline bool equal_strings(const char* s1, const char* s2) { return _tcscmp(s1, s2) == 0; }
|
||||
|
||||
protected:
|
||||
// write to a file the word describing a PLY file data type
|
||||
void write_scalar_type(int);
|
||||
|
||||
// read a line from a file and break it up into separate words
|
||||
typedef SEACAVE::TokenInputStream<false> STRISTREAM;
|
||||
char** get_words(STRISTREAM&, int*, char**);
|
||||
|
||||
// write an item to a file
|
||||
void write_binary_item(const ValueType&, int, int);
|
||||
void write_ascii_item(const ValueType&, int, int);
|
||||
|
||||
// return the value of a stored item
|
||||
static void get_stored_item(const void*, int, ValueType&);
|
||||
|
||||
// get binary or ascii item and store it according to ptr and type
|
||||
void get_binary_item(int, ValueType&);
|
||||
static void get_ascii_item(const char*, int, ValueType&);
|
||||
|
||||
// store a value into where a pointer and a type specify
|
||||
static void store_item(void*, int, const ValueType&, int);
|
||||
|
||||
// add information to a PLY file descriptor
|
||||
void add_element(const char**, int);
|
||||
void add_property(const char**, int);
|
||||
void add_comment(const char*);
|
||||
void add_obj_info(const char*);
|
||||
|
||||
// get a bunch of elements from a file
|
||||
void ascii_get_element(uint8_t*);
|
||||
void binary_get_element(uint8_t*);
|
||||
|
||||
void setup_other_props(PlyElement*);
|
||||
PlyOtherProp* get_other_properties(PlyElement*, int);
|
||||
PlyOtherProp* get_other_properties(const char*, int);
|
||||
|
||||
int matches_rule_name(const char*);
|
||||
int get_prop_type(const char*);
|
||||
|
||||
// copy a property
|
||||
static void copy_property(PlyProperty&, const PlyProperty&);
|
||||
|
||||
// return the value as T stored in val as type
|
||||
template <typename T>
|
||||
static inline T ValueType2Type(const ValueType& val, int type) {
|
||||
switch (type) {
|
||||
case Int8:
|
||||
return (T)val.i8;
|
||||
case Int16:
|
||||
return (T)val.i16;
|
||||
case Int32:
|
||||
return (T)val.i32;
|
||||
case Uint8:
|
||||
return (T)val.u8;
|
||||
case Uint16:
|
||||
return (T)val.u16;
|
||||
case Uint32:
|
||||
return (T)val.u32;
|
||||
case Float32:
|
||||
return (T)val.f;
|
||||
case Float64:
|
||||
return (T)val.d;
|
||||
}
|
||||
ASSERT("error: bad type" == NULL);
|
||||
return T(0);
|
||||
}
|
||||
|
||||
protected:
|
||||
// description of PLY file
|
||||
std::string filename; // file name
|
||||
int file_type; // ascii or binary
|
||||
float version; // version number of file
|
||||
std::vector<PlyElement*> elems; // list of elements
|
||||
std::vector<std::string> comments;// list of comments
|
||||
std::vector<std::string> obj_info;// list of object info items
|
||||
PlyElement* which_elem; // element we're currently reading or writing
|
||||
PlyOtherElems* other_elems; // "other" elements from a PLY file
|
||||
PlyPropRules* current_rules; // current propagation rules
|
||||
PlyRuleList* rule_list; // rule list from user
|
||||
std::vector<double> vals; // rule list from user
|
||||
|
||||
union {
|
||||
SEACAVE::ISTREAM* istream; // input file pointer
|
||||
SEACAVE::OSTREAM* ostream; // output file pointer
|
||||
};
|
||||
SEACAVE::MemFile* mfp; // mem-file pointer (optional)
|
||||
const char* const* write_type_names; // names of scalar types to be used for writing (new types by default)
|
||||
|
||||
static const char* const type_names[9]; // names of scalar types
|
||||
static const char* const old_type_names[9]; // old names of types for backward compatibility
|
||||
static const int ply_type_size[9];
|
||||
static const RuleName rule_name_list[7];
|
||||
};
|
||||
|
||||
#endif // __SEACAVE_PLY_H__
|
||||
File diff suppressed because it is too large.
Load diff
+2368
File diff suppressed because it is too large.
Load diff
+20406
File diff suppressed because it is too large.
Load diff
+7754
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user