Suggestions as per @wpferguson: "We came to a decision a while ago to not translate debug messages(i.e. print_log() and print_error()) because the author might not be able to read the output if it was a language they weren't familiar with. So the only thing we translate are labels, tooltips, and dt.print() messages." "df.check_if_bin_exists() returns the full path to the executable. Using the returned value would let the script run on windows and macos too."
110 lines
4.1 KiB
Lua
110 lines
4.1 KiB
Lua
--[[ fujifilm_dynamic_range-0.1
|
|
|
|
Compensate for Fujifilm raw files made using "dynamic range".
|
|
|
|
Copyright (C) 2021 Dan Torop <dant@pnym.net>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
]]
|
|
|
|
--[[About this Plugin
|
|
Support for adjusting darktable exposure by Fujifilm raw exposure
|
|
bias. This corrects for a DR100/DR200/DR400 "dynamic range" setting.
|
|
|
|
Dependencies:
|
|
- exiftool (https://www.sno.phy.queensu.ca/~phil/exiftool/)
|
|
|
|
Based upon fujifilm_ratings by Ben Mendis
|
|
|
|
The relevant tag is RawExposureBias (0x9650). This appears to
|
|
represent the shift in EV for the chosen DR setting (whether manual or
|
|
automatic). Note that even at 100DR ("standard") there is an EV shift:
|
|
|
|
100 DR -> -0.72 EV
|
|
200 DR -> -1.72 EV
|
|
400 DR -> -2.72 EV
|
|
|
|
The ideal would be to use exiv2 to read this tag, as this is the same
|
|
code which darktable import uses. Unfortunately, exiv2 as of v0.27.3
|
|
can't read this tag. As it is encoded as a 4-byte ratio of two signed
|
|
shorts -- a novel data type -- it will require some attention to fix
|
|
this.
|
|
|
|
There is an exiv2-readable DevelopmentDynamicRange tag which maps to
|
|
RawExposureBias as above. DevelopmentDynamicRange is only present
|
|
when tag DynamicRangeSetting (0x1402) is Manual/Raw (0x0001). When it
|
|
is Auto (0x0000), the equivalent data is tag AutoDynamicRange
|
|
(0x140b). But exiv2 currently can't read that tag either.
|
|
|
|
Hence for now this code uses exiftool to read RawExposureBias, as a
|
|
more general solution. As exiftool is approx. 10x slower than exiv2
|
|
(Perl vs. C++), this may slow large imports.
|
|
|
|
These tags have been checked on a Fujifilm X100S and X100V. Other
|
|
cameras may behave in other ways.
|
|
|
|
--]]
|
|
|
|
local dt = require "darktable"
|
|
local du = require "lib/dtutils"
|
|
local df = require "lib/dtutils.file"
|
|
|
|
du.check_min_api_version("4.0.0", "fujifilm_dynamic_range")
|
|
|
|
local function detect_dynamic_range(event, image)
|
|
if image.exif_maker ~= "FUJIFILM" then
|
|
dt.print_log("[fujifilm_dynamic_range] ignoring non-Fujifilm image")
|
|
return
|
|
end
|
|
-- it would be nice to check image.is_raw but this appears to not yet be set
|
|
if not string.match(image.filename, "%.RAF$") then
|
|
dt.print_log("[fujifilm_dynamic_range] ignoring non-raw image")
|
|
return
|
|
end
|
|
local command = df.check_if_bin_exists("exiftool")
|
|
if not command then
|
|
dt.print_error("[fujifilm_dynamic_range] exiftool not found")
|
|
return
|
|
end
|
|
local RAF_filename = df.sanitize_filename(tostring(image))
|
|
-- without -n flag, exiftool will round to the nearest tenth
|
|
command = command .. " -RawExposureBias -n -t " .. RAF_filename
|
|
dt.print_log(command)
|
|
output = io.popen(command)
|
|
local raf_result = output:read("*all")
|
|
output:close()
|
|
if #raf_result == 0 then
|
|
dt.print_error("[fujifilm_dynamic_range] no output returned by exiftool")
|
|
return
|
|
end
|
|
raf_result = string.match(raf_result, "\t(.*)")
|
|
if not raf_result then
|
|
dt.print_error("[fujifilm_dynamic_range] could not parse exiftool output")
|
|
return
|
|
end
|
|
if image.exif_exposure_bias ~= image.exif_exposure_bias then
|
|
-- is NAN (this is unlikely as RAFs should have ExposureBiasValue set)
|
|
image.exif_exposure_bias = 0
|
|
end
|
|
-- this should be auto-applied if plugins/darkroom/workflow is scene-referred
|
|
-- note that scene-referred workflow exposure preset also pushes exposure up by 0.5 EV
|
|
image.exif_exposure_bias = image.exif_exposure_bias + tonumber(raf_result)
|
|
dt.print_log("[fujifilm_dynamic_range] raw exposure bias " .. tostring(raf_result))
|
|
end
|
|
|
|
dt.register_event("post-import-image", detect_dynamic_range)
|
|
|
|
dt.print_log("[fujifilm_dynamic_range] loaded")
|