Java - 如何将 png/jpeg 转换为 tga/targa?
Java - How to convert png/jpeg to tga/targa?
我想用 Java 将 png 图像转换为 tga 图像。我在网上四处寻找,但遗憾的是没有找到任何 Java 代码示例。有人有做这种转换的代码吗?
编辑:
由于这不是代码共享服务:
任何人都可以指出一个描述 png 到 tga 转换的算法,因为我没有找到任何算法。
我开始回想起 Targa 格式以今天的标准来说相对简单,所以我忍不住快速实现:
public void writeTargaImageTo(Path file,
BufferedImage image)
throws IOException {
try (WritableByteChannel channel = Files.newByteChannel(file,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {
writeTargaImageTo(channel, image);
}
}
public void writeTargaImageTo(WritableByteChannel out,
BufferedImage image)
throws IOException {
short originX = (short) image.getMinX();
short originY = (short) image.getMinY();
short width = (short) image.getWidth();
short height = (short) image.getHeight();
ByteBuffer header = ByteBuffer.allocate(18);
header.order(ByteOrder.LITTLE_ENDIAN);
header.put((byte) 0); // Length of string Identification
header.put((byte) 0); // No colormap
header.put((byte) 10); // Image type: RLE compressed RGB
header.putShort((short) 0); // Colormap type (irrelevant, no colormap)
header.putShort((short) 0); // Colormap first index (irrelevant)
header.put((byte) 0); // Colormap bits per entry (irrelevant)
header.putShort(originX); // Origin x coordinate
header.putShort(originY); // Origin y coordinate
header.putShort(width); // Image width
header.putShort(height); // Image height
header.put((byte) 32); // Bits per pixel
header.put((byte) (
8 // Number of alpha bits
| (1 << 5) // Origin is upper left
));
header.flip();
out.write(header);
int lastPixel = 0;
int runLength = 0;
ByteBuffer rlePacket = ByteBuffer.allocate(1 + 4);
ByteBuffer rawPacket = ByteBuffer.allocate(1 + 128 * 4);
rlePacket.order(ByteOrder.LITTLE_ENDIAN);
rawPacket.order(ByteOrder.LITTLE_ENDIAN);
rawPacket.put((byte) 0); // placeholder for header
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(originX + x, originY + y);
if (x == 0 && y == 0) {
lastPixel = pixel;
runLength = 1;
rawPacket.putInt(pixel);
continue;
}
boolean finalPixel = (x == width - 1 && y == height - 1);
if (finalPixel) {
if (pixel == lastPixel) {
runLength++;
} else {
rawPacket.putInt(pixel);
}
}
if (runLength >= 128 ||
(runLength > 1 &&
(finalPixel || pixel != lastPixel))) {
rlePacket.clear();
rlePacket.put((byte) (0x80 | (runLength - 1)));
rlePacket.putInt(lastPixel);
rlePacket.flip();
out.write(rlePacket);
runLength = 0;
rawPacket.clear();
rawPacket.put((byte) 0); // placeholder for header
}
if (!rawPacket.hasRemaining() ||
(rawPacket.position() > 1 &&
(finalPixel || pixel == lastPixel))) {
// "Forget" duplicated pixel, since it will be in RLE
if (!finalPixel) {
rawPacket.position(rawPacket.position() - 4);
}
int rawPixelCount = (rawPacket.position() - 1) / 4;
if (rawPixelCount > 0) {
rawPacket.put(0, (byte) (rawPixelCount - 1));
rawPacket.flip();
out.write(rawPacket);
}
runLength = 1;
rawPacket.clear();
rawPacket.put((byte) 0); // placeholder for header
}
if (!finalPixel) {
if (pixel == lastPixel) {
runLength++;
} else {
rawPacket.putInt(pixel);
lastPixel = pixel;
}
}
}
}
}
我的实现是故意简化的。它总是写入没有颜色图的 32 位图像,如果输入图像具有较小的深度或使用索引颜色,这是非常浪费的。但你至少会从中得到一张 Targa 图像。
参考文献:https://en.wikipedia.org/wiki/Truevision_TGA and http://www.paulbourke.net/dataformats/tga/
我想用 Java 将 png 图像转换为 tga 图像。我在网上四处寻找,但遗憾的是没有找到任何 Java 代码示例。有人有做这种转换的代码吗?
编辑: 由于这不是代码共享服务: 任何人都可以指出一个描述 png 到 tga 转换的算法,因为我没有找到任何算法。
我开始回想起 Targa 格式以今天的标准来说相对简单,所以我忍不住快速实现:
public void writeTargaImageTo(Path file,
BufferedImage image)
throws IOException {
try (WritableByteChannel channel = Files.newByteChannel(file,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {
writeTargaImageTo(channel, image);
}
}
public void writeTargaImageTo(WritableByteChannel out,
BufferedImage image)
throws IOException {
short originX = (short) image.getMinX();
short originY = (short) image.getMinY();
short width = (short) image.getWidth();
short height = (short) image.getHeight();
ByteBuffer header = ByteBuffer.allocate(18);
header.order(ByteOrder.LITTLE_ENDIAN);
header.put((byte) 0); // Length of string Identification
header.put((byte) 0); // No colormap
header.put((byte) 10); // Image type: RLE compressed RGB
header.putShort((short) 0); // Colormap type (irrelevant, no colormap)
header.putShort((short) 0); // Colormap first index (irrelevant)
header.put((byte) 0); // Colormap bits per entry (irrelevant)
header.putShort(originX); // Origin x coordinate
header.putShort(originY); // Origin y coordinate
header.putShort(width); // Image width
header.putShort(height); // Image height
header.put((byte) 32); // Bits per pixel
header.put((byte) (
8 // Number of alpha bits
| (1 << 5) // Origin is upper left
));
header.flip();
out.write(header);
int lastPixel = 0;
int runLength = 0;
ByteBuffer rlePacket = ByteBuffer.allocate(1 + 4);
ByteBuffer rawPacket = ByteBuffer.allocate(1 + 128 * 4);
rlePacket.order(ByteOrder.LITTLE_ENDIAN);
rawPacket.order(ByteOrder.LITTLE_ENDIAN);
rawPacket.put((byte) 0); // placeholder for header
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(originX + x, originY + y);
if (x == 0 && y == 0) {
lastPixel = pixel;
runLength = 1;
rawPacket.putInt(pixel);
continue;
}
boolean finalPixel = (x == width - 1 && y == height - 1);
if (finalPixel) {
if (pixel == lastPixel) {
runLength++;
} else {
rawPacket.putInt(pixel);
}
}
if (runLength >= 128 ||
(runLength > 1 &&
(finalPixel || pixel != lastPixel))) {
rlePacket.clear();
rlePacket.put((byte) (0x80 | (runLength - 1)));
rlePacket.putInt(lastPixel);
rlePacket.flip();
out.write(rlePacket);
runLength = 0;
rawPacket.clear();
rawPacket.put((byte) 0); // placeholder for header
}
if (!rawPacket.hasRemaining() ||
(rawPacket.position() > 1 &&
(finalPixel || pixel == lastPixel))) {
// "Forget" duplicated pixel, since it will be in RLE
if (!finalPixel) {
rawPacket.position(rawPacket.position() - 4);
}
int rawPixelCount = (rawPacket.position() - 1) / 4;
if (rawPixelCount > 0) {
rawPacket.put(0, (byte) (rawPixelCount - 1));
rawPacket.flip();
out.write(rawPacket);
}
runLength = 1;
rawPacket.clear();
rawPacket.put((byte) 0); // placeholder for header
}
if (!finalPixel) {
if (pixel == lastPixel) {
runLength++;
} else {
rawPacket.putInt(pixel);
lastPixel = pixel;
}
}
}
}
}
我的实现是故意简化的。它总是写入没有颜色图的 32 位图像,如果输入图像具有较小的深度或使用索引颜色,这是非常浪费的。但你至少会从中得到一张 Targa 图像。
参考文献:https://en.wikipedia.org/wiki/Truevision_TGA and http://www.paulbourke.net/dataformats/tga/