Got JPG/PNG loading from disk and from memory

This commit is contained in:
Joshua Granick
2014-07-27 19:35:53 -07:00
parent df3ba5992f
commit 6e37b82c4c
5 changed files with 176 additions and 35 deletions

View File

@@ -1,6 +1,7 @@
package lime.graphics;
import lime.utils.ByteArray;
import lime.utils.UInt8Array;
import lime.system.System;
@@ -115,6 +116,22 @@ class Image {
}
public static function loadFromBytes (bytes:ByteArray):Image {
#if (cpp || neko)
var imageData = lime_image_load_bytes (bytes);
return (imageData == null ? null : new Image (new UInt8Array (imageData.data), imageData.width, imageData.height, imageData.bpp));
#else
throw "Image.loadFromFile not supported on this target";
#end
}
public static function loadFromFile (path:String) {
#if (cpp || neko)
@@ -123,9 +140,9 @@ class Image {
return (imageData == null ? null : new Image (new UInt8Array (imageData.data), imageData.width, imageData.height, imageData.bpp));
#else
throw "Image.loadFromFile not supported on this target";
#end
}
@@ -193,6 +210,7 @@ class Image {
#if (cpp || neko)
private static var lime_image_load = System.load ("lime", "lime_image_load", 1);
private static var lime_image_load_bytes = System.load ("lime", "lime_image_load_bytes", 1);
#end

View File

@@ -10,12 +10,14 @@ namespace lime {
struct Resource {
Resource (const char* path) { this->path = path; }
Resource (ByteArray *data) { this->data = data; }
Resource (const char* path) : data (NULL), path (path) {}
Resource (ByteArray *data) : data (data), path (NULL) {}
ByteArray *data;
const char* path;
};

View File

@@ -57,7 +57,34 @@ namespace lime {
value lime_image_load (value path) {
Image image;
Resource resource = Resource (val_string (path));
Resource resource (val_string (path));
#ifdef LIME_PNG
if (PNG::Decode (&resource, &image)) {
return image.Value ();
}
#endif
#ifdef LIME_JPEG
if (JPEG::Decode (&resource, &image)) {
return image.Value ();
}
#endif
return alloc_null ();
}
value lime_image_load_bytes (value bytes) {
Image image;
ByteArray data (bytes);
Resource resource (&data);
#ifdef LIME_PNG
if (PNG::Decode (&resource, &image)) {
@@ -251,6 +278,7 @@ namespace lime {
DEFINE_PRIM (lime_application_exec, 1);
DEFINE_PRIM (lime_application_get_ticks, 0);
DEFINE_PRIM (lime_image_load, 1);
DEFINE_PRIM (lime_image_load_bytes, 1);
DEFINE_PRIM (lime_font_load, 1);
DEFINE_PRIM (lime_font_load_glyphs, 3);
DEFINE_PRIM (lime_key_event_manager_register, 2);

View File

@@ -127,16 +127,19 @@ namespace lime {
//cinfo.err = jpeg_std_error (&jerr);
struct ErrorData jpegError;
cinfo.err = jpeg_std_error (&jpegError.base);
jpegError.base.error_exit = OnError;
jpegError.base.output_message = OnOutput;
cinfo.err = jpeg_std_error (&jpegError.base);
FILE *file;
FILE *file = NULL;
if (setjmp (jpegError.on_error)) {
if (file)
if (file) {
lime::fclose (file);
}
jpeg_destroy_decompress (&cinfo);
return false;
@@ -196,9 +199,13 @@ namespace lime {
}
lime::fclose (file);
jpeg_destroy_decompress (&cinfo);
if (file) {
lime::fclose (file);
}
jpeg_destroy_decompress (&cinfo);
return decoded;
}

View File

@@ -1,40 +1,110 @@
extern "C" {
#include <png.h>
#include <pngstruct.h>
#define PNG_SIG_SIZE 8
}
#include <setjmp.h>
#include <graphics/PNG.h>
#include <utils/FileIO.h>
#include <utils/QuickVec.h>
namespace lime {
struct ReadBuf {
ReadBuf (const uint8 *inData, int inLen) : mData (inData), mLen (inLen) {}
bool Read (uint8 *outBuffer, int inN) {
if (inN > mLen) {
memset (outBuffer, 0, inN);
return false;
}
memcpy (outBuffer, mData, inN);
mData += inN;
mLen -= inN;
return true;
}
const uint8 *mData;
int mLen;
};
static void user_error_fn (png_structp png_ptr, png_const_charp error_msg) {
longjmp (png_ptr->jmp_buf_local, 1);
}
static void user_warning_fn (png_structp png_ptr, png_const_charp warning_msg) {}
static void user_read_data_fn (png_structp png_ptr, png_bytep data, png_size_t length) {
png_voidp buffer = png_get_io_ptr (png_ptr);
((ReadBuf *)buffer)->Read (data, length);
}
void user_write_data (png_structp png_ptr, png_bytep data, png_size_t length) {
QuickVec<unsigned char> *buffer = (QuickVec<unsigned char> *)png_get_io_ptr (png_ptr);
buffer->append ((unsigned char *)data,(int)length);
}
void user_flush_data (png_structp png_ptr) {}
bool PNG::Decode (Resource *resource, Image *image) {
unsigned char png_sig[PNG_SIG_SIZE];
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type;
int bit_depth, color_type, interlace_type;
FILE *file = lime::fopen (resource->path, "rb");
if (!file) return false;
FILE *file = NULL;
// verify the PNG signature
int read = lime::fread (png_sig, PNG_SIG_SIZE, 1, file);
if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) {
if (resource->path) {
lime::fclose (file);
return false;
file = lime::fopen (resource->path, "rb");
if (!file) return false;
// verify the PNG signature
/*int read = lime::fread (png_sig, PNG_SIG_SIZE, 1, file);
if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) {
lime::fclose (file);
return false;
}*/
} else {
// TODO: optimize ByteArray Format check?
}
if ((png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) {
lime::fclose (file);
if (file) lime::fclose (file);
return false;
}
@@ -42,7 +112,7 @@ namespace lime {
if ((info_ptr = png_create_info_struct (png_ptr)) == NULL) {
png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
lime::fclose (file);
if (file) lime::fclose (file);
return false;
}
@@ -51,43 +121,59 @@ namespace lime {
if (setjmp (png_jmpbuf (png_ptr))) {
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
lime::fclose (file);
if (file) lime::fclose (file);
return false;
}
png_init_io (png_ptr, file);
png_set_sig_bytes (png_ptr, PNG_SIG_SIZE);
if (file) {
png_init_io (png_ptr, file);
} else {
ReadBuf buffer (resource->data->Bytes (), resource->data->Size ());
png_set_read_fn (png_ptr, (void *)&buffer, user_read_data_fn);
}
png_read_info (png_ptr, info_ptr);
width = png_get_image_width (png_ptr, info_ptr);
height = png_get_image_height (png_ptr, info_ptr);
color_type = png_get_color_type (png_ptr, info_ptr);
bit_depth = png_get_bit_depth (png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
bool has_alpha = (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS));
png_set_expand (png_ptr);
png_set_filler (png_ptr, 0xff, PNG_FILLER_AFTER);
//png_set_gray_1_2_4_to_8 (png_ptr);
png_set_palette_to_rgb (png_ptr);
png_set_gray_to_rgb (png_ptr);
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
//png_set_bgr (png_ptr);
int bpp = 4;
const unsigned int stride = width * bpp;
image->Resize(width, height, bpp);
image->Resize (width, height, bpp);
png_bytepp row_ptrs = new png_bytep[height];
unsigned char *bytes = image->data->Bytes ();
for (size_t i = 0; i < height; i++) {
int number_of_passes = png_set_interlace_handling (png_ptr);
for (int pass = 0; pass < number_of_passes; pass++) {
row_ptrs[i] = bytes + i * stride;
for (int i = 0; i < height; i++) {
png_bytep anAddr = (png_bytep)(bytes + i * stride);
png_read_rows (png_ptr, (png_bytepp) &anAddr, NULL, 1);
}
}
png_read_image (png_ptr, row_ptrs);
png_read_end (png_ptr, NULL);
delete[] row_ptrs;
png_read_end (png_ptr, info_ptr);
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
return true;