Files
ParkingRobot/docs/superpowers/plans/2026-07-23-trap-map-pure-png.md
T

126 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TrapMap Managed PNG Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Remove TrapMap's platform-specific drawing dependency and produce the same bounded 300 DPI PNG with a managed encoder that runs inside Clumsy.
**Architecture:** Keep `TrapMapImageExporter.ExportIfEnabled` and its file-reservation/publication behavior. Replace only the renderer with an internal RGBA raster surface, primitive drawing functions, a compact embedded bitmap font, and `StbImageWriteSharp` for PNG encoding; insert the 300 DPI `pHYs` chunk after encoding.
**Tech Stack:** C# 10, .NET Standard 2.0, `StbImageWriteSharp` 1.16.7, PowerShell contract/PNG parsing tests.
## Global Constraints
- Do not inspect or modify `TrajPlanner`.
- Do not commit or stage any file.
- Do not change grid construction, Painter behavior, movement behavior, switches, output location, naming, 300 DPI, 4 pixels per cell, 4000-pixel edge limit, or 50 MiB limit.
- The only new image package is `StbImageWriteSharp` version 1.16.7; do not add native assets or another graphics package.
- `TrapMapImageExporter` must have no runtime reference to `System.Drawing.Common` or `System.Drawing`.
- Preserve collision-safe temporary-file reservation, encoded-size validation, atomic publication, and contained export failures.
---
### Task 1: Replace System.Drawing rendering with a managed Stb PNG encoder
**Files:**
- Modify: `ClumsyPilot/ClumsyPilot.csproj`
- Modify: `ClumsyPilot/TrapMapImageExporter.cs`
- Modify: `ClumsyPilot/tests/verify_trapmap_image.ps1`
- Modify: `docs/superpowers/specs/2026-07-22-trap-map-image-and-console-design.md`
- Modify: `docs/superpowers/plans/2026-07-22-trap-map-image-and-console.md`
**Interfaces:**
- Preserve: `TrapMapImageExporter.ExportIfEnabled(bool, TrapMapImageExportRequest)` and all public request/result properties and constants.
- Add only private implementation units: `RgbaSurface`, integer drawing helpers, bitmap-font helpers, and `PngWriter`.
- `RenderToTemporaryPng` continues to consume the existing request/dimensions and write to the already exclusively reserved stream.
- [ ] **Step 1: Add dependency-removal and PNG-structure assertions**
Update `verify_trapmap_image.ps1` before production code. Require that:
```powershell
if ($project.PackageReference.Include -contains 'System.Drawing.Common') {
throw 'TrapMap must not depend on System.Drawing.Common.'
}
if ($project.Target.Name -contains 'DeployFrameworkDrawingRuntime') {
throw 'Legacy drawing-runtime deployment target remains.'
}
if (-not ($project.PackageReference | Where-Object {
$_.Include -eq 'StbImageWriteSharp' -and $_.Version -eq '1.16.7'
})) { throw 'Exact managed PNG package is missing.' }
if ($exporterSource -match 'System\.Drawing|\bBitmap\b|\bGraphics\b|ImageFormat') {
throw 'Exporter still uses the external drawing API.'
}
```
Parse the generated PNG without loading a drawing assembly. Verify signature, one `IHDR`, one `pHYs`, one or more `IDAT`, and `IEND`; verify every chunk CRC. Assert `IHDR` width/height and RGBA8 fields and `pHYs` values `11811,11811,1`. Decode representative pixels with a test-only PNG decoder or the Stb package and reuse the existing color/Y-inversion assertions.
Add a clean-output assertion after build:
```powershell
$drawingDll = Join-Path (Split-Path -Parent $AssemblyPath) 'System.Drawing.Common.dll'
if (Test-Path -LiteralPath $drawingDll) {
throw 'System.Drawing.Common.dll must not be deployed for TrapMap.'
}
```
- [ ] **Step 2: Run RED verification**
```powershell
dotnet build ClumsyPilot\ClumsyPilot.csproj --no-restore -v:minimal
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_image.ps1
```
Expected: the image test fails because the package, deployment target, `using System.Drawing`, and renderer still exist.
- [ ] **Step 3: Remove the drawing package and deployment target**
Delete the `System.Drawing.Common` `PackageReference` and the entire `DeployFrameworkDrawingRuntime` target. Add `<PackageReference Include="StbImageWriteSharp" Version="1.16.7" />`. Do not change the target framework or other references. Ensure a clean build cannot retain the old DLL: the verification command must remove only `ClumsyPilot/bin/Debug/netstandard2.0/System.Drawing.Common.dll` before rebuilding, after resolving and validating that exact path is under the project output directory.
- [ ] **Step 4: Implement the RGBA raster surface**
Replace drawing types with a private surface backed by `byte[]` in RGBA order. Required primitives and semantics:
```csharp
SetPixel(int x, int y, byte r, byte g, byte b, byte a = 255);
FillRectangle(int x, int y, int width, int height, Color32 color);
DrawLine(int x0, int y0, int x1, int y1, Color32 color, int thickness);
DrawRectangle(int x, int y, int width, int height, Color32 color, int thickness);
DrawCircle(int centerX, int centerY, int radius, Color32 color, int thickness);
FillCircle(int centerX, int centerY, int radius, Color32 color);
FillPolygon(PointD[] points, Color32 color);
```
Clip every primitive to the surface. Use pre-clipped Bresenham lines, scale-normalized scanline polygon filling, and a canvas-clipped bounded circle scan whose work is proportional to visible rows/columns rather than radius. Preserve exact white, red, LightGray `(211,211,211)`, black, blue, and LimeGreen `(0,255,0)` colors. Convert vehicle/workstation world positions using the existing discrete-grid-aligned transform.
- [ ] **Step 5: Implement deterministic bitmap text**
Embed a private 5×7 ASCII glyph table for code points 32126. Draw scaled glyphs using integer pixels; unsupported characters render as `?`. Use a 2× scale for header text and 1× scale for the workstation label. Keep all five header baselines inside `HeaderHeightPixels=140` with fixed non-overlapping line boxes. Continue building the same five metadata lines, including occupancy rate; sanitize only the exported header text, not logs.
- [ ] **Step 6: Encode PNG and add 300 DPI metadata**
Use `StbImageWriteSharp.ImageWriter.WritePng` to encode the RGBA buffer. Then insert:
```text
pHYs: X=11811, Y=11811, unit=1
```
Encode into a temporary `MemoryStream`, validate the PNG signature and first `IHDR` chunk, then copy the signature+IHDR, append the 13-byte `pHYs` chunk, and copy the remaining encoded chunks. Use big-endian integers and standard CRC-32 over `pHYs`+data. Do not close the caller-owned reserved stream before the existing file-size/atomic-move flow finishes.
- [ ] **Step 7: Update documentation and run GREEN verification**
Remove all claims that TrapMap deploys or requires `System.Drawing.Common`; document the pure C# encoder and BCL-only runtime.
Run from a clean output state:
```powershell
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_inputs.ps1
dotnet build ClumsyPilot\ClumsyPilot.csproj --no-restore -v:minimal
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_grid.ps1
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_lifecycle.ps1
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_image.ps1
git diff --check
$staged = git diff --cached --name-only; if ($staged) { throw "Unexpected staged files: $staged" }
```
Expected: build succeeds without a drawing DLL in output; all tests pass; PNG parser reports correct dimensions, CRCs, 300 DPI metadata, RGBA pixels, unique filenames, file size at or below 50 MiB, and no temporary files.