FAILURE MAP
← Case archive

FA-79056 / Image orientation metadata / Open access

Lossless rotate trims 4:2:2 images along the wrong MCU axis · case 01

Rotated 4:2:2 JPEGs lose the wrong number of edge pixels or keep a partial block that shifts the image.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The 4:2:2 MCU is recorded as 8 wide by 16 high, but horizontal chroma subsampling makes it 16 wide by 8 high.

VERIFIED REPAIR

Use a 16x8 MCU for 4:2:2.

Unsuccessful approach: A 16x16 MCU over-trims the height of 4:2:2 images.

Case contract

Input [w, h, tag, sampling]. A lossless JPEG transform that bakes the orientation can only move whole MCUs (444: 8x8, 422: 16 wide x 8 high, 420: 16x16, 440: 8 wide x 16 high), so any partial MCU column or row that would move to the leading edge is trimmed. The tag decomposes into stored-space flips (fx, fy) followed by an optional transpose; fx trims the width and fy trims the height to a multiple of the MCU size. Invalid tags are treated as 1. Return the displayed [width, height], "refuse" when a trimmed side becomes 0, or "unknown-sampling".

Why this case matters

Camera, phone and scanner images carry an orientation hint separately from the stored pixels; galleries, thumbnailers, editors and upload pipelines must interpret it consistently or photos appear sideways, mirrored or doubly rotated.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    w, h, tag, sampling = x
    mcu = {'444': (8, 8), '422': (8, 16), '420': (16, 16), '440': (8, 16)}
    if sampling not in mcu:
        return 'unknown-sampling'
    mw, mh = mcu[sampling]
    flips = {1: (0, 0, 0), 2: (1, 0, 0), 3: (1, 1, 0), 4: (0, 1, 0), 5: (0, 0, 1), 6: (0, 1, 1), 7: (1, 1, 1), 8: (1, 0, 1)}
    fx, fy, tr = flips.get(tag, (0, 0, 0))
    tw = w - w % mw if fx else w
    th = h - h % mh if fy else h
    if tw == 0 or th == 0:
        return 'refuse'
    if tr:
        tw, th = th, tw
    return [tw, th]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[8, 24, 3, '422'], 'refuse'], [[22, 12, 7, '422'], [8, 16]], [[81, 1275, 6, '422'], [1272, 81]], [[24, 12, 0, '440'], [24, 12]], [[2969, 96, 1, '422'], [2969, 96]], [[24, 16, 5, '422'], [16, 24]], [[40, 2600, 0, '440'], [40, 2600]], [[12, 8, 8, '422'], 'refuse']], [[[12, 8, 6, '422'], [8, 12]], [[86, 2621, 4, '422'], [86, 2616]], [[25, 40, 4, '422'], [25, 40]], [[12, 1946, 4, '420'], [12, 1936]], [[8, 12, 1, '411'], 'unknown-sampling'], [[25, 8, 8, '420'], [8, 16]], [[24, 24, 2, '440'], [24, 24]], [[12, 24, 8, '422'], 'refuse']], [[[8, 8, 8, '422'], 'refuse'], [[16, 24, 7, '422'], [24, 16]], [[36, 24, 3, '422'], [32, 24]], [[24, 8, 4, '444'], [24, 8]], [[12, 12, 3, '420'], 'refuse'], [[24, 24, 0, '420'], [24, 24]], [[8, 20, 6, '420'], [16, 8]], [[24, 12, 6, '422'], [8, 24]]], [[[8, 60, 6, '422'], [56, 8]], [[40, 8, 3, '422'], [32, 8]], [[2427, 12, 6, '422'], [8, 2427]], [[24, 12, 6, '420'], 'refuse'], [[40, 8, 5, '440'], [8, 40]], [[16, 272, 4, '422'], [16, 272]], [[24, 16, 6, '440'], [16, 24]], [[61, 12, 2, '422'], [48, 12]]], [[[8, 16, 8, '422'], 'refuse'], [[24, 12, 7, '422'], [8, 16]], [[12, 8, 6, '422'], [8, 12]], [[8, 67, 7, '444'], [64, 8]], [[16, 24, 2, '411'], 'unknown-sampling'], [[40, 18, 1, '420'], [40, 18]], [[79, 24, 7, '440'], [16, 72]], [[24, 8, 6, '422'], [8, 24]]]]
