All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bloodshura.x.assets.image.codec.TgaCodec Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/*
 * 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