/*
Image class
for loading and saving images
Not tested
Compiles with: g++ -c Image.cpp -o Image.o -I /usr/X11/include
Curerntly saving isn't implemented yet
Only PNG and JPG supported at the moment
Baseline implementation using system libjpeg and libpng
Currently not using standalone implementations of these so not slimmed down for tiny embedded use
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jpeglib.h>
#include <png.h>
#include "Image.h"
namespace details
{
enum ImageExt
{
EXT_NONE,
EXT_PNG,
EXT_JPG
};
ImageExt extension(const char* a_fileName)
{
int i = strlen(a_fileName) - 1;
while (i >= 0 && a_fileName[i] != '.')
i--;
if (!strcmp(a_fileName + i, ".png"))
return EXT_PNG;
if (!strcmp(a_fileName + i, ".jpg"))
return EXT_JPG;
return EXT_NONE;
}
}
Image::Image()
{
init(0, 0, 0);
}
Image::Image(const char* a_fileName)
{
if (a_fileName)
{
FILE *file = fopen(a_fileName, "r");
if ( !file ) {
printf("Error opening file %s\n", a_fileName);
} else {
bool okay = false;
if (details::extension(a_fileName) == details::EXT_PNG)
okay = initFromPng(file);
else if (details::extension(a_fileName) == details::EXT_JPG)
okay = initFromJpg(file);
fclose(file);
if (okay)
return;
}
}
init(0, 0, 0);
}
Image::Image(int a_width, int a_height, int a_bytesPerPixel)
{
init(a_width, a_height, a_bytesPerPixel);
}
Image::~Image()
{
for (int i = m_height - 1; i >= 0; i--)
free(m_scanLines[i]);
free(m_scanLines);
}
void Image::init(int a_width, int a_height, int a_bytesPerPixel)
{
m_width = a_width;
m_height = a_height;
m_scanLines = (uint32_t**)malloc(sizeof(char*)*m_height);
for (int i = m_height - 1; i >= 0; i--)
m_scanLines[i] = (uint32_t*)malloc(4*m_width);
}
bool Image::initFromJpg(FILE* a_file)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr err;
cinfo.err = jpeg_std_error(&err);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, a_file);
jpeg_read_header(&cinfo, TRUE);
jpeg_calc_output_dimensions(&cinfo);
jpeg_start_decompress(&cinfo);
// Setup image
init(cinfo.output_width, cinfo.output_height, 3);
// Decode image
for (int i = 0; i < m_height; i++)
jpeg_read_scanlines(&cinfo, (JSAMPLE**)&m_scanLines[i], 1);
// Clean up
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return true;
}
bool Image::initFromPng(FILE* a_file)
{
int width, height;
png_structp png;
png_infop cinfo;
png_infop cinfo_end;
struct png_read_struct *reads;
// Initialise
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
cinfo = png_create_info_struct(png);
cinfo_end = png_create_info_struct(png);
png_init_io(png, a_file);
png_read_info(png, cinfo);
width = png_get_image_width(png, cinfo);
height = png_get_image_height(png, cinfo);
// Setup image
init(width, height, 4);
// Decode image
png_start_read_image(png);
png_read_image(png, (png_bytepp)m_scanLines);
// Clean up
png_read_end(png, cinfo_end);
png_destroy_read_struct(&png, &cinfo, &cinfo_end);
return true;
}
bool Image::save(const char* a_fileName)
{
bool okay = false;
if (a_fileName)
{
FILE *file = fopen(a_fileName, "w");
if ( !file ) {
printf("Error opening file %s for saving\n", a_fileName);
} else {
if (details::extension(a_fileName) == details::EXT_PNG)
okay = saveToPng(file);
else if (details::extension(a_fileName) == details::EXT_JPG)
okay = saveToJpg(file);
fclose(file);
}
}
return false;
}
bool Image::saveToPng(FILE* a_file)
{
return false;
}
bool Image::saveToJpg(FILE* a_file)
{
return false;
}