Skip to content

Commit

Permalink
Stable gimp-darktable calling interface
Browse files Browse the repository at this point in the history
As we want to support darktable as a gimp plugin in the best possible way we put the
burden of "how to do so" on the dt dev team instead of having that on the gimp side as
we likely know better to achieve this.

Summary of currently implemented darktable features
- always use default resources
- don't print any logs
- while being in darkroom ignore any requests to change view

**************************************************************************************
The GIMP support cli API 

Added --gimp <mode> option to the cli interface. <mode> is always a string, can be
"version" "file" "thumb"

Whenever we call 'darktable --gimp' the result is a string <res> written to stdout.
Also the returncode is 0.

In case of errors <res> is "error" and returncode will be 1

As darktable makes use of external libraries <ret> might be preceeded by other text,
the <res> is always the last written line string (eol before and after)

version            Returns the current API version (for initial commit will be 1)
file <path>        Starts darktable in darkroom mode using image defined by <path>.
                   When closing the darkroom window the file is exported as an
                   xcf file to a temporary location.
                   The full path of the exported file is returned as <res>
thumb <path> <dim> Write a thumbnail jpg file to a temporary location.
                   <path> is the image file
                   <dim> (in pixels) is used for the greater of width/height and ratio is kept.
                   The returned <res> has the following format:
                   * The full path of the exported file on the first line
                   * The width and height as space-separated integers on the second line.
                     These dimensions are informational and may not be accurate.
                     For raw files this is sensor size containing valid data.
  • Loading branch information
jenshannoschwalm authored and TurboGit committed Feb 2, 2024
1 parent ced8a13 commit a5a3680
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ FILE(GLOB SOURCE_FILES
"common/file_location.c"
"common/film.c"
"common/gaussian.c"
"common/gimp.c"
"common/gpx.c"
"common/grouping.c"
"common/guided_filter.c"
Expand Down
55 changes: 51 additions & 4 deletions src/common/darktable.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include "common/points.h"
#include "common/resource_limits.h"
#include "common/undo.h"
#include "common/gimp.h"
#include "control/conf.h"
#include "control/control.h"
#include "control/crawler.h"
Expand Down Expand Up @@ -1128,6 +1129,52 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load
darktable.pipe_cache = FALSE;
argv[k] = NULL;
}
else if(!strcmp(argv[k], "--gimp"))
{
argv[k] = NULL;
darktable.gimp.error = TRUE;

if(argc > k + 1)
{
darktable.gimp.mode = argv[++k];
argv[k-1] = NULL;
argv[k] = NULL;

if(dt_check_gimpmode("version"))
darktable.gimp.error = FALSE;
else if(dt_check_gimpmode("file") && (argc > k + 1))
{
darktable.gimp.path = argv[++k];
argv[k-1] = NULL;
argv[k] = NULL;

if(g_file_test(darktable.gimp.path, G_FILE_TEST_IS_REGULAR))
darktable.gimp.error = FALSE;

}
else if(dt_check_gimpmode("thumb") && (argc > k + 2))
{
darktable.gimp.path = argv[++k];
argv[k-1] = NULL;
argv[k] = NULL;
if(g_file_test(darktable.gimp.path, G_FILE_TEST_IS_REGULAR))
{
darktable.gimp.size = atol(argv[k + 1]);
k++;
argv[k-1] = NULL;
argv[k] = NULL;
if(darktable.gimp.size > 0)
darktable.gimp.error = FALSE;
}
}

if(!darktable.gimp.error)
{
dbfilename_from_command = ":memory:";
dt_gimp_init_settings();
}
}
}
else if(!strcmp(argv[k], "--"))
{
// "--" confuses the argument parser of glib/gtk. remove it.
Expand Down Expand Up @@ -1440,7 +1487,8 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load
res->total_memory = _get_total_memory() * 1024lu;

char *config_info = calloc(1, DT_PERF_INFOSIZE);
if(last_configure_version != DT_CURRENT_PERFORMANCE_CONFIGURE_VERSION)
if(last_configure_version != DT_CURRENT_PERFORMANCE_CONFIGURE_VERSION
&& !darktable.gimp.mode)
dt_configure_runtime_performance(last_configure_version, config_info);

dt_get_sysresource_level();
Expand Down Expand Up @@ -1666,7 +1714,6 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load

dt_print(DT_DEBUG_CONTROL,
"[dt_init] startup took %f seconds\n", dt_get_wtime() - start_wtime);

return 0;
}

Expand All @@ -1677,7 +1724,7 @@ void dt_get_sysresource_level()
static int oldtunehead = -999;

