Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
cli/main.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2012, 2014-2015 johannes hanika.
4 Copyright (C) 2012, 2014-2016, 2019-2021 Pascal Obry.
5 Copyright (C) 2012-2017, 2019-2020 Tobias Ellinghaus.
6 Copyright (C) 2013-2014 Jérémy Rosen.
7 Copyright (C) 2013-2014 Pascal de Bruijn.
8 Copyright (C) 2013 Thomas Pryds.
9 Copyright (C) 2014 Pedro Côrte-Real.
10 Copyright (C) 2014-2016 Roman Lebedev.
11 Copyright (C) 2017, 2020 Heiko Bauke.
12 Copyright (C) 2018 Bill Ferguson.
13 Copyright (C) 2018 Michael Mayer.
14 Copyright (C) 2019 Denis Dyakov.
15 Copyright (C) 2019 parafin.
16 Copyright (C) 2019 Philippe Weyland.
17 Copyright (C) 2020 bobobo1618.
18 Copyright (C) 2020 David-Tillmann Schaefer.
19 Copyright (C) 2020 Hubert Kowalski.
20 Copyright (C) 2021 Aldric Renaudin.
21 Copyright (C) 2021 Christian Kreibich.
22 Copyright (C) 2021 Hanno Schwalm.
23 Copyright (C) 2021 Ralf Brown.
24 Copyright (C) 2022-2023, 2025 Aurélien PIERRE.
25 Copyright (C) 2022 Martin Bařinka.
26 Copyright (C) 2022 Miloš Komarčević.
27 Copyright (C) 2023 Alynx Zhou.
28
29 darktable is free software: you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation, either version 3 of the License, or
32 (at your option) any later version.
33
34 darktable is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
38
39 You should have received a copy of the GNU General Public License
40 along with darktable. If not, see <http://www.gnu.org/licenses/>.
41*/
42
52#include "common/collection.h"
53#include "common/darktable.h"
54#include "common/debug.h"
55#include "common/exif.h"
56#include "common/film.h"
58#include "common/history.h"
59#include "common/image.h"
60#include "common/image_cache.h"
61#include "common/imageio.h"
62#include "common/imageio_jpeg.h"
64#include "common/l10n.h"
65#include "common/points.h"
66#include "control/conf.h"
67#include "develop/imageop.h"
68
69#include <inttypes.h>
70#include <libintl.h>
71#include <sys/time.h>
72#include <unistd.h>
73
74#ifdef __APPLE__
75#include "osx/osx.h"
76#endif
77
78#ifdef _WIN32
79#include "win/main_wrapper.h"
80#endif
81
82#define DT_MAX_STYLE_NAME_LENGTH 128
83
84// Make sure it's OK to limit output extension length
85#define DT_MAX_OUTPUT_EXT_LENGTH 5
86
87static void usage(const char *progname)
88{
89 fprintf(stderr, "usage: %s [<input file or dir>] [<xmp file>] <output destination> [options] [--core <darktable options>]\n", progname);
90 fprintf(stderr, "\n");
91 fprintf(stderr, "options:\n");
92 fprintf(stderr, " --width <max width> default: 0 = full resolution\n");
93 fprintf(stderr, " --height <max height> default: 0 = full resolution\n");
94 fprintf(stderr, " --bpp <bpp>, unsupported\n");
95 fprintf(stderr, " --export_masks <0|1|false|true>, default: false\n");
96 fprintf(stderr, " --style <style name>\n");
97 fprintf(stderr, " --apply-custom-presets <0|1|false|true>, default: true\n");
98 fprintf(stderr, " disable for multiple instances\n");
99 fprintf(stderr, " --out-ext <extension>, default from output destination or '.jpg'\n");
100 fprintf(stderr, " if specified, takes preference over output\n");
101 fprintf(stderr, " --import <file or dir> specify input file or dir, can be used'\n");
102 fprintf(stderr, " multiple times instead of input file\n");
103 fprintf(stderr, " --icc-type <type> specify icc type, default to NONE\n");
104 fprintf(stderr, " use --help icc-type for list of supported types\n");
105 fprintf(stderr, " --icc-file <file> specify icc filename, default to NONE\n");
106 fprintf(stderr, " --icc-intent <intent> specify icc intent, default to LAST\n");
107 fprintf(stderr, " use --help icc-intent for list of supported intents\n");
108 fprintf(stderr, " --verbose\n");
109 fprintf(stderr, " --help,-h [option]\n");
110 fprintf(stderr, " --version\n");
111}
112
113static void icc_types()
114{
115 // TODO: Can this be automated to keep in sync with colorspaces.h?
116 fprintf(stderr, "available ICC types:\n");
117 fprintf(stderr, " NONE\n");
118 fprintf(stderr, " FILE\n");
119 fprintf(stderr, " SRGB\n");
120 fprintf(stderr, " ADOBERGB\n");
121 fprintf(stderr, " LIN_REC709\n");
122 fprintf(stderr, " LIN_REC2020\n");
123 fprintf(stderr, " XYZ\n");
124 fprintf(stderr, " LAB\n");
125 fprintf(stderr, " INFRARED\n");
126 fprintf(stderr, " DISPLAY\n");
127 fprintf(stderr, " EMBEDDED_ICC\n");
128 fprintf(stderr, " EMBEDDED_MATRIX\n");
129 fprintf(stderr, " STANDARD_MATRIX\n");
130 fprintf(stderr, " ENHANCED_MATRIX\n");
131 fprintf(stderr, " VENDOR_MATRIX\n");
132 fprintf(stderr, " ALTERNATE_MATRIX\n");
133 fprintf(stderr, " BRG\n");
134 fprintf(stderr, " EXPORT\n"); // export and softproof are categories and will return NULL with dt_colorspaces_get_profile()
135 fprintf(stderr, " SOFTPROOF\n");
136 fprintf(stderr, " WORK\n");
137 fprintf(stderr, " REC709\n");
138 fprintf(stderr, " PROPHOTO_RGB\n");
139 fprintf(stderr, " PQ_REC2020\n");
140 fprintf(stderr, " HLG_REC2020\n");
141 fprintf(stderr, " PQ_P3\n");
142 fprintf(stderr, " HLG_P3\n");
143 fprintf(stderr, " DISPLAY_P3\n");
144}
145
146#define ICC_FROM_STR(name) if(!strcmp(option, #name)) return DT_COLORSPACE_ ## name;
148{
150 ICC_FROM_STR(FILE);
151 ICC_FROM_STR(SRGB);
152 ICC_FROM_STR(ADOBERGB);
153 ICC_FROM_STR(LIN_REC709);
154 ICC_FROM_STR(LIN_REC2020);
156 ICC_FROM_STR(LAB);
157 ICC_FROM_STR(INFRARED);
158 ICC_FROM_STR(DISPLAY);
159 ICC_FROM_STR(EMBEDDED_ICC);
160 ICC_FROM_STR(EMBEDDED_MATRIX);
161 ICC_FROM_STR(STANDARD_MATRIX);
162 ICC_FROM_STR(ENHANCED_MATRIX);
163 ICC_FROM_STR(VENDOR_MATRIX);
164 ICC_FROM_STR(ALTERNATE_MATRIX);
165 ICC_FROM_STR(BRG);
166 ICC_FROM_STR(EXPORT); // export and softproof are categories and will return NULL with dt_colorspaces_get_profile()
167 ICC_FROM_STR(SOFTPROOF);
168 ICC_FROM_STR(WORK);
169 ICC_FROM_STR(REC709);
170 ICC_FROM_STR(PROPHOTO_RGB);
171 ICC_FROM_STR(PQ_REC2020);
172 ICC_FROM_STR(HLG_REC2020);
173 ICC_FROM_STR(PQ_P3);
174 ICC_FROM_STR(HLG_P3);
175 ICC_FROM_STR(DISPLAY_P3);
176 return DT_COLORSPACE_LAST;
177}
178#undef ICC_FROM_STR
179
180static void icc_intents()
181{
182 // TODO: Can this be automated to keep in sync with colorspaces.h?
183 fprintf(stderr, "available ICC intents:\n");
184 fprintf(stderr, " PERCEPTUAL\n");
185 fprintf(stderr, " RELATIVE_COLORIMETRIC\n");
186 fprintf(stderr, " SATURATION\n");
187 fprintf(stderr, " ABSOLUTE_COLORIMETRIC\n");
188}
189#define ICC_INTENT_FROM_STR(name) if(!strcmp(option, #name)) return DT_INTENT_ ## name;
190static dt_iop_color_intent_t get_icc_intent(const char* option)
191{
192 ICC_INTENT_FROM_STR(PERCEPTUAL);
193 ICC_INTENT_FROM_STR(RELATIVE_COLORIMETRIC);
194 ICC_INTENT_FROM_STR(SATURATION);
195 ICC_INTENT_FROM_STR(ABSOLUTE_COLORIMETRIC);
196 return DT_INTENT_LAST;
197}
198#undef ICC_INTENT_FROM_STR
199
200int main(int argc, char *arg[])
201{
202#ifdef __APPLE__
204#endif
205
206 // get valid locale dir
207 dt_loc_init(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
208 char localedir[PATH_MAX] = { 0 };
209 dt_loc_get_localedir(localedir, sizeof(localedir));
210 bindtextdomain(GETTEXT_PACKAGE, localedir);
211
212 // gtk_parse_args may trigger GTK initialization, so disable GTK locale handling first.
214 if(!gtk_parse_args(&argc, &arg)) exit(1);
215
216 // parse command line arguments
217 char *input_filename = NULL;
218 char *xmp_filename = NULL;
219 gchar *output_filename = NULL;
220 gchar *output_ext = NULL;
221 char *style = NULL;
222 int file_counter = 0;
223 int width = 0, height = 0, bpp = 0;
224 gboolean verbose = FALSE, custom_presets = TRUE, export_masks = FALSE,
225 output_to_dir = FALSE;
226
227 GList* inputs = NULL;
228
230 gchar *icc_filename = NULL;
232
233 int k;
234 for(k = 1; k < argc; k++)
235 {
236 if(arg[k][0] == '-')
237 {
238 if(!strcmp(arg[k], "--help") || !strcmp(arg[k], "-h"))
239 {
240 usage(arg[0]);
241 if(k+1 < argc) {
242 if(!strcmp(arg[k+1], "icc-type"))
243 icc_types();
244 if(!strcmp(arg[k+1], "icc-intent"))
245 icc_intents();
246 }
247 exit(1);
248 }
249 else if(!strcmp(arg[k], "--version"))
250 {
251 printf("this is ansel-cli %s\ncopyright (c) 2012-%s johannes hanika, tobias ellinghaus\n",
253 exit(0);
254 }
255 else if(!strcmp(arg[k], "--width") && argc > k + 1)
256 {
257 k++;
258 width = MAX(atoi(arg[k]), 0);
259 }
260 else if(!strcmp(arg[k], "--height") && argc > k + 1)
261 {
262 k++;
263 height = MAX(atoi(arg[k]), 0);
264 }
265 else if(!strcmp(arg[k], "--bpp") && argc > k + 1)
266 {
267 k++;
268 bpp = MAX(atoi(arg[k]), 0);
269 fprintf(stderr, _("TODO: sorry, due to API restrictions we currently cannot set the BPP to %d.\n"), bpp);
270 }
271 else if(!strcmp(arg[k], "--export_masks") && argc > k + 1)
272 {
273 k++;
274 gchar *str = g_ascii_strup(arg[k], -1);
275 if(!g_strcmp0(str, "0") || !g_strcmp0(str, "FALSE"))
276 export_masks = FALSE;
277 else if(!g_strcmp0(str, "1") || !g_strcmp0(str, "TRUE"))
278 export_masks = TRUE;
279 else
280 {
281 fprintf(stderr, _("unknown option for --export_masks: %s.\n"), arg[k]);
282 usage(arg[0]);
283 exit(1);
284 }
285 dt_free(str);
286 }
287 else if(!strcmp(arg[k], "--style") && argc > k + 1)
288 {
289 k++;
290 style = arg[k];
291 }
292 else if(!strcmp(arg[k], "--apply-custom-presets") && argc > k + 1)
293 {
294 k++;
295 gchar *str = g_ascii_strup(arg[k], -1);
296 if(!g_strcmp0(str, "0") || !g_strcmp0(str, "FALSE"))
297 custom_presets = FALSE;
298 else if(!g_strcmp0(str, "1") || !g_strcmp0(str, "TRUE"))
299 custom_presets = TRUE;
300 else
301 {
302 fprintf(stderr, _("unknown option for --apply-custom-presets: %s.\n"), arg[k]);
303 usage(arg[0]);
304 exit(1);
305 }
306 dt_free(str);
307 }
308 else if(!strcmp(arg[k], "--out-ext") && argc > k + 1)
309 {
310 k++;
311 if(strlen(arg[k])> DT_MAX_OUTPUT_EXT_LENGTH)
312 {
313 fprintf(stderr, _("too long ext for --out-ext: %s.\n"), arg[k]);
314 usage(arg[0]);
315 exit(1);
316 }
317 if (*arg[k] == '.')
318 {
319 //remove dot ;)
320 arg[k]++;
321 }
322 output_ext = g_strdup(arg[k]);
323 }
324 else if(!strcmp(arg[k], "--import") && argc > k + 1)
325 {
326 k++;
327 if(g_file_test(arg[k], G_FILE_TEST_EXISTS))
328 inputs = g_list_prepend(inputs, g_strdup(arg[k]));
329 else
330 fprintf(stderr, _("notice: input file or dir '%s' doesn't exist, skipping\n"), arg[k]);
331 }
332 else if(!strcmp(arg[k], "--icc-type") && argc > k + 1)
333 {
334 k++;
335 gchar *str = g_ascii_strup(arg[k], -1);
336 icc_type = get_icc_type(str);
337 dt_free(str);
338 if(icc_type >= DT_COLORSPACE_LAST){
339 fprintf(stderr, _("incorrect ICC type for --icc-type: '%s'\n"), arg[k]);
340 icc_types();
341 usage(arg[0]);
342 exit(1);
343 }
344 }
345 else if(!strcmp(arg[k], "--icc-file") && argc > k + 1)
346 {
347 k++;
348 if(g_file_test(arg[k], G_FILE_TEST_EXISTS) && ! g_file_test(arg[k], G_FILE_TEST_IS_DIR))
349 {
350 if(icc_filename)
351 dt_free(icc_filename);
352 icc_filename = g_strdup(arg[k]);
353 }
354 else
355 fprintf(stderr, _("notice: ICC file '%s' doesn't exist, skipping\n"), arg[k]);
356 }
357 else if(!strcmp(arg[k], "--icc-intent") && argc > k + 1)
358 {
359 k++;
360 gchar *str = g_ascii_strup(arg[k], -1);
361 icc_intent = get_icc_intent(str);
362 dt_free(str);
363 if(icc_intent >= DT_INTENT_LAST){
364 fprintf(stderr, _("incorrect ICC intent for --icc-intent: '%s'\n"), arg[k]);
365 icc_intents();
366 usage(arg[0]);
367 exit(1);
368 }
369 }
370 else if(!strcmp(arg[k], "-v") || !strcmp(arg[k], "--verbose"))
371 {
372 verbose = TRUE;
373 }
374 else if(!strcmp(arg[k], "--core"))
375 {
376 // everything from here on should be passed to the core
377 k++;
378 break;
379 }
380 else
381 {
382 fprintf(stderr, _("warning: unknown option '%s'\n"), arg[k]);
383 }
384 }
385 else
386 {
387 if(file_counter == 0)
388 input_filename = arg[k];
389 else if(file_counter == 1)
390 xmp_filename = arg[k];
391 else if(file_counter == 2)
392 {
393 output_filename = g_strdup(arg[k]);
394 }
395 file_counter++;
396 }
397 }
398
399 int m_argc = 0;
400 char **m_arg = malloc(sizeof(char *) * (5 + argc - k + 1));
401 m_arg[m_argc++] = "ansel-cli";
402 m_arg[m_argc++] = "--library";
403 m_arg[m_argc++] = ":memory:";
404 m_arg[m_argc++] = "--conf";
405 m_arg[m_argc++] = "write_sidecar_files=FALSE";
406 for(; k < argc; k++) m_arg[m_argc++] = arg[k];
407 m_arg[m_argc] = NULL;
408
409 if( (inputs && file_counter < 1) || (IS_NULL_PTR(inputs) && file_counter < 2) || file_counter > 3)
410 {
411 usage(arg[0]);
412 dt_free(m_arg);
413 if(output_filename)
414 {
415 dt_free(output_filename);
416 }
417 if(output_ext)
418 {
419 dt_free(output_ext);
420 }
421 if(inputs)
422 {
423 g_list_free_full(inputs, dt_free_gpointer);
424 inputs = NULL;
425 }
426 exit(1);
427 }
428 else if(inputs && file_counter == 1)
429 {
430 //user specified inputs as options, and only dest is present
431 if(output_filename)
432 dt_free(output_filename);
433 output_filename = g_strdup(input_filename);
434 input_filename = xmp_filename = NULL;
435 }
436 else if (inputs && file_counter == 2)
437 {
438 // inputs as options, xmp & output specified
439 if(output_filename)
440 dt_free(output_filename);
441 output_filename = g_strdup(xmp_filename);
442 xmp_filename = input_filename;
443 input_filename = NULL;
444 }
445 else if (inputs && file_counter == 3)
446 {
447 fprintf(stderr, _("error: input file and import opts specified! that's not supported!\n"));
448 usage(arg[0]);
449 dt_free(m_arg);
450 if(output_filename)
451 {
452 dt_free(output_filename);
453 }
454 if(output_ext)
455 {
456 dt_free(output_ext);
457 }
458 g_list_free_full(inputs, dt_free_gpointer);
459 inputs = NULL;
460 exit(1);
461 }
462 else if(file_counter == 2)
463 {
464 // assume no xmp file given
465 if(output_filename)
466 dt_free(output_filename);
467 output_filename = g_strdup(xmp_filename);
468 xmp_filename = NULL;
469 }
470
471 if(IS_NULL_PTR(inputs) && input_filename)
472 {
473 // input is present as param
474 inputs = g_list_prepend(inputs, g_strdup(input_filename));
475 input_filename = NULL;
476 }
477
478 if(g_file_test(output_filename, G_FILE_TEST_IS_DIR))
479 {
480 output_to_dir = TRUE;
481 if(IS_NULL_PTR(output_ext))
482 {
483 output_ext = g_strdup("jpg");
484 }
485 fprintf(stderr, _("notice: output location is a directory. assuming '%s/$(FILE_NAME).%s' output pattern"), output_filename, output_ext);
486 fprintf(stderr, "\n");
487 gchar* temp_of = g_strdup(output_filename);
488 dt_free(output_filename);
489 if(g_str_has_suffix(temp_of, "/"))
490 temp_of[strlen(temp_of) - 1] = '\0';
491 output_filename = g_strconcat(temp_of, "/$(FILE_NAME)", NULL);
492 dt_free(temp_of);
493 }
494
495 // the output file already exists, so there will be a sequence number added
496 if(g_file_test(output_filename, G_FILE_TEST_EXISTS) && !output_to_dir)
497 {
498 if(IS_NULL_PTR(output_ext) || (output_ext && g_str_has_suffix(output_filename, output_ext) && !g_strcmp0(output_ext,strrchr(output_filename, '.')+1))){
499 //output file exists or there's output ext specified and it's same as file...
500 fprintf(stderr, "%s\n", _("output file already exists, it will get renamed"));
501 }
502 //TODO: test if file with replaced ext exists
503 // or not if we decide we don't replace file ext with output ext specified
504 }
505
506 // init dt without gui and without data.db:
507 if(dt_init(m_argc, m_arg, FALSE, custom_presets))
508 {
509 dt_free(m_arg);
510 dt_free(output_filename);
511 if(output_ext)
512 {
513 dt_free(output_ext);
514 }
515 if(inputs)
516 {
517 g_list_free_full(inputs, dt_free_gpointer);
518 inputs = NULL;
519 }
520 exit(1);
521 }
522
523 GList *id_list = NULL;
524
525 for(GList *l = inputs; !IS_NULL_PTR(l); l=g_list_next(l))
526 {
527 gchar* input = l->data;
528
529 if(g_file_test(input, G_FILE_TEST_IS_DIR))
530 {
531 const int filmid = dt_film_import(input);
532 if(!filmid)
533 {
534 // one of inputs was a failure, no prob
535 fprintf(stderr, _("error: can't open folder %s"), input);
536 fprintf(stderr, "\n");
537 continue;
538 }
539 id_list = g_list_concat(id_list, dt_film_get_image_ids(filmid));
540 }
541 else
542 {
543 dt_film_t film;
544 int filmid = 0;
545
546 gchar *directory = g_path_get_dirname(input);
547 filmid = dt_film_new(&film, directory);
548 const int32_t id = dt_image_import(filmid, input, TRUE);
549 dt_free(directory);
550 if(!id)
551 {
552 fprintf(stderr, _("error: can't open file %s"), input);
553 fprintf(stderr, "\n");
554 continue;
555 }
556 id_list = g_list_append(id_list, GINT_TO_POINTER(id));
557 }
558 }
559
560 //we no longer need inputs
561 if(inputs)
562 {
563 g_list_free_full(inputs, dt_free_gpointer);
564 inputs = NULL;
565 }
566
567 const int total = g_list_length(id_list);
568
569 if(total == 0)
570 {
571 fprintf(stderr, _("no images to export, aborting\n"));
572 dt_free(m_arg);
573 dt_free(output_filename);
574 if(output_ext)
575 {
576 dt_free(output_ext);
577 }
578 exit(1);
579 }
580
581 // attach xmp, if requested:
582 if(xmp_filename)
583 {
584 for(GList *iter = id_list; iter; iter = g_list_next(iter))
585 {
586 int id = GPOINTER_TO_INT(iter->data);
588 if(dt_exif_xmp_read(image, xmp_filename, 1) != 0)
589 {
590 fprintf(stderr, _("error: can't open xmp file %s"), xmp_filename);
591 fprintf(stderr, "\n");
592 dt_free(m_arg);
593 dt_free(output_filename);
594 if(output_ext)
595 {
596 dt_free(output_ext);
597 }
598 exit(1);
599 }
600 // don't write new xmp:
602 }
603 }
604
605 // print the history stack. only look at the first image and assume all got the same processing applied
606 if(verbose)
607 {
608 int id = GPOINTER_TO_INT(id_list->data);
609 gchar *history = dt_history_get_items_as_string(id);
610 if(history)
611 printf("%s\n", history);
612 else
613 printf("[%s]\n", _("empty history stack"));
614 }
615
616 if(IS_NULL_PTR(output_ext))
617 {
618 // by this point we're sure output is not dir, there's no output ext specified
619 // so only place to look for it is in filename
620 // try to find out the export format from the output_filename
621 char *ext = strrchr(output_filename, '.');
622 if(ext && strlen(ext) > DT_MAX_OUTPUT_EXT_LENGTH)
623 {
624 // too long ext, no point in wasting time
625 fprintf(stderr, _("too long output file extension: %s\n"), ext);
626 usage(arg[0]);
627 dt_free(output_filename);
628 exit(1);
629 }
630 else if(!ext || strlen(ext) <= 1)
631 {
632 // no ext or empty ext, no point in wasting time
633 fprintf(stderr, _("no output file extension given\n"));
634 usage(arg[0]);
635 dt_free(output_filename);
636 exit(1);
637 }
638 *ext = '\0';
639 ext++;
640 output_ext = g_strdup(ext);
641 } else {
642 // check and remove redundant file ext
643 char *ext = strrchr(output_filename, '.');
644 if(ext && !strcmp(output_ext, ext+1))
645 {
646 *ext = '\0';
647 }
648 }
649
650 if(!strcmp(output_ext, "jpg"))
651 {
652 dt_free(output_ext);
653 output_ext = g_strdup("jpeg");
654 }
655
656 if(!strcmp(output_ext, "tif"))
657 {
658 dt_free(output_ext);
659 output_ext = g_strdup("tiff");
660 }
661
662 // init the export data structures
665 dt_imageio_module_data_t *sdata, *fdata;
666
667 storage = dt_imageio_get_storage_by_name("disk"); // only exporting to disk makes sense
668 if(IS_NULL_PTR(storage))
669 {
670 fprintf(
671 stderr, "%s\n",
672 _("cannot find disk storage module. please check your installation, something seems to be broken."));
673 dt_free(m_arg);
674 dt_free(output_filename);
675 dt_free(output_ext);
676 exit(1);
677 }
678
679 sdata = storage->get_params(storage);
680 if(IS_NULL_PTR(sdata))
681 {
682 fprintf(stderr, "%s\n", _("failed to get parameters from storage module, aborting export ..."));
683 dt_free(m_arg);
684 dt_free(output_filename);
685 dt_free(output_ext);
686 exit(1);
687 }
688
689 // and now for the really ugly hacks. don't tell your children about this one or they won't sleep at night
690 // any longer ...
691 g_strlcpy((char *)sdata, output_filename, DT_MAX_PATH_FOR_PARAMS);
692 // all is good now, the last line didn't happen.
693 dt_free(output_filename);
694
695 format = dt_imageio_get_format_by_name(output_ext);
696 if(IS_NULL_PTR(format))
697 {
698 fprintf(stderr, _("unknown extension '.%s'"), output_ext);
699 fprintf(stderr, "\n");
700 dt_free(m_arg);
701 dt_free(output_ext);
702 exit(1);
703 }
704
705 fdata = format->get_params(format);
706 if(IS_NULL_PTR(fdata))
707 {
708 fprintf(stderr, "%s\n", _("failed to get parameters from format module, aborting export ..."));
709 dt_free(m_arg);
710 dt_free(output_ext);
711 exit(1);
712 }
713
714 uint32_t w, h, fw, fh, sw, sh;
715 fw = fh = sw = sh = 0;
716 storage->dimension(storage, sdata, &sw, &sh);
717 format->dimension(format, fdata, &fw, &fh);
718
719 if(sw == 0 || fw == 0)
720 w = sw > fw ? sw : fw;
721 else
722 w = sw < fw ? sw : fw;
723
724 if(sh == 0 || fh == 0)
725 h = sh > fh ? sh : fh;
726 else
727 h = sh < fh ? sh : fh;
728
729 fdata->max_width = width;
730 fdata->max_height = height;
731 fdata->max_width = (w != 0 && fdata->max_width > w) ? w : fdata->max_width;
732 fdata->max_height = (h != 0 && fdata->max_height > h) ? h : fdata->max_height;
733 fdata->style[0] = '\0';
734
735 if(style)
736 {
737 g_strlcpy((char *)fdata->style, style, DT_MAX_STYLE_NAME_LENGTH);
738 fdata->style[127] = '\0';
739 }
740
741 if(storage->initialize_store)
742 {
743 storage->initialize_store(storage, sdata, &format, &fdata, &id_list, TRUE);
744
745 format->set_params(format, fdata, format->params_size(format));
746 storage->set_params(storage, sdata, storage->params_size(storage));
747 }
748
749 // TODO: add a callback to set the bpp without going through the config
750
751 int num = 1, res = 0;
752 for(GList *iter = id_list; iter; iter = g_list_next(iter), num++)
753 {
754 const int id = GPOINTER_TO_INT(iter->data);
755 // TODO: have a parameter in command line to get the export presets
756 dt_export_metadata_t metadata;
758 metadata.list = NULL;
759 if(storage->store(storage, sdata, id, format, fdata, num, total, TRUE, export_masks,
760 icc_type, icc_filename, icc_intent, &metadata) != 0)
761 res = 1;
762 }
763
764 // cleanup time
765 if(storage->finalize_store) storage->finalize_store(storage, sdata);
766 storage->free_params(storage, sdata);
767 format->free_params(format, fdata);
768 g_list_free(id_list);
769 id_list = NULL;
770
771 if(icc_filename)
772 {
773 dt_free(icc_filename);
774 }
775
776 dt_cleanup();
777
778 dt_free(m_arg);
779 exit(res);
780}
781
782// clang-format off
783// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
784// vim: shiftwidth=2 expandtab tabstop=2 cindent
785// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
786// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static void usage(const char *progname)
Definition cli/main.c:87
static void icc_types()
Definition cli/main.c:113
static dt_iop_color_intent_t get_icc_intent(const char *option)
Definition cli/main.c:190
#define DT_MAX_OUTPUT_EXT_LENGTH
Definition cli/main.c:85
#define ICC_INTENT_FROM_STR(name)
Definition cli/main.c:189
static dt_colorspaces_color_profile_type_t get_icc_type(const char *option)
Definition cli/main.c:147
#define DT_MAX_STYLE_NAME_LENGTH
Definition cli/main.c:82
#define ICC_FROM_STR(name)
Definition cli/main.c:146
static void icc_intents()
Definition cli/main.c:180
dt_iop_color_intent_t
Definition colorspaces.h:63
@ DT_INTENT_LAST
Definition colorspaces.h:68
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_NONE
Definition colorspaces.h:82
@ DT_COLORSPACE_LAST
static dt_aligned_pixel_t XYZ
char * dt_history_get_items_as_string(const int32_t imgid)
int32_t dt_image_import(const int32_t film_id, const char *filename, gboolean raise_signals)
const char darktable_package_version[]
#define GETTEXT_PACKAGE
const char darktable_last_commit_year[]
void dt_cleanup()
Definition darktable.c:1311
darktable_t darktable
Definition darktable.c:181
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
Definition darktable.c:451
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MAX_PATH_FOR_PARAMS
Definition darktable.h:1071
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
int dt_exif_xmp_read(dt_image_t *img, const char *filename, const int history_only)
Definition exif.cc:3105
void dt_loc_get_localedir(char *localedir, size_t bufsize)
void dt_loc_init(const char *datadir, const char *moduledir, const char *localedir, const char *configdir, const char *cachedir, const char *tmpdir, const char *kerneldir)
int dt_film_new(dt_film_t *film, const char *directory)
Definition film.c:161
GList * dt_film_get_image_ids(const int filmid)
Definition film.c:497
int dt_film_import(const char *dirname)
Definition film.c:236
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
@ DT_IMAGE_CACHE_RELAXED
Definition image_cache.h:51
int bpp
dt_imageio_module_format_t * dt_imageio_get_format_by_name(const char *name)
dt_imageio_module_storage_t * dt_imageio_get_storage_by_name(const char *name)
void dt_l10n_disable_setlocale_early(void)
Definition l10n.c:90
float *const restrict const size_t k
uint32_t dt_lib_export_metadata_default_flags(void)
void dt_osx_prepare_environment()
Definition osx.mm:212
int main()
Definition prova.c:47
struct dt_image_cache_t * image_cache
Definition darktable.h:777
#define MAX(a, b)
Definition thinplate.c:29