From cc7e8c1b1fb4f427545bbd9c0f7af7ea926cb550 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 27 Aug 2012 11:37:10 -0400 Subject: [PATCH] Add preliminary hooks for reading out png data... --- IO/ImageFile.cpp | 17 ++++ IO/ImageLoader.h.in | 49 +++++++++--- IO/ImageLoaderPNG.cpp | 179 +++++++++++++++++++++++++++++++++++++++++- IO/ImageLoaderPNG.h | 6 +- 4 files changed, 240 insertions(+), 11 deletions(-) diff --git a/IO/ImageFile.cpp b/IO/ImageFile.cpp index 58324c7..9b53120 100644 --- a/IO/ImageFile.cpp +++ b/IO/ImageFile.cpp @@ -63,6 +63,23 @@ EImageFileFormat ImageFile::DetectFileFormat(const char *filename) { } bool ImageFile::LoadImage(const unsigned char *rawImageData) { + + ImageLoader *loader = NULL; + switch(m_FileFormat) { + +#ifdef PNG_FOUND + case eFileFormat_PNG: + { + loader = new ImageLoaderPNG(rawImageData); + } + break; +#endif // PNG_FOUND + + default: + fprintf(stderr, "Unable to load image: unknown file format.\n"); + break; + } + return false; } diff --git a/IO/ImageLoader.h.in b/IO/ImageLoader.h.in index 9b54d9b..758b9a5 100644 --- a/IO/ImageLoader.h.in +++ b/IO/ImageLoader.h.in @@ -10,25 +10,56 @@ enum EImageFileFormat { class ImageLoader { protected: - int m_RedChannelPrecision; + + unsigned int m_Width; + unsigned int m_Height; + + unsigned int m_RedChannelPrecision; unsigned char *m_RedData; - int m_GreenChannelPrecision; + unsigned int m_GreenChannelPrecision; unsigned char *m_GreenData; - - int m_BlueChannelPrecision; - unsigned char *m_BlueData; - int m_AlphaChannelPrecision; + unsigned int m_BlueChannelPrecision; + unsigned char *m_BlueData; + + unsigned int m_AlphaChannelPrecision; unsigned char *m_AlphaData; const unsigned char *const m_RawData; - ImageLoader(const unsigned char *rawData); - virtual ~ImageLoader(); + ImageLoader(const unsigned char *rawData) : m_RawData(rawData) + , m_Width(0), m_Height(0) + , m_RedChannelPrecision(0), m_RedData(0) + , m_GreenChannelPrecision(0), m_GreenData(0) + , m_BlueChannelPrecision(0), m_BlueData(0) + , m_AlphaChannelPrecision(0), m_AlphaData(0) + { } + + virtual ~ImageLoader() { + if(m_RedData) { + delete [] m_RedData; + m_RedData = 0; + } + + if(m_GreenData) { + delete [] m_GreenData; + m_GreenData = 0; + } + + if(m_BlueData) { + delete [] m_BlueData; + m_BlueData = 0; + } + + if(m_AlphaData) { + delete [] m_AlphaData; + m_AlphaData = 0; + } + } public: - virtual void ReadData() = 0; + virtual bool ReadData() = 0; int GetRedChannelPrecision() const { return m_RedChannelPrecision; } unsigned char * GetRedPixelData() const { return m_RedData; } diff --git a/IO/ImageLoaderPNG.cpp b/IO/ImageLoaderPNG.cpp index 9c8f8a6..77231eb 100644 --- a/IO/ImageLoaderPNG.cpp +++ b/IO/ImageLoaderPNG.cpp @@ -1,7 +1,22 @@ #include "ImageLoaderPNG.h" +#include +#include + #include +class PNGStreamReader { +public: + static void ReadDataFromStream( + png_structp png_ptr, + png_bytep outBytes, + png_size_t byteCountToRead + ) { + + + } +}; + ImageLoaderPNG::ImageLoaderPNG(const unsigned char *rawData) : ImageLoader(rawData) { @@ -10,5 +25,167 @@ ImageLoaderPNG::ImageLoaderPNG(const unsigned char *rawData) ImageLoaderPNG::~ImageLoaderPNG() { } -void ImageLoaderPNG::ReadData() { +static void ReportError(const char *msg) { + fprintf(stderr, "ERROR: ImageLoaderPNG -- %s\n", msg); +} + +bool ImageLoaderPNG::ReadData() { + + const int kNumSigBytesToRead = 8; + if(!png_sig_cmp(m_RawData, 0, kNumSigBytesToRead)) { + ReportError("Incorrect PNG signature"); + return false; + } + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(!png_ptr) { + ReportError("Could not create read struct"); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if(!info_ptr) { + ReportError("Could not create info struct"); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return false; + } + + // Read from our buffer, not a file pointer... + png_set_read_fn(png_ptr, this, PNGStreamReader::ReadDataFromStream); + + // Make sure to tell libpng how many bytes we've read... + png_set_sig_bytes(png_ptr, kNumSigBytesToRead); + + png_read_info(png_ptr, info_ptr); + + int bitDepth = 0; + int colorType = -1; + + if( 1 != png_get_IHDR(png_ptr, info_ptr, + &m_Width, &m_Height, + &bitDepth, &colorType, + NULL, NULL, NULL) + ) { + ReportError("Could not read PNG header"); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return false; + } + + if(bitDepth != 8) { + ReportError("Only 8-bit images currently supported."); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return false; + } + + const int numPixels = m_Width * m_Height; + unsigned int bpr = png_get_rowbytes(png_ptr, info_ptr); + png_bytep rowData = new png_byte[bpr]; + + switch(colorType) { + default: + case PNG_COLOR_TYPE_PALETTE: + ReportError("PNG color type unsupported"); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return false; + + case PNG_COLOR_TYPE_GRAY: { + m_RedChannelPrecision = bitDepth; + m_RedData = new unsigned char[numPixels]; + + for(int i = 0; i < m_Height; i++) { + + png_read_row(png_ptr, rowData, NULL); + + unsigned int rowOffset = i * m_Height; + + unsigned int byteIdx = 0; + for(int j = 0; j < m_Width; j++) { + + } + + assert(byteIdx == bpr); + } + } + break; + + case PNG_COLOR_TYPE_RGB: + m_RedChannelPrecision = bitDepth; + m_RedData = new unsigned char[numPixels]; + m_GreenChannelPrecision = bitDepth; + m_GreenData = new unsigned char[numPixels]; + m_BlueChannelPrecision = bitDepth; + m_BlueData = new unsigned char[numPixels]; + + for(int i = 0; i < m_Height; i++) { + + png_read_row(png_ptr, rowData, NULL); + + unsigned int rowOffset = i * m_Height; + + unsigned int byteIdx = 0; + for(int j = 0; j < m_Width; j++) { + m_RedData[rowOffset + j] = rowData[byteIdx++]; + m_GreenData[rowOffset + j] = rowData[byteIdx++]; + m_BlueData[rowOffset + j] = rowData[byteIdx++]; + } + + assert(byteIdx == bpr); + } + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + m_RedChannelPrecision = bitDepth; + m_RedData = new unsigned char[numPixels]; + m_GreenChannelPrecision = bitDepth; + m_GreenData = new unsigned char[numPixels]; + m_BlueChannelPrecision = bitDepth; + m_BlueData = new unsigned char[numPixels]; + m_AlphaChannelPrecision = bitDepth; + m_AlphaData = new unsigned char[numPixels]; + + for(int i = 0; i < m_Height; i++) { + + png_read_row(png_ptr, rowData, NULL); + + unsigned int rowOffset = i * m_Height; + + unsigned int byteIdx = 0; + for(int j = 0; j < m_Width; j++) { + m_RedData[rowOffset + j] = rowData[byteIdx++]; + m_GreenData[rowOffset + j] = rowData[byteIdx++]; + m_BlueData[rowOffset + j] = rowData[byteIdx++]; + m_AlphaData[rowOffset + j] = rowData[byteIdx++]; + } + + assert(byteIdx == bpr); + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + m_RedChannelPrecision = bitDepth; + m_RedData = new unsigned char[numPixels]; + m_AlphaChannelPrecision = bitDepth; + m_AlphaData = new unsigned char[numPixels]; + + for(int i = 0; i < m_Height; i++) { + + png_read_row(png_ptr, rowData, NULL); + + unsigned int rowOffset = i * m_Height; + + unsigned int byteIdx = 0; + for(int j = 0; j < m_Width; j++) { + m_RedData[rowOffset + j] = rowData[byteIdx++]; + m_AlphaData[rowOffset + j] = rowData[byteIdx++]; + } + + assert(byteIdx == bpr); + } + break; + } + + // Cleanup + delete [] rowData; + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return true; } diff --git a/IO/ImageLoaderPNG.h b/IO/ImageLoaderPNG.h index dfb80e0..209f17e 100644 --- a/IO/ImageLoaderPNG.h +++ b/IO/ImageLoaderPNG.h @@ -8,7 +8,11 @@ class ImageLoaderPNG : public ImageLoader { ImageLoaderPNG(const unsigned char *rawData); virtual ~ImageLoaderPNG(); - virtual void ReadData(); + virtual bool ReadData(); + +private: + unsigned int m_StreamPosition; + friend class PNGStreamReader; }; #endif // _IMAGE_LOADER_H_