Improve handling of Image endianness (resolve #1018, resolve #1070)

This commit is contained in:
Joshua Granick
2017-09-12 12:32:02 -07:00
parent 2932a9b517
commit 45054e39d6
9 changed files with 86 additions and 40 deletions

View File

@@ -89,7 +89,7 @@ class NativeCFFI {
@:cffi private static function lime_image_data_util_multiply_alpha (image:Dynamic):Void; @:cffi private static function lime_image_data_util_multiply_alpha (image:Dynamic):Void;
@:cffi private static function lime_image_data_util_resize (image:Dynamic, buffer:Dynamic, width:Int, height:Int):Void; @:cffi private static function lime_image_data_util_resize (image:Dynamic, buffer:Dynamic, width:Int, height:Int):Void;
@:cffi private static function lime_image_data_util_set_format (image:Dynamic, format:Int):Void; @:cffi private static function lime_image_data_util_set_format (image:Dynamic, format:Int):Void;
@:cffi private static function lime_image_data_util_set_pixels (image:Dynamic, rect:Dynamic, bytes:Dynamic, offset:Int, format:Int):Void; @:cffi private static function lime_image_data_util_set_pixels (image:Dynamic, rect:Dynamic, bytes:Dynamic, offset:Int, format:Int, endian:Int):Void;
@:cffi private static function lime_image_data_util_threshold (image:Dynamic, sourceImage:Dynamic, sourceRect:Dynamic, destPoint:Dynamic, operation:Int, thresholdRG:Int, thresholdBA:Int, colorRG:Int, colorBA:Int, maskRG:Int, maskBA:Int, copySource:Bool):Int; @:cffi private static function lime_image_data_util_threshold (image:Dynamic, sourceImage:Dynamic, sourceRect:Dynamic, destPoint:Dynamic, operation:Int, thresholdRG:Int, thresholdBA:Int, colorRG:Int, colorBA:Int, maskRG:Int, maskBA:Int, copySource:Bool):Int;
@:cffi private static function lime_image_data_util_unmultiply_alpha (image:Dynamic):Void; @:cffi private static function lime_image_data_util_unmultiply_alpha (image:Dynamic):Void;
@:cffi private static function lime_joystick_get_device_guid (id:Int):Dynamic; @:cffi private static function lime_joystick_get_device_guid (id:Int):Dynamic;

View File

@@ -23,6 +23,8 @@ import lime.math.Rectangle;
import lime.math.Vector2; import lime.math.Vector2;
import lime.net.HTTPRequest; import lime.net.HTTPRequest;
import lime.system.CFFI; import lime.system.CFFI;
import lime.system.Endian;
import lime.system.System;
import lime.utils.ArrayBuffer; import lime.utils.ArrayBuffer;
import lime.utils.BytePointer; import lime.utils.BytePointer;
import lime.utils.Log; import lime.utils.Log;
@@ -1074,16 +1076,18 @@ class Image {
} }
public function setPixels (rect:Rectangle, bytePointer:BytePointer, format:PixelFormat = null):Void { public function setPixels (rect:Rectangle, bytePointer:BytePointer, format:PixelFormat = null, endian:Endian = null):Void {
rect = __clipRect (rect); rect = __clipRect (rect);
if (buffer == null || rect == null) return; if (buffer == null || rect == null) return;
//if (endian == null) endian = System.endianness; // TODO: System endian order
if (endian == null) endian = BIG_ENDIAN;
switch (type) { switch (type) {
case CANVAS: case CANVAS:
ImageCanvasUtil.setPixels (this, rect, bytePointer, format); ImageCanvasUtil.setPixels (this, rect, bytePointer, format, endian);
case DATA: case DATA:
@@ -1091,7 +1095,7 @@ class Image {
ImageCanvasUtil.convertToData (this); ImageCanvasUtil.convertToData (this);
#end #end
ImageDataUtil.setPixels (this, rect, bytePointer, format); ImageDataUtil.setPixels (this, rect, bytePointer, format, endian);
case FLASH: case FLASH:

View File

@@ -9,6 +9,7 @@ import lime.graphics.PixelFormat;
import lime.math.ColorMatrix; import lime.math.ColorMatrix;
import lime.math.Rectangle; import lime.math.Rectangle;
import lime.math.Vector2; import lime.math.Vector2;
import lime.system.Endian;
import lime.utils.BytePointer; import lime.utils.BytePointer;
import lime.utils.UInt8Array; import lime.utils.UInt8Array;
@@ -411,11 +412,11 @@ class ImageCanvasUtil {
} }
public static function setPixels (image:Image, rect:Rectangle, bytePointer:BytePointer, format:PixelFormat):Void { public static function setPixels (image:Image, rect:Rectangle, bytePointer:BytePointer, format:PixelFormat, endian:Endian):Void {
convertToData (image); convertToData (image);
ImageDataUtil.setPixels (image, rect, bytePointer, format); ImageDataUtil.setPixels (image, rect, bytePointer, format, endian);
} }

View File

@@ -15,6 +15,7 @@ import lime.math.ColorMatrix;
import lime.math.Rectangle; import lime.math.Rectangle;
import lime.math.Vector2; import lime.math.Vector2;
import lime.system.CFFI; import lime.system.CFFI;
import lime.system.Endian;
import lime.utils.BytePointer; import lime.utils.BytePointer;
import lime.utils.UInt8Array; import lime.utils.UInt8Array;
@@ -1261,12 +1262,12 @@ class ImageDataUtil {
} }
public static function setPixels (image:Image, rect:Rectangle, bytePointer:BytePointer, format:PixelFormat):Void { public static function setPixels (image:Image, rect:Rectangle, bytePointer:BytePointer, format:PixelFormat, endian:Endian):Void {
if (image.buffer.data == null) return; if (image.buffer.data == null) return;
#if (lime_cffi && !disable_cffi && !macro) #if (lime_cffi && !disable_cffi && !macro)
if (CFFI.enabled) NativeCFFI.lime_image_data_util_set_pixels (image, rect, bytePointer.bytes, bytePointer.offset, format); else if (CFFI.enabled) NativeCFFI.lime_image_data_util_set_pixels (image, rect, bytePointer.bytes, bytePointer.offset, format, endian == BIG_ENDIAN ? 1 : 0); else
#end #end
{ {
@@ -1278,6 +1279,7 @@ class ImageDataUtil {
var transparent = image.transparent; var transparent = image.transparent;
var bytes = bytePointer.bytes; var bytes = bytePointer.bytes;
var dataPosition = bytePointer.offset; var dataPosition = bytePointer.offset;
var littleEndian = (endian != BIG_ENDIAN);
for (y in 0...dataView.height) { for (y in 0...dataView.height) {
@@ -1285,8 +1287,16 @@ class ImageDataUtil {
for (x in 0...dataView.width) { for (x in 0...dataView.width) {
//color = bytes.getInt32 (dataPosition); if (littleEndian) {
color = bytes.getInt32 (dataPosition); // can this be trusted on big endian systems?
} else {
color = bytes.get (dataPosition + 3) | (bytes.get (dataPosition + 2) << 8) | (bytes.get (dataPosition + 1) << 16) | (bytes.get (dataPosition) << 24); color = bytes.get (dataPosition + 3) | (bytes.get (dataPosition + 2) << 8) | (bytes.get (dataPosition + 1) << 16) | (bytes.get (dataPosition) << 24);
}
dataPosition += 4; dataPosition += 4;
switch (format) { switch (format) {

View File

@@ -8,6 +8,7 @@
#include <math/ColorMatrix.h> #include <math/ColorMatrix.h>
#include <math/Rectangle.h> #include <math/Rectangle.h>
#include <math/Vector2.h> #include <math/Vector2.h>
#include <system/Endian.h>
#include <system/System.h> #include <system/System.h>
#include <utils/Bytes.h> #include <utils/Bytes.h>
#include <stdint.h> #include <stdint.h>
@@ -31,7 +32,7 @@ namespace lime {
static void MultiplyAlpha (Image* image); static void MultiplyAlpha (Image* image);
static void Resize (Image* image, ImageBuffer* buffer, int width, int height); static void Resize (Image* image, ImageBuffer* buffer, int width, int height);
static void SetFormat (Image* image, PixelFormat format); static void SetFormat (Image* image, PixelFormat format);
static void SetPixels (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format); static void SetPixels (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format, Endian endian);
static int Threshold (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int operation, int32_t threshold, int32_t color, int32_t mask, bool copySource); static int Threshold (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int operation, int32_t threshold, int32_t color, int32_t mask, bool copySource);
static void UnmultiplyAlpha (Image* image); static void UnmultiplyAlpha (Image* image);

View File

@@ -3,6 +3,7 @@
#include <graphics/PixelFormat.h> #include <graphics/PixelFormat.h>
#include <system/Endian.h>
#include <stdint.h> #include <stdint.h>
#include <math.h> #include <math.h>
@@ -110,22 +111,31 @@ namespace lime {
} }
inline void ReadUInt8 (const unsigned char* data, int offset, PixelFormat format, bool premultiplied) { inline void ReadUInt8 (const unsigned char* data, int offset, PixelFormat format, bool premultiplied, Endian endian) {
switch (format) { switch (format) {
case BGRA32: case BGRA32:
if (endian == LITTLE_ENDIAN)
Set (data[offset + 1], data[offset + 2], data[offset + 3], data[offset]);
else
Set (data[offset + 2], data[offset + 1], data[offset], data[offset + 3]); Set (data[offset + 2], data[offset + 1], data[offset], data[offset + 3]);
break; break;
case RGBA32: case RGBA32:
if (endian == LITTLE_ENDIAN)
Set (data[offset + 3], data[offset + 2], data[offset + 1], data[offset]);
else
Set (data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); Set (data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
break; break;
case ARGB32: case ARGB32:
if (endian == LITTLE_ENDIAN)
Set (data[offset + 2], data[offset + 1], data[offset], data[offset + 3]);
else
Set (data[offset + 1], data[offset + 2], data[offset + 3], data[offset]); Set (data[offset + 1], data[offset + 2], data[offset + 3], data[offset]);
break; break;

View File

@@ -0,0 +1,19 @@
#ifndef LIME_SYSTEM_ENDIAN_H
#define LIME_SYSTEM_ENDIAN_H
namespace lime {
enum Endian {
LITTLE_ENDIAN,
BIG_ENDIAN
};
}
#endif

View File

@@ -23,6 +23,7 @@
#include <system/CFFIPointer.h> #include <system/CFFIPointer.h>
#include <system/Clipboard.h> #include <system/Clipboard.h>
#include <system/ClipboardEvent.h> #include <system/ClipboardEvent.h>
#include <system/Endian.h>
#include <system/JNI.h> #include <system/JNI.h>
#include <system/Locale.h> #include <system/Locale.h>
#include <system/SensorEvent.h> #include <system/SensorEvent.h>
@@ -978,13 +979,14 @@ namespace lime {
} }
void lime_image_data_util_set_pixels (value image, value rect, value bytes, int offset, int format) { void lime_image_data_util_set_pixels (value image, value rect, value bytes, int offset, int format, int endian) {
Image _image = Image (image); Image _image = Image (image);
Rectangle _rect = Rectangle (rect); Rectangle _rect = Rectangle (rect);
Bytes _bytes (bytes); Bytes _bytes (bytes);
PixelFormat _format = (PixelFormat)format; PixelFormat _format = (PixelFormat)format;
ImageDataUtil::SetPixels (&_image, &_rect, &_bytes, offset, _format); Endian _endian = (Endian)endian;
ImageDataUtil::SetPixels (&_image, &_rect, &_bytes, offset, _format, _endian);
} }
@@ -1847,7 +1849,7 @@ namespace lime {
DEFINE_PRIME1v (lime_image_data_util_multiply_alpha); DEFINE_PRIME1v (lime_image_data_util_multiply_alpha);
DEFINE_PRIME4v (lime_image_data_util_resize); DEFINE_PRIME4v (lime_image_data_util_resize);
DEFINE_PRIME2v (lime_image_data_util_set_format); DEFINE_PRIME2v (lime_image_data_util_set_format);
DEFINE_PRIME5v (lime_image_data_util_set_pixels); DEFINE_PRIME6v (lime_image_data_util_set_pixels);
DEFINE_PRIME12 (lime_image_data_util_threshold); DEFINE_PRIME12 (lime_image_data_util_threshold);
DEFINE_PRIME1v (lime_image_data_util_unmultiply_alpha); DEFINE_PRIME1v (lime_image_data_util_unmultiply_alpha);
DEFINE_PRIME4 (lime_image_encode); DEFINE_PRIME4 (lime_image_encode);

View File

@@ -1,6 +1,5 @@
#include <graphics/utils/ImageDataUtil.h> #include <graphics/utils/ImageDataUtil.h>
#include <math/color/RGBA.h> #include <math/color/RGBA.h>
#include <system/System.h>
#include <utils/QuickVec.h> #include <utils/QuickVec.h>
#include <math.h> #include <math.h>
@@ -38,7 +37,7 @@ namespace lime {
offset = row + (x * 4); offset = row + (x * 4);
pixel.ReadUInt8 (data, offset, format, premultiplied); pixel.ReadUInt8 (data, offset, format, premultiplied, BIG_ENDIAN);
pixel.Set (redTable[pixel.r], greenTable[pixel.g], blueTable[pixel.b], alphaTable[pixel.a]); pixel.Set (redTable[pixel.r], greenTable[pixel.g], blueTable[pixel.b], alphaTable[pixel.a]);
pixel.WriteUInt8 (data, offset, format, premultiplied); pixel.WriteUInt8 (data, offset, format, premultiplied);
@@ -74,8 +73,8 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
srcPixel.ReadUInt8 (srcData, srcPosition, srcFormat, srcPremultiplied); srcPixel.ReadUInt8 (srcData, srcPosition, srcFormat, srcPremultiplied, BIG_ENDIAN);
destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied, BIG_ENDIAN);
switch (srcChannel) { switch (srcChannel) {
@@ -144,8 +143,8 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied, BIG_ENDIAN);
destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied, BIG_ENDIAN);
sourceAlpha = sourcePixel.a / 255.0; sourceAlpha = sourcePixel.a / 255.0;
destAlpha = destPixel.a / 255.0; destAlpha = destPixel.a / 255.0;
@@ -194,7 +193,7 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied, BIG_ENDIAN);
sourcePixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); sourcePixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied);
sourcePosition += 4; sourcePosition += 4;
@@ -228,9 +227,9 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied, BIG_ENDIAN);
destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied, BIG_ENDIAN);
alphaPixel.ReadUInt8 (alphaData, alphaPosition, alphaFormat, false); alphaPixel.ReadUInt8 (alphaData, alphaPosition, alphaFormat, false, BIG_ENDIAN);
sourceAlpha = (alphaPixel.a / 255.0) * (sourcePixel.a / 255.0); sourceAlpha = (alphaPixel.a / 255.0) * (sourcePixel.a / 255.0);
@@ -267,8 +266,8 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied, BIG_ENDIAN);
alphaPixel.ReadUInt8 (alphaData, alphaPosition, alphaFormat, false); alphaPixel.ReadUInt8 (alphaData, alphaPosition, alphaFormat, false, BIG_ENDIAN);
sourcePixel.a = int (0.5 + (sourcePixel.a * (alphaPixel.a / 255.0))); sourcePixel.a = int (0.5 + (sourcePixel.a * (alphaPixel.a / 255.0)));
sourcePixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied); sourcePixel.WriteUInt8 (destData, destPosition, destFormat, destPremultiplied);
@@ -338,7 +337,7 @@ namespace lime {
if (premultiplied) fillColor.MultiplyAlpha (); if (premultiplied) fillColor.MultiplyAlpha ();
RGBA hitColor; RGBA hitColor;
hitColor.ReadUInt8 (data, ((y + image->offsetY) * (image->buffer->width * 4)) + ((x + image->offsetX) * 4), format, premultiplied); hitColor.ReadUInt8 (data, ((y + image->offsetY) * (image->buffer->width * 4)) + ((x + image->offsetX) * 4), format, premultiplied, BIG_ENDIAN);
if (!image->buffer->transparent) { if (!image->buffer->transparent) {
@@ -381,7 +380,7 @@ namespace lime {
} }
nextPointOffset = (nextPointY * image->width + nextPointX) * 4; nextPointOffset = (nextPointY * image->width + nextPointX) * 4;
readColor.ReadUInt8 (data, nextPointOffset, format, premultiplied); readColor.ReadUInt8 (data, nextPointOffset, format, premultiplied, BIG_ENDIAN);
if (readColor == hitColor) { if (readColor == hitColor) {
@@ -420,7 +419,7 @@ namespace lime {
for (int x = 0; x < dataView.width; x++) { for (int x = 0; x < dataView.width; x++) {
pixel.ReadUInt8 (data, position, sourceFormat, premultiplied); pixel.ReadUInt8 (data, position, sourceFormat, premultiplied, BIG_ENDIAN);
pixel.WriteUInt8 (destData, destPosition, format, false); pixel.WriteUInt8 (destData, destPosition, format, false);
position += 4; position += 4;
@@ -456,8 +455,8 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied); sourcePixel.ReadUInt8 (sourceData, sourcePosition, sourceFormat, sourcePremultiplied, BIG_ENDIAN);
destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied); destPixel.ReadUInt8 (destData, destPosition, destFormat, destPremultiplied, BIG_ENDIAN);
destPixel.r = int (((sourcePixel.r * redMultiplier) + (destPixel.r * (256 - redMultiplier))) / 256); destPixel.r = int (((sourcePixel.r * redMultiplier) + (destPixel.r * (256 - redMultiplier))) / 256);
destPixel.g = int (((sourcePixel.g * greenMultiplier) + (destPixel.g * (256 - greenMultiplier))) / 256); destPixel.g = int (((sourcePixel.g * greenMultiplier) + (destPixel.g * (256 - greenMultiplier))) / 256);
@@ -485,7 +484,7 @@ namespace lime {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pixel.ReadUInt8 (data, i * 4, format, false); pixel.ReadUInt8 (data, i * 4, format, false, BIG_ENDIAN);
pixel.WriteUInt8 (data, i * 4, format, true); pixel.WriteUInt8 (data, i * 4, format, true);
} }
@@ -634,7 +633,7 @@ namespace lime {
} }
void ImageDataUtil::SetPixels (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format) { void ImageDataUtil::SetPixels (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format, Endian endian) {
uint8_t* data = (uint8_t*)image->buffer->data->Data (); uint8_t* data = (uint8_t*)image->buffer->data->Data ();
PixelFormat sourceFormat = image->buffer->format; PixelFormat sourceFormat = image->buffer->format;
@@ -654,7 +653,7 @@ namespace lime {
for (int x = 0; x < dataView.width; x++) { for (int x = 0; x < dataView.width; x++) {
pixel.ReadUInt8 (byteArray, srcPosition, format, false); pixel.ReadUInt8 (byteArray, srcPosition, format, false, endian);
if (!transparent) pixel.a = 0xFF; if (!transparent) pixel.a = 0xFF;
pixel.WriteUInt8 (data, row + (x * 4), sourceFormat, premultiplied); pixel.WriteUInt8 (data, row + (x * 4), sourceFormat, premultiplied);
@@ -752,7 +751,7 @@ namespace lime {
for (int x = 0; x < destView.width; x++) { for (int x = 0; x < destView.width; x++) {
srcPixel.ReadUInt8 (srcData, srcPosition, srcFormat, srcPremultiplied); srcPixel.ReadUInt8 (srcData, srcPosition, srcFormat, srcPremultiplied, BIG_ENDIAN);
pixelMask = srcPixel.Get () & mask; pixelMask = srcPixel.Get () & mask;
@@ -801,7 +800,7 @@ namespace lime {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
pixel.ReadUInt8 (data, i * 4, format, true); pixel.ReadUInt8 (data, i * 4, format, true, BIG_ENDIAN);
pixel.WriteUInt8 (data, i * 4, format, false); pixel.WriteUInt8 (data, i * 4, format, false);
} }