labels = ["regression: 4:2:2 MCU geometry", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("%s %d" % (labels[i % len(labels)], i), solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: 4:2:2 MCU geometry 0[8, 16]refuseFailed
repair trap 1refuse[8, 16]Failed
combined fault 2[1264, 81][1272, 81]Failed
control 3[24, 12][24, 12]Passed
control 4[2969, 96][2969, 96]Passed
boundary 5[16, 24][16, 24]Passed
boundary 6[40, 2600][40, 2600]Passed
control 7[8, 8]refuseFailed

SHA-256 / bc9c2adf4e39d74372f64a18254acb6e09c6045c2151669566d046df7be56543

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    w, h, tag, sampling = x
    mcu = {'444': (8, 8), '422': (16, 16), '420': (16, 16), '440': (8, 16)}
    if sampling not in mcu:
        return 'unknown-sampling'
    mw, mh = mcu[sampling]
    flips = {1: (0, 0, 0), 2: (1, 0, 0), 3: (1, 1, 0), 4: (0, 1, 0), 5: (0, 0, 1), 6: (0, 1, 1), 7: (1, 1, 1), 8: (1, 0, 1)}
    fx, fy, tr = flips.get(tag, (0, 0, 0))
    tw = w - w % mw if fx else w
    th = h - h % mh if fy else h
    if tw == 0 or th == 0:
        return 'refuse'
    if tr:
        tw, th = th, tw
    return [tw, th]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[8, 24, 3, '422'], 'refuse'], [[22, 12, 7, '422'], [8, 16]], [[81, 1275, 6, '422'], [1272, 81]], [[24, 12, 0, '440'], [24, 12]], [[2969, 96, 1, '422'], [2969, 96]], [[24, 16, 5, '422'], [16, 24]], [[40, 2600, 0, '440'], [40, 2600]], [[12, 8, 8, '422'], 'refuse']], [[[12, 8, 6, '422'], [8, 12]], [[86, 2621, 4, '422'], [86, 2616]], [[25, 40, 4, '422'], [25, 40]], [[12, 1946, 4, '420'], [12, 1936]], [[8, 12, 1, '411'], 'unknown-sampling'], [[25, 8, 8, '420'], [8, 16]], [[24, 24, 2, '440'], [24, 24]], [[12, 24, 8, '422'], 'refuse']], [[[8, 8, 8, '422'], 'refuse'], [[16, 24, 7, '422'], [24, 16]], [[36, 24, 3, '422'], [32, 24]], [[24, 8, 4, '444'], [24, 8]], [[12, 12, 3, '420'], 'refuse'], [[24, 24, 0, '420'], [24, 24]], [[8, 20, 6, '420'], [16, 8]], [[24, 12, 6, '422'], [8, 24]]], [[[8, 60, 6, '422'], [56, 8]], [[40, 8, 3, '422'], [32, 8]], [[2427, 12, 6, '422'], [8, 2427]], [[24, 12, 6, '420'], 'refuse'], [[40, 8, 5, '440'], [8, 40]], [[16, 272, 4, '422'], [16, 272]], [[24, 16, 6, '440'], [16, 24]], [[61, 12, 2, '422'], [48, 12]]], [[[8, 16, 8, '422'], 'refuse'], [[24, 12, 7, '422'], [8, 16]], [[12, 8, 6, '422'], [8, 12]], [[8, 67, 7, '444'], [64, 8]], [[16, 24, 2, '411'], 'unknown-sampling'], [[40, 18, 1, '420'], [40, 18]], [[79, 24, 7, '440'], [16, 72]], [[24, 8, 6, '422'], [8, 24]]]]
