You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MpPreview/app/src/main/java/com/xypower/mppreview/utils/ImageConverterUtil.java

196 lines
6.8 KiB
Java

package com.xypower.mppreview.utils;
import static com.xypower.mppreview.utils.HdrUtil.generateTimestamp;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.media.Image;
import android.os.Environment;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class ImageConverterUtil {
private final String TAG = "ImageConverterUtil";
public void saveYuvImageFromImageReader(Image image, RenderScript rs, String i) {
// Image image = null;
try {
// // Acquire the latest image from ImageReader
// image = imageReader.acquireLatestImage();
// if (image == null) {
// Log.e(TAG, "No image available");
// return;
// }
// Convert Image to Bitmap directly using RenderScript
Bitmap bitmap = imageYuvToBitmap(image, rs);
// Save the bitmap to file (PNG format to avoid lossy compression)
saveBitmapToFile(bitmap, i);
Log.d(TAG, "Image saved successfully");
} catch (Exception e) {
Log.e(TAG, "Error saving image: " + e.getMessage());
} finally {
if (image != null) {
image.close();
}
}
}
public Bitmap imageYuvToBitmap(Image image, RenderScript rs) {
if (image.getFormat() != ImageFormat.YUV_420_888) {
throw new IllegalArgumentException("Only YUV_420_888 format is supported");
}
int width = image.getWidth();
int height = image.getHeight();
// Convert YUV to NV21 format
byte[] nv21Data = yuv420ToNv21(image);
// Create output bitmap
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// Use RenderScript for YUV to RGB conversion (more efficient)
Allocation inputAllocation = Allocation.createSized(rs, Element.U8(rs), nv21Data.length);
inputAllocation.copyFrom(nv21Data);
Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs))
.setX(width)
.setY(height)
.setYuvFormat(ImageFormat.NV21);
Allocation yuvAllocation = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
yuvAllocation.copyFrom(nv21Data);
Allocation outputAllocation = Allocation.createFromBitmap(rs, bitmap);
ScriptIntrinsicYuvToRGB yuvToRgbScript = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
yuvToRgbScript.setInput(yuvAllocation);
yuvToRgbScript.forEach(outputAllocation);
outputAllocation.copyTo(bitmap);
// Clean up allocations
inputAllocation.destroy();
yuvAllocation.destroy();
outputAllocation.destroy();
yuvToRgbScript.destroy();
return bitmap;
}
private byte[] yuv420ToNv21(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer yBuffer = planes[0].getBuffer();
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
int ySize = yBuffer.remaining();
int width = image.getWidth();
int height = image.getHeight();
int uvSize = width * height / 4; // U and V are quarter size
byte[] nv21 = new byte[ySize + uvSize * 2];
// Copy Y plane as-is
yBuffer.get(nv21, 0, ySize);
// Interleave V and U planes into NV21 format (which is really NV12 with U and V swapped)
int uvRowStride = planes[1].getRowStride();
int uvPixelStride = planes[1].getPixelStride();
int pos = ySize;
for (int row = 0; row < height / 2; row++) {
for (int col = 0; col < width / 2; col++) {
int vuPos = col * uvPixelStride + row * uvRowStride;
nv21[pos++] = vBuffer.get(vuPos);
nv21[pos++] = uBuffer.get(vuPos);
}
}
return nv21;
}
// Alternative method using direct YUV-to-RGB color space conversion
private Bitmap yuvImageToBitmapDirect(Image image) {
if (image.getFormat() != ImageFormat.YUV_420_888) {
throw new IllegalArgumentException("Only YUV_420_888 format is supported");
}
int width = image.getWidth();
int height = image.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// Get YUV data
Image.Plane[] planes = image.getPlanes();
ByteBuffer yBuffer = planes[0].getBuffer();
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
int yRowStride = planes[0].getRowStride();
int uvRowStride = planes[1].getRowStride();
int uvPixelStride = planes[1].getPixelStride();
// Convert YUV to RGB directly, pixel by pixel
int[] rgbData = new int[width * height];
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
int yIndex = j * yRowStride + i;
int uvJ = j / 2;
int uvI = i / 2;
int uvIndex = uvJ * uvRowStride + uvI * uvPixelStride;
int y = yBuffer.get(yIndex) & 0xFF;
int u = uBuffer.get(uvIndex) & 0xFF;
int v = vBuffer.get(uvIndex) & 0xFF;
// YUV to RGB conversion
y = y - 16;
u = u - 128;
v = v - 128;
int r = (int) (1.164 * y + 1.596 * v);
int g = (int) (1.164 * y - 0.813 * v - 0.391 * u);
int b = (int) (1.164 * y + 2.018 * u);
// Clamp RGB values
r = r > 255 ? 255 : (r < 0 ? 0 : r);
g = g > 255 ? 255 : (g < 0 ? 0 : g);
b = b > 255 ? 255 : (b < 0 ? 0 : b);
rgbData[j * width + i] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
bitmap.setPixels(rgbData, 0, width, 0, 0, width, height);
return bitmap;
}
private void saveBitmapToFile(Bitmap bitmap, String fileName) throws IOException {
// File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File outputFile = new File(picturesDir, "YUV_" + generateTimestamp() + "_" + fileName + ".bmp");
FileOutputStream outputStream = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
outputStream.close();
}
}