Skip to content

RafDecoder: read the aspect ratio dialed in on the camera - #988

Open
hennikul wants to merge 1 commit into
darktable-org:developfrom
hennikul:fuji-aspect-ratio
Open

hennikul wants to merge 1 commit into
darktable-org:developfrom
hennikul:fuji-aspect-ratio

Conversation

@hennikul

Copy link
Copy Markdown

Supersedes #986, which was closed so the work could be squashed into a single
commit. Same change, plus the two fixes that testing forced out.

AI disclosure

Per AGENTS.md, this change was written with AI assistance (Claude Code
with Claude Opus 5). I have read and reviewed it, it builds clean, and I bear
responsibility for it. I am happy to argue any part of it.

What

Fujifilm bodies with an aspect ratio setting record the choice but leave the
raw data uncropped. Consumers therefore see the full sensor readout and the
framing chosen while shooting is lost, where other raw processors reproduce
it and let the user take it back.

The value is tag 0x0115 in the same Fujifilm proprietary directory that
RafDecoder::getDefaultCrop() already reads 0x0110 and 0x0111 from:

  • FUJI_RAWIMAGEASPECTRATIO = 0x0115 in TiffTag.h, aliasing
    SAMPLESPERPIXEL the same way FUJI_RAWIMAGECROPTOPLEFT aliases MODEL
  • the tag listed among those FiffParser reads as SHORT; left to the
    default UNDEFINED its count is the byte length rather than the number of
    shorts and the entry cannot be read at all
  • ImageMetaData::cameraAspectRatio, an Optional<std::array<int, 2>>
  • read it in RafDecoder::decodeMetaDataInternal(), ignoring it when it
    matches the cropped size, since the tag is written whether or not a ratio
    was picked and reporting a native 3:2 would have consumers crop every raf

Why a ratio and not a rectangle

The box a vendor describes is relative to that vendor's own output area,
which is not the area rawspeed hands out. A consumer given a rectangle would
have to track that difference per vendor; a consumer given a ratio can center
it on whatever it actually received. It is also all there is here: Fujifilm's
RawImageCroppedSize beside this tag stays at the native shape whatever
ratio is selected, so there is no usable rectangle to hand out.

The field is named for the concept rather than for Fujifilm, so the other
decoders can fill it as and when someone does that work.

Testing

CC0 samples from raw.pixls.us, consumed end to end through darktable:

Sample Shot at Result
X-T200 DSCF0074.RAF 16:9 reports {16, 9}, exports 16:9
X100V DSCF0734.RAF native 3:2 reports nothing, exports full frame

The X100V pair also settles the byte order, reading (2, 3) against a
cropped size of (4160, 6240), so height first, as getDefaultCrop()
already assumes for the sibling tag.

Both problems above were found by running it rather than by reading it, which
is worth saying plainly: as first submitted to #986 this read nothing at all,
and once reading, it would have cropped every raf.

Not covered: fuji_xe4_32_lossy.RAF from the same database fails to
decompress on current develop with "compressed RAF header check". That is
unrelated and happens before this code, but it leaves lossy compressed rafs
unverified here.

Happy to add a test if you point me at where a sample would live.

Context

The consuming side is darktable-org/darktable#22088, which reproduces this
framing as an editable crop and already reads Canon and Olympus through
Exiv2. Fujifilm cannot be read that way, the value being in the raf container
rather than the Exif makernote, which is why it wants doing here. Consuming
this field is a follow-up and not part of this PR.

Fujifilm bodies with an aspect ratio setting record the choice but leave the
raw data uncropped, so the framing chosen while shooting is otherwise lost to
consumers where other raw processors reproduce it. The value sits in the same
proprietary directory as the crop tags getDefaultCrop() already reads, two
entries along, stored height then width like the cropped size beside it.

Expose it as ImageMetaData::cameraAspectRatio rather than as a rectangle. The
box a vendor describes is relative to that vendor's own output area, which is
not the area we hand out, so a consumer that centers a ratio itself does not
have to track the difference. It is also all some vendors record: Fujifilm's
own cropped size here stays at the native shape whatever ratio is selected,
so there is no usable rectangle to hand out.

The tag is written whether or not a ratio was picked, so a plain 3:2 frame
carries one too. Reporting that would have consumers crop every raf to an
exact 3:2 and trim the sensor margins off images nobody chose a ratio for, so
it is compared against the cropped size and only a differing ratio is
reported.

FiffParser needs the tag listed among those read as SHORT. Left to the
default UNDEFINED its count comes out as the byte length rather than the
number of shorts, and the entry cannot be read at all.

The field is named for the concept rather than for Fujifilm, so the other
decoders can fill it as and when someone does that work.

Verified against CC0 samples from raw.pixls.us: Fujifilm X-T200
DSCF0074.RAF, shot at 16:9, reports {16, 9} and exports 16:9 through
darktable; Fujifilm X100V DSCF0734.RAF, shot at the native 3:2, reports
nothing and exports the full frame. The X100V pair also confirms the byte
order, reading (2, 3) against a cropped size of (4160, 6240).

Not covered: fuji_xe4_32_lossy.RAF from the same database fails to
decompress on develop with "compressed RAF header check", which happens
before this code and is unrelated, but leaves lossy compressed rafs
unverified here.

AI disclosure, per AGENTS.md: this change was written with AI assistance
(Claude Code with Claude Opus 5). I have reviewed it, it builds clean, and I
take responsibility for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant