Add native JPEG/PNG encoding
This commit is contained in:
@@ -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);
|
||||
@@ -319,12 +325,21 @@ class Image {
|
||||
return ByteArray.fromBytes (output.getBytes ());
|
||||
|
||||
} 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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
return false;
|
||||
png_infop info_ptr = png_create_info_struct (png_ptr);
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr );
|
||||
if (!info_ptr) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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++)
|
||||
{
|
||||
uint8 *buf = &row_data[0];
|
||||
const uint8 *src = (const uint8 *)inSurface->Row(y);
|
||||
for(int x=0;x<w;x++)
|
||||
{
|
||||
buf[0] = src[2];
|
||||
buf[1] = src[1];
|
||||
buf[2] = src[0];
|
||||
src+=3;
|
||||
buf+=3;
|
||||
if (do_alpha)
|
||||
*buf++ = *src;
|
||||
src++;
|
||||
}
|
||||
png_write_rows(png_ptr, &row, 1);
|
||||
}
|
||||
QuickVec<uint8> row_data (w * 4);
|
||||
png_bytep row = &row_data[0];
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
|
||||
uint8 *buf = &row_data[0];
|
||||
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[2];
|
||||
src += 3;
|
||||
buf += 3;
|
||||
|
||||
if (do_alpha) {
|
||||
|
||||
*buf++ = *src;
|
||||
|
||||
}
|
||||
|
||||
src++;
|
||||
|
||||
}
|
||||
|
||||
png_write_rows (png_ptr, &row, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, NULL);
|
||||
png_write_end (png_ptr, NULL);
|
||||
|
||||
*outBytes = ByteArray(out_buffer);
|
||||
*bytes = ByteArray (out_buffer);
|
||||
|
||||
return true;*/
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user