Add native JPEG/PNG encoding

This commit is contained in:
Joshua Granick
2014-11-11 10:48:14 -08:00
parent f5c049d7ff
commit 1f24e162ec
8 changed files with 283 additions and 50 deletions

View File

@@ -283,14 +283,20 @@ class Image {
}
public function encode (format:String = "png"):ByteArray {
public function encode (format:String = "png", quality:Int = 90):ByteArray {
#if (!html5 && !flash)
#if format
switch (format) {
case "png":
#if (sys && (!disable_cffi || !format))
return lime_image_encode (buffer, 0, quality);
#else
try {
var bytes = Bytes.alloc (width * height * 4 + height);
@@ -320,11 +326,20 @@ class Image {
} catch (e:Dynamic) {}
#end
case "jpg", "jpeg":
#if (sys && (!disable_cffi || !format))
return lime_image_encode (buffer, 1, quality);
#end
default:
}
#end
#end
return null;
@@ -1163,6 +1178,7 @@ class Image {
#if (cpp || neko || nodejs)
private static var lime_image_encode:ImageBuffer -> Int -> Int -> ByteArray = System.load ("lime", "lime_image_encode", 3);
private static var lime_image_load:Dynamic = System.load ("lime", "lime_image_load", 1);
#end

View File

@@ -15,6 +15,7 @@ namespace lime {
public:
ImageBuffer ();
ImageBuffer (value imageBuffer);
~ImageBuffer ();
void Blit (const unsigned char *data, int x, int y, int width, int height);

View File

@@ -3,6 +3,7 @@
#include <graphics/ImageBuffer.h>
#include <utils/ByteArray.h>
#include <utils/Resource.h>
@@ -15,6 +16,7 @@ namespace lime {
public:
static bool Decode (Resource *resource, ImageBuffer *imageBuffer);
static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes, int quality);
};

View File

@@ -3,6 +3,7 @@
#include <graphics/ImageBuffer.h>
#include <utils/ByteArray.h>
#include <utils/Resource.h>
@@ -15,6 +16,7 @@ namespace lime {
public:
static bool Decode (Resource *resource, ImageBuffer *imageBuffer);
static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes);
};

View File

@@ -207,6 +207,47 @@ namespace lime {
}
value lime_image_encode (value buffer, value type, value quality) {
ImageBuffer imageBuffer = ImageBuffer (buffer);
ByteArray data;
switch (val_int (type)) {
case 0:
#ifdef LIME_PNG
if (PNG::Encode (&imageBuffer, &data)) {
//delete imageBuffer.data;
return data.mValue;
}
#endif
break;
case 1:
#ifdef LIME_JPEG
if (JPEG::Encode (&imageBuffer, &data, val_int (quality))) {
//delete imageBuffer.data;
return data.mValue;
}
#endif
break;
default: break;
}
//delete imageBuffer.data;
return alloc_null ();
}
value lime_image_load (value data) {
ImageBuffer imageBuffer;
@@ -434,6 +475,7 @@ namespace lime {
DEFINE_PRIM (lime_font_load_glyphs, 3);
DEFINE_PRIM (lime_font_load_range, 4);
DEFINE_PRIM (lime_font_outline_decompose, 2);
DEFINE_PRIM (lime_image_encode, 3);
DEFINE_PRIM (lime_image_load, 1);
DEFINE_PRIM (lime_key_event_manager_register, 2);
DEFINE_PRIM (lime_lzma_encode, 1);

View File

@@ -4,10 +4,12 @@
namespace lime {
static int id_bitsPerPixel;
static int id_bpp;
static int id_buffer;
static int id_data;
static int id_height;
static int id_width;
static int id_bpp;
static bool init = false;
@@ -21,6 +23,28 @@ namespace lime {
}
ImageBuffer::ImageBuffer (value imageBuffer) {
if (!init) {
id_bpp = val_id ("bpp");
id_bitsPerPixel = val_id ("bitsPerPixel");
id_buffer = val_id ("buffer");
id_width = val_id ("width");
id_height = val_id ("height");
id_data = val_id ("data");
init = true;
}
width = val_int (val_field (imageBuffer, id_width));
height = val_int (val_field (imageBuffer, id_height));
bpp = val_int (val_field (imageBuffer, id_bitsPerPixel));
data = new ByteArray (val_field (val_field (imageBuffer, id_data), id_buffer));
}
ImageBuffer::~ImageBuffer () {
delete data;
@@ -62,10 +86,12 @@ namespace lime {
if (!init) {
id_bpp = val_id ("bpp");
id_bitsPerPixel = val_id ("bitsPerPixel");
id_buffer = val_id ("buffer");
id_width = val_id ("width");
id_height = val_id ("height");
id_data = val_id ("data");
id_bpp = val_id ("bpp");
init = true;
}

View File

@@ -119,6 +119,65 @@ namespace lime {
};
struct MyDestManager {
enum { BUF_SIZE = 4096 };
struct jpeg_destination_mgr pub; /* public fields */
QuickVec<uint8> mOutput;
uint8 mTmpBuf[BUF_SIZE];
MyDestManager () {
pub.init_destination = init_buffer;
pub.empty_output_buffer = copy_buffer;
pub.term_destination = term_buffer;
pub.next_output_byte = mTmpBuf;
pub.free_in_buffer = BUF_SIZE;
}
void CopyBuffer () {
mOutput.append (mTmpBuf, BUF_SIZE);
pub.next_output_byte = mTmpBuf;
pub.free_in_buffer = BUF_SIZE;
}
void TermBuffer () {
mOutput.append (mTmpBuf, BUF_SIZE - pub.free_in_buffer);
}
static void init_buffer (jpeg_compress_struct* cinfo) {}
static boolean copy_buffer (jpeg_compress_struct* cinfo) {
MyDestManager *man = (MyDestManager *)cinfo->dest;
man->CopyBuffer ();
return TRUE;
}
static void term_buffer (jpeg_compress_struct* cinfo) {
MyDestManager *man = (MyDestManager *)cinfo->dest;
man->TermBuffer ();
}
};
bool JPEG::Decode (Resource *resource, ImageBuffer* imageBuffer) {
struct jpeg_decompress_struct cinfo;
@@ -211,4 +270,71 @@ namespace lime {
}
bool JPEG::Encode (ImageBuffer *imageBuffer, ByteArray *bytes, int quality) {
struct jpeg_compress_struct cinfo;
struct ErrorData jpegError;
cinfo.err = jpeg_std_error (&jpegError.base);
jpegError.base.error_exit = OnError;
jpegError.base.output_message = OnOutput;
MyDestManager dest;
int w = imageBuffer->width;
int h = imageBuffer->height;
QuickVec<uint8> row_buf (w * 3);
jpeg_create_compress (&cinfo);
if (setjmp (jpegError.on_error)) {
jpeg_destroy_compress (&cinfo);
return false;
}
cinfo.dest = (jpeg_destination_mgr *)&dest;
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults (&cinfo);
jpeg_set_quality (&cinfo, quality, true);
jpeg_start_compress (&cinfo, true);
JSAMPROW row_pointer = &row_buf[0];
unsigned char* imageData = imageBuffer->data->Bytes();
int stride = w * imageBuffer->bpp;
while (cinfo.next_scanline < cinfo.image_height) {
const uint8 *src = (const uint8 *)(imageData + (stride * cinfo.next_scanline));
uint8 *dest = &row_buf[0];
for(int x = 0; x < w; x++) {
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest += 3;
src += 4;
}
jpeg_write_scanlines (&cinfo, &row_pointer, 1);
}
jpeg_finish_compress (&cinfo);
*bytes = ByteArray (dest.mOutput);
return true;
}
}

View File

@@ -8,6 +8,8 @@ extern "C" {
#include <setjmp.h>
#include <graphics/format/PNG.h>
#include <graphics/ImageBuffer.h>
#include <utils/ByteArray.h>
#include <utils/FileIO.h>
#include <utils/QuickVec.h>
@@ -194,71 +196,87 @@ namespace lime {
}
static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes) {
bool PNG::Encode (ImageBuffer *imageBuffer, ByteArray *bytes) {
return true;
png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn);
/*png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn);
if (!png_ptr) {
if (!png_ptr)
return false;
}
png_infop info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr)
if (!info_ptr) {
return false;
if (setjmp(png_jmpbuf(png_ptr)))
{
}
if (setjmp (png_jmpbuf (png_ptr))) {
png_destroy_write_struct (&png_ptr, &info_ptr);
return false;
}
QuickVec<uint8> out_buffer;
png_set_write_fn (png_ptr, &out_buffer, user_write_data, user_flush_data);
int w = inSurface->Width();
int h = inSurface->Height();
int w = imageBuffer->width;
int h = imageBuffer->height;
int bit_depth = 8;
int color_type = (inSurface->Format()&pfHasAlpha) ?
PNG_COLOR_TYPE_RGB_ALPHA :
PNG_COLOR_TYPE_RGB;
png_set_IHDR(png_ptr, info_ptr, w, h,
bit_depth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
//int color_type = (inSurface->Format () & pfHasAlpha) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
int color_type = PNG_COLOR_TYPE_RGB_ALPHA;
png_set_IHDR (png_ptr, info_ptr, w, h, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info (png_ptr, info_ptr);
bool do_alpha = color_type==PNG_COLOR_TYPE_RGBA;
bool do_alpha = (color_type == PNG_COLOR_TYPE_RGBA);
unsigned char* imageData = imageBuffer->data->Bytes();
int stride = w * imageBuffer->bpp;
{
QuickVec<uint8> row_data (w * 4);
png_bytep row = &row_data[0];
for(int y=0;y<h;y++)
{
for (int y = 0; y < h; y++) {
uint8 *buf = &row_data[0];
const uint8 *src = (const uint8 *)inSurface->Row(y);
for(int x=0;x<w;x++)
{
buf[0] = src[2];
const uint8 *src = (const uint8 *)(imageData + (stride * y));
for (int x = 0; x < w; x++) {
buf[0] = src[0];
buf[1] = src[1];
buf[2] = src[0];
buf[2] = src[2];
src += 3;
buf += 3;
if (do_alpha)
if (do_alpha) {
*buf++ = *src;
}
src++;
}
png_write_rows (png_ptr, &row, 1);
}
}
png_write_end (png_ptr, NULL);
*outBytes = ByteArray(out_buffer);
*bytes = ByteArray (out_buffer);
return true;*/
return true;
}