diff --git a/ext/decoders/native/main.c b/ext/decoders/native/main.c index 77f541f..90829d7 100644 --- a/ext/decoders/native/main.c +++ b/ext/decoders/native/main.c @@ -2,6 +2,15 @@ #include #include #include "astc.h" +#include "rgb.h" + +static VALUE rb_decode_rgb565(VALUE self, VALUE rb_data, VALUE size, VALUE big) { + uint8_t *image = (uint8_t*)malloc(FIX2LONG(size) * 3); + decode_rgb565((uint16_t*)RSTRING_PTR(rb_data), FIX2INT(size), RTEST(big), image); + VALUE ret = rb_str_new((char*)image, FIX2LONG(size) * 3); + free(image); + return ret; +} static VALUE rb_decode_astc(VALUE self, VALUE rb_data, VALUE w, VALUE h, VALUE bw, VALUE bh) { const uint8_t *data = (uint8_t*)RSTRING_PTR(rb_data); @@ -16,4 +25,5 @@ void Init_native() { VALUE mMikunyan = rb_define_module("Mikunyan"); VALUE mDecodeHelper = rb_define_module_under(mMikunyan, "DecodeHelper"); rb_define_module_function(mDecodeHelper, "decode_astc", rb_decode_astc, 5); + rb_define_module_function(mDecodeHelper, "decode_rgb565", rb_decode_rgb565, 3); } diff --git a/ext/decoders/native/rgb.c b/ext/decoders/native/rgb.c new file mode 100644 index 0000000..6d4f7e6 --- /dev/null +++ b/ext/decoders/native/rgb.c @@ -0,0 +1,30 @@ +#include + +static inline int is_system_little() { + int x = 1; + return *(char*)&x == 1; +} + +void decode_rgb565(const uint16_t* data, const int size, const int is_big_endian, uint8_t* image) { + const uint16_t *d = data; + uint8_t *p = image; + if (is_big_endian == is_system_little()) { + for (int i = 0; i < size; i++, d++, p += 3) { + uint8_t r = *d & 0x00f8; + uint8_t g = (*d & 0x0007) << 5 | (*d & 0xe000) >> 11; + uint8_t b = (*d & 0x1f00) >> 5; + p[0] = r | r >> 5; + p[1] = g | g >> 6; + p[2] = b | b >> 5; + } + } else { + for (int i = 0; i < size; i++, d++, p += 3) { + uint8_t r = (*d & 0xf800) >> 8; + uint8_t g = (*d & 0x07e0) >> 3; + uint8_t b = (*d & 0x001f) << 3; + p[0] = r | r >> 5; + p[1] = g | g >> 6; + p[2] = b | b >> 5; + } + } +} diff --git a/ext/decoders/native/rgb.h b/ext/decoders/native/rgb.h new file mode 100644 index 0000000..d144634 --- /dev/null +++ b/ext/decoders/native/rgb.h @@ -0,0 +1,8 @@ +#ifndef RGB_H +#define RGB_H + +#include + +void decode_rgb565(const uint16_t*, const int, const int, uint8_t*); + +#endif /* end of include guard: RGB_H */ diff --git a/lib/mikunyan/decoders/image_decoder.rb b/lib/mikunyan/decoders/image_decoder.rb index f551729..eab79ec 100644 --- a/lib/mikunyan/decoders/image_decoder.rb +++ b/lib/mikunyan/decoders/image_decoder.rb @@ -127,15 +127,7 @@ module Mikunyan # @param [Symbol] endian endianness of binary # @return [ChunkyPNG::Image] decoded image def self.decode_rgb565(width, height, bin, endian = :big) - mem = String.new(capacity: width * height * 3) - (width * height).times do |i| - c = endian == :little ? BinUtils.get_int16_le(bin, i*2) : BinUtils.get_int16_be(bin, i*2) - r = (c & 0xf800) >> 8 - g = (c & 0x07e0) >> 3 - b = (c & 0x001f) << 3 - BinUtils.append_int8!(mem, r | r >> 5, g | g >> 6, b | b >> 5) - end - ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip + ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_rgb565(bin, width * height, endian == :big)).flip end # Decode image from A8 binary