Gadfly on #103:
- (4 models) applyOrientation allocated a WxH RGBA then threw it away for a
quarter-turn to allocate HxW. Compute the output dims once, allocate one
buffer.
- (perf) The At/Set loop boxed a color.Color per pixel — millions of heap
allocs on a full-res rotation. Convert to *image.RGBA once (draw.Draw)
then copy 4 bytes per pixel by offset. No boxing.
- (2 findings) exifOrientation didn't skip 0xFF fill bytes before a marker,
so a spec-valid padded APP1 would be misread. Skip them.
- (2 findings) orientationFromApp1 read the tag's inline value without
checking its type/count — a mistyped LONG/offset would be read as a
bogus SHORT. Require type=SHORT, count=1; also validate the TIFF 0x2A
magic agrees with the byte order.
- Tests now cover all 8 orientations (added the mirror/transpose cases
2/4/5/7, the most error-prone switch arms) as t.Run subtests.
All imagenorm tests green; gofmt clean; still CGO_ENABLED=0.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
imagenorm decoded and re-encoded to JPEG but ignored the EXIF Orientation
tag. Phone cameras store the sensor pixels one way and set an EXIF flag to
rotate on display, so a "portrait" JPEG is really a landscape bitmap tagged
"rotate 90°" — and our re-encode strips EXIF, so without baking the rotation
in, a packet photographed in portrait reaches the vision model sideways
(bad OCR) and any future thumbnail is wrong.
- exifOrientation: a small pure-Go parser that walks the JPEG APP1/Exif
segment for tag 0x0112, returning 1 (normal) for non-JPEG or unparseable
input — never guess a rotation onto a correct image. No cgo, no new dep.
- applyOrientation: bakes in all 8 orientations (the 4 rotations + mirrors)
after downscale (cheaper to rotate the small image; a 90° turn swaps the
sides but not the longest edge, so the downscale bound still holds).
- Non-JPEG paths (HEIC/webp/png) are untouched — their decoders own
orientation and they carry no JPEG EXIF.
Tests build oriented JPEGs (a corner marker + a spliced Exif APP1) and
assert the marker lands where each orientation says, dims swapping for the
quarter-turns; plus parser defaults for non-JPEG / no-EXIF / garbage.
Stays CGO_ENABLED=0.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