/* This file is part of darktable, Copyright (C) 2019-2022 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 . */ #define cimg_verbosity 0 #include #include #include extern "C" { // otherwise the name will be mangled and the linker won't be able to see the function ... 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); 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); void _lut3d_add_lutname_to_list(void *g, const char *const lutname); void _lut3d_clear_lutname_list(void *g); } 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) { gmic_list image_list; gmic_list image_names; gmic g_instance; g_instance.verbosity = -1; char gmic_cmd[512]; image_list.assign(1); gmic_image &img = image_list[0]; img.assign(1, nb_input_keypoints, 1, 6); // set the keypoint image float *ptr = img; for(size_t i = 0; i < nb_input_keypoints * 6; ++i) *(ptr++) = (float)input_keypoints[i]; // decompress the keypoints to LUT // -cut 0,255 is added to mask GMIC 2.6.4 compressed clut issue. std::snprintf(gmic_cmd, sizeof(gmic_cmd), "-decompress_clut %u,%u,%u -cut 0,255", output_resolution, output_resolution, output_resolution); try { g_instance.run(gmic_cmd, image_list, image_names); } catch(gmic_exception &e) // In case something went wrong. { std::printf("[lut3d gmic] error: \"%s\"\n", e.what()); image_list.assign(0); return; } // save in cache if possible - compatible G'MIC try { std::snprintf(gmic_cmd, sizeof(gmic_cmd), "-o \"%s\",uchar", filename); g_instance.run(gmic_cmd, image_list, image_names); } catch(...) { std::fprintf(stderr, "[lut3d gmic] error - saving cache LUT (does the cache folder exist?)\n"); } // format for dt try { g_instance.run("-div 255.0 -permute cxyz", image_list, image_names); // scale to [0,1] } catch(gmic_exception &e) // In case something went wrong. { std::printf("[lut3d gmic] error: \"%s\"\n", e.what()); image_list.assign(0); return; } const size_t img_size = image_list[0]._width * image_list[0]._height * image_list[0]._depth * image_list[0]._spectrum; std::memcpy(output_clut_data, image_list[0]._data, img_size * sizeof(float)); image_list.assign(0); } unsigned int lut3d_get_cached_clut(float *const output_clut_data, const unsigned int output_resolution, const char *const filename) { gmic_list image_list; gmic_list image_names; char gmic_cmd[512]; gmic g_instance; g_instance.verbosity = -1; // get the cache file try { std::snprintf(gmic_cmd, sizeof(gmic_cmd), "-i \"%s\"", filename); g_instance.run(gmic_cmd, image_list, image_names); } catch(...) { // no cached lut image_list.assign(0); return 0; } // expected LUT size ? const unsigned int output_size = 3 * output_resolution * output_resolution * output_resolution; unsigned int output_res = output_resolution; size_t img_size = image_list[0]._width * image_list[0]._height * image_list[0]._depth * image_list[0]._spectrum; if(output_size < img_size) // downsize the cached lut { std::snprintf(gmic_cmd, sizeof(gmic_cmd), "-r %u,%u,%u,3,3", output_resolution, output_resolution, output_resolution); try { g_instance.run(gmic_cmd, image_list, image_names); } catch(gmic_exception &e) // In case something went wrong. { std::printf("[lut3d gmic] error: \"%s\"\n", e.what()); image_list.assign(0); return 0; } img_size = image_list[0]._width * image_list[0]._height * image_list[0]._depth * image_list[0]._spectrum; } else if(output_size > img_size) // reduce the expected lut size { output_res = image_list[0]._width; } // format for dt try { g_instance.run("-div 255.0 -permute cxyz", image_list, image_names); // scale to [0,1] } catch(gmic_exception &e) // In case something went wrong. { std::printf("[lut3d gmic] error: \"%s\"\n", e.what()); image_list.assign(0); return 0; } std::memcpy(output_clut_data, image_list[0]._data, img_size * sizeof(float)); image_list.assign(0); return output_res; } gboolean lut3d_read_gmz(int *const nb_keypoints, unsigned char *const keypoints, const char *const filename, int *const nb_lut, void *g, const char *const lutname, const gboolean newlutname) { gmic_list image_list; gmic_list image_names; char gmic_cmd[512]; gmic g_instance; g_instance.verbosity = -1; gboolean lut_found = FALSE; // read the compressed lut file try { std::snprintf(gmic_cmd, sizeof(gmic_cmd), "-i \"%s\"", filename); g_instance.run(gmic_cmd, image_list, image_names); } catch(gmic_exception &e) // In case something went wrong. { std::printf("[lut3d gmic] error: \"%s\"\n", e.what()); *nb_lut = 0; image_list.assign(0); image_names.assign(0); return lut_found; } unsigned int l = 0; if(lutname[0]) // find this specific lut { for(unsigned int i = 0; i < image_names._width; ++i) { if(strcmp(image_names[i]._data, lutname) == 0) { l = i; lut_found = TRUE; break; } } } *nb_lut = (int)image_names._width; if(!newlutname) { // list of luts for this new file _lut3d_clear_lutname_list(g); for(unsigned int i = 0; i < image_names._width; ++i) { _lut3d_add_lutname_to_list(g, image_names[i]._data); } } int nb_kp = *nb_keypoints = (int)image_list[l]._height; if(image_list[l]._width == 1 && image_list[l]._height <= 2048 && image_list[l]._depth == 1 && image_list[l]._spectrum == 6) { // color lut gmic_image &img = image_list[l]; for(int i = 0; i < nb_kp * 6; ++i) keypoints[i] = (unsigned char)img[i]; } else if(image_list[l]._width == 1 && image_list[l]._height <= 2048 && image_list[l]._depth == 1 && image_list[l]._spectrum == 4) { // black & white lut gmic_image &img = image_list[l]; for(int i = 0; i < nb_kp * 3; ++i) keypoints[i] = (unsigned char)img[i]; for(int i = 0; i < nb_kp; ++i) keypoints[nb_kp * 3 + i] = keypoints[nb_kp * 4 + i] = keypoints[nb_kp * 5 + i] = (unsigned char)img[nb_kp * 3 + i]; } else std::printf("[lut3d gmic] error: incompatible compressed LUT [%u] %s\n", l, image_names[l]._data); image_list.assign(0); image_names.assign(0); return lut_found; } // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh // vim: shiftwidth=2 expandtab tabstop=2 cindent // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;