diff --git a/project/src/common/ExternalInterface.cpp b/project/src/common/ExternalInterface.cpp index 47d12553f..f7cafb82c 100644 --- a/project/src/common/ExternalInterface.cpp +++ b/project/src/common/ExternalInterface.cpp @@ -55,6 +55,7 @@ namespace nme { void InitCamera(); void GetGLStats(int *statsArray, int n); +extern bool gRespectExifOrientation; // Not static int _id_id=0; @@ -4363,6 +4364,13 @@ int nme_bitmap_data_get_format(value inHandle) DEFINE_PRIME1(nme_bitmap_data_get_format); +void nme_bitmap_data_set_respect_exif_orientation(bool respect) +{ + gRespectExifOrientation = respect; +} +DEFINE_PRIME1v(nme_bitmap_data_set_respect_exif_orientation); + + value nme_bitmap_data_from_bytes(value inRGBBytes, value inAlphaBytes, value inOnAppData) { ByteData bytes; diff --git a/project/src/common/SurfaceIO.cpp b/project/src/common/SurfaceIO.cpp index 5f048c397..4ee3bbafe 100644 --- a/project/src/common/SurfaceIO.cpp +++ b/project/src/common/SurfaceIO.cpp @@ -117,6 +117,8 @@ struct MySrcManager namespace nme { +bool gRespectExifOrientation = true; + static bool isLittleEndian() { unsigned short val = 0; @@ -195,6 +197,73 @@ bool SoftwareDecodeJPeg(unsigned char *inDest, int inWidth, int inHeight, const } } +// Returns requiured CW quardant rotation +static int parseExif(const uint8 *data, int inLen) +{ + //printf("parseExif %d %c%c%c%c\n",inLen, data[0], data[1], data[2], data[3]); + int rotation = 0; + + #define NEXT_SHORT (exif[msb]<<8) | exif[1-msb]; exif+=2 + #define NEXT_INT big ? (exif[0]<<24) | (exif[1]<<16) | (exif[2]<<8) | exif[3] : \ + (exif[3]<<24) | (exif[2]<<16) | (exif[1]<<8) | exif[0]; \ + exif+=4; + + if (inLen>10 && data[0]=='E' && data[1]=='x' && data[2]=='i' && data[3]=='f') + { + const uint8 *exif = data + 6; + const uint8 *end = data + inLen; + + bool little = exif[0]==0x49 && exif[1]==0x49; + bool big = exif[0]==0x4D && exif[1]==0x4D; + if (!little && !big) + return rotation; + exif += 2; + int msb = big ? 0 : 1; + int test = NEXT_SHORT; + if (test!=42) + return rotation; + + int offset = NEXT_INT; + if (offset>=8 && exif+(offset-8)+2 <= end ) + { + exif += offset-8; + int entries = NEXT_SHORT; + //printf("Found exif entries:%d\n", entries); + for(int e=0; e0 ? inDataLen : 1<<20; - jpeg_save_markers(&cinfo, COM, bufSize); - for(int i=0;i<15;i++) - jpeg_save_markers(&cinfo, APP0 + i, bufSize); + if (onAppData) + { + jpeg_save_markers(&cinfo, COM, bufSize); + for(int i=0;i<15;i++) + jpeg_save_markers(&cinfo, APP0 + i, bufSize); + } + else + { + jpeg_save_markers(&cinfo, APP0 + 1, bufSize); + } } // Read file parameters with jpeg_read_header(). if (jpeg_read_header(&cinfo, TRUE)!=JPEG_HEADER_OK) return 0; + int rotation = 0; + if (gRespectExifOrientation) + { + jpeg_saved_marker_ptr marker = cinfo.marker_list; + while(marker) + { + if (marker->marker==APP0+1) + { + rotation = parseExif(marker->data, marker->data_length); + if (rotation) + break; + } + marker = marker->next; + } + } + cinfo.out_color_space = JCS_RGB; // Start decompressor. jpeg_start_decompress(&cinfo); - result = new SimpleSurface(cinfo.output_width, cinfo.output_height, pfRGB); + int imageW = rotation==1 || rotation==3 ? cinfo.output_height : cinfo.output_width; + int imageH = rotation==1 || rotation==3 ? cinfo.output_width : cinfo.output_height; + result = new SimpleSurface(imageW, imageH, pfRGB); result->IncRef(); - RenderTarget target = result->BeginRender(Rect(cinfo.output_width, cinfo.output_height)); + std::vector rowBuf; + if (rotation!=0) + rowBuf.resize(cinfo.output_width); + + + RenderTarget target = result->BeginRender(Rect(imageW, imageH)); while (cinfo.output_scanline < cinfo.output_height) { - uint8 * dest = target.Row(cinfo.output_scanline); + int y = cinfo.output_scanline; + uint8 * dest = rotation==0 ? target.Row(y) : (uint8 *)&rowBuf[0]; jpeg_read_scanlines(&cinfo, &dest, 1); + + if (rotation==1) + { + // 90 CW. First row starts at the right and goes down + RGB *col = ((RGB *)target.Row(0)) + imageW - 1 - y; + for(int x=0; xEndRender(); diff --git a/src/nme/display/BitmapData.hx b/src/nme/display/BitmapData.hx index 97e8b4d00..338c225ea 100644 --- a/src/nme/display/BitmapData.hx +++ b/src/nme/display/BitmapData.hx @@ -68,6 +68,7 @@ class BitmapData implements IBitmapDrawable public var nmeHandle:NativeHandle; public var data(get,null):UInt8Array; public var mipmaps(get, set):Bool; + public static var respectExifOrientation(null, set):Bool; public function new(inWidth:Int, inHeight:Int, inTransparent:Bool = true, ?inFillARGB:Int, inPixelFormat:Int = -1) @@ -482,6 +483,11 @@ class BitmapData implements IBitmapDrawable public static inline function extractColor(v:Int):Int { return v & 0xFFFFFF; } + static function set_respectExifOrientation(val:Bool) + { + nme_bitmap_data_set_respect_exif_orientation(val); + return val; + } static inline function sameValue(a:Int, b:Int) { @@ -857,6 +863,7 @@ class BitmapData implements IBitmapDrawable private static var nme_bitmap_data_get_uints8 = PrimeLoader.load("nme_bitmap_data_get_uints8", "ooiiiiv"); private static var nme_bitmap_data_set_uints8 = PrimeLoader.load("nme_bitmap_data_set_uints8", "ooiiiiv"); private static var nme_bitmap_data_get_data_handle = PrimeLoader.load("nme_bitmap_data_get_data_handle", "oo"); + private static var nme_bitmap_data_set_respect_exif_orientation = PrimeLoader.load("nme_bitmap_data_set_respect_exif_orientation", "bv"); }