com.github.bloodshura.x.assets.image.codec.TgaCodec Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shurax-assets Show documentation
Show all versions of shurax-assets Show documentation
An API for reading, writing and manipulating fonts, images and sounds.
/*
* Copyright (c) 2013-2018, João Vitor Verona Biazibetti - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* https://www.github.com/BloodShura
*/
package com.github.bloodshura.x.assets.image.codec;
import com.github.bloodshura.x.assets.image.ImageFormat;
import javax.annotation.Nonnull;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class TgaCodec implements ImageCodec {
private int readOffset;
@Override
public boolean hasDecoder(@Nonnull ImageFormat format) {
return format == ImageFormat.TGA;
}
@Override
public boolean hasEncoder(@Nonnull ImageFormat format) {
return format == ImageFormat.TGA;
}
@Nonnull
@Override
public BufferedImage read(@Nonnull InputStream input) throws IOException {
byte[] buffer = new byte[input.available()];
this.readOffset = 0;
input.read(buffer);
input.close();
for (int i = 0; i < 12; i++) {
read(buffer);
}
int width = read(buffer) + (read(buffer) << 8);
int height = read(buffer) + (read(buffer) << 8);
read(buffer);
read(buffer);
int remaining = width * height;
int[] pixels = new int[remaining];
int index = pixels.length - 1;
if (buffer[2] == 0x02 && (buffer[16] == 0x20 || buffer[16] == 0x18)) {
while (remaining > 0) {
int b = read(buffer);
int g = read(buffer);
int r = read(buffer);
int a = buffer[16] == 0x20 ? read(buffer) : 255;
int v = a << 24 | r << 16 | g << 8 | b;
pixels[index--] = v;
remaining--;
}
}
else {
while (remaining > 0) {
int nb = read(buffer);
if ((nb & 0x80) == 0) {
for (int i = 0; i <= nb; i++) {
int b = read(buffer);
int g = read(buffer);
int r = read(buffer);
pixels[index--] = 0xff000000 | r << 16 | g << 8 | b;
}
}
else {
nb &= 0x7F;
int b = read(buffer);
int g = read(buffer);
int r = read(buffer);
int v = 0xff000000 | r << 16 | g << 8 | b;
for (int i = 0; i <= nb; i++) {
pixels[index--] = v;
}
}
remaining -= nb + 1;
}
}
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
image.setRGB(0, 0, width, height, pixels, 0, width);
return image;
}
@Override
public void write(@Nonnull BufferedImage image, @Nonnull ImageFormat format, @Nonnull OutputStream output) throws IOException {
DataBuffer buffer = image.getRaster().getDataBuffer();
boolean alpha = image.getColorModel().hasAlpha();
byte[] data;
if (buffer instanceof DataBufferByte) {
byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
int expectedLength = image.getWidth() * image.getHeight() * (alpha ? 4 : 3);
if (pixels.length != expectedLength) {
throw new IOException("Data buffer length " + pixels.length + ", expected " + expectedLength);
}
data = new byte[pixels.length];
int i = 0;
int p = pixels.length - 1;
while (i < data.length) {
byte r = pixels[p - 2];
byte g = pixels[p - 1];
byte b = pixels[p];
data[i++] = r;
data[i++] = g;
data[i++] = b;
if (alpha) {
data[i++] = pixels[p - 3];
p--;
}
p -= 3;
}
}
else if (buffer instanceof DataBufferInt) {
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
int expectedLength = image.getWidth() * image.getHeight();
if (pixels.length != expectedLength) {
throw new IOException("Data buffer length " + pixels.length + ", expected " + expectedLength);
}
data = new byte[pixels.length * (alpha ? 4 : 3)];
int i = 0;
int p = pixels.length - 1;
while (i < data.length) {
data[i++] = (byte) (pixels[p] & 0xFF);
data[i++] = (byte) (pixels[p] >> 8 & 0xFF);
data[i++] = (byte) (pixels[p] >> 16 & 0xFF);
if (alpha) {
data[i++] = (byte) (pixels[p] >> 24 & 0xFF);
}
p--;
}
}
else {
throw new IOException("Data buffer not supported: " + buffer.getClass().getSimpleName());
}
byte[] header = new byte[18];
header[2] = 0x02;
header[12] = (byte) (image.getWidth() & 0xFF);
header[13] = (byte) (image.getWidth() >> 8 & 0xFF);
header[14] = (byte) (image.getHeight() & 0xFF);
header[15] = (byte) (image.getHeight() >> 8 & 0xFF);
header[16] = (byte) (alpha ? 32 : 24);
header[17] = (byte) ((alpha ? 8 : 0) | 1 << 4);
output.write(header);
output.write(data);
output.flush();
}
private int read(byte[] buffer) {
int a = buffer[readOffset++];
return a < 0 ? 256 + a : a;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy