Skip to content

Commit 68533b5

Browse files
committed
add support for header skip option to adjust planar data offset
1 parent 743d9a2 commit 68533b5

3 files changed

Lines changed: 22 additions & 6 deletions

File tree

AmigaRawImageConverter/Options.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ internal class Options
2222
HelpText = "Require palette footer; if false, use grayscale palette and treat all bytes as planar data.")]
2323
public bool RequirePalette { get; set; }
2424

25+
[Option("header-skip", Default = 0,
26+
HelpText = "Number of bytes to skip at the start of the file before reading planar data.")]
27+
public int HeaderSkip { get; set; }
28+
2529
[Option("min-planes", Default = 3, HelpText = "Minimum bitplane count to evaluate when guessing geometry.")]
2630
public int MinPlanes { get; set; }
2731

AmigaRawImageConverter/Program.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,23 +68,34 @@ private static int Run(Options opts)
6868
private static void ConvertOne(string inputPath, string outputPath, Options opts)
6969
{
7070
var raw = File.ReadAllBytes(inputPath);
71+
if (opts.HeaderSkip < 0)
72+
{
73+
throw new InvalidOperationException("Header skip cannot be negative.");
74+
}
75+
76+
if (opts.HeaderSkip > raw.Length)
77+
{
78+
throw new InvalidOperationException("Header skip exceeds file size.");
79+
}
80+
81+
var data = raw.AsSpan(opts.HeaderSkip);
7182
ReadOnlySpan<byte> planar;
7283
Rgba32[] palette;
7384

7485
if (opts.RequirePalette)
7586
{
76-
if (raw.Length < PaletteLength)
87+
if (data.Length < PaletteLength)
7788
{
7889
throw new InvalidOperationException("File too small to contain palette.");
7990
}
8091

81-
var paletteTail = raw.AsSpan(raw.Length - PaletteLength, PaletteLength);
92+
var paletteTail = data.Slice(data.Length - PaletteLength, PaletteLength);
8293
palette = DecodePalette(paletteTail);
83-
planar = raw.AsSpan(0, raw.Length - PaletteLength);
94+
planar = data[..^PaletteLength];
8495
}
8596
else
8697
{
87-
planar = raw;
98+
planar = data;
8899
var maxPlanes = Math.Max(opts.MinPlanes, opts.MaxPlanes);
89100
var paletteSize = 1 << Math.Max(1, maxPlanes);
90101
palette = BuildGrayscalePalette(paletteSize);

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Candidate PNGs are written under the chosen output directory with names based on
5252
- `-n`, `--max-candidates` (default: 5): How many best geometry candidates to emit per file.
5353
- `-p`, `--raw-file-pattern` (default: `*.raw`): Filename pattern to match for RAW files when input is a directory.
5454
- `--require-palette` (default: true): If true, expect a palette footer; if false, use all bytes as planar data and generate a grayscale palette.
55+
- `--header-skip` (default: 0): Number of bytes to skip at the start of the file before reading planar data.
5556
- `--min-planes` (default: 3): Minimum bitplane count to evaluate when guessing geometry.
5657
- `--max-planes` (default: 6): Maximum bitplane count to evaluate when guessing geometry.
5758
- `--min-width` (default: 64): Minimum image width (pixels) to evaluate when guessing geometry.
@@ -61,7 +62,7 @@ Candidate PNGs are written under the chosen output directory with names based on
6162
- `--width-increment` (default: 16): Step (pixels) between tested widths when scanning candidates.
6263

6364
## Notes on geometry detection
64-
- Defaults to scanning 3–6 bitplanes (common Amiga modes); plane counts that need more palette entries than are present are skipped. With `--require-palette false`, a grayscale palette sized to the maximum plane count is generated.
65+
- Defaults to scanning 3–6 bitplanes (common Amiga modes); plane counts that need more palette entries than are present are skipped. With `--require-palette false`, a grayscale palette sized to the maximum plane count is generated. `--header-skip` is applied before reading planar data or palettes.
6566
- By default scans widths from 64 to 640 pixels in steps of 16 (`--min-width`, `--max-width`, `--width-increment`).
6667
- Width must be divisible by 8 and exactly consume the planar data (given height and plane count) or the candidate is skipped.
6768
- Scores candidates by row smoothness (mean + stddev of row deltas); lower is better.
@@ -72,7 +73,7 @@ The last 32 bytes are 16 big-endian words, layout `0RRR GGGG BBBB` (4 bits/chann
7273
each channel is scaled to 0–255 for PNG output.
7374

7475
## Limitations & gotchas
75-
- When `--require-palette` is true, expects the palette to be the final 32 bytes; extra non-planar data at the end will confuse detection.
76+
- When `--require-palette` is true, expects the palette to be the final 32 bytes (after honoring `--header-skip`); extra non-planar data at the end will confuse detection.
7677
- With autogenerated grayscale palette, bitplane counts requiring more colors than the generated palette size (based on max planes) are ignored.
7778
- Width/height search ranges are controlled via CLI options; exotic sizes outside the search window will not be considered.
7879
- Smoothness scoring can still pick a wrong candidate for very noisy or synthetic images—inspect the outputs.

0 commit comments

Comments
 (0)