Task 725: .TGA File Format
Task 725: .TGA File Format
1. List of Properties Intrinsic to the .TGA File Format
The .TGA (Truevision TARGA) file format specifications were obtained from established sources, including the detailed structure provided by Paul Bourke's documentation. The format consists primarily of an 18-byte header, followed by optional image identification data, color map data, and image pixel data. The properties intrinsic to the file format, particularly those embedded in the file structure for identification, dimensions, and rendering, are derived from the header fields. These are as follows:
- ID Length: A 1-byte unsigned integer (offset 0) indicating the number of bytes in the optional Image Identification Field (range: 0–255).
- Color Map Type: A 1-byte unsigned integer (offset 1) specifying whether a color map is included (0 = no color map; 1 = color map present).
- Image Type: A 1-byte unsigned integer (offset 2) defining the type of image data (e.g., 0 = no image data; 2 = uncompressed RGB; 10 = run-length encoded RGB).
- Color Map First Entry Index: A 2-byte unsigned integer (offset 3, little-endian) representing the starting index of the color map.
- Color Map Length: A 2-byte unsigned integer (offset 5, little-endian) indicating the number of entries in the color map.
- Color Map Entry Size: A 1-byte unsigned integer (offset 7) specifying the bit depth of each color map entry (e.g., 16, 24, or 32 bits).
- X Origin: A 2-byte unsigned integer (offset 8, little-endian) defining the X-coordinate of the image's lower-left corner.
- Y Origin: A 2-byte unsigned integer (offset 10, little-endian) defining the Y-coordinate of the image's lower-left corner.
- Image Width: A 2-byte unsigned integer (offset 12, little-endian) specifying the width of the image in pixels.
- Image Height: A 2-byte unsigned integer (offset 14, little-endian) specifying the height of the image in pixels.
- Pixel Depth: A 1-byte unsigned integer (offset 16) indicating the number of bits per pixel (e.g., 8, 16, 24, or 32).
- Image Descriptor: A 1-byte unsigned integer (offset 17) containing bit flags for additional attributes:
- Bits 0–3: Number of attribute bits per pixel (typically alpha channel bits).
- Bit 4: Reserved (must be 0).
- Bit 5: Screen origin (0 = lower-left corner; 1 = upper-left corner).
- Bits 6–7: Data interleaving mode (00 = none; 01 = two-way; 10 = four-way; 11 = reserved).
These properties are fundamental to the file's structure and are used to interpret the subsequent data sections, such as the optional Image Identification Field (variable length, immediately after the header), Color Map Data (if applicable), and Image Data (pixel values, potentially run-length encoded).
2. Two Direct Download Links for .TGA Files
The following are direct download links to sample .TGA files, sourced from publicly available repositories:
- https://filesamples.com/samples/image/tga/sample_640×426.tga
- https://filesamples.com/samples/image/tga/sample_1280×853.tga
3. Ghost Blog Embedded HTML/JavaScript for Drag-and-Drop .TGA Property Dump
The following is a self-contained HTML page with embedded JavaScript that allows users to drag and drop a .TGA file. Upon dropping, it reads the file, decodes the header, and displays all the properties listed in section 1 on the screen.
4. Python Class for .TGA File Handling
The following Python class can open a .TGA file, decode its header, read the properties, print them to the console, and write a new .TGA file with modified properties (basic implementation for uncompressed RGB; full image data handling is simplified for demonstration).
import struct
class TGAHandler:
def __init__(self, filepath=None):
self.properties = {}
if filepath:
self.read(filepath)
def read(self, filepath):
with open(filepath, 'rb') as f:
header = f.read(18)
if len(header) < 18:
raise ValueError("Invalid TGA file.")
self.properties = {
'ID Length': struct.unpack('<B', header[0:1])[0],
'Color Map Type': struct.unpack('<B', header[1:2])[0],
'Image Type': struct.unpack('<B', header[2:3])[0],
'Color Map First Entry Index': struct.unpack('<H', header[3:5])[0],
'Color Map Length': struct.unpack('<H', header[5:7])[0],
'Color Map Entry Size': struct.unpack('<B', header[7:8])[0],
'X Origin': struct.unpack('<H', header[8:10])[0],
'Y Origin': struct.unpack('<H', header[10:12])[0],
'Image Width': struct.unpack('<H', header[12:14])[0],
'Image Height': struct.unpack('<H', header[14:16])[0],
'Pixel Depth': struct.unpack('<B', header[16:17])[0],
'Image Descriptor': struct.unpack('<B', header[17:18])[0]
}
# Skip ID field, color map, and read image data (simplified)
f.seek(18 + self.properties['ID Length'])
# Color map and image data would be read here if needed
def print_properties(self):
for key, value in self.properties.items():
print(f"{key}: {value}")
def write(self, filepath, image_data=b''): # image_data: bytes for pixels
header = struct.pack('<B', self.properties.get('ID Length', 0))
header += struct.pack('<B', self.properties.get('Color Map Type', 0))
header += struct.pack('<B', self.properties.get('Image Type', 2)) # Default to uncompressed RGB
header += struct.pack('<H', self.properties.get('Color Map First Entry Index', 0))
header += struct.pack('<H', self.properties.get('Color Map Length', 0))
header += struct.pack('<B', self.properties.get('Color Map Entry Size', 0))
header += struct.pack('<H', self.properties.get('X Origin', 0))
header += struct.pack('<H', self.properties.get('Y Origin', 0))
header += struct.pack('<H', self.properties.get('Image Width', 0))
header += struct.pack('<H', self.properties.get('Image Height', 0))
header += struct.pack('<B', self.properties.get('Pixel Depth', 24))
header += struct.pack('<B', self.properties.get('Image Descriptor', 0))
with open(filepath, 'wb') as f:
f.write(header)
# Write ID field, color map if any (omitted for simplicity)
f.write(image_data)
# Example usage:
# tga = TGAHandler('sample.tga')
# tga.print_properties()
# tga.write('output.tga')
5. Java Class for .TGA File Handling
The following Java class can open a .TGA file, decode its header, read the properties, print them to the console, and write a new .TGA file with modified properties (basic implementation for uncompressed RGB; full image data handling is simplified).
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class TGAHandler {
private int idLength;
private int colorMapType;
private int imageType;
private int colorMapFirstEntryIndex;
private int colorMapLength;
private int colorMapEntrySize;
private int xOrigin;
private int yOrigin;
private int imageWidth;
private int imageHeight;
private int pixelDepth;
private int imageDescriptor;
public TGAHandler(String filepath) throws IOException {
read(filepath);
}
public void read(String filepath) throws IOException {
try (FileInputStream fis = new FileInputStream(filepath)) {
byte[] header = new byte[18];
if (fis.read(header) < 18) {
throw new IOException("Invalid TGA file.");
}
ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
idLength = bb.get(0) & 0xFF;
colorMapType = bb.get(1) & 0xFF;
imageType = bb.get(2) & 0xFF;
colorMapFirstEntryIndex = bb.getShort(3) & 0xFFFF;
colorMapLength = bb.getShort(5) & 0xFFFF;
colorMapEntrySize = bb.get(7) & 0xFF;
xOrigin = bb.getShort(8) & 0xFFFF;
yOrigin = bb.getShort(10) & 0xFFFF;
imageWidth = bb.getShort(12) & 0xFFFF;
imageHeight = bb.getShort(14) & 0xFFFF;
pixelDepth = bb.get(16) & 0xFF;
imageDescriptor = bb.get(17) & 0xFF;
// Skip ID, color map, image data as needed
}
}
public void printProperties() {
System.out.println("ID Length: " + idLength);
System.out.println("Color Map Type: " + colorMapType);
System.out.println("Image Type: " + imageType);
System.out.println("Color Map First Entry Index: " + colorMapFirstEntryIndex);
System.out.println("Color Map Length: " + colorMapLength);
System.out.println("Color Map Entry Size: " + colorMapEntrySize);
System.out.println("X Origin: " + xOrigin);
System.out.println("Y Origin: " + yOrigin);
System.out.println("Image Width: " + imageWidth);
System.out.println("Image Height: " + imageHeight);
System.out.println("Pixel Depth: " + pixelDepth);
System.out.println("Image Descriptor: " + imageDescriptor);
}
public void write(String filepath, byte[] imageData) throws IOException {
try (FileOutputStream fos = new FileOutputStream(filepath)) {
ByteBuffer bb = ByteBuffer.allocate(18).order(ByteOrder.LITTLE_ENDIAN);
bb.put((byte) idLength);
bb.put((byte) colorMapType);
bb.put((byte) imageType);
bb.putShort((short) colorMapFirstEntryIndex);
bb.putShort((short) colorMapLength);
bb.put((byte) colorMapEntrySize);
bb.putShort((short) xOrigin);
bb.putShort((short) yOrigin);
bb.putShort((short) imageWidth);
bb.putShort((short) imageHeight);
bb.put((byte) pixelDepth);
bb.put((byte) imageDescriptor);
fos.write(bb.array());
// Write ID, color map if any (omitted)
fos.write(imageData);
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// TGAHandler tga = new TGAHandler("sample.tga");
// tga.printProperties();
// tga.write("output.tga", new byte[0]);
// }
}
6. JavaScript Class for .TGA File Handling
The following JavaScript class (for Node.js environment) can open a .TGA file, decode its header, read the properties, print them to the console, and write a new .TGA file with modified properties (basic implementation for uncompressed RGB; requires 'fs' module).
const fs = require('fs');
class TGAHandler {
constructor(filepath) {
this.properties = {};
if (filepath) {
this.read(filepath);
}
}
read(filepath) {
const buffer = fs.readFileSync(filepath);
if (buffer.length < 18) {
throw new Error('Invalid TGA file.');
}
const view = new DataView(buffer.buffer);
this.properties = {
'ID Length': view.getUint8(0),
'Color Map Type': view.getUint8(1),
'Image Type': view.getUint8(2),
'Color Map First Entry Index': view.getUint16(3, true),
'Color Map Length': view.getUint16(5, true),
'Color Map Entry Size': view.getUint8(7),
'X Origin': view.getUint16(8, true),
'Y Origin': view.getUint16(10, true),
'Image Width': view.getUint16(12, true),
'Image Height': view.getUint16(14, true),
'Pixel Depth': view.getUint8(16),
'Image Descriptor': view.getUint8(17)
};
// Image data reading omitted for simplicity
}
printProperties() {
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key}: ${value}`);
}
}
write(filepath, imageData = Buffer.alloc(0)) {
const buffer = Buffer.alloc(18);
const view = new DataView(buffer.buffer);
view.setUint8(0, this.properties['ID Length'] || 0);
view.setUint8(1, this.properties['Color Map Type'] || 0);
view.setUint8(2, this.properties['Image Type'] || 2);
view.setUint16(3, this.properties['Color Map First Entry Index'] || 0, true);
view.setUint16(5, this.properties['Color Map Length'] || 0, true);
view.setUint8(7, this.properties['Color Map Entry Size'] || 0);
view.setUint16(8, this.properties['X Origin'] || 0, true);
view.setUint16(10, this.properties['Y Origin'] || 0, true);
view.setUint16(12, this.properties['Image Width'] || 0, true);
view.setUint16(14, this.properties['Image Height'] || 0, true);
view.setUint8(16, this.properties['Pixel Depth'] || 24);
view.setUint8(17, this.properties['Image Descriptor'] || 0);
fs.writeFileSync(filepath, Buffer.concat([buffer, imageData]));
}
}
// Example usage:
// const tga = new TGAHandler('sample.tga');
// tga.printProperties();
// tga.write('output.tga');
7. C++ Class for .TGA File Handling
The following C++ class can open a .TGA file, decode its header, read the properties, print them to the console, and write a new .TGA file with modified properties (basic implementation for uncompressed RGB; full image data handling is simplified).
#include <iostream>
#include <fstream>
#include <cstdint>
#include <vector>
class TGAHandler {
private:
uint8_t idLength;
uint8_t colorMapType;
uint8_t imageType;
uint16_t colorMapFirstEntryIndex;
uint16_t colorMapLength;
uint8_t colorMapEntrySize;
uint16_t xOrigin;
uint16_t yOrigin;
uint16_t imageWidth;
uint16_t imageHeight;
uint8_t pixelDepth;
uint8_t imageDescriptor;
public:
TGAHandler(const std::string& filepath) {
read(filepath);
}
void read(const std::string& filepath) {
std::ifstream file(filepath, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot open file.");
}
std::vector<uint8_t> header(18);
file.read(reinterpret_cast<char*>(header.data()), 18);
if (file.gcount() < 18) {
throw std::runtime_error("Invalid TGA file.");
}
idLength = header[0];
colorMapType = header[1];
imageType = header[2];
colorMapFirstEntryIndex = static_cast<uint16_t>(header[3]) | (static_cast<uint16_t>(header[4]) << 8);
colorMapLength = static_cast<uint16_t>(header[5]) | (static_cast<uint16_t>(header[6]) << 8);
colorMapEntrySize = header[7];
xOrigin = static_cast<uint16_t>(header[8]) | (static_cast<uint16_t>(header[9]) << 8);
yOrigin = static_cast<uint16_t>(header[10]) | (static_cast<uint16_t>(header[11]) << 8);
imageWidth = static_cast<uint16_t>(header[12]) | (static_cast<uint16_t>(header[13]) << 8);
imageHeight = static_cast<uint16_t>(header[14]) | (static_cast<uint16_t>(header[15]) << 8);
pixelDepth = header[16];
imageDescriptor = header[17];
// Image data reading omitted
}
void printProperties() const {
std::cout << "ID Length: " << static_cast<int>(idLength) << std::endl;
std::cout << "Color Map Type: " << static_cast<int>(colorMapType) << std::endl;
std::cout << "Image Type: " << static_cast<int>(imageType) << std::endl;
std::cout << "Color Map First Entry Index: " << colorMapFirstEntryIndex << std::endl;
std::cout << "Color Map Length: " << colorMapLength << std::endl;
std::cout << "Color Map Entry Size: " << static_cast<int>(colorMapEntrySize) << std::endl;
std::cout << "X Origin: " << xOrigin << std::endl;
std::cout << "Y Origin: " << yOrigin << std::endl;
std::cout << "Image Width: " << imageWidth << std::endl;
std::cout << "Image Height: " << imageHeight << std::endl;
std::cout << "Pixel Depth: " << static_cast<int>(pixelDepth) << std::endl;
std::cout << "Image Descriptor: " << static_cast<int>(imageDescriptor) << std::endl;
}
void write(const std::string& filepath, const std::vector<uint8_t>& imageData = {}) const {
std::ofstream file(filepath, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot write file.");
}
uint8_t header[18] = {
idLength,
colorMapType,
imageType,
static_cast<uint8_t>(colorMapFirstEntryIndex & 0xFF),
static_cast<uint8_t>((colorMapFirstEntryIndex >> 8) & 0xFF),
static_cast<uint8_t>(colorMapLength & 0xFF),
static_cast<uint8_t>((colorMapLength >> 8) & 0xFF),
colorMapEntrySize,
static_cast<uint8_t>(xOrigin & 0xFF),
static_cast<uint8_t>((xOrigin >> 8) & 0xFF),
static_cast<uint8_t>(yOrigin & 0xFF),
static_cast<uint8_t>((yOrigin >> 8) & 0xFF),
static_cast<uint8_t>(imageWidth & 0xFF),
static_cast<uint8_t>((imageWidth >> 8) & 0xFF),
static_cast<uint8_t>(imageHeight & 0xFF),
static_cast<uint8_t>((imageHeight >> 8) & 0xFF),
pixelDepth,
imageDescriptor
};
file.write(reinterpret_cast<const char*>(header), 18);
file.write(reinterpret_cast<const char*>(imageData.data()), imageData.size());
}
};
// Example usage:
// int main() {
// try {
// TGAHandler tga("sample.tga");
// tga.printProperties();
// tga.write("output.tga");
// } catch (const std::exception& e) {
// std::cerr << e.what() << std::endl;
// }
// return 0;
// }