dt_sys_resources_t *res = &darktable.dtresources;
const gboolean tunehead = dt_conf_get_bool("opencl_tune_headroom");
const gboolean tunehead = !darktable.gimp.mode && dt_conf_get_bool("opencl_tune_headroom");
int level = 1;
const char *config = dt_conf_get_string_const("resourcelevel");
/** These levels must correspond with preferences in xml.in
Expand All @@ -1688,7 +1735,7 @@ void dt_get_sysresource_level()
- add a line of fraction in int fractions[] or ref_resources[] above
- add a line in darktableconfig.xml.in if available via UI
*/
if(config)
if(config && !darktable.gimp.mode)
{
if(!strcmp(config, "default")) level = 1;
else if(!strcmp(config, "small")) level = 0;
Expand Down
15 changes: 15 additions & 0 deletions src/common/darktable.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,15 @@ typedef struct dt_backthumb_t
int32_t mipsize;
} dt_backthumb_t;

typedef struct dt_gimp_t
{
int32_t size;
char *mode;
char *path;
dt_imgid_t imgid;
gboolean error;
} dt_gimp_t;

typedef struct darktable_t
{
dt_codepath_t codepath;
Expand Down Expand Up @@ -395,6 +404,7 @@ typedef struct darktable_t
GDateTime *origin_gdt;
struct dt_sys_resources_t dtresources;
struct dt_backthumb_t backthumbs;
struct dt_gimp_t gimp;
} darktable_t;

typedef struct
Expand Down Expand Up @@ -906,6 +916,11 @@ static inline const gchar *NQ_(const gchar *String)
return context_end ? context_end + 1 : String;
}

static inline gboolean dt_check_gimpmode(const char *mode)
{
return darktable.gimp.mode ? strcmp(darktable.gimp.mode, mode) == 0 : FALSE;
}

#ifdef __cplusplus
} // extern "C"
#endif /* __cplusplus */
Expand Down
114 changes: 114 additions & 0 deletions src/common/gimp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
This file is part of darktable,
Copyright (C) 2024 darktable developers.
darktable 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.
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
*/

#include "common/image.h"
#include "common/image_cache.h"
#include "control/control.h"
#include <glib.h>

void dt_gimp_init_settings(void)
{
darktable.unmuted_signal_dbg_acts = 0;
darktable.unmuted = 0;
}

gboolean dt_export_gimp_file(const dt_imgid_t id)
{
const gboolean thumb = dt_check_gimpmode("thumb");
char *tmp_directory = g_dir_make_tmp("darktable_XXXXXX", NULL);
char path[PATH_MAX]= { 0 };

snprintf(path, sizeof(path), "%s/%s", tmp_directory, thumb ? "thumb" : "image");
g_free(tmp_directory);

// init the export data structures
dt_imageio_module_storage_t *storage = dt_imageio_get_storage_by_name("disk");
if(storage == NULL) return FALSE;

dt_imageio_module_data_t *sdata = storage->get_params(storage);
if(sdata == NULL) return FALSE;

// and now for the really ugly hacks. don't tell your children about this one or they won't sleep at night
// any longer ...
g_strlcpy((char *)sdata, path, DT_MAX_PATH_FOR_PARAMS);

dt_imageio_module_format_t *format = dt_imageio_get_format_by_name(thumb ? "jpeg" : "xcf");
if(format == NULL) return FALSE;

dt_imageio_module_data_t *fdata = format->get_params(format);
if(fdata == NULL) return FALSE;

// For disk exporting and used formats we dont have to check dimensions
const size_t dim = MIN(MAX(darktable.gimp.size, 32), 1024);

fdata->max_width = thumb ? dim : 0;
fdata->max_height = thumb ? dim : 0;
fdata->style[0] = '\0';
fdata->style_append = FALSE;

storage->store(storage, sdata, id, format, fdata, 1, 1,
thumb ? FALSE : TRUE, // high_quality,
FALSE, // never upscale
thumb ? FALSE : TRUE, // export_masks
DT_COLORSPACE_SRGB, // for xcf it's irrelevant, for jpeg we want it
NULL, // icc_filename
DT_INTENT_PERCEPTUAL, // for xcf it's irrelevant, for jpeg we want it
NULL); // &metadata
fprintf(stdout, "\n%s%s\n", path, thumb ? ".jpg" : ".xcf");
if(thumb)
{
dt_image_t *image = dt_image_cache_get(darktable.image_cache, id, 'r');
fprintf(stdout, "%i %i\n", image->width, image->height);
dt_image_cache_read_release(darktable.image_cache, image);
}
return TRUE;
}

