|
| 1 | +--[[ fujifilm_dynamic_range-0.1 |
| 2 | +
|
| 3 | +Compensate for Fujifilm raw files made using "dynamic range". |
| 4 | +
|
| 5 | +Copyright (C) 2021 Dan Torop <[email protected]> |
| 6 | +
|
| 7 | +This program is free software; you can redistribute it and/or modify |
| 8 | +it under the terms of the GNU General Public License as published by |
| 9 | +the Free Software Foundation; either version 2 of the License, or |
| 10 | +(at your option) any later version. |
| 11 | +
|
| 12 | +This program is distributed in the hope that it will be useful, |
| 13 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | +GNU General Public License for more details. |
| 16 | +
|
| 17 | +You should have received a copy of the GNU General Public License along |
| 18 | +with this program; if not, write to the Free Software Foundation, Inc., |
| 19 | +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 20 | +]] |
| 21 | + |
| 22 | +--[[About this Plugin |
| 23 | +Support for adjusting darktable exposure by Fujifilm raw exposure |
| 24 | +bias. This corrects for a DR100/DR200/DR400 "dynamic range" setting. |
| 25 | +
|
| 26 | +Dependencies: |
| 27 | +- exiftool (https://www.sno.phy.queensu.ca/~phil/exiftool/) |
| 28 | +
|
| 29 | +Based upon fujifilm_ratings by Ben Mendis |
| 30 | +
|
| 31 | +The relevant tag is RawExposureBias (0x9650). This appears to |
| 32 | +represent the shift in EV for the chosen DR setting (whether manual or |
| 33 | +automatic). Note that even at 100DR ("standard") there is an EV shift: |
| 34 | +
|
| 35 | +100 DR -> -0.72 EV |
| 36 | +200 DR -> -1.72 EV |
| 37 | +400 DR -> -2.72 EV |
| 38 | +
|
| 39 | +The ideal would be to use exiv2 to read this tag, as this is the same |
| 40 | +code which darktable import uses. Unfortunately, exiv2 as of v0.27.3 |
| 41 | +can't read this tag. As it is encoded as a 4-byte ratio of two signed |
| 42 | +shorts -- a novel data type -- it will require some attention to fix |
| 43 | +this. |
| 44 | +
|
| 45 | +There is an exiv2-readable DevelopmentDynamicRange tag which maps to |
| 46 | +RawExposureBias as above. DevelopmentDynamicRange is only present |
| 47 | +when tag DynamicRangeSetting (0x1402) is Manual/Raw (0x0001). When it |
| 48 | +is Auto (0x0000), the equivalent data is tag AutoDynamicRange |
| 49 | +(0x140b). But exiv2 currently can't read that tag either. |
| 50 | +
|
| 51 | +Hence for now this code uses exiftool to read RawExposureBias, as a |
| 52 | +more general solution. As exiftool is approx. 10x slower than exiv2 |
| 53 | +(Perl vs. C++), this may slow large imports. |
| 54 | +
|
| 55 | +These tags have been checked on a Fujifilm X100S and X100V. Other |
| 56 | +cameras may behave in other ways. |
| 57 | +
|
| 58 | +--]] |
| 59 | + |
| 60 | +local dt = require "darktable" |
| 61 | +local du = require "lib/dtutils" |
| 62 | +local df = require "lib/dtutils.file" |
| 63 | + |
| 64 | +du.check_min_api_version("4.0.0", "fujifilm_dynamic_range") |
| 65 | + |
| 66 | +local function detect_dynamic_range(event, image) |
| 67 | + if image.exif_maker ~= "FUJIFILM" then |
| 68 | + dt.print_log("[fujifilm_dynamic_range] ignoring non-Fujifilm image") |
| 69 | + return |
| 70 | + end |
| 71 | + -- it would be nice to check image.is_raw but this appears to not yet be set |
| 72 | + if not string.match(image.filename, "%.RAF$") then |
| 73 | + dt.print_log("[fujifilm_dynamic_range] ignoring non-raw image") |
| 74 | + return |
| 75 | + end |
| 76 | + local command = df.check_if_bin_exists("exiftool") |
| 77 | + if not command then |
| 78 | + dt.print_error("[fujifilm_dynamic_range] exiftool not found") |
| 79 | + return |
| 80 | + end |
| 81 | + local RAF_filename = df.sanitize_filename(tostring(image)) |
| 82 | + -- without -n flag, exiftool will round to the nearest tenth |
| 83 | + command = command .. " -RawExposureBias -n -t " .. RAF_filename |
| 84 | + dt.print_log(command) |
| 85 | + output = io.popen(command) |
| 86 | + local raf_result = output:read("*all") |
| 87 | + output:close() |
| 88 | + if #raf_result == 0 then |
| 89 | + dt.print_error("[fujifilm_dynamic_range] no output returned by exiftool") |
| 90 | + return |
| 91 | + end |
| 92 | + raf_result = string.match(raf_result, "\t(.*)") |
| 93 | + if not raf_result then |
| 94 | + dt.print_error("[fujifilm_dynamic_range] could not parse exiftool output") |
| 95 | + return |
| 96 | + end |
| 97 | + if image.exif_exposure_bias ~= image.exif_exposure_bias then |
| 98 | + -- is NAN (this is unlikely as RAFs should have ExposureBiasValue set) |
| 99 | + image.exif_exposure_bias = 0 |
| 100 | + end |
| 101 | + -- this should be auto-applied if plugins/darkroom/workflow is scene-referred |
| 102 | + -- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV |
| 103 | + image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result) |
| 104 | + dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result)) |
| 105 | +end |
| 106 | + |
| 107 | +dt.register_event("post-import-image", detect_dynamic_range) |
| 108 | + |
| 109 | +dt.print_log("[fujifilm_dynamic_range] loaded") |
0 commit comments