Task 620: .RS File Format
Task 620: .RS File Format
1. List of Properties for the .RS File Format
The .RS file format refers to the Sun Raster image format (also known as Sun Rasterfile), a bitmap format developed by Sun Microsystems. It is a binary format with a fixed 32-byte header (big-endian), an optional color map, and image data that may be uncompressed or RLE-compressed. The properties intrinsic to the format (i.e., the core metadata fields from the header that define the file's structure and content) are:
- Magic Number: A 4-byte identifier always set to 0x59a66a95 (in hexadecimal) to confirm it's a Sun Raster file.
- Width: A 4-byte unsigned integer representing the image width in pixels. Scan lines are padded to multiples of 16 bits.
- Height: A 4-byte unsigned integer representing the image height in pixels.
- Depth: A 4-byte unsigned integer indicating bits per pixel (common values: 1 for monochrome, 8 for paletted/grayscale, 24 or 32 for true color; 32-bit includes an alpha or pad byte).
- Length: A 4-byte unsigned integer for the size of the image data section in bytes (excludes header and color map; may need calculation in older files).
- Type: A 4-byte unsigned integer specifying the encoding/version (e.g., 0 = old/uncompressed, 1 = standard/uncompressed, 2 = RLE-compressed, 3 = RGB order, others for experimental or converted formats).
- Color Map Type: A 4-byte unsigned integer indicating color map presence (0 = none, 1 = RGB, 2 = raw/other).
- Color Map Length: A 4-byte unsigned integer for the size of the color map in bytes (0 if no map; for RGB maps, typically a multiple of 3 for red/green/blue planes).
These properties are extracted from the header. The color map (if present) and image data follow, but they are not "properties" per se—rather, variable content based on the header.
2. Two Direct Download Links for .RS Format Files
- https://fredrik.hubbe.net/plugger/test.rs (a sample Sun Raster image file with .rs extension)
- https://netghost.narod.ru/gff/graphics/marbles.sun (a sample Sun Raster image file; note: .sun extension but identical format to .rs; can be renamed if needed)
3. HTML/JavaScript for Drag-and-Drop .RS File Dumper (Embeddable in a Ghost Blog or Similar)
Here's a self-contained HTML page with embedded JavaScript. It allows dragging and dropping a .RS file, parses the header, and displays the properties on screen. Embed this in a blog post using an HTML block.
4. Python Class for .RS File Handling
import struct
import os
class RSFile:
HEADER_FORMAT = '>8I' # Big-endian, 8 unsigned ints (32 bytes)
MAGIC = 0x59a66a95
def __init__(self, filepath):
self.filepath = filepath
self.magic = None
self.width = None
self.height = None
self.depth = None
self.length = None
self.type = None
self.map_type = None
self.map_length = None
self.color_map = b''
self.image_data = b''
def read(self):
with open(self.filepath, 'rb') as f:
header = f.read(32)
if len(header) < 32:
raise ValueError("File too small for header")
unpacked = struct.unpack(self.HEADER_FORMAT, header)
self.magic, self.width, self.height, self.depth, self.length, self.type, self.map_type, self.map_length = unpacked
if self.magic != self.MAGIC:
raise ValueError("Invalid magic number")
self.color_map = f.read(self.map_length)
self.image_data = f.read(self.length) # Note: Does not decode RLE if present
def print_properties(self):
if self.magic is None:
raise ValueError("File not read yet")
print(f"Magic Number: 0x{self.magic:08x}")
print(f"Width: {self.width}")
print(f"Height: {self.height}")
print(f"Depth: {self.depth}")
print(f"Length: {self.length}")
print(f"Type: {self.type}")
print(f"Color Map Type: {self.map_type}")
print(f"Color Map Length: {self.map_length}")
def write(self, new_filepath=None):
if self.magic is None:
raise ValueError("No data to write")
filepath = new_filepath or self.filepath
with open(filepath, 'wb') as f:
header = struct.pack(self.HEADER_FORMAT, self.magic, self.width, self.height, self.depth,
self.length, self.type, self.map_type, self.map_length)
f.write(header)
f.write(self.color_map)
f.write(self.image_data)
# Example usage:
# rs = RSFile('example.rs')
# rs.read()
# rs.print_properties()
# rs.write('modified.rs')
This class reads the file (decodes header, loads map and data), prints properties, and writes back (without modifying data; RLE encoding not implemented for simplicity).
5. Java Class for .RS File Handling
import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
public class RSFile {
private static final int MAGIC = 0x59a66a95;
private static final int HEADER_SIZE = 32;
private String filepath;
private int magic;
private int width;
private int height;
private int depth;
private int length;
private int type;
private int mapType;
private int mapLength;
private byte[] colorMap;
private byte[] imageData;
public RSFile(String filepath) {
this.filepath = filepath;
}
public void read() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filepath, "r")) {
FileChannel channel = raf.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE).order(ByteOrder.BIG_ENDIAN);
channel.read(buffer);
buffer.flip();
magic = buffer.getInt();
if (magic != MAGIC) {
throw new IOException("Invalid magic number");
}
width = buffer.getInt();
height = buffer.getInt();
depth = buffer.getInt();
length = buffer.getInt();
type = buffer.getInt();
mapType = buffer.getInt();
mapLength = buffer.getInt();
colorMap = new byte[mapLength];
buffer = ByteBuffer.allocate(mapLength);
channel.read(buffer);
buffer.flip();
buffer.get(colorMap);
imageData = new byte[length];
buffer = ByteBuffer.allocate(length);
channel.read(buffer);
buffer.flip();
buffer.get(imageData);
}
}
public void printProperties() {
System.out.printf("Magic Number: 0x%08X%n", magic);
System.out.println("Width: " + width);
System.out.println("Height: " + height);
System.out.println("Depth: " + depth);
System.out.println("Length: " + length);
System.out.println("Type: " + type);
System.out.println("Color Map Type: " + mapType);
System.out.println("Color Map Length: " + mapLength);
}
public void write(String newFilepath) throws IOException {
String outPath = (newFilepath != null) ? newFilepath : filepath;
try (RandomAccessFile raf = new RandomAccessFile(outPath, "rw")) {
FileChannel channel = raf.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE).order(ByteOrder.BIG_ENDIAN);
buffer.putInt(magic);
buffer.putInt(width);
buffer.putInt(height);
buffer.putInt(depth);
buffer.putInt(length);
buffer.putInt(type);
buffer.putInt(mapType);
buffer.putInt(mapLength);
buffer.flip();
channel.write(buffer);
buffer = ByteBuffer.wrap(colorMap);
channel.write(buffer);
buffer = ByteBuffer.wrap(imageData);
channel.write(buffer);
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// RSFile rs = new RSFile("example.rs");
// rs.read();
// rs.printProperties();
// rs.write("modified.rs");
// }
}
6. JavaScript Class for .RS File Handling
class RSFile {
constructor(filepath) {
this.filepath = filepath; // Note: In browser, use File object; here assuming Node.js for fs
this.magic = null;
this.width = null;
this.height = null;
this.depth = null;
this.length = null;
this.type = null;
this.mapType = null;
this.mapLength = null;
this.colorMap = null;
this.imageData = null;
}
async read() {
const fs = require('fs/promises');
const buffer = await fs.readFile(this.filepath);
const view = new DataView(buffer.buffer);
if (buffer.length < 32) {
throw new Error('File too small for header');
}
this.magic = view.getUint32(0, false); // Big-endian
if (this.magic !== 0x59a66a95) {
throw new Error('Invalid magic number');
}
this.width = view.getUint32(4, false);
this.height = view.getUint32(8, false);
this.depth = view.getUint32(12, false);
this.length = view.getUint32(16, false);
this.type = view.getUint32(20, false);
this.mapType = view.getUint32(24, false);
this.mapLength = view.getUint32(28, false);
this.colorMap = buffer.slice(32, 32 + this.mapLength);
this.imageData = buffer.slice(32 + this.mapLength, 32 + this.mapLength + this.length);
}
printProperties() {
if (this.magic === null) {
throw new Error('File not read yet');
}
console.log(`Magic Number: 0x${this.magic.toString(16)}`);
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(`Color Map Type: ${this.mapType}`);
console.log(`Color Map Length: ${this.mapLength}`);
}
async write(newFilepath = this.filepath) {
const fs = require('fs/promises');
const header = new ArrayBuffer(32);
const view = new DataView(header);
view.setUint32(0, this.magic, false);
view.setUint32(4, this.width, false);
view.setUint32(8, this.height, false);
view.setUint32(12, this.depth, false);
view.setUint32(16, this.length, false);
view.setUint32(20, this.type, false);
view.setUint32(24, this.mapType, false);
view.setUint32(28, this.mapLength, false);
const fullBuffer = Buffer.concat([Buffer.from(header), this.colorMap, this.imageData]);
await fs.writeFile(newFilepath, fullBuffer);
}
}
// Example usage (Node.js):
// const rs = new RSFile('example.rs');
// await rs.read();
// rs.printProperties();
// await rs.write('modified.rs');
(Note: This assumes Node.js for file I/O; for browser, adapt with FileReader similar to the drag-drop script.)
7. C "Class" (Struct and Functions) for .RS File Handling
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <arpa/inet.h> // For htonl/ntohl (big-endian conversion)
#define MAGIC 0x59a66a95
#define HEADER_SIZE 32
typedef struct {
uint32_t magic;
uint32_t width;
uint32_t height;
uint32_t depth;
uint32_t length;
uint32_t type;
uint32_t map_type;
uint32_t map_length;
uint8_t *color_map;
uint8_t *image_data;
} RSFile;
RSFile* rsfile_create(const char *filepath) {
RSFile *rs = malloc(sizeof(RSFile));
if (rs == NULL) return NULL;
rs->color_map = NULL;
rs->image_data = NULL;
// Read immediately or separately; here we leave for read function
return rs;
}
void rsfile_read(RSFile *rs, const char *filepath) {
FILE *f = fopen(filepath, "rb");
if (!f) {
perror("Failed to open file");
return;
}
uint32_t header[8];
if (fread(header, sizeof(uint32_t), 8, f) != 8) {
fprintf(stderr, "File too small for header\n");
fclose(f);
return;
}
// Convert from big-endian
for (int i = 0; i < 8; i++) {
header[i] = ntohl(header[i]);
}
rs->magic = header[0];
if (rs->magic != MAGIC) {
fprintf(stderr, "Invalid magic number\n");
fclose(f);
return;
}
rs->width = header[1];
rs->height = header[2];
rs->depth = header[3];
rs->length = header[4];
rs->type = header[5];
rs->map_type = header[6];
rs->map_length = header[7];
rs->color_map = malloc(rs->map_length);
if (rs->color_map && fread(rs->color_map, 1, rs->map_length, f) != rs->map_length) {
free(rs->color_map);
rs->color_map = NULL;
}
rs->image_data = malloc(rs->length);
if (rs->image_data && fread(rs->image_data, 1, rs->length, f) != rs->length) {
free(rs->image_data);
rs->image_data = NULL;
}
fclose(f);
}
void rsfile_print_properties(const RSFile *rs) {
if (rs->magic == 0) {
fprintf(stderr, "File not read yet\n");
return;
}
printf("Magic Number: 0x%08x\n", rs->magic);
printf("Width: %u\n", rs->width);
printf("Height: %u\n", rs->height);
printf("Depth: %u\n", rs->depth);
printf("Length: %u\n", rs->length);
printf("Type: %u\n", rs->type);
printf("Color Map Type: %u\n", rs->map_type);
printf("Color Map Length: %u\n", rs->map_length);
}
void rsfile_write(const RSFile *rs, const char *new_filepath) {
if (rs->magic == 0) {
fprintf(stderr, "No data to write\n");
return;
}
FILE *f = fopen(new_filepath, "wb");
if (!f) {
perror("Failed to open file for writing");
return;
}
uint32_t header[8] = {
htonl(rs->magic), htonl(rs->width), htonl(rs->height), htonl(rs->depth),
htonl(rs->length), htonl(rs->type), htonl(rs->map_type), htonl(rs->map_length)
};
fwrite(header, sizeof(uint32_t), 8, f);
if (rs->color_map) fwrite(rs->color_map, 1, rs->map_length, f);
if (rs->image_data) fwrite(rs->image_data, 1, rs->length, f);
fclose(f);
}
void rsfile_destroy(RSFile *rs) {
free(rs->color_map);
free(rs->image_data);
free(rs);
}
// Example usage:
// int main() {
// RSFile *rs = rsfile_create("example.rs");
// rsfile_read(rs, "example.rs");
// rsfile_print_properties(rs);
// rsfile_write(rs, "modified.rs");
// rsfile_destroy(rs);
// return 0;
// }