提交scripts

This commit is contained in:
hesuicong committed 2025-07-21 10:09:12 +08:00
1 parent 82caf72036
commit 07dabbd186
224 files changed
+130146

No files matched your search

+51
View File
@@ -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")
+12
View File
@@ -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"
+63
View File
@@ -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__
+935
View File
@@ -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
View File
@@ -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__
+261
View File
@@ -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
+36
View File
@@ -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__
+341
View File
@@ -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
+36
View File
@@ -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__
+281
View File
@@ -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
+44
View File
@@ -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__
+307
View File
@@ -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
+46
View File
@@ -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__
+78
View File
@@ -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
/*----------------------------------------------------------------*/
+34
View File
@@ -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__
+146
View File
@@ -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
+39
View File
@@ -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__
+567
View File
@@ -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
+44
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+315
View File
@@ -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__
+2987
View File
File diff suppressed because it is too large. Load diff
+2368
View File
File diff suppressed because it is too large. Load diff
+20406
View File
File diff suppressed because it is too large. Load diff
+7754
View File
File diff suppressed because it is too large. Load diff