dt_imgid_t dt_gimp_load_image(const char *file)
{
char *filename = dt_util_normalize_path(file);
if(filename == NULL)
return NO_IMGID;

gchar *directory = g_path_get_dirname((const gchar *)filename);
dt_film_t film;
const dt_filmid_t filmid = dt_film_new(&film, directory);
g_free(directory);
if(!dt_is_valid_filmid(filmid))
{
g_free(filename);
return NO_IMGID;
}

const dt_imgid_t id = dt_image_import(filmid, filename, TRUE, TRUE);
g_free(filename);

darktable.gimp.imgid = id;
return id;
}

dt_imgid_t dt_gimp_load_darkroom(const char *file)
{
const dt_imgid_t id = dt_gimp_load_image(file);
if(dt_is_valid_imgid(id))
{
dt_control_set_mouse_over_id(id);
dt_ctl_switch_mode_to("darkroom");
}
return id;
}
25 changes: 25 additions & 0 deletions src/common/gimp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
This file is part of darktable,
Copyright (C) 2024 darktable developers.
darktable 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.
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
*/

#define DT_GIMP_VERSION 1

void dt_gimp_init_settings(void);
gboolean dt_export_gimp_file(const dt_imgid_t id);

dt_imgid_t dt_gimp_load_darkroom(const char *file);
dt_imgid_t dt_gimp_load_image(const char *file);
2 changes: 2 additions & 0 deletions src/common/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ void dt_image_film_roll(const dt_image_t *img,
dt_imageio_write_xmp_t dt_image_get_xmp_mode()
{
dt_imageio_write_xmp_t res = DT_WRITE_XMP_NEVER;
if(darktable.gimp.mode) return res;

const char *config = dt_conf_get_string_const("write_sidecar_files");
if(config)
{
Expand Down
1 change: 0 additions & 1 deletion src/gui/gtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,6 @@ void dt_gui_gtk_run(dt_gui_gtk_t *gui)
cairo_surface_destroy(darktable.gui->surface);
darktable.gui->surface = NULL;
}
dt_cleanup();
}

// refactored function to read current ppd, because gtk for osx has been unreliable
Expand Down
56 changes: 56 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
along with darktable. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/darktable.h"
#include "common/image.h"
#include "develop/develop.h"
#include "common/gimp.h"
#include "common/image_cache.h"
#include "gui/gtk.h"
#include <stdlib.h>

Expand Down Expand Up @@ -91,8 +95,60 @@ int main(int argc, char *argv[])
#endif

if(dt_init(argc, argv, TRUE, TRUE, NULL)) exit(1);

if(dt_check_gimpmode("version"))
{
fprintf(stdout, "\n%d\n", DT_GIMP_VERSION);
exit(0);
}

if(dt_check_gimpmode("file") && !darktable.gimp.error)
{
const dt_imgid_t id = dt_gimp_load_darkroom(darktable.gimp.path);
if(!dt_is_valid_imgid(id))
darktable.gimp.error = TRUE;
}

if(dt_check_gimpmode("thumb") && !darktable.gimp.error)
{
const dt_imgid_t id = dt_gimp_load_image(darktable.gimp.path);
if(dt_is_valid_imgid(id))
{
if(!dt_export_gimp_file(id))
darktable.gimp.error = TRUE;
}
else
darktable.gimp.error = TRUE;
}

if(darktable.gimp.error)
{
fprintf(stdout, "\nerror\n");
exit(1);
}

if(dt_check_gimpmode("thumb")) exit(darktable.gimp.error ? 1 : 0);

dt_gui_gtk_run(darktable.gui);

if(dt_check_gimpmode("file") && !darktable.gimp.error)
{
const dt_imgid_t id = darktable.gimp.imgid;
if(!darktable.gimp.error && dt_is_valid_imgid(id))
{
if(!dt_export_gimp_file(id))
darktable.gimp.error = TRUE;
}
}
dt_cleanup();

if(darktable.gimp.error)
{
fprintf(stdout, "\nerror\n");
exit(1);
}


#ifdef _WIN32
if(redirect_output)
{
Expand Down
8 changes: 8 additions & 0 deletions src/views/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ gboolean dt_view_manager_switch_by_view(dt_view_manager_t *vm,
dt_view_t *old_view = vm->current_view;
dt_view_t *new_view = (dt_view_t *)nv; // views belong to us, we can de-const them :-)

// possibly avoid switch for as we are gimping
if(old_view
&& new_view
&& dt_check_gimpmode("file")
&& !darktable.gimp.error
&& dt_view_get_current() == DT_VIEW_DARKROOM)
return FALSE;

// reset the cursor to the default one
dt_control_change_cursor(GDK_LEFT_PTR);

Expand Down

0 comments on commit a5a3680

Please sign in to comment.