Add JPEG and PNG decodeBytes/decodeFile, with support for skipping imageBuffer.data

This commit is contained in:
Joshua Granick
2015-06-12 11:30:33 -07:00
parent 172ab1a307
commit 0090c953b7
8 changed files with 244 additions and 55 deletions

View File

@@ -2,6 +2,7 @@ package lime.graphics.format;
import lime.graphics.Image;
import lime.graphics.ImageBuffer;
import lime.system.System;
import lime.utils.ByteArray;
@@ -9,6 +10,48 @@ import lime.utils.ByteArray;
class JPEG {
public static function decodeBytes (bytes:ByteArray, decodeData:Bool = true):Image {
#if (cpp || neko || nodejs)
var bufferData = lime_jpeg_decode_bytes (bytes, decodeData);
if (bufferData != null) {
var buffer = new ImageBuffer (bufferData.data, bufferData.width, bufferData.height, bufferData.bpp, bufferData.format);
buffer.transparent = bufferData.transparent;
return new Image (buffer);
}
#end
return null;
}
public static function decodeFile (path:String, decodeData:Bool = true):Image {
#if (cpp || neko || nodejs)
var bufferData = lime_jpeg_decode_file (path, decodeData);
if (bufferData != null) {
var buffer = new ImageBuffer (bufferData.data, bufferData.width, bufferData.height, bufferData.bpp, bufferData.format);
buffer.transparent = bufferData.transparent;
return new Image (buffer);
}
#end
return null;
}
public static function encode (image:Image, quality:Int):ByteArray {
#if java
@@ -32,6 +75,8 @@ class JPEG {
#if (cpp || neko || nodejs)
private static var lime_jpeg_decode_bytes:ByteArray -> Bool -> Dynamic = System.load ("lime", "lime_jpeg_decode_bytes", 2);
private static var lime_jpeg_decode_file:String -> Bool -> Dynamic = System.load ("lime", "lime_jpeg_decode_file", 2);
private static var lime_image_encode:ImageBuffer -> Int -> Int -> ByteArray = System.load ("lime", "lime_image_encode", 3);
#end

View File

@@ -17,6 +17,48 @@ import haxe.io.BytesOutput;
class PNG {
public static function decodeBytes (bytes:ByteArray, decodeData:Bool = true):Image {
#if (cpp || neko || nodejs)
var bufferData = lime_png_decode_bytes (bytes, decodeData);
if (bufferData != null) {
var buffer = new ImageBuffer (bufferData.data, bufferData.width, bufferData.height, bufferData.bpp, bufferData.format);
buffer.transparent = bufferData.transparent;
return new Image (buffer);
}
#end
return null;
}
public static function decodeFile (path:String, decodeData:Bool = true):Image {
#if (cpp || neko || nodejs)
var bufferData = lime_png_decode_file (path, decodeData);
if (bufferData != null) {
var buffer = new ImageBuffer (bufferData.data, bufferData.width, bufferData.height, bufferData.bpp, bufferData.format);
buffer.transparent = bufferData.transparent;
return new Image (buffer);
}
#end
return null;
}
public static function encode (image:Image):ByteArray {
#if java
@@ -90,6 +132,8 @@ class PNG {
#if (cpp || neko || nodejs)
private static var lime_png_decode_bytes:ByteArray -> Bool -> Dynamic = System.load ("lime", "lime_png_decode_bytes", 2);
private static var lime_png_decode_file = System.load ("lime", "lime_png_decode_file", 2);
private static var lime_image_encode:ImageBuffer -> Int -> Int -> ByteArray = System.load ("lime", "lime_image_encode", 3);
#end

View File

@@ -15,7 +15,7 @@ namespace lime {
public:
static bool Decode (Resource *resource, ImageBuffer *imageBuffer);
static bool Decode (Resource *resource, ImageBuffer *imageBuffer, bool decodeData = true);
static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes, int quality);

View File

@@ -15,7 +15,7 @@ namespace lime {
public:
static bool Decode (Resource *resource, ImageBuffer *imageBuffer);
static bool Decode (Resource *resource, ImageBuffer *imageBuffer, bool decodeData = true);
static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes);

View File

@@ -616,6 +616,44 @@ namespace lime {
}
value lime_jpeg_decode_bytes (value data, value decodeData) {
ImageBuffer imageBuffer;
ByteArray bytes (data);
Resource resource = Resource (&bytes);
#ifdef LIME_JPEG
if (JPEG::Decode (&resource, &imageBuffer, val_bool (decodeData))) {
return imageBuffer.Value ();
}
#endif
return alloc_null ();
}
value lime_jpeg_decode_file (value data, value decodeData) {
ImageBuffer imageBuffer;
Resource resource = Resource (val_string (data));
#ifdef LIME_JPEG
if (JPEG::Decode (&resource, &imageBuffer, val_bool (decodeData))) {
return imageBuffer.Value ();
}
#endif
return alloc_null ();
}
value lime_key_event_manager_register (value callback, value eventObject) {
KeyEvent::callback = new AutoGCRoot (callback);
@@ -718,6 +756,44 @@ namespace lime {
}
value lime_png_decode_bytes (value data, value decodeData) {
ImageBuffer imageBuffer;
ByteArray bytes (data);
Resource resource = Resource (&bytes);
#ifdef LIME_PNG
if (PNG::Decode (&resource, &imageBuffer, val_bool (decodeData))) {
return imageBuffer.Value ();
}
#endif
return alloc_null ();
}
value lime_png_decode_file (value data, value decodeData) {
ImageBuffer imageBuffer;
Resource resource = Resource (val_string (data));
#ifdef LIME_PNG
if (PNG::Decode (&resource, &imageBuffer, val_bool (decodeData))) {
return imageBuffer.Value ();
}
#endif
return alloc_null ();
}
value lime_render_event_manager_register (value callback, value eventObject) {
RenderEvent::callback = new AutoGCRoot (callback);
@@ -1054,6 +1130,8 @@ namespace lime {
DEFINE_PRIM (lime_image_encode, 3);
DEFINE_PRIM (lime_image_load, 1);
DEFINE_PRIM (lime_jni_getenv, 0);
DEFINE_PRIM (lime_jpeg_decode_bytes, 2);
DEFINE_PRIM (lime_jpeg_decode_file, 2);
DEFINE_PRIM (lime_key_event_manager_register, 2);
DEFINE_PRIM (lime_lzma_decode, 1);
DEFINE_PRIM (lime_lzma_encode, 1);
@@ -1064,6 +1142,8 @@ namespace lime {
DEFINE_PRIM (lime_mouse_show, 0);
DEFINE_PRIM (lime_mouse_warp, 3);
DEFINE_PRIM (lime_neko_execute, 1);
DEFINE_PRIM (lime_png_decode_bytes, 2);
DEFINE_PRIM (lime_png_decode_file, 2);
DEFINE_PRIM (lime_renderer_create, 1);
DEFINE_PRIM (lime_renderer_flip, 1);
DEFINE_PRIM (lime_renderer_lock, 1);

View File

@@ -117,7 +117,7 @@ namespace lime {
alloc_field (mValue, id_height, alloc_int (height));
alloc_field (mValue, id_bpp, alloc_int (bpp));
alloc_field (mValue, id_transparent, alloc_bool (transparent));
alloc_field (mValue, id_data, data->mValue);
alloc_field (mValue, id_data, data ? data->mValue : alloc_null ());
alloc_field (mValue, id_format, alloc_int (format));
return mValue;

View File

@@ -178,7 +178,7 @@ namespace lime {
};
bool JPEG::Decode (Resource *resource, ImageBuffer* imageBuffer) {
bool JPEG::Decode (Resource *resource, ImageBuffer* imageBuffer, bool decodeData) {
struct jpeg_decompress_struct cinfo;
@@ -246,35 +246,45 @@ namespace lime {
cinfo.out_color_space = JCS_RGB;
jpeg_start_decompress (&cinfo);
int components = cinfo.num_components;
imageBuffer->Resize (cinfo.output_width, cinfo.output_height);
unsigned char *bytes = imageBuffer->data->Bytes ();
unsigned char *scanline = new unsigned char [imageBuffer->width * imageBuffer->height * components];
while (cinfo.output_scanline < cinfo.output_height) {
if (decodeData) {
jpeg_read_scanlines (&cinfo, &scanline, 1);
jpeg_start_decompress (&cinfo);
int components = cinfo.num_components;
imageBuffer->Resize (cinfo.output_width, cinfo.output_height);
// convert 24-bit scanline to 32-bit
const unsigned char *line = scanline;
const unsigned char *const end = line + imageBuffer->width * components;
unsigned char *bytes = imageBuffer->data->Bytes ();
unsigned char *scanline = new unsigned char [imageBuffer->width * imageBuffer->height * components];
while (line != end) {
while (cinfo.output_scanline < cinfo.output_height) {
*bytes++ = *line++;
*bytes++ = *line++;
*bytes++ = *line++;
*bytes++ = 0xFF;
jpeg_read_scanlines (&cinfo, &scanline, 1);
// convert 24-bit scanline to 32-bit
const unsigned char *line = scanline;
const unsigned char *const end = line + imageBuffer->width * components;
while (line != end) {
*bytes++ = *line++;
*bytes++ = *line++;
*bytes++ = *line++;
*bytes++ = 0xFF;
}
}
delete[] scanline;
jpeg_finish_decompress (&cinfo);
} else {
imageBuffer->width = cinfo.image_width;
imageBuffer->height = cinfo.image_height;
}
delete[] scanline;
jpeg_finish_decompress (&cinfo);
decoded = true;
}

View File

@@ -75,7 +75,7 @@ namespace lime {
void user_flush_data (png_structp png_ptr) {}
bool PNG::Decode (Resource *resource, ImageBuffer *imageBuffer) {
bool PNG::Decode (Resource *resource, ImageBuffer *imageBuffer, bool decodeData) {
unsigned char png_sig[PNG_SIG_SIZE];
png_structp png_ptr;
@@ -159,46 +159,56 @@ namespace lime {
png_read_info (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 < 8) {
if (decodeData) {
png_set_packing (png_ptr);
//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));
} else if (bit_depth == 16) {
png_set_expand (png_ptr);
png_set_scale_16 (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);
}
//png_set_bgr (png_ptr);
int bpp = 4;
const unsigned int stride = width * bpp;
imageBuffer->Resize (width, height, bpp);
unsigned char *bytes = imageBuffer->data->Bytes ();
int number_of_passes = png_set_interlace_handling (png_ptr);
for (int pass = 0; pass < number_of_passes; pass++) {
for (int i = 0; i < height; i++) {
if (bit_depth < 8) {
png_bytep anAddr = (png_bytep)(bytes + i * stride);
png_read_rows (png_ptr, (png_bytepp) &anAddr, NULL, 1);
png_set_packing (png_ptr);
} else if (bit_depth == 16) {
png_set_scale_16 (png_ptr);
}
//png_set_bgr (png_ptr);
int bpp = 4;
const unsigned int stride = width * bpp;
imageBuffer->Resize (width, height, bpp);
unsigned char *bytes = imageBuffer->data->Bytes ();
int number_of_passes = png_set_interlace_handling (png_ptr);
for (int pass = 0; pass < number_of_passes; pass++) {
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_end (png_ptr, NULL);
} else {
imageBuffer->width = width;
imageBuffer->height = height;
}
png_read_end (png_ptr, NULL);
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
if (file) lime::fclose (file);