Last active
September 20, 2018 06:41
-
-
Save suzumura-ss/9a3f85d4dc088656d712c437a2e96603 to your computer and use it in GitHub Desktop.
Unity/Android環境向けに1個のJPEGを2個のRGBバイト列に分割ロードするローダー / 幅4K〜8KのEqui画像をロードする想定
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
#if UNITY_ANDROID | |
#else | |
// PCではopenCVSharpを利用 | |
using System.Runtime.InteropServices; | |
using OpenCvSharp; | |
#endif | |
public class JPEGLoader | |
{ | |
public delegate void OnCompleteSplitBlock(byte[] leftBytes, byte[] rightBytes, int width, int height, TextureFormat format); | |
public delegate void OnCompleteRsizeBlock(byte[] bytes, int width, int height, TextureFormat format); | |
public delegate void OnFailedBlock(Exception e); | |
/* | |
@param[in] sourceName Android: ex. /mnt/sdcard/DCIM/SAMPLE.JPG, PC: ex. C:/SAMPLE.JPG | |
@param[in] onCompleteBlock(byte[] leftBytes, byte[] rightBytes, int width, int height, TextureFormat format) | |
@param[in] onFailedBlock(Exceptione e) | |
*/ | |
#if UNITY_ANDROID | |
static public void Load(string sourceName, OnCompleteSplitBlock onCompleteBlock, OnFailedBlock onFailedBlock) | |
{ | |
using(AndroidJavaClass BitmapFactory = new AndroidJavaClass("android.graphics.BitmapFactory")) | |
{ | |
try | |
{ | |
using(AndroidJavaObject bitmap = BitmapFactory.CallStatic<AndroidJavaObject>("decodeFile", new object[]{ sourceName })) | |
{ | |
LoadBytesInternal(bitmap, onCompleteBlock); | |
} | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError($"JPEGLoader: Load({sourceName}) failed - {e}"); | |
onFailedBlock(e); | |
} | |
} | |
} | |
static public void LoadResource(string sourceName, OnCompleteSplitBlock onCompleteBlock, OnFailedBlock onFailedBlock) | |
{ | |
using(AndroidJavaClass BitmapFactory = new AndroidJavaClass("android.graphics.BitmapFactory")) | |
{ | |
try | |
{ | |
TextAsset sourceAsset = Resources.Load(sourceName) as TextAsset; | |
using(AndroidJavaObject bitmap = BitmapFactory.CallStatic<AndroidJavaObject>("decodeByteArray", new object[]{ sourceAsset.bytes, 0, sourceAsset.bytes.Length })) | |
{ | |
LoadBytesInternal(bitmap, onCompleteBlock); | |
} | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError($"JPEGLoader: LoadResource({sourceName}) failed - {e}"); | |
onFailedBlock(e); | |
} | |
} | |
} | |
static void LoadBytesInternal( /* android.graphics.Bitmap */ AndroidJavaObject bitmap, OnCompleteSplitBlock onCompleteBlock) | |
{ | |
byte[] leftBytes = null, rightBytes = null; | |
int width, height; | |
using(AndroidJavaClass Bitmap = new AndroidJavaClass("android.graphics.Bitmap")) | |
using(AndroidJavaClass ByteBuffer = new AndroidJavaClass("java.nio.ByteBuffer")) | |
using(AndroidJavaObject flip = new AndroidJavaObject("android.graphics.Matrix")) | |
{ | |
Func<AndroidJavaObject, int, int, int, byte[]> extractPixels = (bmp, w, h, offset) => | |
{ | |
using(AndroidJavaObject partBmp = Bitmap.CallStatic<AndroidJavaObject>("createBitmap", new object[]{ bmp, offset, 0, w, h, flip, false })) | |
{ | |
int size = partBmp.Call<int>("getByteCount"); | |
using(AndroidJavaObject buffer = ByteBuffer.CallStatic<AndroidJavaObject>("allocate", new object[]{ size })) | |
{ | |
partBmp.Call("copyPixelsToBuffer", new object[]{ buffer }); | |
return buffer.Call<byte[]>("array"); | |
} | |
} | |
}; | |
width = bitmap.Call<int>("getWidth") / 2; | |
height = bitmap.Call<int>("getHeight"); | |
flip.Call<bool>("postScale", new object[]{ 1.0f, -1.0f, (float)width, (float)height }); | |
leftBytes = extractPixels(bitmap, width, height, 0); | |
rightBytes = extractPixels(bitmap, width, height, width); | |
} | |
onCompleteBlock(leftBytes, rightBytes, width, height, TextureFormat.RGBA32); | |
} | |
static public void Load(string sourceName, int width, int height, OnCompleteRsizeBlock onCompleteBlock, OnFailedBlock onFailedBlock) | |
{ | |
using(AndroidJavaClass BitmapFactory = new AndroidJavaClass("android.graphics.BitmapFactory")) | |
{ | |
try | |
{ | |
using(AndroidJavaObject bitmap = BitmapFactory.CallStatic<AndroidJavaObject>("decodeFile", new object[]{ sourceName })) | |
{ | |
LoadBytesInternal(bitmap, width, height, onCompleteBlock); | |
} | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError($"JPEGLoader: Load {sourceName}({width}x{height}) failed - {e}"); | |
onFailedBlock(e); | |
} | |
} | |
} | |
static void LoadBytesInternal( /* android.graphics.Bitmap */ AndroidJavaObject bitmap, int width, int height, OnCompleteRsizeBlock onCompleteBlock) | |
{ | |
byte[] bytes = null; | |
using(AndroidJavaClass Bitmap = new AndroidJavaClass("android.graphics.Bitmap")) | |
using(AndroidJavaClass ByteBuffer = new AndroidJavaClass("java.nio.ByteBuffer")) | |
using(AndroidJavaObject flipResize = new AndroidJavaObject("android.graphics.Matrix")) | |
{ | |
int orig_w = bitmap.Call<int>("getWidth"); | |
int orig_h = bitmap.Call<int>("getHeight"); | |
flipResize.Call<bool>("preScale", new object[]{ (float)width / (float)orig_w, -(float)height / (float)orig_h }); | |
using(AndroidJavaObject partBmp = Bitmap.CallStatic<AndroidJavaObject>("createBitmap", new object[]{ bitmap, 0, 0, orig_w, orig_h, flipResize, true })) | |
{ | |
int size = partBmp.Call<int>("getByteCount"); | |
using(AndroidJavaObject buffer = ByteBuffer.CallStatic<AndroidJavaObject>("allocate", new object[]{ size })) | |
{ | |
width = partBmp.Call<int>("getWidth"); | |
height = partBmp.Call<int>("getHeight"); | |
partBmp.Call("copyPixelsToBuffer", new object[]{ buffer }); | |
bytes = buffer.Call<byte[]>("array"); | |
} | |
} | |
} | |
onCompleteBlock(bytes, width, height, TextureFormat.RGBA32); | |
} | |
#else | |
static public void Load(string sourceName, OnCompleteSplitBlock onCompleteBlock, OnFailedBlock onFailedBlock) | |
{ | |
try | |
{ | |
LoadBytesInternal(new Mat(sourceName), onCompleteBlock); | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError($"JPEGLoader: Load {sourceName} failed - {e}"); | |
onFailedBlock(e); | |
} | |
} | |
static public void LoadResource(string sourceName, OnCompleteSplitBlock onCompleteBlock, OnFailedBlock onFailedBlock) | |
{ | |
try | |
{ | |
TextAsset sourceAsset = Resources.Load(sourceName) as TextAsset; | |
LoadBytesInternal(Cv2.ImDecode(sourceAsset.bytes, ImreadModes.Color), onCompleteBlock); | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError($"JPEGLoader: Load {sourceName} failed - {e}"); | |
onFailedBlock(e); | |
} | |
} | |
static void LoadBytesInternal(Mat bitmap, OnCompleteSplitBlock onCompleteBlock) | |
{ | |
Func<Mat, int, int, int, byte[]> extractPixels = (bmp, w, h, offset) => | |
{ | |
Mat partBmp = bmp.Clone(new OpenCvSharp.Rect(offset, 0, w, h)); | |
byte[] pix = new byte[partBmp.Width * partBmp.Height * partBmp.ElemSize()]; | |
Marshal.Copy(partBmp.Data, pix, 0, pix.Length); | |
return pix; | |
}; | |
Mat[] bgr = Cv2.Split(bitmap.Flip(FlipMode.X)); | |
Mat rgb = new Mat(); | |
Cv2.Merge(new Mat[]{ bgr[2], bgr[1], bgr[0] }, rgb); | |
int width = bitmap.Width / 2; | |
byte[] leftBytes = extractPixels(rgb, width, bitmap.Height, 0); | |
byte[] rightBytes = extractPixels(rgb, width, bitmap.Height, width); | |
onCompleteBlock(leftBytes, rightBytes, width, bitmap.Height, TextureFormat.RGB24); | |
} | |
static public void Load(string sourceName, int width, int height, OnCompleteRsizeBlock onCompleteBlock, OnFailedBlock onFailedBlock) | |
{ | |
try | |
{ | |
LoadBytesInternal(new Mat(sourceName), width, height, onCompleteBlock); | |
} | |
catch (Exception e) | |
{ | |
Debug.LogError($"JPEGLoader: Load {sourceName}({width}x{height}) failed - {e}"); | |
onFailedBlock(e); | |
} | |
} | |
static void LoadBytesInternal(Mat bitmap, int width, int height, OnCompleteRsizeBlock onCompleteBlock) | |
{ | |
Mat[] bgr = Cv2.Split(bitmap.Resize(new Size(width, height)).Flip(FlipMode.X)); | |
Mat rgb = new Mat(); | |
Cv2.Merge(new Mat[]{ bgr[2], bgr[1], bgr[0] }, rgb); | |
byte[] pix = new byte[rgb.Width * rgb.Height * rgb.ElemSize()]; | |
Marshal.Copy(rgb.Data, pix, 0, pix.Length); | |
onCompleteBlock(pix, rgb.Width, rgb.Height, TextureFormat.RGB24); | |
} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment