diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 7307945..0d24cfb 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -1,11 +1,13 @@ SET( SOURCES - "src/ImageFile.cpp" + "src/ImageWriter.cpp" "src/ImageLoader.cpp" "src/FileStream.cpp" + "src/ImageFile.cpp" ) SET( HEADERS + "config/ImageWriter.h.in" "config/ImageLoader.h.in" "include/ImageFile.h" "include/FileStream.h" @@ -17,6 +19,8 @@ IF( PNG_FOUND ) SET( SOURCES ${SOURCES} "src/ImageLoaderPNG.cpp" ) SET( HEADERS ${HEADERS} "src/ImageLoaderPNG.h" ) + SET( SOURCES ${SOURCES} "src/ImageWriterPNG.cpp" ) + SET( HEADERS ${HEADERS} "src/ImageWriterPNG.h" ) ENDIF() CONFIGURE_FILE( @@ -24,6 +28,11 @@ CONFIGURE_FILE( "include/ImageLoader.h" ) +CONFIGURE_FILE( + "config/ImageWriter.h.in" + "include/ImageWriter.h" +) + INCLUDE_DIRECTORIES( ${TexC_BINARY_DIR}/IO/include ) INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/IO/include ) INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/include ) @@ -35,5 +44,5 @@ ADD_LIBRARY(TexCompIO IF( PNG_FOUND ) TARGET_LINK_LIBRARIES( TexCompIO ${PNG_LIBRARY} ) - TARGET_LINK_LIBRARIES( TexCompIO ${ZLIB_LIBRARY} ) + TARGET_LINK_LIBRARIES( TexCompIO ${ZLIB_LIBRARY} ) ENDIF() diff --git a/IO/config/ImageWriter.h.in b/IO/config/ImageWriter.h.in new file mode 100644 index 0000000..f0e9102 --- /dev/null +++ b/IO/config/ImageWriter.h.in @@ -0,0 +1,45 @@ +#ifndef _IMAGE_WRITER_H_ +#define _IMAGE_WRITER_H_ + +#include "ImageFileFormat.h" +#include "TexCompTypes.h" + +class ImageWriter { + + protected: + + uint32 m_Width; + uint32 m_Height; + + const uint8 *m_PixelData; + uint32 m_RawFileDataSz; + uint8 *m_RawFileData; + + ImageWriter(const int width, const int height, const uint8 *rawData) + : m_PixelData(rawData) + , m_Width(width), m_Height(height) + , m_RawFileDataSz(256) + , m_RawFileData(new uint8[m_RawFileDataSz]) + { } + + uint32 GetChannelForPixel(uint32 x, uint32 y, uint32 ch); + + public: + virtual ~ImageWriter() { + if(m_RawFileData) { + delete m_RawFileData; + m_RawFileData = 0; + } + } + + uint32 GetWidth() const { return m_Width; } + uint32 GetHeight() const { return m_Height; } + uint32 GetImageDataSz() const { return m_Width * m_Height * 4; } + uint32 GetRawImageDataSz() const { return m_RawFileDataSz; } + uint8 *GetRawImageData() const { return m_RawFileData; } + virtual bool WriteImage() = 0; +}; + +#cmakedefine PNG_FOUND + +#endif // _IMAGE_LOADER_H_ diff --git a/IO/src/ImageWriter.cpp b/IO/src/ImageWriter.cpp new file mode 100644 index 0000000..18b8172 --- /dev/null +++ b/IO/src/ImageWriter.cpp @@ -0,0 +1,7 @@ +#include "ImageWriter.h" + +uint32 ImageWriter::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) { + uint32 bytesPerRow = GetWidth() * 4; + uint32 byteLocation = y * bytesPerRow + x*4 + ch; + return m_PixelData[byteLocation]; +} diff --git a/IO/src/ImageWriterPNG.cpp b/IO/src/ImageWriterPNG.cpp new file mode 100644 index 0000000..3b97442 --- /dev/null +++ b/IO/src/ImageWriterPNG.cpp @@ -0,0 +1,110 @@ +#include "ImageWriterPNG.h" + +#include +#include +#include + +#include "Image.h" + +#include + +class PNGStreamWriter { +public: + static void WriteDataToStream( + png_structp png_ptr, + png_bytep outBytes, + png_size_t byteCountToWrite + ) { + png_voidp io_ptr = png_get_io_ptr( png_ptr ); + if( io_ptr == NULL ) { + fprintf(stderr, "Write callback had invalid io pointer.\n"); + return; + } + + ImageWriterPNG &writer = *(ImageWriterPNG *)(io_ptr); + + while(writer.m_StreamPosition + byteCountToWrite > writer.m_RawFileDataSz) { + uint8 *newData = new uint8[writer.m_RawFileDataSz << 1]; + memcpy(newData, writer.m_RawFileData, writer.m_RawFileDataSz); + writer.m_RawFileDataSz <<= 1; + delete writer.m_RawFileData; + writer.m_RawFileData = newData; + } + + unsigned char *stream = &(writer.m_RawFileData[writer.m_StreamPosition]); + memcpy(stream, outBytes, byteCountToWrite); + + writer.m_StreamPosition += byteCountToWrite; + } + + static void FlushStream(png_structp png_ptr) { /* Do nothing... */ } + +}; + +ImageWriterPNG::ImageWriterPNG(const Image &im) + : ImageWriter(im.GetWidth(), im.GetHeight(), im.RawData()) + , m_StreamPosition(0) + , m_TotalBytesWritten(0) +{ +} + +bool ImageWriterPNG::WriteImage() { + + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_byte ** row_pointers = NULL; + int pixel_size = 4; + int depth = 8; + + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) { + return false; + } + + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL) { + png_destroy_write_struct (&png_ptr, &info_ptr); + return false; + } + + /* Set image attributes. */ + + png_set_IHDR (png_ptr, + info_ptr, + m_Width, + m_Height, + depth, + PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + /* Initialize rows of PNG. */ + + row_pointers = (png_byte **)png_malloc (png_ptr, m_Height * sizeof (png_byte *)); + for (int y = 0; y < m_Height; ++y) { + png_byte *row = (png_byte *)png_malloc (png_ptr, sizeof (uint8) * m_Width * pixel_size); + + row_pointers[y] = row; + + for (int x = 0; x < m_Width; ++x) { + for(int ch = 0; ch < 4; ch++) { + *row++ = GetChannelForPixel(x, y, ch); + } + } + } + + png_set_write_fn(png_ptr, this, PNGStreamWriter::WriteDataToStream, PNGStreamWriter::FlushStream); + png_set_rows (png_ptr, info_ptr, row_pointers); + png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + for (int y = 0; y < m_Height; y++) { + png_free (png_ptr, row_pointers[y]); + } + png_free (png_ptr, row_pointers); + + png_destroy_write_struct (&png_ptr, &info_ptr); + + m_RawFileDataSz = m_StreamPosition; + return true; +} diff --git a/IO/src/ImageWriterPNG.h b/IO/src/ImageWriterPNG.h new file mode 100644 index 0000000..2167c00 --- /dev/null +++ b/IO/src/ImageWriterPNG.h @@ -0,0 +1,20 @@ +#ifndef _IMAGE_WRITER_PNG_H_ +#define _IMAGE_WRITER_PNG_H_ + +#include "ImageWriter.h" + +// Forward Declare +class Image; +class ImageWriterPNG : public ImageWriter { + public: + ImageWriterPNG(const Image &); + virtual ~ImageWriterPNG(); + + virtual bool WriteImage(); + private: + uint32 m_StreamPosition; + uint32 m_TotalBytesWritten; + friend class PNGStreamWriter; +}; + +#endif // _IMAGE_LOADER_H_