| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- #include "Base.h"
- #include "FileSystem.h"
- #include "Image.h"
- namespace gameplay
- {
- // Callback for reading a png image using Stream
- static void readStream(png_structp png, png_bytep data, png_size_t length)
- {
- Stream* stream = reinterpret_cast<Stream*>(png_get_io_ptr(png));
- if (stream == NULL || stream->read(data, 1, length) != length)
- {
- png_error(png, "Error reading PNG.");
- }
- }
- Image* Image::create(const char* path)
- {
- GP_ASSERT(path);
- // Open the file.
- std::auto_ptr<Stream> stream(FileSystem::open(path));
- if (stream.get() == NULL || !stream->canRead())
- {
- GP_ERROR("Failed to open image file '%s'.", path);
- return NULL;
- }
- // Verify PNG signature.
- unsigned char sig[8];
- if (stream->read(sig, 1, 8) != 8 || png_sig_cmp(sig, 0, 8) != 0)
- {
- GP_ERROR("Failed to load file '%s'; not a valid PNG.", path);
- return NULL;
- }
- // Initialize png read struct (last three parameters use stderr+longjump if NULL).
- png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png == NULL)
- {
- GP_ERROR("Failed to create PNG structure for reading PNG file '%s'.", path);
- return NULL;
- }
- // Initialize info struct.
- png_infop info = png_create_info_struct(png);
- if (info == NULL)
- {
- GP_ERROR("Failed to create PNG info structure for PNG file '%s'.", path);
- png_destroy_read_struct(&png, NULL, NULL);
- return NULL;
- }
- // Set up error handling (required without using custom error handlers above).
- if (setjmp(png_jmpbuf(png)))
- {
- GP_ERROR("Failed to set up error handling for reading PNG file '%s'.", path);
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- // Initialize file io.
- png_set_read_fn(png, stream.get(), readStream);
- // Indicate that we already read the first 8 bytes (signature).
- png_set_sig_bytes(png, 8);
- // Read the entire image into memory.
- png_read_png(png, info, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
- Image* image = new Image();
- image->_width = png_get_image_width(png, info);
- image->_height = png_get_image_height(png, info);
- png_byte colorType = png_get_color_type(png, info);
- switch (colorType)
- {
- case PNG_COLOR_TYPE_RGBA:
- image->_format = Image::RGBA;
- break;
- case PNG_COLOR_TYPE_RGB:
- image->_format = Image::RGB;
- break;
- default:
- GP_ERROR("Unsupported PNG color type (%d) for image file '%s'.", (int)colorType, path);
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- size_t stride = png_get_rowbytes(png, info);
- // Allocate image data.
- image->_data = new unsigned char[stride * image->_height];
- // Read rows into image data.
- png_bytepp rows = png_get_rows(png, info);
- for (unsigned int i = 0; i < image->_height; ++i)
- {
- memcpy(image->_data+(stride * (image->_height-1-i)), rows[i], stride);
- }
- // Clean up.
- png_destroy_read_struct(&png, &info, NULL);
- return image;
- }
- Image* Image::create(unsigned int width, unsigned int height, Image::Format format, unsigned char* data)
- {
- GP_ASSERT(width > 0 && height > 0);
- GP_ASSERT(format >= RGB && format <= RGBA);
- unsigned int pixelSize = 0;
- switch(format)
- {
- case Image::RGB:
- pixelSize = 3;
- break;
- case Image::RGBA:
- pixelSize = 4;
- break;
- }
- Image* image = new Image();
- unsigned int dataSize = width * height * pixelSize;
- image->_width = width;
- image->_height = height;
- image->_format = format;
- image->_data = new unsigned char[dataSize];
- if (data)
- memcpy(image->_data, data, dataSize);
- return image;
- }
- Image::Image()
- {
- // Unused
- }
- Image::~Image()
- {
- SAFE_DELETE_ARRAY(_data);
- }
- }
|