labels = ["regression: 4:2:2 MCU geometry", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("%s %d" % (labels[i % len(labels)], i), solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: 4:2:2 MCU geometry 0refuserefusePassed
repair trap 1refuse[8, 16]Failed
combined fault 2[1264, 81][1272, 81]Failed
control 3[24, 12][24, 12]Passed
control 4[2969, 96][2969, 96]Passed
boundary 5[16, 24][16, 24]Passed
boundary 6[40, 2600][40, 2600]Passed
control 7refuserefusePassed

SHA-256 / 1ed0167d5623b57c3947eb41924ba304b3ec31c9a1ba3cf2213d2fde8b423334

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    w, h, tag, sampling = x
    mcu = {'444': (8, 8), '422': (16, 8), '420': (16, 16), '440': (8, 16)}
    if sampling not in mcu:
        return 'unknown-sampling'
    mw, mh = mcu[sampling]
    flips = {1: (0, 0, 0), 2: (1, 0, 0), 3: (1, 1, 0), 4: (0, 1, 0), 5: (0, 0, 1), 6: (0, 1, 1), 7: (1, 1, 1), 8: (1, 0, 1)}
    fx, fy, tr = flips.get(tag, (0, 0, 0))
    tw = w - w % mw if fx else w
    th = h - h % mh if fy else h
    if tw == 0 or th == 0:
        return 'refuse'
    if tr:
        tw, th = th, tw
    return [tw, th]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[8, 24, 3, '422'], 'refuse'], [[22, 12, 7, '422'], [8, 16]], [[81, 1275, 6, '422'], [1272, 81]], [[24, 12, 0, '440'], [24, 12]], [[2969, 96, 1, '422'], [2969, 96]], [[24, 16, 5, '422'], [16, 24]], [[40, 2600, 0, '440'], [40, 2600]], [[12, 8, 8, '422'], 'refuse']], [[[12, 8, 6, '422'], [8, 12]], [[86, 2621, 4, '422'], [86, 2616]], [[25, 40, 4, '422'], [25, 40]], [[12, 1946, 4, '420'], [12, 1936]], [[8, 12, 1, '411'], 'unknown-sampling'], [[25, 8, 8, '420'], [8, 16]], [[24, 24, 2, '440'], [24, 24]], [[12, 24, 8, '422'], 'refuse']], [[[8, 8, 8, '422'], 'refuse'], [[16, 24, 7, '422'], [24, 16]], [[36, 24, 3, '422'], [32, 24]], [[24, 8, 4, '444'], [24, 8]], [[12, 12, 3, '420'], 'refuse'], [[24, 24, 0, '420'], [24, 24]], [[8, 20, 6, '420'], [16, 8]], [[24, 12, 6, '422'], [8, 24]]], [[[8, 60, 6, '422'], [56, 8]], [[40, 8, 3, '422'], [32, 8]], [[2427, 12, 6, '422'], [8, 2427]], [[24, 12, 6, '420'], 'refuse'], [[40, 8, 5, '440'], [8, 40]], [[16, 272, 4, '422'], [16, 272]], [[24, 16, 6, '440'], [16, 24]], [[61, 12, 2, '422'], [48, 12]]], [[[8, 16, 8, '422'], 'refuse'], [[24, 12, 7, '422'], [8, 16]], [[12, 8, 6, '422'], [8, 12]], [[8, 67, 7, '444'], [64, 8]], [[16, 24, 2, '411'], 'unknown-sampling'], [[40, 18, 1, '420'], [40, 18]], [[79, 24, 7, '440'], [16, 72]], [[24, 8, 6, '422'], [8, 24]]]]
labels = ["regression: 4:2:2 MCU geometry", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("%s %d" % (labels[i % len(labels)], i), solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: 4:2:2 MCU geometry 0refuserefusePassed
repair trap 1[8, 16][8, 16]Passed
combined fault 2[1272, 81][1272, 81]Passed
control 3[24, 12][24, 12]Passed
control 4[2969, 96][2969, 96]Passed
boundary 5[16, 24][16, 24]Passed
boundary 6[40, 2600][40, 2600]Passed
control 7refuserefusePassed

SHA-256 / 30813bba52f6d0c008ef35fde62c0947b4e6a3dfe45ebe6418a3539a6f9ba7cd

Verification & scope

A deterministic bounded teaching model with a stipulated contract; it makes no claim of conformance to any published specification. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:49:41.126025+00:00.

Case digest / 36c236c5ce38724d5df626d1d7a2aad548734a202b7f1327c934f02efd99b569