diff --git a/lime/graphics/Image.hx b/lime/graphics/Image.hx index c2042113e..086a0e7ef 100644 --- a/lime/graphics/Image.hx +++ b/lime/graphics/Image.hx @@ -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 diff --git a/project/include/graphics/ImageBuffer.h b/project/include/graphics/ImageBuffer.h index f9d93d549..d6ddf291f 100644 --- a/project/include/graphics/ImageBuffer.h +++ b/project/include/graphics/ImageBuffer.h @@ -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); diff --git a/project/include/graphics/format/JPEG.h b/project/include/graphics/format/JPEG.h index 18e0cb2f7..48f3cf6e0 100644 --- a/project/include/graphics/format/JPEG.h +++ b/project/include/graphics/format/JPEG.h @@ -3,6 +3,7 @@ #include +#include #include @@ -15,6 +16,7 @@ namespace lime { public: static bool Decode (Resource *resource, ImageBuffer *imageBuffer); + static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes, int quality); }; diff --git a/project/include/graphics/format/PNG.h b/project/include/graphics/format/PNG.h index e3160ba04..6715ca561 100644 --- a/project/include/graphics/format/PNG.h +++ b/project/include/graphics/format/PNG.h @@ -3,6 +3,7 @@ #include +#include #include @@ -15,6 +16,7 @@ namespace lime { public: static bool Decode (Resource *resource, ImageBuffer *imageBuffer); + static bool Encode (ImageBuffer *imageBuffer, ByteArray *bytes); }; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index d34c3f3a8..bee40c6e8 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -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); diff --git a/project/src/graphics/ImageBuffer.cpp b/project/src/graphics/ImageBuffer.cpp index 1fdd4b5e3..39b337bbf 100644 --- a/project/src/graphics/ImageBuffer.cpp +++ b/project/src/graphics/ImageBuffer.cpp @@ -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; } diff --git a/project/src/graphics/format/JPEG.cpp b/project/src/graphics/format/JPEG.cpp index 2e20e4697..a51d2b991 100644 --- a/project/src/graphics/format/JPEG.cpp +++ b/project/src/graphics/format/JPEG.cpp @@ -119,6 +119,65 @@ namespace lime { }; + struct MyDestManager { + + + enum { BUF_SIZE = 4096 }; + struct jpeg_destination_mgr pub; /* public fields */ + QuickVec 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 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; + + } + + } \ No newline at end of file diff --git a/project/src/graphics/format/PNG.cpp b/project/src/graphics/format/PNG.cpp index 2459f73bd..710fc375e 100644 --- a/project/src/graphics/format/PNG.cpp +++ b/project/src/graphics/format/PNG.cpp @@ -8,6 +8,8 @@ extern "C" { #include #include +#include +#include #include #include @@ -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 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 row_data(w*4); - png_bytep row = &row_data[0]; - for(int y=0;yRow(y); - for(int x=0;x 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; }