Task 578: .PSPPALETTE File Format
Task 578: .PSPPALETTE File Format
.PSPPALETTE File Format Specifications
The .PSPPALETTE file format is used by PaintShop Pro (now by Corel) for storing color palettes. It is essentially the JASC-PAL format, named after Jasc Software, the original developer of PaintShop Pro. The file is a plain text file with Windows line endings (\r\n), containing a header, version, color count, and RGB color values.
1. List of All Properties Intrinsic to This File Format
- Signature: The string "JASC-PAL" (first line).
- Version: The string "0100" (second line, indicating version 1.00).
- Number of Colors: An integer representing the number of colors in the palette (third line, typically 16 or 256, but can be any positive integer).
- Color Entries: A list of RGB triples, one per line starting from the fourth line, with each color specified as three space-separated integers (0-255) in the format "R G B". There are exactly as many entries as specified in the number of colors.
2. Two Direct Download Links for .PSPPALETTE Files
- https://raw.githubusercontent.com/Mailaender/ArtSrc/f3e8d2f33a34e1ce3258b3b8dd21543acd72a2d4/ra/palettes/PaintShopPro.pal (Note: This is a .pal file, but it uses the identical JASC-PAL format as .PSPPALETTE; the extension is interchangeable in practice.)
- https://lospec.com/palette-list/playpal.pal (Another sample in JASC-PAL format, downloadable directly.)
3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop File Dump
Here's a self-contained HTML snippet with JavaScript that can be embedded in a Ghost blog (or any HTML page). It allows dragging and dropping a .PSPPALETTE file (or .pal) and dumps the properties to the screen.
Drag and drop a .PSPPALETTE file here
4. Python Class for .PSPPALETTE Files
import sys
class PspPalette:
def __init__(self, filename=None):
self.signature = "JASC-PAL"
self.version = "0100"
self.num_colors = 0
self.colors = [] # list of (r, g, b) tuples
if filename:
self.read(filename)
def read(self, filename):
with open(filename, 'r') as f:
lines = f.readlines()
if len(lines) < 3:
raise ValueError("Invalid .PSPPALETTE file")
self.signature = lines[0].strip()
self.version = lines[1].strip()
try:
self.num_colors = int(lines[2].strip())
except ValueError:
raise ValueError("Invalid number of colors")
self.colors = []
for line in lines[3:3 + self.num_colors]:
parts = line.strip().split()
if len(parts) != 3:
raise ValueError("Invalid color entry")
self.colors.append(tuple(map(int, parts)))
def write(self, filename):
with open(filename, 'w') as f:
f.write(f"{self.signature}\r\n")
f.write(f"{self.version}\r\n")
f.write(f"{self.num_colors}\r\n")
for r, g, b in self.colors:
f.write(f"{r} {g} {b}\r\n")
def print_properties(self):
print(f"Signature: {self.signature}")
print(f"Version: {self.version}")
print(f"Number of Colors: {self.num_colors}")
print("Colors:")
for color in self.colors:
print(color)
# Example usage:
if __name__ == "__main__":
if len(sys.argv) > 1:
pal = PspPalette(sys.argv[1])
pal.print_properties()
5. Java Class for .PSPPALETTE Files
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class PspPalette {
private String signature = "JASC-PAL";
private String version = "0100";
private int numColors = 0;
private List<int[]> colors = new ArrayList<>(); // each int[3] is {r, g, b}
public PspPalette(String filename) throws IOException {
read(filename);
}
public PspPalette() {}
public void read(String filename) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line = reader.readLine();
if (line == null) throw new IOException("Invalid file");
signature = line.trim();
line = reader.readLine();
if (line == null) throw new IOException("Invalid file");
version = line.trim();
line = reader.readLine();
if (line == null) throw new IOException("Invalid file");
numColors = Integer.parseInt(line.trim());
colors.clear();
for (int i = 0; i < numColors; i++) {
line = reader.readLine();
if (line == null) throw new IOException("Incomplete colors");
String[] parts = line.trim().split("\\s+");
if (parts.length != 3) throw new IOException("Invalid color");
int[] rgb = {Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2])};
colors.add(rgb);
}
}
}
public void write(String filename) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
writer.write(signature + "\r\n");
writer.write(version + "\r\n");
writer.write(numColors + "\r\n");
for (int[] rgb : colors) {
writer.write(rgb[0] + " " + rgb[1] + " " + rgb[2] + "\r\n");
}
}
}
public void printProperties() {
System.out.println("Signature: " + signature);
System.out.println("Version: " + version);
System.out.println("Number of Colors: " + numColors);
System.out.println("Colors:");
for (int[] rgb : colors) {
System.out.println("(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ")");
}
}
public static void main(String[] args) throws IOException {
if (args.length > 0) {
PspPalette pal = new PspPalette(args[0]);
pal.printProperties();
}
}
}
6. JavaScript Class for .PSPPALETTE Files
class PspPalette {
constructor(filename = null) {
this.signature = 'JASC-PAL';
this.version = '0100';
this.numColors = 0;
this.colors = []; // array of [r, g, b]
if (filename) {
this.read(filename);
}
}
async read(filename) {
const response = await fetch(filename);
if (!response.ok) throw new Error('Failed to read file');
const text = await response.text();
const lines = text.split(/\r?\n/).filter(line => line.trim() !== '');
if (lines.length < 3) throw new Error('Invalid file');
this.signature = lines[0].trim();
this.version = lines[1].trim();
this.numColors = parseInt(lines[2].trim(), 10);
this.colors = [];
for (let i = 3; i < 3 + this.numColors; i++) {
const parts = lines[i].trim().split(/\s+/).map(Number);
if (parts.length !== 3) throw new Error('Invalid color');
this.colors.push(parts);
}
}
write() {
// For browser, this returns a Blob for download
let content = `${this.signature}\r\n${this.version}\r\n${this.numColors}\r\n`;
this.colors.forEach(([r, g, b]) => {
content += `${r} ${g} ${b}\r\n`;
});
const blob = new Blob([content], { type: 'text/plain' });
return blob; // Use URL.createObjectURL(blob) to download
}
printProperties() {
console.log(`Signature: ${this.signature}`);
console.log(`Version: ${this.version}`);
console.log(`Number of Colors: ${this.numColors}`);
console.log('Colors:', this.colors);
}
}
// Example usage (in browser console or Node with fs/promises):
// const pal = new PspPalette('example.pal');
// await pal.read('example.pal');
// pal.printProperties();
7. C "Class" (Struct with Functions) for .PSPPALETTE Files
Since C does not have classes, here's a struct with associated functions for reading, writing, and printing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *signature;
char *version;
int num_colors;
int (*colors)[3]; // array of [r, g, b]
} PspPalette;
PspPalette* psp_palette_new() {
PspPalette* pal = malloc(sizeof(PspPalette));
pal->signature = strdup("JASC-PAL");
pal->version = strdup("0100");
pal->num_colors = 0;
pal->colors = NULL;
return pal;
}
void psp_palette_free(PspPalette* pal) {
free(pal->signature);
free(pal->version);
free(pal->colors);
free(pal);
}
int psp_palette_read(PspPalette* pal, const char* filename) {
FILE* f = fopen(filename, "r");
if (!f) return -1;
char line[256];
if (!fgets(line, sizeof(line), f)) goto error;
pal->signature = strdup(strtok(line, "\r\n"));
if (!fgets(line, sizeof(line), f)) goto error;
pal->version = strdup(strtok(line, "\r\n"));
if (!fgets(line, sizeof(line), f)) goto error;
pal->num_colors = atoi(line);
pal->colors = malloc(pal->num_colors * sizeof(int[3]));
for (int i = 0; i < pal->num_colors; i++) {
if (!fgets(line, sizeof(line), f)) goto error;
sscanf(line, "%d %d %d", &pal->colors[i][0], &pal->colors[i][1], &pal->colors[i][2]);
}
fclose(f);
return 0;
error:
fclose(f);
return -1;
}
int psp_palette_write(PspPalette* pal, const char* filename) {
FILE* f = fopen(filename, "w");
if (!f) return -1;
fprintf(f, "%s\r\n", pal->signature);
fprintf(f, "%s\r\n", pal->version);
fprintf(f, "%d\r\n", pal->num_colors);
for (int i = 0; i < pal->num_colors; i++) {
fprintf(f, "%d %d %d\r\n", pal->colors[i][0], pal->colors[i][1], pal->colors[i][2]);
}
fclose(f);
return 0;
}
void psp_palette_print_properties(PspPalette* pal) {
printf("Signature: %s\n", pal->signature);
printf("Version: %s\n", pal->version);
printf("Number of Colors: %d\n", pal->num_colors);
printf("Colors:\n");
for (int i = 0; i < pal->num_colors; i++) {
printf("(%d, %d, %d)\n", pal->colors[i][0], pal->colors[i][1], pal->colors[i][2]);
}
}
int main(int argc, char** argv) {
if (argc > 1) {
PspPalette* pal = psp_palette_new();
if (psp_palette_read(pal, argv[1]) == 0) {
psp_palette_print_properties(pal);
} else {
printf("Error reading file\n");
}
psp_palette_free(pal);
}
return 0;
}