/* This file is part of darktable, copyright (c) 2019 edgardo hoszowski. 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 . */ #include "color_conversion.h" #include "rgb_norms.h" float get_gamma(const float x, const float gamma) { return dtcl_pow(x, gamma); } float get_lut_gamma(const float x, const float gamma, read_only image2d_t lut) { if(x > 1.0f) { return get_gamma(x, gamma); } else { const int xi = clamp((int)(x * 0x10000ul), 0, 0xffff); const int2 p = (int2)((xi & 0xff), (xi >> 8)); return read_imagef(lut, sampleri, p).x; } } float get_contrast(const float x, const float contrast, const float middle_grey, const float inv_middle_grey) { return dtcl_pow(x * inv_middle_grey, contrast) * middle_grey; } float get_lut_contrast(const float x, const float contrast, const float middle_grey, const float inv_middle_grey, read_only image2d_t lut) { if(x > 1.0f) { return get_contrast(x, contrast, middle_grey, inv_middle_grey); } else { const int xi = clamp((int)(x * 0x10000ul), 0, 0xffff); const int2 p = (int2)((xi & 0xff), (xi >> 8)); return read_imagef(lut, sampleri, p).x; } } float hlcurve(const float level, const float hlcomp, const float hlrange) { if(hlcomp > 0.0f) { float val = level + (hlrange - 1.f); // to avoid division by zero if(val == 0.0f) { val = 0.000001f; } float Y = val / hlrange; Y *= hlcomp; // to avoid log(<=0) if(Y <= -1.0f) { Y = -.999999f; } float R = hlrange / (val * hlcomp); return log1p(Y) * R; } else { return 1.f; } } kernel void basicadj(read_only image2d_t in, write_only image2d_t out, const int width, const int height, read_only image2d_t lut_gamma, read_only image2d_t lut_contrast, const float black_point, const float scale, const int process_gamma, const float gamma, const int plain_contrast, const int preserve_colors, const float contrast, const int process_saturation_vibrance, const float saturation, const float vibrance, const int process_hlcompr, const float hlcomp, const float hlrange, const float middle_grey, const float inv_middle_grey, constant dt_colorspaces_iccprofile_info_cl_t *profile_info, read_only image2d_t lut, const int use_work_profile) { const int x = get_global_id(0); const int y = get_global_id(1); if(x >= width || y >= height) return; float4 pixel = read_imagef(in, sampleri, (int2)(x, y)); const float w = pixel.w; // exposure pixel = (pixel - black_point) * scale; // highlight compression if(process_hlcompr) { const float lum = (use_work_profile == 0) ? dt_camera_rgb_luminance(pixel): get_rgb_matrix_luminance(pixel, profile_info, profile_info->matrix_in, lut); if(lum > 0.f) { const float ratio = hlcurve(lum, hlcomp, hlrange); pixel *= ratio; } } // gamma if(process_gamma) { if(pixel.x > 0.f) pixel.x = get_lut_gamma(pixel.x, gamma, lut_gamma); if(pixel.y > 0.f) pixel.y = get_lut_gamma(pixel.y, gamma, lut_gamma); if(pixel.z > 0.f) pixel.z = get_lut_gamma(pixel.z, gamma, lut_gamma); } // contrast if(plain_contrast) { if(pixel.x > 0.f) pixel.x = get_lut_contrast(pixel.x, contrast, middle_grey, inv_middle_grey, lut_contrast); if(pixel.y > 0.f) pixel.y = get_lut_contrast(pixel.y, contrast, middle_grey, inv_middle_grey, lut_contrast); if(pixel.z > 0.f) pixel.z = get_lut_contrast(pixel.z, contrast, middle_grey, inv_middle_grey, lut_contrast); } // contrast (with preserve colors) if(preserve_colors != DT_RGB_NORM_NONE) { float ratio = 1.f; const float lum = dt_rgb_norm(pixel, preserve_colors, use_work_profile, profile_info, lut); if(lum > 0.f) { const float contrast_lum = dtcl_pow(lum / middle_grey, contrast) * middle_grey; ratio = contrast_lum / lum; } pixel *= ratio; } // saturation if(process_saturation_vibrance) { const float average = (pixel.x + pixel.y + pixel.z) / 3; const float delta = fast_length(pixel - average); const float P = vibrance * (1 - dtcl_pow(delta, fabs(vibrance))); pixel = average + (saturation + P) * (pixel - average); } pixel.w = w; write_imagef(out, (int2)(x, y), pixel); }