Task 604: .RAS File Format
Task 604: .RAS File Format
1. List of Properties for the .RAS File Format
The .RAS file format (Sun Raster) consists of a fixed 32-byte header followed by an optional color map and the image data. All header fields are 32-bit unsigned integers (DWORD) stored in big-endian byte order. The intrinsic properties (header fields) are:
- MagicNumber: A 32-bit magic identifier, always 0x59A66A95 (used to verify the file type).
- Width: The width of the image in pixels.
- Height: The height of the image in pixels.
- Depth: The number of bits per pixel (common values: 1, 8, 24, 32).
- Length: The length of the image data in bytes (may be 0 in older files, in which case it's calculated as (Width * Height * Depth) / 8).
- Type: The encoding type (0: Old/uncompressed, 1: Standard/uncompressed, 2: RLE compressed, 3: RGB order instead of BGR, etc.).
- ColorMapType: The type of color map (0: None, 1: RGB, 2: Raw).
- ColorMapLength: The length of the color map in bytes (0 if no color map).
These properties define the core structure. The color map (if present) and image data follow the header but are not fixed "properties" as they vary.
2. Two Direct Download Links for .RAS Files
- https://netghost.narod.ru/gff/graphics/marbles.sun
- https://www.fileformat.info/format/sunraster/sample/1f154a940b844d238bf66154d8745926/download
(Note: .SUN is an equivalent extension for the same format.)
3. Embedded HTML JavaScript for Drag-and-Drop .RAS File Property Dump
Here's a self-contained HTML snippet with JavaScript that can be embedded in a blog (e.g., Ghost platform). It creates a drag-and-drop area. When a .RAS file is dropped, it reads the file, parses the 32-byte header using DataView for big-endian values, validates the magic number, and displays the properties on the screen.
4. Python Class for .RAS File Handling
import struct
import os
class RasFileHandler:
def __init__(self):
self.magic = 0x59A66A95
self.width = 0
self.height = 0
self.depth = 0
self.length = 0
self.type = 0
self.color_map_type = 0
self.color_map_length = 0
def read_and_decode(self, file_path):
if not os.path.exists(file_path):
print("File not found.")
return False
with open(file_path, 'rb') as f:
header = f.read(32)
if len(header) < 32:
print("File too small for header.")
return False
# Unpack big-endian (> for big-endian, I for uint32)
unpacked = struct.unpack('>8I', header)
self.magic, self.width, self.height, self.depth, self.length, self.type, self.color_map_type, self.color_map_length = unpacked
if self.magic != 0x59A66A95:
print("Invalid .RAS file (wrong magic number).")
return False
self.print_properties()
return True
def print_properties(self):
print("MagicNumber: 0x{:08X}".format(self.magic))
print("Width: {}".format(self.width))
print("Height: {}".format(self.height))
print("Depth: {}".format(self.depth))
print("Length: {}".format(self.length))
print("Type: {}".format(self.type))
print("ColorMapType: {}".format(self.color_map_type))
print("ColorMapLength: {}".format(self.color_map_length))
def write(self, file_path, width=100, height=100, depth=8, type=1, color_map_type=0, color_map_length=0, image_data=b''):
self.width = width
self.height = height
self.depth = depth
self.type = type
self.color_map_type = color_map_type
self.color_map_length = color_map_length
self.length = len(image_data) # Update length based on provided data
header = struct.pack('>8I', self.magic, self.width, self.height, self.depth, self.length, self.type, self.color_map_type, self.color_map_length)
with open(file_path, 'wb') as f:
f.write(header)
# Skip color map for simplicity (assume none)
f.write(image_data) # Write provided image data (e.g., raw bytes)
print("File written successfully.")
self.print_properties()
# Example usage:
# handler = RasFileHandler()
# handler.read_and_decode('example.ras')
# handler.write('output.ras', image_data=b'\x00' * (100*100)) # Simple 100x100 8-bit grayscale
5. Java Class for .RAS File Handling
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class RasFileHandler {
private static final long MAGIC = 0x59A66A95L;
private long width;
private long height;
private long depth;
private long length;
private long type;
private long colorMapType;
private long colorMapLength;
public boolean readAndDecode(String filePath) {
try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) {
byte[] header = new byte[32];
if (raf.read(header) < 32) {
System.out.println("File too small for header.");
return false;
}
ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.BIG_ENDIAN);
long magic = bb.getInt() & 0xFFFFFFFFL;
this.width = bb.getInt() & 0xFFFFFFFFL;
this.height = bb.getInt() & 0xFFFFFFFFL;
this.depth = bb.getInt() & 0xFFFFFFFFL;
this.length = bb.getInt() & 0xFFFFFFFFL;
this.type = bb.getInt() & 0xFFFFFFFFL;
this.colorMapType = bb.getInt() & 0xFFFFFFFFL;
this.colorMapLength = bb.getInt() & 0xFFFFFFFFL;
if (magic != MAGIC) {
System.out.println("Invalid .RAS file (wrong magic number).");
return false;
}
printProperties();
return true;
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
return false;
}
}
public void printProperties() {
System.out.printf("MagicNumber: 0x%08X%n", MAGIC);
System.out.printf("Width: %d%n", width);
System.out.printf("Height: %d%n", height);
System.out.printf("Depth: %d%n", depth);
System.out.printf("Length: %d%n", length);
System.out.printf("Type: %d%n", type);
System.out.printf("ColorMapType: %d%n", colorMapType);
System.out.printf("ColorMapLength: %d%n", colorMapLength);
}
public void write(String filePath, long width, long height, long depth, long type, long colorMapType, long colorMapLength, byte[] imageData) {
this.width = width;
this.height = height;
this.depth = depth;
this.type = type;
this.colorMapType = colorMapType;
this.colorMapLength = colorMapLength;
this.length = imageData.length;
try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
ByteBuffer bb = ByteBuffer.allocate(32).order(ByteOrder.BIG_ENDIAN);
bb.putInt((int) MAGIC);
bb.putInt((int) this.width);
bb.putInt((int) this.height);
bb.putInt((int) this.depth);
bb.putInt((int) this.length);
bb.putInt((int) this.type);
bb.putInt((int) this.colorMapType);
bb.putInt((int) this.colorMapLength);
raf.write(bb.array());
// Skip color map for simplicity
raf.write(imageData);
System.out.println("File written successfully.");
printProperties();
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
}
// Example usage:
// public static void main(String[] args) {
// RasFileHandler handler = new RasFileHandler();
// handler.readAndDecode("example.ras");
// byte[] data = new byte[100*100]; // Simple 100x100 8-bit
// handler.write("output.ras", 100, 100, 8, 1, 0, 0, data);
// }
}
6. JavaScript Class for .RAS File Handling
(This is for Node.js, using fs for file I/O. For browser, use FileReader as in part 3.)
const fs = require('fs');
class RasFileHandler {
constructor() {
this.magic = 0x59A66A95;
this.width = 0;
this.height = 0;
this.depth = 0;
this.length = 0;
this.type = 0;
this.colorMapType = 0;
this.colorMapLength = 0;
}
readAndDecode(filePath) {
if (!fs.existsSync(filePath)) {
console.log('File not found.');
return false;
}
const buffer = fs.readFileSync(filePath);
if (buffer.length < 32) {
console.log('File too small for header.');
return false;
}
const dataView = new DataView(buffer.buffer);
this.magic = dataView.getUint32(0, false); // Big-endian
if (this.magic !== 0x59A66A95) {
console.log('Invalid .RAS file (wrong magic number).');
return false;
}
this.width = dataView.getUint32(4, false);
this.height = dataView.getUint32(8, false);
this.depth = dataView.getUint32(12, false);
this.length = dataView.getUint32(16, false);
this.type = dataView.getUint32(20, false);
this.colorMapType = dataView.getUint32(24, false);
this.colorMapLength = dataView.getUint32(28, false);
this.printProperties();
return true;
}
printProperties() {
console.log(`MagicNumber: 0x${this.magic.toString(16).toUpperCase()}`);
console.log(`Width: ${this.width}`);
console.log(`Height: ${this.height}`);
console.log(`Depth: ${this.depth}`);
console.log(`Length: ${this.length}`);
console.log(`Type: ${this.type}`);
console.log(`ColorMapType: ${this.colorMapType}`);
console.log(`ColorMapLength: ${this.colorMapLength}`);
}
write(filePath, width = 100, height = 100, depth = 8, type = 1, colorMapType = 0, colorMapLength = 0, imageData = Buffer.alloc(0)) {
this.width = width;
this.height = height;
this.depth = depth;
this.type = type;
this.colorMapType = colorMapType;
this.colorMapLength = colorMapLength;
this.length = imageData.length;
const header = Buffer.alloc(32);
const dataView = new DataView(header.buffer);
dataView.setUint32(0, this.magic, false);
dataView.setUint32(4, this.width, false);
dataView.setUint32(8, this.height, false);
dataView.setUint32(12, this.depth, false);
dataView.setUint32(16, this.length, false);
dataView.setUint32(20, this.type, false);
dataView.setUint32(24, this.colorMapType, false);
dataView.setUint32(28, this.colorMapLength, false);
const fullBuffer = Buffer.concat([header, imageData]); // Skip color map
fs.writeFileSync(filePath, fullBuffer);
console.log('File written successfully.');
this.printProperties();
}
}
// Example usage:
// const handler = new RasFileHandler();
// handler.readAndDecode('example.ras');
// handler.write('output.ras', 100, 100, 8, 1, 0, 0, Buffer.alloc(100*100));
7. C Implementation for .RAS File Handling
(C uses a struct instead of a class. Includes functions for read/decode/print and write.)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <endian.h> // For big-endian conversion if needed
struct RasHeader {
uint32_t magic;
uint32_t width;
uint32_t height;
uint32_t depth;
uint32_t length;
uint32_t type;
uint32_t color_map_type;
uint32_t color_map_length;
};
int read_and_decode(const char* file_path, struct RasHeader* header) {
FILE* file = fopen(file_path, "rb");
if (!file) {
printf("File not found.\n");
return 0;
}
uint32_t raw_header[8];
if (fread(raw_header, sizeof(uint32_t), 8, file) < 8) {
printf("File too small for header.\n");
fclose(file);
return 0;
}
fclose(file);
// Convert from big-endian to host
header->magic = be32toh(raw_header[0]);
if (header->magic != 0x59A66A95) {
printf("Invalid .RAS file (wrong magic number).\n");
return 0;
}
header->width = be32toh(raw_header[1]);
header->height = be32toh(raw_header[2]);
header->depth = be32toh(raw_header[3]);
header->length = be32toh(raw_header[4]);
header->type = be32toh(raw_header[5]);
header->color_map_type = be32toh(raw_header[6]);
header->color_map_length = be32toh(raw_header[7]);
print_properties(header);
return 1;
}
void print_properties(const struct RasHeader* header) {
printf("MagicNumber: 0x%08X\n", header->magic);
printf("Width: %u\n", header->width);
printf("Height: %u\n", header->height);
printf("Depth: %u\n", header->depth);
printf("Length: %u\n", header->length);
printf("Type: %u\n", header->type);
printf("ColorMapType: %u\n", header->color_map_type);
printf("ColorMapLength: %u\n", header->color_map_length);
}
void write(const char* file_path, uint32_t width, uint32_t height, uint32_t depth, uint32_t type,
uint32_t color_map_type, uint32_t color_map_length, const uint8_t* image_data, size_t data_size) {
struct RasHeader header = {
.magic = 0x59A66A95,
.width = width,
.height = height,
.depth = depth,
.length = (uint32_t)data_size,
.type = type,
.color_map_type = color_map_type,
.color_map_length = color_map_length
};
FILE* file = fopen(file_path, "wb");
if (!file) {
printf("Error opening file for write.\n");
return;
}
// Convert to big-endian
uint32_t raw_header[8] = {
htobe32(header.magic),
htobe32(header.width),
htobe32(header.height),
htobe32(header.depth),
htobe32(header.length),
htobe32(header.type),
htobe32(header.color_map_type),
htobe32(header.color_map_length)
};
fwrite(raw_header, sizeof(uint32_t), 8, file);
// Skip color map for simplicity
if (image_data) {
fwrite(image_data, 1, data_size, file);
}
fclose(file);
printf("File written successfully.\n");
print_properties(&header);
}
// Example usage:
// int main() {
// struct RasHeader header;
// read_and_decode("example.ras", &header);
// uint8_t data[100*100] = {0}; // Simple 100x100 8-bit
// write("output.ras", 100, 100, 8, 1, 0, 0, data, sizeof(data));
// return 0;
// }