320 lines
9.7 KiB
Lua
320 lines
9.7 KiB
Lua
--[[
|
|
|
|
gimp.lua - export and edit with GIMP
|
|
|
|
Copyright (C) 2016 Bill Ferguson <wpferguson@gmail.com>.
|
|
|
|
Portions are lifted from hugin.lua and thus are
|
|
|
|
Copyright (c) 2014 Wolfgang Goetz
|
|
Copyright (c) 2015 Christian Kanzian
|
|
Copyright (c) 2015 Tobias Jakobs
|
|
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
|
]]
|
|
--[[
|
|
gimp - export an image and open with GIMP for editing
|
|
|
|
This script provides another storage (export target) for darktable. Selected
|
|
images are exported in the specified format to temporary storage. GIMP is launched
|
|
and opens the files. After editing, the exported images are overwritten to save the
|
|
changes. When GIMP exits, the exported files are moved into the current collection
|
|
and imported into the database. The imported files then show up grouped with the
|
|
originally selected images.
|
|
|
|
ADDITIONAL SOFTWARE NEEDED FOR THIS SCRIPT
|
|
* GIMP - http://www.gimp.org
|
|
|
|
USAGE
|
|
* require this script from your main lua file
|
|
* select an image or images for editing with GIMP
|
|
* in the export dialog select "Edit with GIMP" and select the format and bit depth for the
|
|
exported image
|
|
* Press "export"
|
|
* Edit the image with GIMP then save the changes with File->Overwrite....
|
|
* Exit GIMP
|
|
* The edited image will be imported and grouped with the original image
|
|
|
|
CAVEATS
|
|
* Developed and tested on Ubuntu 14.04 LTS with darktable 2.0.3 and GIMP 2.9.3 (development version with
|
|
> 8 bit color)
|
|
* There is no provision for dealing with the xcf files generated by GIMP, since darktable doesn't deal with
|
|
them. You may want to save the xcf file if you intend on doing further edits to the image or need to save
|
|
the layers used. Where you save them is up to you.
|
|
|
|
BUGS, COMMENTS, SUGGESTIONS
|
|
* Send to Bill Ferguson, wpferguson@gmail.com
|
|
|
|
CHANGES
|
|
* 20160823 - os.rename doesn't work across filesystems. Added fileCopy and fileMove functions to move the file
|
|
from the temporary location to the collection location irregardless of what filesystem it is on. If an
|
|
issue is encountered, a message is printed back to the UI so the user isn't left wondering what happened.
|
|
]]
|
|
|
|
local dt = require "darktable"
|
|
require "official/yield"
|
|
|
|
local gettext = dt.gettext
|
|
|
|
dt.configuration.check_version(...,{3,0,0})
|
|
|
|
-- Tell gettext where to find the .mo file translating messages for a particular domain
|
|
gettext.bindtextdomain("gimp",dt.configuration.config_dir.."/lua/")
|
|
|
|
local function split_filepath(str)
|
|
local result = {}
|
|
-- Thank you Tobias Jakobs for the awesome regular expression, which I tweaked a little
|
|
result["path"], result["filename"], result["basename"], result["filetype"] = string.match(str, "(.-)(([^\\/]-)%.?([^%.\\/]*))$")
|
|
return result
|
|
end
|
|
|
|
local function get_path(str)
|
|
local parts = split_filepath(str)
|
|
return parts["path"]
|
|
end
|
|
|
|
local function get_filename(str)
|
|
local parts = split_filepath(str)
|
|
return parts["filename"]
|
|
end
|
|
|
|
local function get_basename(str)
|
|
local parts = split_filepath(str)
|
|
return parts["basename"]
|
|
end
|
|
|
|
local function get_filetype(str)
|
|
local parts = split_filepath(str)
|
|
return parts["filetype"]
|
|
end
|
|
|
|
local function _(msgid)
|
|
return gettext.dgettext("gimp", msgid)
|
|
end
|
|
|
|
local function checkIfBinExists(bin)
|
|
local handle = io.popen("which "..bin)
|
|
local result = handle:read()
|
|
local ret
|
|
handle:close()
|
|
if (result) then
|
|
dt.print_error("true checkIfBinExists: "..bin)
|
|
ret = true
|
|
else
|
|
dt.print_error(bin.." not found")
|
|
ret = false
|
|
end
|
|
return ret
|
|
end
|
|
|
|
-- Thanks Tobias Jakobs for the idea and the correction
|
|
function checkIfFileExists(filepath)
|
|
local file = io.open(filepath,"r")
|
|
local ret
|
|
if file ~= nil then
|
|
io.close(file)
|
|
dt.print_error("true checkIfFileExists: "..filepath)
|
|
ret = true
|
|
else
|
|
dt.print_error(filepath.." not found")
|
|
ret = false
|
|
end
|
|
return ret
|
|
end
|
|
|
|
local function filename_increment(filepath)
|
|
|
|
-- break up the filepath into parts
|
|
local path = get_path(filepath)
|
|
local basename = get_basename(filepath)
|
|
local filetype = get_filetype(filepath)
|
|
|
|
-- check to see if we've incremented before
|
|
local increment = string.match(basename, "_(%d-)$")
|
|
|
|
if increment then
|
|
-- we do 2 digit increments so make sure we didn't grab part of the filename
|
|
if string.len(increment) > 2 then
|
|
-- we got the filename so set the increment to 01
|
|
increment = "01"
|
|
else
|
|
increment = string.format("%02d", tonumber(increment) + 1)
|
|
basename = string.gsub(basename, "_(%d-)$", "")
|
|
end
|
|
else
|
|
increment = "01"
|
|
end
|
|
local incremented_filepath = path .. basename .. "_" .. increment .. "." .. filetype
|
|
|
|
dt.print_error("original file was " .. filepath)
|
|
dt.print_error("incremented file is " .. incremented_filepath)
|
|
|
|
return incremented_filepath
|
|
end
|
|
|
|
local function groupIfNotMember(img, new_img)
|
|
local image_table = img:get_group_members()
|
|
local is_member = false
|
|
for _,image in ipairs(image_table) do
|
|
dt.print_error(image.filename .. " is a member")
|
|
if image.filename == new_img.filename then
|
|
is_member = true
|
|
dt.print_error("Already in group")
|
|
end
|
|
end
|
|
if not is_member then
|
|
dt.print_error("group leader is "..img.group_leader.filename)
|
|
new_img:group_with(img.group_leader)
|
|
dt.print_error("Added to group")
|
|
end
|
|
end
|
|
|
|
local function sanitize_filename(filepath)
|
|
local path = get_path(filepath)
|
|
local basename = get_basename(filepath)
|
|
local filetype = get_filetype(filepath)
|
|
|
|
local sanitized = string.gsub(basename, " ", "\\ ")
|
|
|
|
return path .. sanitized .. "." .. filetype
|
|
end
|
|
|
|
local function show_status(storage, image, format, filename,
|
|
number, total, high_quality, extra_data)
|
|
dt.print(string.format(_("Export Image %i/%i"), number, total))
|
|
end
|
|
|
|
local function fileCopy(fromFile, toFile)
|
|
local result = nil
|
|
-- if cp exists, use it
|
|
if checkIfBinExists("cp") then
|
|
result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
|
|
end
|
|
-- if cp was not present, or if cp failed, then a pure lua solution
|
|
if not result then
|
|
local fileIn, err = io.open(fromFile, 'rb')
|
|
if fileIn then
|
|
local fileOut, errr = io.open(toFile, 'w')
|
|
if fileOut then
|
|
local content = fileIn:read(4096)
|
|
while content do
|
|
fileOut:write(content)
|
|
content = fileIn:read(4096)
|
|
end
|
|
result = true
|
|
fileIn:close()
|
|
fileOut:close()
|
|
else
|
|
dt.print_error("fileCopy Error: " .. errr)
|
|
end
|
|
else
|
|
dt.print_error("fileCopy Error: " .. err)
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function fileMove(fromFile, toFile)
|
|
local success = os.rename(fromFile, toFile)
|
|
if not success then
|
|
-- an error occurred, so let's try using the operating system function
|
|
if checkIfBinExists("mv") then
|
|
success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
|
|
end
|
|
-- if the mv didn't exist or succeed, then...
|
|
if not success then
|
|
-- pure lua solution
|
|
success = fileCopy(fromFile, toFile)
|
|
if success then
|
|
os.remove(fromFile)
|
|
else
|
|
dt.print_error("fileMove Error: Unable to move " .. fromFile .. " to " .. toFile .. ". Leaving " .. fromFile .. " in place.")
|
|
dt.print(string.format(_("Unable to move edited file into collection. Leaving it as %s"), fromFile))
|
|
end
|
|
end
|
|
end
|
|
return success -- nil on error, some value if success
|
|
end
|
|
|
|
local function gimp_edit(storage, image_table, extra_data) --finalize
|
|
if not checkIfBinExists("gimp") then
|
|
dt.print_error(_("GIMP not found"))
|
|
return
|
|
end
|
|
|
|
-- list of exported images
|
|
local img_list
|
|
|
|
-- reset and create image list
|
|
img_list = ""
|
|
|
|
for _,exp_img in pairs(image_table) do
|
|
exp_img = sanitize_filename(exp_img)
|
|
img_list = img_list ..exp_img.. " "
|
|
end
|
|
|
|
dt.print(_("Launching GIMP..."))
|
|
|
|
local gimpStartCommand
|
|
gimpStartCommand = "gimp "..img_list
|
|
|
|
dt.print_error(gimpStartCommand)
|
|
|
|
dt.control.execute( gimpStartCommand)
|
|
|
|
-- for each of the image, exported image pairs
|
|
-- move the exported image into the directory with the original
|
|
-- then import the image into the database which will group it with the original
|
|
-- and then copy over any tags other than darktable tags
|
|
|
|
for image,exported_image in pairs(image_table) do
|
|
|
|
local myimage_name = image.path .. "/" .. get_filename(exported_image)
|
|
|
|
while checkIfFileExists(myimage_name) do
|
|
myimage_name = filename_increment(myimage_name)
|
|
-- limit to 99 more exports of the original export
|
|
if string.match(get_basename(myimage_name), "_(d-)$") == "99" then
|
|
break
|
|
end
|
|
end
|
|
|
|
dt.print_error("moving " .. exported_image .. " to " .. myimage_name)
|
|
local result = fileMove(exported_image, myimage_name)
|
|
|
|
if result then
|
|
dt.print_error("importing file")
|
|
local myimage = dt.database.import(myimage_name)
|
|
|
|
groupIfNotMember(image, myimage)
|
|
|
|
for _,tag in pairs(dt.tags.get_tags(image)) do
|
|
if not (string.sub(tag.name,1,9) == "darktable") then
|
|
dt.print_error("attaching tag")
|
|
dt.tags.attach(tag,myimage)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
-- Register
|
|
dt.register_storage("module_gimp", _("Edit with GIMP"), show_status, gimp_edit)
|
|
|
|
--
|
|
|
|
|