Add Gjallar bitmap family verifier
This commit is contained in:
parent
b5c60a0522
commit
564b25957d
3 changed files with 132 additions and 9 deletions
|
|
@ -87,11 +87,21 @@ and Ubuntu Sans; those are not substitutes for Gjallar's raster cell fonts.
|
|||
For any scale Gjallar claims as Japanese-capable, the font must provide Latin,
|
||||
hiragana, and katakana in the same fixed cell grid. The target ladder is:
|
||||
|
||||
- display: roughly 16px or larger;
|
||||
- body: roughly 12px;
|
||||
- small: roughly 10px.
|
||||
- display: 16x16;
|
||||
- body: 14x14;
|
||||
- small: 12x12.
|
||||
|
||||
`PsfFont` reads Unicode-mapped PSF fonts and `FontAtlas` prefers
|
||||
kana-capable faces when hiragana or katakana appears in panel titles or body text. The
|
||||
asset line is still explicit: package or generate approved Unicode raster
|
||||
atlases for the 16/12/10 ladder before claiming full Japanese pixel parity.
|
||||
`PsfFont` reads Unicode-mapped PSF fonts and `FontAtlas` selects from the
|
||||
packaged Shinonome bitmap family. Default startup now treats that family as a
|
||||
hard contract: if any required raster is missing, mis-sized, or missing kana,
|
||||
Gjallar fails loudly instead of falling back to random system console fonts.
|
||||
|
||||
The repo-native verification path is:
|
||||
|
||||
- `tools/verify_bitmap_family.ps1`
|
||||
|
||||
That verifier builds Gjallar, runs specimen mode against a temp framebuffer, and
|
||||
proves the shipped 12/14/16 family loads with zero missing glyphs for a mixed
|
||||
Latin/hiragana/katakana specimen string including `メタめ`. The verifier uses
|
||||
`--specimen-text-file` so UTF-8 specimen content does not depend on shell
|
||||
argument encoding quirks.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ internal sealed record GjallarConfig(
|
|||
IntArg(args, "--height", 0),
|
||||
StringArg(args, "--font", ""),
|
||||
StringArg(args, "--mouse", "/dev/input/mice"),
|
||||
StringArg(args, "--specimen-text", ""));
|
||||
ResolveSpecimenText(args));
|
||||
|
||||
private static string StringArg(IReadOnlyList<string> args, string name, string fallback)
|
||||
{
|
||||
|
|
@ -57,6 +57,17 @@ internal sealed record GjallarConfig(
|
|||
|
||||
private static int IntArg(IReadOnlyList<string> args, string name, int fallback) =>
|
||||
int.TryParse(StringArg(args, name, ""), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value) ? value : fallback;
|
||||
|
||||
private static string ResolveSpecimenText(IReadOnlyList<string> args)
|
||||
{
|
||||
var file = StringArg(args, "--specimen-text-file", "");
|
||||
if (!string.IsNullOrWhiteSpace(file))
|
||||
{
|
||||
return File.ReadAllText(file, Encoding.UTF8);
|
||||
}
|
||||
|
||||
return StringArg(args, "--specimen-text", "");
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GjallarRenderer : IDisposable
|
||||
|
|
|
|||
102
tools/verify_bitmap_family.ps1
Normal file
102
tools/verify_bitmap_family.ps1
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
param(
|
||||
[string] $GjallarRoot = "E:\Projects\Gjallar",
|
||||
[string] $SpecimenText = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($SpecimenText)) {
|
||||
$SpecimenText = "VOID " +
|
||||
[string]([char]0x30E1) + [string]([char]0x30BF) + [string]([char]0x3081) + " " +
|
||||
[string]([char]0x3042) + [string]([char]0x30A2) + " " +
|
||||
[string]([char]0x304B) + [string]([char]0x306A) + " " +
|
||||
[string]([char]0x30AB) + [string]([char]0x30CA)
|
||||
}
|
||||
|
||||
$projectPath = Join-Path $GjallarRoot "src\Gjallar\Gjallar.csproj"
|
||||
$buildDir = Join-Path $GjallarRoot "src\Gjallar\bin\Debug\net10.0"
|
||||
$exePath = Join-Path $buildDir "Gjallar.exe"
|
||||
$scratchDir = Join-Path $GjallarRoot "scratch"
|
||||
$framebufferPath = Join-Path $scratchDir "verify-bitmap-family.fb"
|
||||
$statusPath = Join-Path $scratchDir "verify-bitmap-family.status.json"
|
||||
$frameDumpPath = Join-Path $scratchDir "verify-bitmap-family.ppm"
|
||||
$specimenPath = Join-Path $scratchDir "verify-bitmap-family-specimen.txt"
|
||||
|
||||
dotnet build $projectPath | Out-Host
|
||||
|
||||
if (!(Test-Path $exePath)) {
|
||||
throw "Gjallar executable not found at $exePath"
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $scratchDir | Out-Null
|
||||
[System.IO.File]::WriteAllText($specimenPath, $SpecimenText, [System.Text.Encoding]::UTF8)
|
||||
|
||||
$bufferBytes = 1920 * 1080 * 4
|
||||
$file = [System.IO.File]::Open($framebufferPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::ReadWrite)
|
||||
try {
|
||||
$file.SetLength($bufferBytes)
|
||||
}
|
||||
finally {
|
||||
$file.Dispose()
|
||||
}
|
||||
|
||||
& $exePath `
|
||||
--fb $framebufferPath `
|
||||
--width 1920 `
|
||||
--height 1080 `
|
||||
--frames 1 `
|
||||
--mouse "" `
|
||||
--stats-path $statusPath `
|
||||
--frame-dump-path $frameDumpPath `
|
||||
--specimen-text-file $specimenPath | Out-Host
|
||||
|
||||
if (!(Test-Path $statusPath)) {
|
||||
throw "Gjallar did not write status to $statusPath"
|
||||
}
|
||||
|
||||
$status = Get-Content $statusPath -Raw | ConvertFrom-Json
|
||||
|
||||
if ($status.status -ne "specimen-rendered") {
|
||||
throw "Expected specimen-rendered status, got '$($status.status)'"
|
||||
}
|
||||
|
||||
$expectedFamily = @(
|
||||
@{ width = 12; height = 12 }
|
||||
@{ width = 14; height = 14 }
|
||||
@{ width = 16; height = 16 }
|
||||
)
|
||||
|
||||
$actualFamily = @($status.fonts.loaded | ForEach-Object {
|
||||
[pscustomobject]@{
|
||||
width = [int]$_.width
|
||||
height = [int]$_.height
|
||||
kana = [bool]$_.kana
|
||||
}
|
||||
})
|
||||
|
||||
if ($actualFamily.Count -ne $expectedFamily.Count) {
|
||||
throw "Expected $($expectedFamily.Count) loaded packaged fonts, got $($actualFamily.Count)"
|
||||
}
|
||||
|
||||
for ($i = 0; $i -lt $expectedFamily.Count; $i++) {
|
||||
$expected = $expectedFamily[$i]
|
||||
$actual = $actualFamily[$i]
|
||||
if ($actual.width -ne $expected.width -or $actual.height -ne $expected.height) {
|
||||
throw ("Loaded font mismatch at index {0}: expected {1}x{2}, got {3}x{4}" -f $i, $expected.width, $expected.height, $actual.width, $actual.height)
|
||||
}
|
||||
if (-not $actual.kana) {
|
||||
throw "Loaded font $($actual.width)x$($actual.height) is not kana-capable"
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($entry in @($status.fonts.specimenSupport)) {
|
||||
if ($entry.missing.Count -ne 0) {
|
||||
throw "Font $($entry.width)x$($entry.height) is missing specimen glyphs: $($entry.missing -join ', ')"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Gjallar bitmap family verification passed."
|
||||
Write-Host " specimenText=$SpecimenText"
|
||||
Write-Host " loaded=$((@($actualFamily) | ForEach-Object { ""$($_.width)x$($_.height)"" }) -join ', ')"
|
||||
Write-Host " statusPath=$statusPath"
|
||||
Write-Host " frameDumpPath=$frameDumpPath"
|
||||
Reference in a new issue