![見出し画像](https://assets.st-note.com/production/uploads/images/22973516/rectangle_large_type_2_f5947803228b3878a22518e35e481028.jpg?width=800)
AndroidのImageProxyをBitmapに変換
AndroidのImageProxyをBitmapに変換する方法をまとめました。
1. Image
「Image」は、メディアソースで使用する画像バッファです。アプリから画像のピクセルデータに効率的にアクセスできます。ピクセルデータは「Plane」にカプセル化して保持します。
画像のプレーンの数と意味は、画像形式によって異なります。
・JPEG(プレーンの数:1)
・YUV_420_888(プレーンの数:3)
・YUV_422_888(プレーンの数:3)
・YUV_444_888(プレーンの数:3)
・FLEX_RGB_888(プレーンの数:3)
・FLEX_RGBA_8888(プレーンの数:4)
・RAW_SENSOR(プレーンの数:1)
・RAW_PRIVATE(プレーンの数:1)
・HEIC(プレーンの数:1)
「Image」は多くの場合ハードウェアによって直接生成されるため、システム全体で共有されるリソースであり、不要になったらクローズする必要があります。
主なメソッドは次のとおりです。
void close()
画像のクローズ。
int getFormat()
画像形式の取得。
Plane[] getPlanes()
プレーン群の取得。
int getWidth()
画像の幅の取得。
int getHeight()
画像の高さの取得。
2. ImageProxy
「ImageProxy」は、「Image」と同様のインターフェースを持つ画像プロキシです。
主なメソッドは次のとおりです。
void close()
画像のクローズ。
int getFormat()
画像形式の取得。
Plane[] getPlanes()
プレーン群の取得。
int getWidth()
画像の幅の取得。
int getHeight()
画像の高さの取得。
Image getImage()
Imageの取得。
3. Image.Plane
「Image.Plane」は、画像データのピクセル平面です。画像がクローズされると、プレーンのByteBufferへのアクセスはできなくなります。
主なメソッドは次のとおりです。
ByteBuffer getBuffer()
フレームデータを含む直接ByteBufferの取得。
int getPixelStride()
ピクセルストライド(バイト単位)の取得。
int getRowStride()
行ストライド(バイト単位)の取得。
4. AndroidのImageをBitmapに変換
AndroidのImageをBitmapに変換するコードは、次のとおりです。
// ImageProxy → Bitmap
private Bitmap imageToToBitmap(Image image, int rotationDegrees) {
byte[] data = imageToByteArray(image);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (rotationDegrees == 0) {
return bitmap;
} else {
return rotateBitmap(bitmap, rotationDegrees);
}
}
// Bitmapの回転
private Bitmap rotateBitmap(Bitmap bitmap, int rotationDegrees) {
Matrix mat = new Matrix();
mat.postRotate(rotationDegrees);
return Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), mat, true);
}
// Image → JPEGのバイト配列
private byte[] imageToByteArray(Image image) {
byte[] data = null;
if (image.getFormat() == ImageFormat.JPEG) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
data = new byte[buffer.capacity()];
buffer.get(data);
return data;
} else if (image.getFormat() == ImageFormat.YUV_420_888) {
data = NV21toJPEG(YUV_420_888toNV21(image),
image.getWidth(), image.getHeight());
}
return data;
}
// YUV_420_888 → NV21
private byte[] YUV_420_888toNV21(Image image) {
byte[] nv21;
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
nv21 = new byte[ySize + uSize + vSize];
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
return nv21;
}
// NV21 → JPEG
private byte[] NV21toJPEG(byte[] nv21, int width, int height) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out);
return out.toByteArray();
}
この記事が気に入ったらサポートをしてみませんか?