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 (!html5 && !flash)
|
||||||
#if format
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
|
|
||||||
case "png":
|
case "png":
|
||||||
|
|
||||||
|
#if (sys && (!disable_cffi || !format))
|
||||||
|
|
||||||
|
return lime_image_encode (buffer, 0, quality);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
var bytes = Bytes.alloc (width * height * 4 + height);
|
var bytes = Bytes.alloc (width * height * 4 + height);
|
||||||
@@ -319,12 +325,21 @@ class Image {
|
|||||||
return ByteArray.fromBytes (output.getBytes ());
|
return ByteArray.fromBytes (output.getBytes ());
|
||||||
|
|
||||||
} catch (e:Dynamic) {}
|
} catch (e:Dynamic) {}
|
||||||
|
|
||||||
|
#end
|
||||||
|
|
||||||
|
case "jpg", "jpeg":
|
||||||
|
|
||||||
|
#if (sys && (!disable_cffi || !format))
|
||||||
|
|
||||||
|
return lime_image_encode (buffer, 1, quality);
|
||||||
|
|
||||||
|
#end
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#end
|
|
||||||
#end
|
#end
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -1163,6 +1178,7 @@ class Image {
|
|||||||
|
|
||||||
|
|
||||||
#if (cpp || neko || nodejs)
|
#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);
|
private static var lime_image_load:Dynamic = System.load ("lime", "lime_image_load", 1);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace lime {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
ImageBuffer ();
|
ImageBuffer ();
|
||||||
|
ImageBuffer (value imageBuffer);
|
||||||
~ImageBuffer ();
|
~ImageBuffer ();
|
||||||
|
|
||||||
void Blit (const unsigned char *data, int x, int y, int width, int height);
|
void Blit (const unsigned char *data, int x, int y, int width, int height);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <graphics/ImageBuffer.h>
|
#include <graphics/ImageBuffer.h>
|
||||||
|
#include <utils/ByteArray.h>
|
||||||
#include <utils/Resource.h>
|
#include <utils/Resource.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ namespace lime {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static bool Decode (Resource *resource, ImageBuffer *imageBuffer);
|
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 <graphics/ImageBuffer.h>
|
||||||
|
#include <utils/ByteArray.h>
|
||||||
#include <utils/Resource.h>
|
#include <utils/Resource.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ namespace lime {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static bool Decode (Resource *resource, ImageBuffer *imageBuffer);
|
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) {
|
value lime_image_load (value data) {
|
||||||
|
|
||||||
ImageBuffer imageBuffer;
|
ImageBuffer imageBuffer;
|
||||||
@@ -434,6 +475,7 @@ namespace lime {
|
|||||||
DEFINE_PRIM (lime_font_load_glyphs, 3);
|
DEFINE_PRIM (lime_font_load_glyphs, 3);
|
||||||
DEFINE_PRIM (lime_font_load_range, 4);
|
DEFINE_PRIM (lime_font_load_range, 4);
|
||||||
DEFINE_PRIM (lime_font_outline_decompose, 2);
|
DEFINE_PRIM (lime_font_outline_decompose, 2);
|
||||||
|
DEFINE_PRIM (lime_image_encode, 3);
|
||||||
DEFINE_PRIM (lime_image_load, 1);
|
DEFINE_PRIM (lime_image_load, 1);
|
||||||
DEFINE_PRIM (lime_key_event_manager_register, 2);
|
DEFINE_PRIM (lime_key_event_manager_register, 2);
|
||||||
DEFINE_PRIM (lime_lzma_encode, 1);
|
DEFINE_PRIM (lime_lzma_encode, 1);
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
namespace lime {
|
namespace lime {
|
||||||
|
|
||||||
|
|
||||||
|
static int id_bitsPerPixel;
|
||||||
|
static int id_bpp;
|
||||||
|
static int id_buffer;
|
||||||
static int id_data;
|
static int id_data;
|
||||||
static int id_height;
|
static int id_height;
|
||||||
static int id_width;
|
static int id_width;
|
||||||
static int id_bpp;
|
|
||||||
static bool init = false;
|
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 () {
|
ImageBuffer::~ImageBuffer () {
|
||||||
|
|
||||||
delete data;
|
delete data;
|
||||||
@@ -62,10 +86,12 @@ namespace lime {
|
|||||||
|
|
||||||
if (!init) {
|
if (!init) {
|
||||||
|
|
||||||
|
id_bpp = val_id ("bpp");
|
||||||
|
id_bitsPerPixel = val_id ("bitsPerPixel");
|
||||||
|
id_buffer = val_id ("buffer");
|
||||||
id_width = val_id ("width");
|
id_width = val_id ("width");
|
||||||
id_height = val_id ("height");
|
id_height = val_id ("height");
|
||||||
id_data = val_id ("data");
|
id_data = val_id ("data");
|
||||||
id_bpp = val_id ("bpp");
|
|
||||||
init = true;
|
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) {
|
bool JPEG::Decode (Resource *resource, ImageBuffer* imageBuffer) {
|
||||||
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
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 <setjmp.h>
|
||||||
#include <graphics/format/PNG.h>
|
#include <graphics/format/PNG.h>
|
||||||
|
#include <graphics/ImageBuffer.h>
|
||||||
|
#include <utils/ByteArray.h>
|
||||||
#include <utils/FileIO.h>
|
#include <utils/FileIO.h>
|
||||||
#include <utils/QuickVec.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;
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
png_infop info_ptr = png_create_info_struct (png_ptr);
|
||||||
if (!info_ptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (setjmp(png_jmpbuf(png_ptr)))
|
if (!info_ptr) {
|
||||||
{
|
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr );
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp (png_jmpbuf (png_ptr))) {
|
||||||
|
|
||||||
|
png_destroy_write_struct (&png_ptr, &info_ptr);
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickVec<uint8> out_buffer;
|
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 w = imageBuffer->width;
|
||||||
int h = inSurface->Height();
|
int h = imageBuffer->height;
|
||||||
|
|
||||||
int bit_depth = 8;
|
int bit_depth = 8;
|
||||||
int color_type = (inSurface->Format()&pfHasAlpha) ?
|
//int color_type = (inSurface->Format () & pfHasAlpha) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
|
||||||
PNG_COLOR_TYPE_RGB_ALPHA :
|
int color_type = 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);
|
||||||
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);
|
QuickVec<uint8> row_data (w * 4);
|
||||||
png_bytep row = &row_data[0];
|
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);
|
uint8 *buf = &row_data[0];
|
||||||
for(int x=0;x<w;x++)
|
const uint8 *src = (const uint8 *)(imageData + (stride * y));
|
||||||
{
|
|
||||||
buf[0] = src[2];
|
for (int x = 0; x < w; x++) {
|
||||||
buf[1] = src[1];
|
|
||||||
buf[2] = src[0];
|
buf[0] = src[0];
|
||||||
src+=3;
|
buf[1] = src[1];
|
||||||
buf+=3;
|
buf[2] = src[2];
|
||||||
if (do_alpha)
|
src += 3;
|
||||||
*buf++ = *src;
|
buf += 3;
|
||||||
src++;
|
|
||||||
}
|
if (do_alpha) {
|
||||||
png_write_rows(png_ptr, &row, 1);
|
|
||||||
}
|
*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