Source

love-less-deps / src / modules / image / libpng / ImageData.cpp

/**
 * Copyright (c) 2006-2012 LOVE Development Team
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 **/

#include "ImageData.h"

#ifdef LOVE_NODEVIL

// STD
#include <cstring>
#include <iostream>

// LOVE
#include "common/Exception.h"
#include "common/math.h"
#include "filesystem/File.h"


namespace love
{
namespace image
{
namespace libpng
{

ImageData::ImageData(Data *data)
{
	load(data);
}

ImageData::ImageData(filesystem::File *file)
{
	Data *data = file->read();
	load(data);
	data->release();
}

ImageData::ImageData(int width, int height)
{
	this->width = width;
	this->height = height;
	create(width, height);

	// Set to black.
	memset(data, 0, width*height*sizeof(pixel));
}

ImageData::ImageData(int width, int height, void *data)
{
	this->width = width;
	this->height = height;
	create(width, height, data);
}

ImageData::~ImageData()
{
	delete[] data;
}

void ImageData::create(int width, int height, void *data)
{
	try
	{
		this->data = new unsigned char[width*height*sizeof(pixel)];
	}
	catch(std::bad_alloc &)
	{
		throw love::Exception("Out of memory");
	}

	if (data)
		memcpy(this->data, data, width*height*sizeof(pixel));
}

static void love_png_read_helper(png_structp png_ptr, png_bytep outBytes,  png_size_t byteCountToRead)
{
   if(png_ptr->io_ptr == NULL)
      return;   // add custom error handling here

   memcpy(outBytes, png_ptr->io_ptr, byteCountToRead);
   png_ptr->io_ptr = (void *)((char *) png_ptr->io_ptr + byteCountToRead);
} 

void ImageData::load(Data *data)
{
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_bytep bdata = (png_bytep)(data->getData());
	png_bytep* row_ptrs = NULL;
	try {
		if ( data->getSize() < 8 ) throw love::Exception("Image is way to small");

		int is_png = png_sig_cmp(bdata, 0, 8);
		if ( is_png != 0 ) throw love::Exception("Image is not PNG");

		
		png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
		if (!png_ptr) throw love::Exception("Couldn't initialize png read struct");

		info_ptr = png_create_info_struct(png_ptr);
		if (!info_ptr) throw love::Exception("Couldn't initialize png info struct");

		if (setjmp(png_jmpbuf(png_ptr))) throw love::Exception("An error occured while reading the PNG file");
		png_set_read_fn(png_ptr, data->getData(), love_png_read_helper);
		png_read_info(png_ptr, info_ptr);
		
		png_uint_32 width = 0;
		png_uint_32 height = 0;
		int bitdepth = 0;
		int colortype = -1;
		png_uint_32 retval = png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitdepth, &colortype, NULL, NULL, NULL);
		if ( retval != 1 ) throw love::Exception("An error occured while reading the PNG info");

		this->width = width;
		this->height = height;
		create(width, height);

		row_ptrs = new png_bytep[height];
		for (size_t i = 0; i < height; i++) {
			row_ptrs[i] = this->data + i * width * sizeof(pixel);
		}

    		png_read_image(png_ptr, row_ptrs);
		delete[] row_ptrs;
    		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	} catch (std::exception &)
	{
    		if ( png_ptr != NULL ) png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		if ( row_ptrs != NULL ) delete[] row_ptrs;
		throw;
	}
}

void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
{

	if ( format != ImageData::FORMAT_PNG )
		throw love::Exception("PNG Is the only supported image type.");

	throw love::Exception("Not Supported");
	
}

} // libpng
} // image
} // love

#endif // LOVE_NODEVIL