Android中如何将黑白Bitmap转换为单通道JPEG?
解决方案
要生成单通道灰度JPEG的Base64编码,你需要绕过Bitmap.compress()的默认行为(它会将任何彩色/灰度Bitmap编码为3通道JPEG),直接处理单通道像素数据并构造符合灰度JPEG规范的编码数据。以下是具体实现步骤:
步骤1:提取ARGB_8 Bitmap的灰度像素数据
因为你的Bitmap是黑白的,每个像素的R/G/B分量值相同,直接提取其中一个分量即可得到灰度值:
Bitmap argbBitmap = ...; // 你的ARGB_8格式黑白Bitmap int width = argbBitmap.getWidth(); int height = argbBitmap.getHeight(); // 提取所有像素的ARGB值 int[] argbPixels = new int[width * height]; argbBitmap.getPixels(argbPixels, 0, width, 0, 0, width, height); // 转换为单通道灰度数据(0-255) byte[] grayPixels = new byte[width * height]; for (int i = 0; i < argbPixels.length; i++) { // 直接取红色分量(黑白图中R=G=B) grayPixels[i] = (byte) Color.red(argbPixels[i]); }
步骤2:构造NV21格式数据并编码为灰度JPEG
Android的YuvImage类可以将YUV格式数据编码为JPEG,而灰度JPEG本质是YCbCr格式中Cb/Cr分量固定为128的情况。我们需要构造完整的NV21格式数据(Y分量+填充为128的UV分量):
// NV21格式的总长度 = Y分量长度 + UV分量长度(Y长度的1/2) byte[] nv21Data = new byte[width * height * 3 / 2]; // 复制Y分量(灰度数据)到NV21数组的前半部分 System.arraycopy(grayPixels, 0, nv21Data, 0, width * height); // 将UV分量填充为128(灰度图像的标准UV值) Arrays.fill(nv21Data, width * height, nv21Data.length, (byte) 128); // 使用YuvImage压缩为JPEG YuvImage yuvImage = new YuvImage(nv21Data, ImageFormat.NV21, width, height, null); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // 第二个参数为JPEG质量(0-100) yuvImage.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); byte[] jpegBytes = outputStream.toByteArray();
步骤3:转换为Base64编码
最后将JPEG字节数组转换为Base64字符串:
String base64Result = Base64.encodeToString(jpegBytes, Base64.DEFAULT);
关键说明
Bitmap.compress()方法无论输入Bitmap是何种格式,都会将其转换为3通道的YCbCr JPEG,因此无法直接生成单通道输出。- 灰度JPEG的本质是YCbCr格式中Cb/Cr分量固定为128,通过构造NV21格式数据并填充UV分量,我们可以让
YuvImage生成符合要求的灰度JPEG。 - 如果你的"黑白Bitmap"不是严格的灰度(比如存在彩色偏差),可以用标准灰度公式计算:
int gray = (int)(0.299 * Color.red(pixel) + 0.587 * Color.green(pixel) + 0.114 * Color.blue(pixel));
内容的提问来源于stack exchange,提问作者VeceluXa
相关产品推荐
相关产品推荐

