使用 alpha 将字节数组转换为 png 图像
Convert byte array to png image with alpha
我已经在这里和整个 Internet 上解决了很多问题,但还没有成功。
我有一个字节数组,它表示应转换为 PNG 图像的原始数据。它有 alpha,所以我的颜色是 RGBA。据我所知,字节数组是原始图像数据本身,没有 headers 或元数据或某些库或方法可能假定的任何其他内容(此字节数组是从 DXT5 解码的)。
如何将原始图像数据字节数组转换为带有 alpha 的 PNG 图像?
编辑:因为我不知道我在这个领域做了什么,我可能会在这里包含比分类问题所需的代码更多的代码。
这是 DXT5 解码的东西:
private void decodeDXT5(ByteBuffer encodedBytes, int position, byte[] decodedBytes, int width, int height, int currentY, int currentX) {
encodedBytes.order(ByteOrder.LITTLE_ENDIAN);
encodedBytes.position(position);
byte alpha0 = encodedBytes.get();
byte alpha1 = encodedBytes.get();
byte[] rgb = new byte[6];
encodedBytes.get(rgb, 0, 6);
byte[] color0 = RGB565_to_RGB888(encodedBytes.getShort());
byte[] color1 = RGB565_to_RGB888(encodedBytes.getShort());
byte[] c = new byte[]{encodedBytes.get(), encodedBytes.get(), encodedBytes.get(), encodedBytes.get()};
byte[] a = new byte[]{
(byte) (0x7 & rgb[0]),
(byte) (0x7 & (rgb[0] >> 3)),
(byte) (0x7 & (((0x1 & rgb[1]) << 2) + (rgb[0] >> 6))),
(byte) (0x7 & (rgb[1] >> 1)),
(byte) (0x7 & (rgb[1] >> 4)),
(byte) (0x7 & (((0x3 & rgb[2]) << 1) + (rgb[1] >> 7))),
(byte) (0x7 & (rgb[2] >> 2)),
(byte) (0x7 & (rgb[2] >> 5)),
(byte) (0x7 & rgb[3]),
(byte) (0x7 & (rgb[3] >> 3)),
(byte) (0x7 & (((0x1 & rgb[4]) << 2) + (rgb[3] >> 6))),
(byte) (0x7 & (rgb[4] >> 1)),
(byte) (0x7 & (rgb[4] >> 4)),
(byte) (0x7 & (((0x3 & rgb[5]) << 1) + (rgb[4] >> 7))),
(byte) (0x7 & (rgb[5] >> 2)),
(byte) (0x7 & (rgb[5] >> 5))
};
for (int i = 0; i < 16; i++) {
int e = Math.floorDiv(i, 4);
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 0] = c2Value(3 & c[e], color0[0], color1[0]); //red
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 1] = c2Value(3 & c[e], color0[1], color1[1]); //green
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 2] = c2Value(3 & c[e], color0[2], color1[2]); //blue
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 3] = a2Value(a[i], alpha0, alpha1); //alpha
c[e] = (byte) (c[e] >> 2);
}
}
private byte[] RGB565_to_RGB888(short rgb) {
byte r = (byte) (((rgb & 0xF800) >> 11) * 8);
byte g = (byte) (((rgb & 0x07E0) >> 5) * 4);
byte b = (byte) ((rgb & 0x001F) * 8);
return new byte[]{r, g, b};
}
private byte c2Value(int code, byte color0, byte color1) {
switch (code) {
case 0:
return color0;
case 1:
return color1;
case 2:
case 3:
return (byte) ((color0 + color1 + 1) >> 1);
}
return color0;
}
private byte a2Value(int code, byte alpha0, byte alpha1) {
if (alpha0 > alpha1) {
switch (code) {
case 0:
return alpha0;
case 1:
return alpha1;
case 2:
return (byte) ((6 * alpha0 + 1 * alpha1) / 7);
case 3:
return (byte) ((5 * alpha0 + 2 * alpha1) / 7);
case 4:
return (byte) ((4 * alpha0 + 3 * alpha1) / 7);
case 5:
return (byte) ((3 * alpha0 + 4 * alpha1) / 7);
case 6:
return (byte) ((2 * alpha0 + 5 * alpha1) / 7);
case 7:
return (byte) ((1 * alpha0 + 6 * alpha1) / 7);
default:
LOG.error("a2Value code : " + code);
}
} else {
switch (code) {
case 0:
return alpha0;
case 1:
return alpha1;
case 2:
return (byte) ((4 * alpha0 + 1 * alpha1) / 5);
case 3:
return (byte) ((3 * alpha0 + 2 * alpha1) / 5);
case 4:
return (byte) ((2 * alpha0 + 3 * alpha1) / 5);
case 5:
return (byte) ((1 * alpha0 + 4 * alpha1) / 5);
case 6:
return 0;
case 7:
return (byte) 0xFF; //why, what, WHY???
default:
LOG.error("a2Value code : " + code);
}
}
return alpha0;
}
运行 来自:
ByteBuffer bbIn = ByteBuffer.allocate(imageDataSize);
bbIn.put(imageData, 0, imageDataSize);
bbIn.position(0);
byte[] decodedImage = new byte[height * width * 4];
int currentX = 0;
int currentY = 0;
int position = 0;
while (position < imageData.length) {
if ((currentX == width) && (currentY == height)) {
break;
}
decodeDXT5(bbIn, position, decodedImage, width, height, currentY, currentX);
currentX += 4;
if (currentX + 4 > width) {
currentX = 0;
currentY += 4;
}
position += 16;
}
PNG 部分在这里。这是我搜索结果中的最新版本,也是最接近的版本。文件大小、尺寸、形状等都在那里;只是颜色不对。有很多工件在进行;不属于图像的颜色。 PNG 代码看起来不错(我尝试了几种不同的波段偏移顺序,但它们都产生了相同的图像)。也许DXT5解码有误?或者 PNG 的东西实际上并不好。就像我说的,我不知道我在这里做什么,因为它在我的领域之外。前面说了这张DXT5解码后的图片是RGBA格式的(各占一个字节)
DataBuffer dataBuffer = new DataBufferByte(decodedImage, decodedImage.length);
int samplesPerPixel = 4;
int[] bandOffsets = {0, 1, 2, 3};
WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
File file = new File("/opt/wildfly/standalone/tmp/temp.png");
ImageIO.write(image, "png", file);
Java 缺少无符号类型,呃,救援...
这是签名与未签名的问题。正如我们所知,Java 没有 unsigned。这实际上不是 PNG 问题,而是从 DXT5 解压缩时出现的问题。当涉及数学时,我需要确保我使用的是无符号类型的等价物(因此在盛大的 Java 传统中,使用下一个最高类型并屏蔽符号位)。
我已经在这里和整个 Internet 上解决了很多问题,但还没有成功。
我有一个字节数组,它表示应转换为 PNG 图像的原始数据。它有 alpha,所以我的颜色是 RGBA。据我所知,字节数组是原始图像数据本身,没有 headers 或元数据或某些库或方法可能假定的任何其他内容(此字节数组是从 DXT5 解码的)。
如何将原始图像数据字节数组转换为带有 alpha 的 PNG 图像?
编辑:因为我不知道我在这个领域做了什么,我可能会在这里包含比分类问题所需的代码更多的代码。
这是 DXT5 解码的东西:
private void decodeDXT5(ByteBuffer encodedBytes, int position, byte[] decodedBytes, int width, int height, int currentY, int currentX) {
encodedBytes.order(ByteOrder.LITTLE_ENDIAN);
encodedBytes.position(position);
byte alpha0 = encodedBytes.get();
byte alpha1 = encodedBytes.get();
byte[] rgb = new byte[6];
encodedBytes.get(rgb, 0, 6);
byte[] color0 = RGB565_to_RGB888(encodedBytes.getShort());
byte[] color1 = RGB565_to_RGB888(encodedBytes.getShort());
byte[] c = new byte[]{encodedBytes.get(), encodedBytes.get(), encodedBytes.get(), encodedBytes.get()};
byte[] a = new byte[]{
(byte) (0x7 & rgb[0]),
(byte) (0x7 & (rgb[0] >> 3)),
(byte) (0x7 & (((0x1 & rgb[1]) << 2) + (rgb[0] >> 6))),
(byte) (0x7 & (rgb[1] >> 1)),
(byte) (0x7 & (rgb[1] >> 4)),
(byte) (0x7 & (((0x3 & rgb[2]) << 1) + (rgb[1] >> 7))),
(byte) (0x7 & (rgb[2] >> 2)),
(byte) (0x7 & (rgb[2] >> 5)),
(byte) (0x7 & rgb[3]),
(byte) (0x7 & (rgb[3] >> 3)),
(byte) (0x7 & (((0x1 & rgb[4]) << 2) + (rgb[3] >> 6))),
(byte) (0x7 & (rgb[4] >> 1)),
(byte) (0x7 & (rgb[4] >> 4)),
(byte) (0x7 & (((0x3 & rgb[5]) << 1) + (rgb[4] >> 7))),
(byte) (0x7 & (rgb[5] >> 2)),
(byte) (0x7 & (rgb[5] >> 5))
};
for (int i = 0; i < 16; i++) {
int e = Math.floorDiv(i, 4);
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 0] = c2Value(3 & c[e], color0[0], color1[0]); //red
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 1] = c2Value(3 & c[e], color0[1], color1[1]); //green
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 2] = c2Value(3 & c[e], color0[2], color1[2]); //blue
decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 3] = a2Value(a[i], alpha0, alpha1); //alpha
c[e] = (byte) (c[e] >> 2);
}
}
private byte[] RGB565_to_RGB888(short rgb) {
byte r = (byte) (((rgb & 0xF800) >> 11) * 8);
byte g = (byte) (((rgb & 0x07E0) >> 5) * 4);
byte b = (byte) ((rgb & 0x001F) * 8);
return new byte[]{r, g, b};
}
private byte c2Value(int code, byte color0, byte color1) {
switch (code) {
case 0:
return color0;
case 1:
return color1;
case 2:
case 3:
return (byte) ((color0 + color1 + 1) >> 1);
}
return color0;
}
private byte a2Value(int code, byte alpha0, byte alpha1) {
if (alpha0 > alpha1) {
switch (code) {
case 0:
return alpha0;
case 1:
return alpha1;
case 2:
return (byte) ((6 * alpha0 + 1 * alpha1) / 7);
case 3:
return (byte) ((5 * alpha0 + 2 * alpha1) / 7);
case 4:
return (byte) ((4 * alpha0 + 3 * alpha1) / 7);
case 5:
return (byte) ((3 * alpha0 + 4 * alpha1) / 7);
case 6:
return (byte) ((2 * alpha0 + 5 * alpha1) / 7);
case 7:
return (byte) ((1 * alpha0 + 6 * alpha1) / 7);
default:
LOG.error("a2Value code : " + code);
}
} else {
switch (code) {
case 0:
return alpha0;
case 1:
return alpha1;
case 2:
return (byte) ((4 * alpha0 + 1 * alpha1) / 5);
case 3:
return (byte) ((3 * alpha0 + 2 * alpha1) / 5);
case 4:
return (byte) ((2 * alpha0 + 3 * alpha1) / 5);
case 5:
return (byte) ((1 * alpha0 + 4 * alpha1) / 5);
case 6:
return 0;
case 7:
return (byte) 0xFF; //why, what, WHY???
default:
LOG.error("a2Value code : " + code);
}
}
return alpha0;
}
运行 来自:
ByteBuffer bbIn = ByteBuffer.allocate(imageDataSize);
bbIn.put(imageData, 0, imageDataSize);
bbIn.position(0);
byte[] decodedImage = new byte[height * width * 4];
int currentX = 0;
int currentY = 0;
int position = 0;
while (position < imageData.length) {
if ((currentX == width) && (currentY == height)) {
break;
}
decodeDXT5(bbIn, position, decodedImage, width, height, currentY, currentX);
currentX += 4;
if (currentX + 4 > width) {
currentX = 0;
currentY += 4;
}
position += 16;
}
PNG 部分在这里。这是我搜索结果中的最新版本,也是最接近的版本。文件大小、尺寸、形状等都在那里;只是颜色不对。有很多工件在进行;不属于图像的颜色。 PNG 代码看起来不错(我尝试了几种不同的波段偏移顺序,但它们都产生了相同的图像)。也许DXT5解码有误?或者 PNG 的东西实际上并不好。就像我说的,我不知道我在这里做什么,因为它在我的领域之外。前面说了这张DXT5解码后的图片是RGBA格式的(各占一个字节)
DataBuffer dataBuffer = new DataBufferByte(decodedImage, decodedImage.length);
int samplesPerPixel = 4;
int[] bandOffsets = {0, 1, 2, 3};
WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
File file = new File("/opt/wildfly/standalone/tmp/temp.png");
ImageIO.write(image, "png", file);
Java 缺少无符号类型,呃,救援...
这是签名与未签名的问题。正如我们所知,Java 没有 unsigned。这实际上不是 PNG 问题,而是从 DXT5 解压缩时出现的问题。当涉及数学时,我需要确保我使用的是无符号类型的等价物(因此在盛大的 Java 传统中,使用下一个最高类型并屏蔽符号位)。