Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
iop/lut3d.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2019 Andreas Schneider.
4 Copyright (C) 2019-2020 Heiko Bauke.
5 Copyright (C) 2019 Jakub Filipowicz.
6 Copyright (C) 2019-2022 Pascal Obry.
7 Copyright (C) 2019-2021 Philippe Weyland.
8 Copyright (C) 2019 Tobias Ellinghaus.
9 Copyright (C) 2020 Aldric Renaudin.
10 Copyright (C) 2020, 2023-2026 Aurélien PIERRE.
11 Copyright (C) 2020 Chris Elston.
12 Copyright (C) 2020 David-Tillmann Schaefer.
13 Copyright (C) 2020-2022 Diederik Ter Rahe.
14 Copyright (C) 2020-2021 Hubert Kowalski.
15 Copyright (C) 2020 Marco.
16 Copyright (C) 2020-2021 Ralf Brown.
17 Copyright (C) 2021-2022 Hanno Schwalm.
18 Copyright (C) 2021 Marco Carrarini.
19 Copyright (C) 2022 Martin Bařinka.
20 Copyright (C) 2022 Philipp Lutz.
21 Copyright (C) 2022 Victor Forsiuk.
22 Copyright (C) 2023 Maurizio Paglia.
23 Copyright (C) 2024 Alynx Zhou.
24
25 darktable is free software: you can redistribute it and/or modify
26 it under the terms of the GNU General Public License as published by
27 the Free Software Foundation, either version 3 of the License, or
28 (at your option) any later version.
29
30 darktable is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
34
35 You should have received a copy of the GNU General Public License
36 along with darktable. If not, see <http://www.gnu.org/licenses/>.
37*/
38#ifdef HAVE_CONFIG_H
39#include "common/darktable.h"
40#include "config.h"
41#endif
42
43#include "bauhaus/bauhaus.h"
44#include "common/imageio_png.h"
45#include "common/imagebuf.h"
46#include "common/colorspaces.h"
49#include "common/iop_profile.h"
50#include "common/lut3d.h"
51#include "control/control.h"
52#include "develop/imageop.h"
53#include "develop/imageop_gui.h"
54#include "develop/develop.h"
55#include "dtgtk/button.h"
56#include "gui/gtk.h"
57
58#include "iop/iop_api.h"
59
60#include <gtk/gtk.h>
61#include <libgen.h>
62#include <png.h>
63#include <stdio.h>
64#include <stdlib.h>
65#include <unistd.h>
66#include <dirent.h>
67#if defined (_WIN32)
68#include "win/getdelim.h"
69#endif // defined (_WIN32)
70
72
73#define DT_IOP_LUT3D_MAX_PATHNAME 512
74#define DT_IOP_LUT3D_MAX_LUTNAME 128
75#define DT_IOP_LUT3D_CLUT_LEVEL 48
76#define DT_IOP_LUT3D_MAX_KEYPOINTS 2048
77
79{
80 DT_IOP_SRGB = 0, // $DESCRIPTION: "sRGB"
81 DT_IOP_ARGB, // $DESCRIPTION: "Adobe RGB"
82 DT_IOP_REC709, // $DESCRIPTION: "gamma Rec709 RGB"
83 DT_IOP_LIN_REC709, // $DESCRIPTION: "linear Rec709 RGB"
84 DT_IOP_LIN_REC2020, // $DESCRIPTION: "linear Rec2020 RGB"
85 DT_IOP_ITUR_BT1886, // $DESCRIPTION: "ITU-R BT.1886 (gamma 2.4 Rec709)"
87
89{
90 DT_IOP_TETRAHEDRAL = 0, // $DESCRIPTION: "tetrahedral"
91 DT_IOP_TRILINEAR = 1, // $DESCRIPTION: "trilinear"
92 DT_IOP_PYRAMID = 2, // $DESCRIPTION: "pyramid"
94
96{
98 dt_iop_lut3d_colorspace_t colorspace; // $DEFAULT: DT_IOP_SRGB $DESCRIPTION: "application color space"
99 dt_iop_lut3d_interpolation_t interpolation; // $DEFAULT: DT_IOP_TETRAHEDRAL
100 int nb_keypoints; // $DEFAULT: 0 >0 indicates the presence of compressed lut
104
106{
111#ifdef HAVE_GMIC
112 GtkWidget *lutentry;
113 GtkWidget *lutname;
114 GtkWidget *lutwindow;
115 gulong lutname_handler_id;
116#endif
118
125
126const char invalid_filepath_prefix[] = "INVALID >> ";
127
129{
131 float *clut; // cube lut pointer
132 uint16_t level; // cube_size
134
142
143#ifdef HAVE_GMIC
144void lut3d_decompress_clut(const unsigned char *const input_keypoints, const unsigned int nb_input_keypoints,
145 const unsigned int output_resolution, float *const output_clut_data,
146 const char *const filename);
147
148unsigned int lut3d_get_cached_clut(float *const output_clut_data, const unsigned int output_resolution,
149 const char *const filename);
150
151gboolean lut3d_read_gmz(int *const nb_keypoints, unsigned char *const keypoints, const char *const filename,
152 int *const nb_lut, void *g, const char *const lutname, const gboolean newlutname);
153
154#endif // HAVE_GMIC
155
156const char *name()
157{
158 return _("lut 3D");
159}
160
161const char **description(struct dt_iop_module_t *self)
162{
163 return dt_iop_set_description(self, _("perform color space corrections and apply look"),
164 _("corrective or creative"),
165 _("linear, RGB, display-referred"),
166 _("defined by profile, RGB"),
167 _("linear or non-linear, RGB, display-referred"));
168}
169
174
176{
177 return IOP_GROUP_COLOR;
178}
179
181{
182 return IOP_CS_RGB;
183}
184
185int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params,
186 const int new_version)
187{
188 if(old_version == 1 && new_version == 3)
189 {
190 typedef struct dt_iop_lut3d_params_v1_t
191 {
192 char filepath[DT_IOP_LUT3D_MAX_PATHNAME];
193 int colorspace;
194 int interpolation;
195 } dt_iop_lut3d_params_v1_t;
196
197 dt_iop_lut3d_params_v1_t *o = (dt_iop_lut3d_params_v1_t *)old_params;
199 g_strlcpy(n->filepath, o->filepath, sizeof(n->filepath));
200 n->colorspace = o->colorspace;
201 n->interpolation = o->interpolation;
202 n->nb_keypoints = 0;
203 memset(&n->c_clut, 0, sizeof(n->c_clut));
204 memset(&n->lutname, 0, sizeof(n->lutname));
205 return 0;
206 }
207 if(old_version == 2 && new_version == 3)
208 {
209 typedef struct dt_iop_lut3d_params_v2_t
210 {
211 char filepath[DT_IOP_LUT3D_MAX_PATHNAME];
212 int colorspace;
213 int interpolation;
214 int nb_keypoints; // >0 indicates the presence of compressed lut
215 char c_clut[DT_IOP_LUT3D_MAX_KEYPOINTS*2*3];
216 char lutname[DT_IOP_LUT3D_MAX_LUTNAME];
217 uint32_t gmic_version;
218 } dt_iop_lut3d_params_v2_t;
219
220 dt_iop_lut3d_params_v2_t *o = (dt_iop_lut3d_params_v2_t *)old_params;
222 memcpy(n, o, sizeof(dt_iop_lut3d_params_t));
223 return 0;
224 }
225
226 return 1;
227}
228void get_cache_filename(const char *const lutname, char *const cache_filename)
229{
230 char *cache_dir = g_build_filename(g_get_user_cache_dir(), "gmic", NULL);
231 char *cache_file = g_build_filename(cache_dir, lutname, NULL);
232 g_strlcpy(cache_filename, cache_file, DT_IOP_LUT3D_MAX_PATHNAME);
233 g_strlcpy(&cache_filename[strlen(cache_filename)], ".cimgz", DT_IOP_LUT3D_MAX_PATHNAME-strlen(cache_file));
234 dt_free(cache_dir);
235 dt_free(cache_file);
236}
237
238#ifdef HAVE_GMIC
239uint8_t calculate_clut_compressed(dt_iop_lut3d_params_t *const p, const char *const filepath, float **clut)
240{
241 uint8_t level = DT_IOP_LUT3D_CLUT_LEVEL;
242 float *lclut;
243 lclut = NULL;
244 char cache_filename[DT_IOP_LUT3D_MAX_PATHNAME];
245 size_t buf_size_lut;
246
247 get_cache_filename(p->lutname, cache_filename);
248 buf_size_lut = (size_t)(level * level * level * 3);
249 lclut = dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * buf_size_lut, 0);
250 if(IS_NULL_PTR(lclut))
251 {
252 fprintf(stderr, "[lut3d] error allocating buffer for gmz lut\n");
253 dt_control_log(_("error allocating buffer for gmz lut"));
254 level = 0;
255 }
256 else
257 {
258 level = lut3d_get_cached_clut(lclut, level, cache_filename);
259 if (!level)
260 { //clut not in cache
261 char *c_clut = p->c_clut;
263 lut3d_decompress_clut((const unsigned char *const)c_clut, p->nb_keypoints,
264 level, lclut, cache_filename);
265 }
266 }
267 *clut = lclut;
268 return level;
269}
270#endif // HAVE_GMIC
271
272
273uint16_t calculate_clut_haldclut(dt_iop_lut3d_params_t *const p, const char *const filepath, float **clut)
274{
276 if(read_header(filepath, &png))
277 {
278 fprintf(stderr, "[lut3d] invalid png file %s\n", filepath);
279 dt_control_log(_("invalid png file %s"), filepath);
280 return 0;
281 }
282 dt_print(DT_DEBUG_DEV, "[lut3d] png: width=%d, height=%d, color_type=%d, bit_depth=%d\n", png.width,
283 png.height, png.color_type, png.bit_depth);
284 if (png.bit_depth !=8 && png.bit_depth != 16)
285 {
286 fprintf(stderr, "[lut3d] png bit-depth %d not supported\n", png.bit_depth);
287 dt_control_log(_("png bit-depth %d not supported"), png.bit_depth);
288 fclose(png.f);
289 png_destroy_read_struct(&png.png_ptr, &png.info_ptr, NULL);
290 return 0;
291 }
292
293 // check the file sizes
294 uint16_t level = 2;
295 while(level * level * level < png.width) ++level;
296
297 if(level * level * level != png.width)
298 {
299#ifdef HAVE_GMIC
300 fprintf(stderr, "[lut3d] invalid level in png file %d %d\n", level, png.width);
301 dt_control_log(_("invalid level in png file %d %d"), level, png.width);
302#else
303 if (png.height == 2)
304 {
305 fprintf(stderr, "[lut3d] this Ansel build is not compatible with compressed clut\n");
306 dt_control_log(_("this Ansel build is not compatible with compressed clut"));
307 }
308 else
309 {
310 fprintf(stderr, "[lut3d] invalid level in png file %d %d\n", level, png.width);
311 dt_control_log(_("invalid level in png file %d %d"), level, png.width);
312 }
313#endif // HAVE_GMIC
314 fclose(png.f);
315 png_destroy_read_struct(&png.png_ptr, &png.info_ptr, NULL);
316 return 0;
317 }
318
319 level *= level; // to be equivalent to cube level
320 if(level > 256)
321 {
322 fprintf(stderr, "[lut3d] error - LUT 3D size %d > 256\n", level);
323 dt_control_log(_("error - lut 3D size %d exceeds the maximum supported"), level);
324 fclose(png.f);
325 png_destroy_read_struct(&png.png_ptr, &png.info_ptr, NULL);
326 return 0;
327 }
328 const size_t buf_size = (size_t)png.height * png_get_rowbytes(png.png_ptr, png.info_ptr);
329 dt_print(DT_DEBUG_DEV, "[lut3d] allocating %" G_GSIZE_FORMAT " bytes for png file\n", buf_size);
330 uint8_t *buf = NULL;
331 buf = dt_pixelpipe_cache_alloc_align_cache(buf_size, 0);
332 if(IS_NULL_PTR(buf))
333 {
334 fprintf(stderr, "[lut3d] error allocating buffer for png lut\n");
335 dt_control_log(_("error allocating buffer for png lut"));
336 fclose(png.f);
337 png_destroy_read_struct(&png.png_ptr, &png.info_ptr, NULL);
338 return 0;
339 }
340 if (read_image(&png, buf))
341 {
342 fprintf(stderr, "[lut3d] error - could not read png image `%s'\n", filepath);
343 dt_control_log(_("error - could not read png image %s"), filepath);
345 return 0;
346 }
347 const size_t buf_size_lut = (size_t)png.height * png.height * 3;
348 dt_print(DT_DEBUG_DEV, "[lut3d] allocating %" G_GSIZE_FORMAT " floats for png lut - level %d\n", buf_size_lut, level);
349 float *lclut = dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * buf_size_lut, 0);
350 if(IS_NULL_PTR(lclut))
351 {
352 fprintf(stderr, "[lut3d] error - allocating buffer for png lut\n");
353 dt_control_log(_("error - allocating buffer for png lut"));
355 return 0;
356 }
357 // get clut values
358 const float norm = 1.0f / (powf(2.f, png.bit_depth) - 1.0f);
359 if (png.bit_depth == 8)
360 {
361 for (size_t i = 0; i < buf_size_lut; ++i)
362 lclut[i] = (float)buf[i] * norm;
363 }
364 else
365 {
366 for (size_t i = 0; i < buf_size_lut; ++i)
367 lclut[i] = (256.0f * (float)buf[2*i] + (float)buf[2*i+1]) * norm;
368 }
370 *clut = lclut;
371 return level;
372}
373
374// provided by @rabauke, atof replaces strtod & sccanf which are locale dependent
375double dt_atof(const char *str)
376{
377 if (strncmp(str, "nan", 3) == 0 || strncmp(str, "NAN", 3) == 0)
378 return NAN;
379 double integral_result = 0;
380 double fractional_result = 0;
381 double sign = 1;
382 if (*str == '+')
383 {
384 str++;
385 sign = +1;
386 } else if (*str == '-')
387 {
388 str++;
389 sign = -1;
390 }
391 if (strncmp(str, "inf", 3) == 0 || strncmp(str, "INF", 3) == 0)
392 return sign * INFINITY;
393 // search for end of integral part and parse from
394 // right to left for numerical stability
395 const char * istr_back = str;
396 while (*str >= '0' && *str <= '9')
397 str++;
398 const char * istr_2 = str;
399 double imultiplier = 1;
400 while (istr_2 != istr_back)
401 {
402 --istr_2;
403 integral_result += (*istr_2 - '0') * imultiplier;
404 imultiplier *= 10;
405 }
406 if (*str == '.')
407 {
408 str++;
409 // search for end of fractional part and parse from
410 // right to left for numerical stability
411 const char * fstr_back = str;
412 while (*str >= '0' && *str <= '9')
413 str++;
414 const char * fstr_2 = str;
415 double fmultiplier = 1;
416 while (fstr_2 != fstr_back)
417 {
418 --fstr_2;
419 fractional_result += (*fstr_2 - '0') * fmultiplier;
420 fmultiplier *= 10;
421 }
422 fractional_result /= fmultiplier;
423 }
424 double result = sign * (integral_result + fractional_result);
425 if (*str == 'e' || *str == 'E')
426 {
427 str++;
428 double power_sign = 1;
429 if (*str == '+')
430 {
431 str++;
432 power_sign = +1;
433 }
434 else if (*str == '-')
435 {
436 str++;
437 power_sign = -1;
438 }
439 double power = 0;
440 while (*str >= '0' && *str <= '9')
441 {
442 power *= 10;
443 power += *str - '0';
444 str++;
445 }
446 if (power_sign > 0)
447 result *= pow(10, power);
448 else
449 result /= pow(10, power);
450 }
451 return result;
452}
453
454// return max 3 tokens from the line (separator = ' ' and token length = 50)
455// if nb tokens > 3, the 3rd one captures the last input
456uint8_t parse_cube_line(char *line, char (*token)[50])
457{
458 const int max_token_len = 50;
459 uint8_t i = 0;
460 uint8_t c = 0;
461 char *t = &token[0][0];
462 char *l = line;
463
464 while (*l != 0 && i < max_token_len)
465 {
466 if (*l == '#' || *l == '\n' || *l == '\r')
467 { // end of useful part of the line
468 if (i > 0)
469 {
470 *t = 0;
471 c++;
472 return c;
473 }
474 else
475 {
476 *t = 0;
477 return c;
478 }
479 }
480 if (*l == ' ' || *l == '\t')
481 { // separator
482 if (i > 0)
483 {
484 *t = 0;
485 c++;
486 i = 0;
487 t = &token[c > 2 ? 2 : c][0];
488 }
489 }
490 else
491 { // capture info
492 *t = *l;
493 t++;
494 i++;
495 }
496 l++;
497 // sometimes the last lf is missing
498 if (*l == 0)
499 {
500 *t = 0;
501 c++;
502 return c;
503 }
504 }
505 token[0][max_token_len - 1] = 0;
506 token[1][max_token_len - 1] = 0;
507 token[2][max_token_len - 1] = 0;
508 return c;
509}
510
511uint16_t calculate_clut_cube(const char *const filepath, float **clut)
512{
513 FILE *cube_file;
514 char *line = NULL;
515 size_t len = 0;
516 ssize_t read;
517 char token[3][50];
518 uint16_t level = 0;
519 float *lclut = NULL;
520 uint32_t i = 0;
521 size_t buf_size = 0;
522 uint32_t out_of_range_nb = 0;
523
524 if(!(cube_file = g_fopen(filepath, "r")))
525 {
526 fprintf(stderr, "[lut3d] invalid cube file: %s\n", filepath);
527 dt_control_log(_("error - invalid cube file: %s"), filepath);
528 return 0;
529 }
530 while ((read = getline(&line, &len, cube_file)) != -1)
531 {
532 const uint8_t nb_token = parse_cube_line(line, token);
533 if (nb_token)
534 {
535 if (token[0][0] == 'T') continue;
536 else if (strcmp("DOMAIN_MIN", token[0]) == 0)
537 {
538 if (strtod(token[1], NULL) != 0.0f)
539 {
540 fprintf(stderr, "[lut3d] DOMAIN MIN <> 0.0 is not supported\n");
541 dt_control_log(_("DOMAIN MIN <> 0.0 is not supported"));
543 dt_free(line);
544 fclose(cube_file);
545 }
546 }
547 else if (strcmp("DOMAIN_MAX", token[0]) == 0)
548 {
549 if (strtod(token[1], NULL) != 1.0f)
550 {
551 fprintf(stderr, "[lut3d] DOMAIN MAX <> 1.0 is not supported\n");
552 dt_control_log(_("DOMAIN MAX <> 1.0 is not supported"));
554 dt_free(line);
555 fclose(cube_file);
556 }
557 }
558 else if (strcmp("LUT_1D_SIZE", token[0]) == 0)
559 {
560 fprintf(stderr, "[lut3d] 1D cube lut is not supported\n");
561 dt_control_log(_("[1D cube lut is not supported"));
562 dt_free(line);
563 fclose(cube_file);
564 return 0;
565 }
566 else if (strcmp("LUT_3D_SIZE", token[0]) == 0)
567 {
568 level = atoll(token[1]);
569 if(level > 256)
570 {
571 fprintf(stderr, "[lut3d] error - LUT 3D size %d > 256\n", level);
572 dt_control_log(_("error - lut 3D size %d exceeds the maximum supported"), level);
573 dt_free(line);
574 fclose(cube_file);
575 return 0;
576 }
577 buf_size = level * level * level * 3;
578 dt_print(DT_DEBUG_DEV, "[lut3d] allocating %" G_GSIZE_FORMAT " bytes for cube lut - level %d\n", buf_size, level);
579 lclut = dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * buf_size, 0);
580 if(IS_NULL_PTR(lclut))
581 {
582 fprintf(stderr, "[lut3d] error - allocating buffer for cube lut\n");
583 dt_control_log(_("error - allocating buffer for cube lut"));
584 dt_free(line);
585 fclose(cube_file);
586 return 0;
587 }
588 }
589 else if (nb_token == 3)
590 {
591 if (!level)
592 {
593 fprintf(stderr, "[lut3d] error - cube lut size is not defined\n");
594 dt_control_log(_("error - cube lut size is not defined"));
595 dt_free(line);
596 fclose(cube_file);
597 return 0;
598 }
599 for (int j=0; j < 3; j++)
600 {
601 lclut[i+j] = dt_atof(token[j]);
602 if(isnan(lclut[i+j]))
603 {
604 fprintf(stderr, "[lut3d] error - invalid number line %d\n", (int)i/3);
605 dt_control_log(_("error - cube lut invalid number line %d"), (int)i/3);
606 dt_free(line);
607 fclose(cube_file);
608 return 0;
609 }
610 else if(lclut[i+j] < 0.0 || lclut[i+j] > 1.0)
611 out_of_range_nb++;
612 }
613 i += 3;
614 }
615 }
616 }
617 if (i != buf_size || i == 0)
618 {
619 fprintf(stderr, "[lut3d] error - cube lut lines number %d is not correct, should be %d\n",
620 (int)i/3, (int)buf_size/3);
621 dt_control_log(_("error - cube lut lines number %d is not correct, should be %d"),
622 (int)i/3, (int)buf_size/3);
624 dt_free(line);
625 fclose(cube_file);
626 return 0;
627 }
628 if(out_of_range_nb)
629 {
630 fprintf(stderr, "[lut3d] warning - %d out of range values [0,1]\n", out_of_range_nb);
631 dt_control_log(_("warning - cube lut %d out of range values [0,1]"), out_of_range_nb);
632 }
633 *clut = lclut;
634 dt_free(line);
635 fclose(cube_file);
636 return level;
637}
638
639uint16_t calculate_clut_3dl(const char *const filepath, float **clut)
640{
641 FILE *cube_file;
642 char *line = NULL;
643 size_t len = 0;
644 ssize_t read;
645 char token[3][50];
646 uint16_t level = 0;
647 float *lclut = NULL;
648 int max_value = 0;
649 uint32_t i = 0;
650 size_t buf_size = 0;
651
652 if(!(cube_file = g_fopen(filepath, "r")))
653 {
654 fprintf(stderr, "[lut3d] invalid 3dl file: %s\n", filepath);
655 dt_control_log(_("error - invalid 3dl file: %s"), filepath);
656 return 0;
657 }
658 while ((read = getline(&line, &len, cube_file)) != -1)
659 {
660 const uint8_t nb_token = parse_cube_line(line, token);
661 if (nb_token)
662 {
663 if (!level)
664 {
665 if (nb_token > 3)
666 {
667 // we assume the shaper is linear and gives the size of the cube (level)
668 const int min_shaper = atoll(token[0]);
669 const int max_shaper = atoll(token[2]);
670 if (max_shaper > min_shaper)
671 {
672 level = nb_token; // max nb_token = 50 < 256
673 if(max_shaper < 128)
674 {
675 fprintf(stderr, "[lut3d] error - the maximum shaper lut value %d is too low\n", max_shaper);
676 dt_control_log(_("error - the maximum shaper lut value %d is too low"), max_shaper);
677 dt_free(line);
678 fclose(cube_file);
679 return 0;
680 }
681 buf_size = level * level * level * 3;
682 dt_print(DT_DEBUG_DEV, "[lut3d] allocating %" G_GSIZE_FORMAT " bytes for cube lut - level %d\n", buf_size, level);
683 lclut = dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * buf_size, 0);
684 if(IS_NULL_PTR(lclut))
685 {
686 fprintf(stderr, "[lut3d] error - allocating buffer for cube lut\n");
687 dt_control_log(_("error - allocating buffer for cube lut"));
688 dt_free(line);
689 fclose(cube_file);
690 return 0;
691 }
692 }
693 }
694 }
695 else if (nb_token == 3)
696 {
697 if (!level)
698 {
699 fprintf(stderr, "[lut3d] error - cube lut size is not defined\n");
700 dt_control_log(_("error - cube lut size is not defined"));
701 dt_free(line);
702 fclose(cube_file);
703 return 0;
704 }
705 // indexing starts with blue instead of red. need to restore the right index
706 const uint32_t level2 = level * level;
707 const uint32_t red = i / level2;
708 const uint32_t rr = i - red * level2;
709 const uint32_t green = rr / level;
710 const uint32_t blue = rr - green * level;
711 const uint32_t k = red + level * green + level2 * blue;
712 for (int j=0; j < 3; j++)
713 {
714 const uint32_t value = atoll(token[j]);
715 lclut[k*3+j] = (float)value;
716 if (value > max_value)
717 max_value = value;
718 }
719 i++;
720 if (i * 3 > buf_size)
721 break;
722 }
723 }
724 }
725 if (i * 3 != buf_size || i == 0)
726 {
727 fprintf(stderr, "[lut3d] error - cube lut lines number is not correct\n");
728 dt_control_log(_("error - cube lut lines number is not correct"));
730 dt_free(line);
731 fclose(cube_file);
732 return 0;
733 }
734 dt_free(line);
735 fclose(cube_file);
736
737 // search bit depth: min 2^x > max_value
738 int inorm = 1;
739 while ((inorm < max_value) && (inorm < 65536)) // bit depth 16
740 inorm <<= 1;
741 if (inorm < 128) // bit depth 7
742 {
743 fprintf(stderr, "[lut3d] error - the maximum lut value does not match any valid bit depth\n");
744 dt_control_log(_("error - the maximum lut value does not match any valid bit depth"));
746 return 0;
747 }
748 const float norm = 1.0f / (float)(inorm - 1);
749 // normalize the lut
750 for (i =0; i < buf_size; i++)
751 lclut[i] = CLAMP(lclut[i] * norm, 0.0f, 1.0f);
752 *clut = lclut;
753 return level;
754}
755
756#ifdef HAVE_OPENCL
757int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
758{
759 const dt_iop_roi_t *const roi_in = &piece->roi_in;
762 cl_int err = CL_SUCCESS;
763 const float *const clut = (float *)d->clut;
764 const int level = d->level;
765 const int kernel = (d->params.interpolation == DT_IOP_TETRAHEDRAL) ? gd->kernel_lut3d_tetrahedral
766 : (d->params.interpolation == DT_IOP_TRILINEAR) ? gd->kernel_lut3d_trilinear
768 const int colorspace
769 = (d->params.colorspace == DT_IOP_SRGB) ? DT_COLORSPACE_SRGB
770 : (d->params.colorspace == DT_IOP_REC709) ? DT_COLORSPACE_REC709
771 : (d->params.colorspace == DT_IOP_ARGB) ? DT_COLORSPACE_ADOBERGB
772 : (d->params.colorspace == DT_IOP_LIN_REC709) ? DT_COLORSPACE_LIN_REC709
773 : (d->params.colorspace == DT_IOP_ITUR_BT1886) ? DT_COLORSPACE_ITUR_BT1886
775 const dt_iop_order_iccprofile_info_t *const lut_profile
776 = dt_ioppr_add_profile_info_to_list(self->dev, colorspace, "", INTENT_PERCEPTUAL);
777 const dt_iop_order_iccprofile_info_t *const work_profile
779 gboolean transform = (!IS_NULL_PTR(work_profile) && !IS_NULL_PTR(lut_profile)) ? TRUE : FALSE;
780 cl_mem clut_cl = NULL;
781 const int devid = pipe->devid;
782 const int width = roi_in->width;
783 const int height = roi_in->height;
784 const size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
785
786 if (clut && level)
787 {
788 clut_cl = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 3 * level * level * level, (void *)clut);
789 if(IS_NULL_PTR(clut_cl))
790 {
791 fprintf(stderr, "[lut3d process_cl] error allocating memory\n");
792 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
793 goto cleanup;
794 }
795 if (transform)
796 {
797 const int success = dt_ioppr_transform_image_colorspace_rgb_cl(devid, dev_in, dev_out, width, height,
798 work_profile, lut_profile, "work profile to LUT profile");
799 if (!success)
801 }
802 if (transform)
803 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_out);
804 else
805 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
806 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_out);
807 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), (void *)&width);
808 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), (void *)&height);
809 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(cl_mem), (void *)&clut_cl);
810 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), (void *)&level);
811 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
812 if (transform)
814 lut_profile, work_profile, "LUT profile to work profile");
815 }
816 else
817 { // no lut: identity kernel
818 dt_opencl_set_kernel_arg(devid, gd->kernel_lut3d_none, 0, sizeof(cl_mem), (void *)&dev_in);
819 dt_opencl_set_kernel_arg(devid, gd->kernel_lut3d_none, 1, sizeof(cl_mem), (void *)&dev_out);
820 dt_opencl_set_kernel_arg(devid, gd->kernel_lut3d_none, 2, sizeof(int), (void *)&width);
821 dt_opencl_set_kernel_arg(devid, gd->kernel_lut3d_none, 3, sizeof(int), (void *)&height);
822 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lut3d_none, sizes);
823 }
824 if(err != CL_SUCCESS)
825 {
826 fprintf(stderr, "[lut3d process_cl] error %i enqueue kernel\n", err);
827 goto cleanup;
828 }
829
830cleanup:
832
833 if(err != CL_SUCCESS) dt_print(DT_DEBUG_OPENCL, "[opencl_lut3d] couldn't enqueue kernel! %d\n", err);
834 return (err == CL_SUCCESS) ? TRUE : FALSE;
835}
836#endif
837
838int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ibuf, void *const obuf)
839{
840 const dt_iop_roi_t *const roi_in = &piece->roi_in;
842 const int width = roi_in->width;
843 const int height = roi_in->height;
844 const int ch = piece->dsc_in.channels;
845 const float *const clut = (float *)d->clut;
846 const uint16_t level = d->level;
847 const int interpolation = d->params.interpolation;
848 const int colorspace
849 = (d->params.colorspace == DT_IOP_SRGB) ? DT_COLORSPACE_SRGB
850 : (d->params.colorspace == DT_IOP_REC709) ? DT_COLORSPACE_REC709
851 : (d->params.colorspace == DT_IOP_ARGB) ? DT_COLORSPACE_ADOBERGB
852 : (d->params.colorspace == DT_IOP_LIN_REC709) ? DT_COLORSPACE_LIN_REC709
853 : (d->params.colorspace == DT_IOP_ITUR_BT1886) ? DT_COLORSPACE_ITUR_BT1886
855 const dt_iop_order_iccprofile_info_t *const lut_profile
856 = dt_ioppr_add_profile_info_to_list(self->dev, colorspace, "", INTENT_PERCEPTUAL);
857 const dt_iop_order_iccprofile_info_t *const work_profile
859 const gboolean transform = (!IS_NULL_PTR(work_profile) && !IS_NULL_PTR(lut_profile)) ? TRUE : FALSE;
860 if (!IS_NULL_PTR(clut))
861 {
862 if (transform)
863 {
865 work_profile, lut_profile, "work profile to LUT profile");
866 dt_lut3d_apply(obuf, obuf, (size_t)width * height, clut, level, 1.f,
867 (dt_lut3d_interpolation_t)interpolation);
869 lut_profile, work_profile, "LUT profile to work profile");
870 }
871 else
872 {
873 dt_lut3d_apply(ibuf, obuf, (size_t)width * height, clut, level, 1.f,
874 (dt_lut3d_interpolation_t)interpolation);
875 }
876 }
877 else // no clut
878 {
880 }
881 return 0;
882}
883
884void filepath_set_unix_separator(char *filepath)
885{ // use the unix separator as it works also on windows
886 const int len = strlen(filepath);
887 for(int i=0; i<len; ++i)
888 if (filepath[i]=='\\') filepath[i] = '/';
889}
890
892{
893 const int program = 28; // rgbcurve.cl, from programs.conf
896 module->data = gd;
897 gd->kernel_lut3d_tetrahedral = dt_opencl_create_kernel(program, "lut3d_tetrahedral");
898 gd->kernel_lut3d_trilinear = dt_opencl_create_kernel(program, "lut3d_trilinear");
899 gd->kernel_lut3d_pyramid = dt_opencl_create_kernel(program, "lut3d_pyramid");
900 gd->kernel_lut3d_none = dt_opencl_create_kernel(program, "lut3d_none");
901
902#ifdef HAVE_GMIC
903 // make sure the cache dir exists
904 char *cache_dir = g_build_filename(g_get_user_cache_dir(), "gmic", NULL);
905 char *cache_gmic_dir = dt_loc_init_generic(cache_dir, NULL, NULL);
906 dt_free(cache_dir);
907 dt_free(cache_gmic_dir);
908#endif // HAVE_GMIC
909}
910
920
921static int calculate_clut(dt_iop_lut3d_params_t *const p, float **clut)
922{
923 uint16_t level = 0;
924 const char *filepath = p->filepath;
925#ifdef HAVE_GMIC
926 if (p->nb_keypoints && filepath[0])
927 {
928 // compressed in params. no need to read the file
929 level = calculate_clut_compressed(p, filepath, clut);
930 }
931 else
932 { // read the file
933#endif // HAVE_GMIC
934 gchar *lutfolder = dt_conf_get_string("plugins/darkroom/lut3d/def_path");
935 if (filepath[0] && lutfolder[0])
936 {
937 char *fullpath = g_build_filename(lutfolder, filepath, NULL);
938 if (g_str_has_suffix (filepath, ".png") || g_str_has_suffix (filepath, ".PNG"))
939 {
940 level = calculate_clut_haldclut(p, fullpath, clut);
941 }
942 else if (g_str_has_suffix (filepath, ".cube") || g_str_has_suffix (filepath, ".CUBE"))
943 {
944 level = calculate_clut_cube(fullpath, clut);
945 }
946 else if (g_str_has_suffix (filepath, ".3dl") || g_str_has_suffix (filepath, ".3DL"))
947 {
948 level = calculate_clut_3dl(fullpath, clut);
949 }
950 dt_free(fullpath);
951 }
952 dt_free(lutfolder);
953#ifdef HAVE_GMIC
954 }
955#endif // HAVE_GMIC
956 return level;
957}
958
959#ifdef HAVE_GMIC
960static gboolean list_match_string(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, dt_iop_lut3d_gui_data_t *g)
961{
962 gchar *str = NULL;
963 gboolean visible;
964
965 gtk_tree_model_get(model, iter, DT_LUT3D_COL_NAME, &str, -1);
966 gchar *haystack = g_utf8_strdown(str, -1);
967 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(g->lutentry)), -1);
968
969 visible = (g_strrstr(haystack, needle) != NULL);
970
971 dt_free(haystack);
972 dt_free(needle);
973 dt_free(str);
974 gtk_list_store_set((GtkListStore *)model, iter, DT_LUT3D_COL_VISIBLE, visible, -1);
975 return FALSE;
976}
977
978static void apply_filter_lutname_list(dt_iop_lut3d_gui_data_t *g)
979{
980 GtkTreeModel *modelf = gtk_tree_view_get_model((GtkTreeView *)g->lutname);
981 GtkTreeModel *model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(modelf));
982 gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)list_match_string, g);
983}
984
985void lut3d_add_lutname_to_list(void *gv, const char *const lutname)
986{
988 GtkTreeModel *modelf = gtk_tree_view_get_model((GtkTreeView *)g->lutname);
989 GtkTreeModel *model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(modelf));
990 GtkTreeIter iter;
991 gtk_list_store_append((GtkListStore *)model, &iter);
992 gtk_list_store_set((GtkListStore *)model, &iter, DT_LUT3D_COL_NAME, lutname, DT_LUT3D_COL_VISIBLE, TRUE, -1);
993}
994
995void lut3d_clear_lutname_list(void *gv)
996{
998 GtkTreeModel *modelf = gtk_tree_view_get_model((GtkTreeView *)g->lutname);
999 GtkTreeModel *model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(modelf));
1000 // keep lutname_callback quiet while clearing the list
1001 GtkTreeSelection *selection = gtk_tree_view_get_selection((GtkTreeView *)g->lutname);
1002 g_signal_handler_block(G_OBJECT(selection), g->lutname_handler_id);
1003 gtk_list_store_clear((GtkListStore *)model);
1004 g_signal_handler_unblock(G_OBJECT(selection), g->lutname_handler_id);
1005}
1006
1007static gboolean select_lutname_in_list(dt_iop_lut3d_gui_data_t *g, const char *const lutname)
1008{
1009 GtkTreeIter iter;
1010 GtkTreeSelection *selection = gtk_tree_view_get_selection((GtkTreeView *)g->lutname);
1011 GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)g->lutname);
1012 if (lutname)
1013 {
1014 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
1015 while (valid)
1016 {
1017 gchar *name;
1018 gtk_tree_model_get(model, &iter, DT_LUT3D_COL_NAME, &name, -1);
1019 if (!g_strcmp0(lutname, name))
1020 {
1021 gtk_tree_selection_select_iter(selection, &iter);
1022 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
1023 gtk_tree_view_scroll_to_cell((GtkTreeView *)g->lutname, path, NULL, TRUE, 0.2, 0);
1024 gtk_tree_path_free(path);
1025 dt_free(name);
1026 return TRUE;
1027 }
1028 dt_free(name);
1029 valid = gtk_tree_model_iter_next(model, &iter);
1030 }
1031 return FALSE;
1032 }
1033 else // select the first in the list
1034 {
1035 if (gtk_tree_model_iter_nth_child(model, &iter, NULL, 0))
1036 {
1037 gtk_tree_selection_select_iter(selection, &iter);
1038 return TRUE;
1039 }
1040 else
1041 {
1042 return FALSE;
1043 }
1044 }
1045}
1046
1047static void get_selected_lutname(dt_iop_lut3d_gui_data_t *g, char *const lutname)
1048{
1049 GtkTreeIter iter;
1050 GtkTreeSelection *selection = gtk_tree_view_get_selection((GtkTreeView *)g->lutname);
1051 GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)g->lutname);
1052 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1053 {
1054 gchar *name;
1055 gtk_tree_model_get(model, &iter, DT_LUT3D_COL_NAME, &name, -1);
1056 g_strlcpy(lutname, name, DT_IOP_LUT3D_MAX_LUTNAME);
1057 dt_free(name);
1058 }
1059 else lutname[0] = 0;
1060}
1061
1062static void get_compressed_clut(dt_iop_module_t *self, gboolean newlutname)
1063{
1066 int nb_lut = 0;
1067 char *lutfolder = dt_conf_get_string("plugins/darkroom/lut3d/def_path");
1068 if (p->filepath[0] && lutfolder[0])
1069 {
1070 if (g_str_has_suffix (p->filepath, ".gmz") || g_str_has_suffix (p->filepath, ".GMZ"))
1071 {
1072 char *fullpath = g_build_filename(lutfolder, p->filepath, NULL);
1073 gboolean lut_found = lut3d_read_gmz(&p->nb_keypoints, (unsigned char *const)p->c_clut, fullpath,
1074 &nb_lut, (void *)g, p->lutname, newlutname);
1075 // to be able to fix evolution issue, keep the gmic version with the compressed lut
1076 if (lut_found)
1077 {
1078 if (!newlutname)
1079 select_lutname_in_list(g, p->lutname);
1080 }
1081 else if (nb_lut)
1082 {
1083 select_lutname_in_list(g, NULL);
1084 get_selected_lutname(g, p->lutname);
1085 }
1086 else if (p->lutname[0])
1087 { // read has failed - make sure lutname appear in the list (for user info)
1088 if (!select_lutname_in_list(g, p->lutname))
1089 {
1090 lut3d_add_lutname_to_list(g, p->lutname);
1091 select_lutname_in_list(g, p->lutname);
1092 }
1093 }
1094 dt_free(fullpath);
1095 }
1096 }
1097 dt_free(lutfolder);
1098}
1099
1100static void show_hide_controls(dt_iop_module_t *self)
1101{
1103 GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)g->lutname);
1104 const int nb_luts = gtk_tree_model_iter_n_children(model, NULL);
1105 if ((nb_luts > 1) || ((nb_luts > 0) &&
1106 g_str_has_prefix(dt_bauhaus_combobox_get_text(g->filepath), invalid_filepath_prefix)))
1107 {
1108 int nb_pixels = (20*(nb_luts+1) > 200) ? 200 : 20*(nb_luts);
1109 if (nb_luts > 100)
1110 gtk_widget_set_visible(g->lutentry, TRUE);
1111 else
1112 gtk_widget_set_visible(g->lutentry, FALSE);
1113 gtk_widget_set_visible(g->lutwindow, TRUE);
1114 gtk_scrolled_window_set_min_content_height((GtkScrolledWindow *)g->lutwindow, DT_PIXEL_APPLY_DPI(nb_pixels));
1115 }
1116 else
1117 {
1118 gtk_widget_set_visible(g->lutentry, FALSE);
1119 gtk_widget_set_visible(g->lutwindow, FALSE);
1120 }
1121}
1122#endif // HAVE_GMIC
1123
1126{
1129
1130 if (strcmp(p->filepath, d->params.filepath) != 0 || strcmp(p->lutname, d->params.lutname) != 0 )
1131 { // new clut file
1132 if (d->clut)
1133 { // reset current clut if any
1135 d->clut = NULL;
1136 d->level = 0;
1137 }
1138 d->level = calculate_clut(p, &d->clut);
1139 }
1140 memcpy(&d->params, p, sizeof(dt_iop_lut3d_params_t));
1141}
1142
1144{
1145 piece->data = dt_calloc_align(sizeof(dt_iop_lut3d_data_t));
1146 piece->data_size = sizeof(dt_iop_lut3d_data_t);
1148 memcpy(&d->params, self->default_params, sizeof(dt_iop_lut3d_params_t));
1149 d->clut = NULL;
1150 d->level = 0;
1151 d->params.filepath[0] = '\0';
1152}
1153
1155{
1158 d->clut = NULL;
1159 d->level = 0;
1160 dt_free_align(piece->data);
1161 piece->data = NULL;
1162}
1163
1165{
1166 if(darktable.gui->reset) return;
1168 char filepath[DT_IOP_LUT3D_MAX_PATHNAME];
1169 g_strlcpy(filepath, dt_bauhaus_combobox_get_text(widget), sizeof(filepath));
1170 fprintf(stdout, "filepath: %s\n", filepath);
1171
1172 if (!g_str_has_prefix(filepath, invalid_filepath_prefix))
1173 {
1175#ifdef HAVE_GMIC
1177 if (strcmp(filepath, p->filepath) != 0 && !(g_str_has_suffix(filepath, ".gmz") || g_str_has_suffix(filepath, ".GMZ")))
1178 {
1179 // if new file is gmz we try to keep the same lut
1180 p->nb_keypoints = 0;
1181 p->lutname[0] = 0;
1183 }
1184 g_strlcpy(p->filepath, filepath, sizeof(p->filepath));
1185 get_compressed_clut(self, FALSE);
1186 show_hide_controls(self);
1187 gtk_entry_set_text(GTK_ENTRY(g->lutentry), "");
1188#else
1189 g_strlcpy(p->filepath, filepath, sizeof(p->filepath));
1190#endif // HAVE_GMIC
1192 }
1193}
1194
1195#ifdef HAVE_GMIC
1196static void entry_callback(GtkEntry *entry, dt_iop_module_t *self)
1197{
1199 apply_filter_lutname_list(g);
1200}
1201
1202static void lutname_callback(GtkTreeSelection *selection, dt_iop_module_t *self)
1203{
1204 if(darktable.gui->reset) return;
1206 GtkTreeIter iter;
1207 GtkTreeModel *model;
1208 gchar *lutname;
1209
1210 if (gtk_tree_selection_get_selected(selection, &model, &iter))
1211 {
1212 gtk_tree_model_get(model, &iter, DT_LUT3D_COL_NAME, &lutname, -1);
1213 if (lutname[0] && strcmp(lutname, p->lutname) != 0)
1214 {
1215 g_strlcpy(p->lutname, lutname, sizeof(p->lutname));
1216 get_compressed_clut(self, TRUE);
1218 }
1219 dt_free(lutname);
1220 }
1221}
1222
1223static gboolean mouse_scroll(GtkWidget *view, GdkEventScroll *event, dt_lib_module_t *self)
1224{
1225 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1226 GtkTreeIter iter;
1227 GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)view);
1228 if(gtk_tree_selection_get_selected(selection, &model, &iter))
1229 {
1230 gboolean next = FALSE;
1231 if(event->delta_y > 0)
1232 next = gtk_tree_model_iter_next(model, &iter);
1233 else
1234 next = gtk_tree_model_iter_previous(model, &iter);
1235 if(next)
1236 {
1237 gtk_tree_selection_select_iter(selection, &iter);
1238 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
1239 gtk_tree_view_set_cursor((GtkTreeView *)view, path, NULL, FALSE);
1240 gtk_tree_path_free(path);
1241 return TRUE;
1242 }
1243 }
1244 return FALSE;
1245}
1246#endif // HAVE_GMIC
1247
1248// remove root lut folder from path
1249static void remove_root_from_path(const char *const lutfolder, char *const filepath)
1250{
1251 const int j = strlen(lutfolder) + 1;
1252 int i;
1253 for(i = 0; filepath[i+j] != '\0'; i++)
1254 filepath[i] = filepath[i+j];
1255 filepath[i] = '\0';
1256}
1257
1258gboolean check_extension(char *filename)
1259{
1260 gboolean res = FALSE;
1261 if (!filename || !filename[0]) return res;
1262 char *p = g_strrstr(filename,".");
1263 if (IS_NULL_PTR(p)) return res;
1264 char *fext = g_ascii_strdown(g_strdup(p), -1);
1265#ifdef HAVE_GMIC
1266 if (!g_strcmp0(fext, ".png") || !g_strcmp0(fext, ".cube") || !g_strcmp0(fext, ".3dl")
1267 || !g_strcmp0(fext, ".gmz")) res = TRUE;
1268#else
1269 if (!g_strcmp0(fext, ".png") || !g_strcmp0(fext, ".cube") || !g_strcmp0(fext, ".3dl") ) res = TRUE;
1270#endif // HAVE_GMIC
1271 dt_free(fext);
1272 return res;
1273}
1274
1275static gint array_str_cmp(gconstpointer a, gconstpointer b)
1276{
1277 return g_strcmp0(((dt_bauhaus_combobox_entry_t *)a)->label, ((dt_bauhaus_combobox_entry_t *)b)->label);
1278}
1279
1280// update filepath combobox with all files in the current folder
1281static void update_filepath_combobox(dt_iop_lut3d_gui_data_t *g, char *filepath, char *lutfolder)
1282{
1283 if (!filepath[0])
1284 dt_bauhaus_combobox_clear(g->filepath);
1285 else if (!dt_bauhaus_combobox_set_from_text(g->filepath, filepath))
1286 {
1287 // new folder -> update the files list
1288 char *relativepath = g_path_get_dirname(filepath);
1289 char *folder = g_build_filename(lutfolder, relativepath, NULL);
1290 struct dirent *dir;
1291 DIR *d = opendir(folder);
1292 if(!IS_NULL_PTR(d))
1293 {
1294 dt_bauhaus_combobox_clear(g->filepath);
1295 while ((dir = readdir(d)) != NULL)
1296 {
1297 char *file = dir->d_name;
1298 if (check_extension(file))
1299 {
1300 char *ofilepath = (strcmp(relativepath, ".") != 0)
1301 ? g_build_filename(relativepath, file, NULL)
1302 : g_strdup(file);
1303 filepath_set_unix_separator(ofilepath);
1304 dt_bauhaus_combobox_add(g->filepath, ofilepath);
1305 dt_free(ofilepath);
1306 }
1307 }
1308 dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(g->filepath);
1309 dt_bauhaus_combobox_data_t *combo_data = &w->data.combobox;
1310 g_ptr_array_sort(combo_data->entries, array_str_cmp);
1311 closedir(d);
1312 }
1313 if(!dt_bauhaus_combobox_set_from_text(g->filepath, filepath))
1314 { // file may have disappeared - show it
1315 char *invalidfilepath = g_strconcat(invalid_filepath_prefix, filepath, NULL);
1316 dt_bauhaus_combobox_add(g->filepath, invalidfilepath);
1317 dt_bauhaus_combobox_set_from_text(g->filepath, invalidfilepath);
1318 dt_free(invalidfilepath);
1319 }
1320 dt_free(relativepath);
1321 dt_free(folder);
1322 }
1323}
1324
1325static void button_clicked(GtkWidget *widget, dt_iop_module_t *self)
1326{
1329 gchar* lutfolder = dt_conf_get_string("plugins/darkroom/lut3d/def_path");
1330 if (strlen(lutfolder) == 0)
1331 {
1332 fprintf(stderr, "[lut3d] Lut root folder not defined\n");
1333 dt_control_log(_("lut root folder not defined"));
1334 dt_free(lutfolder);
1335 return;
1336 }
1338 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
1339 _("select lut file"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
1340 _("_select"), _("_cancel"));
1341 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE);
1342
1343 char *composed = g_build_filename(lutfolder, p->filepath, NULL);
1344 if (strlen(p->filepath) == 0 || g_access(composed, F_OK) == -1)
1345 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), lutfolder);
1346 else
1347 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(filechooser), composed);
1348 dt_free(composed);
1349
1350 GtkFileFilter* filter = GTK_FILE_FILTER(gtk_file_filter_new());
1351 gtk_file_filter_add_pattern(filter, "*.png");
1352 gtk_file_filter_add_pattern(filter, "*.PNG");
1353 gtk_file_filter_add_pattern(filter, "*.cube");
1354 gtk_file_filter_add_pattern(filter, "*.CUBE");
1355 gtk_file_filter_add_pattern(filter, "*.3dl");
1356 gtk_file_filter_add_pattern(filter, "*.3DL");
1357#ifdef HAVE_GMIC
1358 gtk_file_filter_add_pattern(filter, "*.gmz");
1359 gtk_file_filter_add_pattern(filter, "*.GMZ");
1360 gtk_file_filter_set_name(filter, _("hald cluts (png), 3D lut (cube or 3dl) or gmic compressed lut (gmz)"));
1361#else
1362 gtk_file_filter_set_name(filter, _("hald cluts (png) or 3D lut (cube or 3dl)"));
1363#endif // HAVE_GMIC
1364 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1365 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
1366
1367 // let this option to allow the user to see the actual content of the folder
1368 // but any selected file with ext <> png or cube will be ignored
1369 filter = GTK_FILE_FILTER(gtk_file_filter_new());
1370 gtk_file_filter_add_pattern(filter, "*");
1371 gtk_file_filter_set_name(filter, _("all files"));
1372 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1373
1374 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
1375 {
1376 gchar *filepath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
1377 if (strcmp(lutfolder, filepath) < 0)
1378 {
1379 remove_root_from_path(lutfolder, filepath);
1381 update_filepath_combobox(g, filepath, lutfolder);
1382 }
1383 else if (!filepath[0])// file chosen outside of root folder
1384 {
1385 fprintf(stderr, "[lut3d] select file outside Lut root folder is not allowed\n");
1386 dt_control_log(_("select file outside Lut root folder is not allowed"));
1387 }
1388 dt_free(filepath);
1389 gtk_widget_set_sensitive(g->filepath, p->filepath[0]);
1390 g_strlcpy(p->filepath, dt_bauhaus_combobox_get_text(g->filepath), sizeof(p->filepath));
1392 }
1393 dt_free(lutfolder);
1394 g_object_unref(filechooser);
1395}
1396
1398{
1400 GList *iop_order_list = self->dev->iop_order_list;
1401 const int order_lut3d = dt_ioppr_get_iop_order(iop_order_list, self->op, self->multi_priority);
1402 const int order_colorin = dt_ioppr_get_iop_order(iop_order_list, "colorin", -1);
1403 const int order_colorout = dt_ioppr_get_iop_order(iop_order_list, "colorout", -1);
1404 if(order_lut3d < order_colorin || order_lut3d > order_colorout)
1405 {
1406 gtk_widget_hide(g->colorspace);
1407 }
1408 else
1409 {
1410 gtk_widget_show(g->colorspace);
1411 }
1412}
1413
1415{
1418 gchar *lutfolder = dt_conf_get_string("plugins/darkroom/lut3d/def_path");
1419 if (!lutfolder[0])
1420 {
1421 gtk_widget_set_sensitive(g->hbox, FALSE);
1422 gtk_widget_set_sensitive(g->filepath, FALSE);
1423 dt_bauhaus_combobox_clear(g->filepath);
1424 }
1425 else
1426 {
1427 gtk_widget_set_sensitive(g->hbox, TRUE);
1428 gtk_widget_set_sensitive(g->filepath, p->filepath[0]);
1429 update_filepath_combobox(g, p->filepath, lutfolder);
1430 }
1431 dt_free(lutfolder);
1432
1434
1435#ifdef HAVE_GMIC
1436 if (p->lutname[0])
1437 {
1438 get_compressed_clut(self, FALSE);
1439 }
1440 show_hide_controls(self);
1441#endif // HAVE_GMIC
1442}
1443
1444void module_moved_callback(gpointer instance, dt_iop_module_t *self)
1445{
1447}
1448
1450{
1452
1453 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1454
1455 g->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1457#ifdef HAVE_GMIC
1458 gtk_widget_set_tooltip_text(button, _("select a png (haldclut)"
1459 ", a cube, a 3dl or a gmz (compressed lut) file "
1460 "CAUTION: 3D lut folder must be set in preferences/processing before choosing the lut file"));
1461#else
1462 gtk_widget_set_tooltip_text(button, _("select a png (haldclut)"
1463 ", a cube or a 3dl file "
1464 "CAUTION: 3D lut folder must be set in preferences/processing before choosing the lut file"));
1465#endif // HAVE_GMIC
1466 gtk_box_pack_start(GTK_BOX(g->hbox), button, FALSE, FALSE, 0);
1467 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), self);
1468
1470 dt_bauhaus_combobox_set_entries_ellipsis(g->filepath, PANGO_ELLIPSIZE_MIDDLE);
1471 gtk_box_pack_start(GTK_BOX(g->hbox), g->filepath, TRUE, TRUE, 0);
1472#ifdef HAVE_GMIC
1473 gtk_widget_set_tooltip_text(g->filepath,
1474 _("the file path (relative to lut folder) is saved with image along with the lut data if it's a compressed lut (gmz)"));
1475#else
1476 gtk_widget_set_tooltip_text(g->filepath,
1477 _("the file path (relative to lut folder) is saved with image (and not the lut data themselves)"));
1478#endif // HAVE_GMIC
1479 g_signal_connect(G_OBJECT(g->filepath), "value-changed", G_CALLBACK(filepath_callback), self);
1480
1481 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->hbox), TRUE, TRUE, 0);
1482
1483#ifdef HAVE_GMIC
1484 // text entry
1485 GtkWidget *entry = gtk_entry_new();
1487 gtk_widget_set_tooltip_text(entry, _("enter lut name"));
1488 gtk_box_pack_start((GtkBox *)self->widget,entry, TRUE, TRUE, 0);
1489 gtk_widget_add_events(entry, GDK_KEY_RELEASE_MASK);
1490 g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_callback), self);
1491 g->lutentry = entry;
1492 // treeview
1493 GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
1494 g->lutwindow = sw;
1495 gtk_scrolled_window_set_policy((GtkScrolledWindow *)sw, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1496 dt_gui_add_class(sw, "dt_recessed_scroll");
1497 GtkTreeModel *lutmodel = (GtkTreeModel *)gtk_list_store_new(DT_LUT3D_NUM_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN);
1498 GtkTreeModel *lutfilter = gtk_tree_model_filter_new(lutmodel, NULL);
1499 gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(lutfilter), DT_LUT3D_COL_VISIBLE);
1500 g_object_unref(lutmodel);
1501
1502 GtkTreeView *view = (GtkTreeView *)gtk_tree_view_new();
1503 g->lutname = (GtkWidget *)view;
1504 gtk_widget_set_name((GtkWidget *)view, "lutname");
1505 gtk_tree_view_set_model(view, lutfilter);
1506 gtk_tree_view_set_hover_selection(view, FALSE);
1507 gtk_tree_view_set_headers_visible(view, FALSE);
1508 gtk_container_add(GTK_CONTAINER(sw), (GtkWidget *)view);
1509 gtk_widget_set_tooltip_text((GtkWidget *)view, _("select the LUT"));
1510 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
1511 GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes ("lutname", renderer,
1512 "text", DT_LUT3D_COL_NAME, NULL);
1513 gtk_tree_view_append_column(view, col);
1514 GtkTreeSelection *selection = gtk_tree_view_get_selection(view);
1515 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1516 g->lutname_handler_id = g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(lutname_callback), self);
1517 g_signal_connect(G_OBJECT(view), "scroll-event", G_CALLBACK(mouse_scroll), (gpointer)self);
1518 gtk_box_pack_start((GtkBox *)self->widget, sw , TRUE, TRUE, 0);
1519#endif // HAVE_GMIC
1520
1521 g->colorspace = dt_bauhaus_combobox_from_params(self, "colorspace");
1522 gtk_widget_set_tooltip_text(g->colorspace, _("select the color space in which the LUT has to be applied"));
1523
1524 g->interpolation = dt_bauhaus_combobox_from_params(self, N_("interpolation"));
1525 gtk_widget_set_tooltip_text(g->interpolation, _("select the interpolation method"));
1526
1528 G_CALLBACK(module_moved_callback), self);
1529}
1530
1537
1538// clang-format off
1539// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1540// vim: shiftwidth=2 expandtab tabstop=2 cindent
1541// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1542// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
void dt_bauhaus_combobox_clear(GtkWidget *widget)
Definition bauhaus.c:2189
void dt_bauhaus_combobox_set_entries_ellipsis(GtkWidget *widget, PangoEllipsizeMode ellipis)
Definition bauhaus.c:2064
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:2162
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
gboolean dt_bauhaus_combobox_set_from_text(GtkWidget *widget, const char *text)
Definition bauhaus.c:2311
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
#define DT_BAUHAUS_WIDGET(obj)
Definition bauhaus.h:60
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:134
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
static void transform(float *x, float *o, const float *m, const float t_h, const float t_v)
Definition clipping.c:482
static gboolean list_match_string(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
Definition collect.c:794
@ IOP_CS_RGB
@ DT_COLORSPACE_ADOBERGB
Definition colorspaces.h:85
@ DT_COLORSPACE_SRGB
Definition colorspaces.h:84
@ DT_COLORSPACE_REC709
@ DT_COLORSPACE_LIN_REC2020
Definition colorspaces.h:87
@ DT_COLORSPACE_ITUR_BT1886
@ DT_COLORSPACE_LIN_REC709
Definition colorspaces.h:86
void dt_lut3d_apply(const float *const in, float *const out, const size_t pixel_nb, const float *const clut, const uint16_t level, const float normalization, const dt_lut3d_interpolation_t interpolation)
Apply one interpolation model over a packed RGB CLUT.
gchar * dt_conf_get_string(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:761
uint32_t view(const dt_view_t *self)
Definition darkroom.c:227
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
@ DT_DEBUG_OPENCL
Definition darktable.h:722
@ DT_DEBUG_DEV
Definition darktable.h:717
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
static const dt_aligned_pixel_simd_t sign
Definition darktable.h:551
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#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
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
void dtgtk_cairo_paint_directory(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ CPF_NONE
Definition dtgtk/paint.h:60
gchar * dt_loc_init_generic(const char *absolute_value, const char *application_directory, const char *default_value)
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
Definition getdelim.c:157
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
Definition gtk.c:3225
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:133
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
#define DT_GUI_MODULE(x)
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.h:87
int read_image(dt_imageio_png_t *png, void *out)
int read_header(const char *filename, dt_imageio_png_t *png)
Definition imageio_png.c:45
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
#define IOP_GUI_FREE
Definition imageop.h:602
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:166
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_GROUP_COLOR
Definition imageop.h:139
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
static float kernel(const float *x, const float *y)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition iop/lut3d.c:1124
static int calculate_clut(dt_iop_lut3d_params_t *const p, float **clut)
Definition iop/lut3d.c:921
const char ** description(struct dt_iop_module_t *self)
Definition iop/lut3d.c:161
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ibuf, void *const obuf)
Definition iop/lut3d.c:838
int default_group()
Definition iop/lut3d.c:175
uint16_t calculate_clut_3dl(const char *const filepath, float **clut)
Definition iop/lut3d.c:639
const char invalid_filepath_prefix[]
Definition iop/lut3d.c:126
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition iop/lut3d.c:1414
gboolean check_extension(char *filename)
Definition iop/lut3d.c:1258
dt_iop_lut3d_interpolation_t
Definition iop/lut3d.c:89
@ DT_IOP_PYRAMID
Definition iop/lut3d.c:92
@ DT_IOP_TRILINEAR
Definition iop/lut3d.c:91
@ DT_IOP_TETRAHEDRAL
Definition iop/lut3d.c:90
#define DT_IOP_LUT3D_MAX_KEYPOINTS
Definition iop/lut3d.c:76
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition iop/lut3d.c:1143
double dt_atof(const char *str)
Definition iop/lut3d.c:375
uint8_t parse_cube_line(char *line, char(*token)[50])
Definition iop/lut3d.c:456
const char * name()
Definition iop/lut3d.c:156
void module_moved_callback(gpointer instance, dt_iop_module_t *self)
Definition iop/lut3d.c:1444
static void filepath_callback(GtkWidget *widget, dt_iop_module_t *self)
Definition iop/lut3d.c:1164
void gui_init(dt_iop_module_t *self)
Definition iop/lut3d.c:1449
static void button_clicked(GtkWidget *widget, dt_iop_module_t *self)
Definition iop/lut3d.c:1325
#define DT_IOP_LUT3D_CLUT_LEVEL
Definition iop/lut3d.c:75
void filepath_set_unix_separator(char *filepath)
Definition iop/lut3d.c:884
void get_cache_filename(const char *const lutname, char *const cache_filename)
Definition iop/lut3d.c:228
dt_iop_lut3d_colorspace_t
Definition iop/lut3d.c:79
@ DT_IOP_SRGB
Definition iop/lut3d.c:80
@ DT_IOP_ITUR_BT1886
Definition iop/lut3d.c:85
@ DT_IOP_LIN_REC2020
Definition iop/lut3d.c:84
@ DT_IOP_ARGB
Definition iop/lut3d.c:81
@ DT_IOP_REC709
Definition iop/lut3d.c:82
@ DT_IOP_LIN_REC709
Definition iop/lut3d.c:83
static void update_filepath_combobox(dt_iop_lut3d_gui_data_t *g, char *filepath, char *lutfolder)
Definition iop/lut3d.c:1281
#define DT_IOP_LUT3D_MAX_PATHNAME
Definition iop/lut3d.c:73
void gui_cleanup(dt_iop_module_t *self)
Definition iop/lut3d.c:1531
static gint array_str_cmp(gconstpointer a, gconstpointer b)
Definition iop/lut3d.c:1275
void cleanup_global(dt_iop_module_so_t *module)
Definition iop/lut3d.c:911
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition iop/lut3d.c:180
int flags()
Definition iop/lut3d.c:170
uint16_t calculate_clut_haldclut(dt_iop_lut3d_params_t *const p, const char *const filepath, float **clut)
Definition iop/lut3d.c:273
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition iop/lut3d.c:1154
dt_lut3d_cols_t
Definition iop/lut3d.c:120
@ DT_LUT3D_COL_NAME
Definition iop/lut3d.c:121
@ DT_LUT3D_NUM_COLS
Definition iop/lut3d.c:123
@ DT_LUT3D_COL_VISIBLE
Definition iop/lut3d.c:122
static void _show_hide_colorspace(dt_iop_module_t *self)
Definition iop/lut3d.c:1397
uint16_t calculate_clut_cube(const char *const filepath, float **clut)
Definition iop/lut3d.c:511
#define DT_IOP_LUT3D_MAX_LUTNAME
Definition iop/lut3d.c:74
void init_global(dt_iop_module_so_t *module)
Definition iop/lut3d.c:891
static void remove_root_from_path(const char *const lutfolder, char *const filepath)
Definition iop/lut3d.c:1249
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
Definition iop/lut3d.c:757
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition iop/lut3d.c:185
const char * model
int dt_ioppr_get_iop_order(GList *iop_order_list, const char *op_name, const int multi_priority)
Return the iop_order for a given operation/instance pair.
Definition iop_order.c:868
dt_iop_order_iccprofile_info_t * dt_ioppr_add_profile_info_to_list(struct dt_develop_t *dev, const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
void dt_ioppr_transform_image_colorspace_rgb(const float *const restrict image_in, float *const restrict image_out, const int width, const int height, const dt_iop_order_iccprofile_info_t *const profile_info_from, const dt_iop_order_iccprofile_info_t *const profile_info_to, const char *message)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
int dt_ioppr_transform_image_colorspace_rgb_cl(const int devid, cl_mem dev_img_in, cl_mem dev_img_out, const int width, const int height, const dt_iop_order_iccprofile_info_t *const profile_info_from, const dt_iop_order_iccprofile_info_t *const profile_info_to, const char *message)
const int t
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
dt_lut3d_interpolation_t
Definition lut3d.h:25
void lut3d_decompress_clut(const unsigned char *const input_keypoints, const unsigned int nb_input_keypoints, const unsigned int output_resolution, float *const output_clut_data, const char *const filename)
Definition lut3dgmic.cpp:44
void lut3d_clear_lutname_list(void *g)
void lut3d_add_lutname_to_list(void *g, const char *const lutname)
unsigned int lut3d_get_cached_clut(float *const output_clut_data, const unsigned int output_resolution, const char *const filename)
gboolean lut3d_read_gmz(int *const nb_keypoints, unsigned char *const keypoints, const char *const filename, int *const nb_lut, void *widget, const char *const lutname, const gboolean newlutname)
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2136
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2332
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2127
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
@ DT_SIGNAL_DEVELOP_MODULE_MOVED
This signal is raised when order of modules in pipeline is changed.
Definition signal.h:218
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
static gboolean entry_callback(GtkEntry *entry, gpointer user_data)
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_develop_t * develop
Definition darktable.h:770
Definition bauhaus.h:130
dt_bauhaus_data_t data
Definition bauhaus.h:218
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
GList * iop_order_list
Definition develop.h:285
GList * iop
Definition develop.h:279
int32_t reset
Definition gtk.h:172
dt_ui_t * ui
Definition gtk.h:164
png_infop info_ptr
Definition imageio_png.h:41
png_structp png_ptr
Definition imageio_png.h:40
unsigned int channels
Definition format.h:54
dt_iop_lut3d_params_t params
Definition iop/lut3d.c:130
GtkWidget * interpolation
Definition iop/lut3d.c:110
char c_clut[2048 *2 *3]
Definition iop/lut3d.c:101
dt_iop_lut3d_colorspace_t colorspace
Definition iop/lut3d.c:98
dt_iop_lut3d_interpolation_t interpolation
Definition iop/lut3d.c:99
dt_iop_global_data_t * data
Definition imageop.h:233
dt_iop_params_t * default_params
Definition imageop.h:307
GtkWidget * widget
Definition imageop.h:337
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
GModule *dt_dev_operation_t op
Definition imageop.h:256
dt_iop_global_data_t * global_data
Definition imageop.h:314
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72
dt_bauhaus_combobox_data_t combobox
Definition bauhaus.h:160