Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ changes (where available).
colorin module, selectable manually. The existing "embedded
matrix" profile remains the default for fresh imports and
reloading defaults.
DNG files now also supports provided "ProfileHueSatMapData"
and applies these automatically if "DNG forward matrix" is
selected as the colorin profile.
Some images have "ProfileHueSatMapData" but no forward matrix.
You may chose the "DNG embedded look" to apply the DNG look.

- The highlights module will be disabled automatically when a raw
image with a clean history is opended in darkroom the first time
Expand Down
3 changes: 3 additions & 0 deletions src/common/colorspaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -1836,6 +1836,8 @@ const char *dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type,
return _("Display P3");
case DT_COLORSPACE_FORWARD_MATRIX:
return _("DNG forward matrix");
case DT_COLORSPACE_DNG_LOOK:
return _("DNG embedded look");
case DT_COLORSPACE_LAST:
break;
}
Expand Down Expand Up @@ -2654,6 +2656,7 @@ gboolean dt_colorspaces_profile_is_wide_gamut(const dt_colorspaces_color_profile
case DT_COLORSPACE_DISPLAY2:
case DT_COLORSPACE_EMBEDDED_ICC:
case DT_COLORSPACE_EMBEDDED_MATRIX:
case DT_COLORSPACE_DNG_LOOK:
case DT_COLORSPACE_STANDARD_MATRIX:
case DT_COLORSPACE_ENHANCED_MATRIX:
case DT_COLORSPACE_VENDOR_MATRIX:
Expand Down
3 changes: 2 additions & 1 deletion src/common/colorspaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ typedef enum dt_colorspaces_color_profile_type_t
DT_COLORSPACE_HLG_P3 = 25,
DT_COLORSPACE_DISPLAY_P3 = 26,
DT_COLORSPACE_FORWARD_MATRIX = 27,
DT_COLORSPACE_LAST = 28
DT_COLORSPACE_DNG_LOOK = 28,
DT_COLORSPACE_LAST = 29
} dt_colorspaces_color_profile_type_t;

typedef enum dt_colorspaces_color_mode_t
Expand Down
55 changes: 50 additions & 5 deletions src/common/exif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1077,8 +1077,8 @@ static bool _valid_dng_matrix(const float *M)
return fabsf(det) > 1e-6f;
}

static void _check_forward_matrix(Exiv2::ExifData &exifData,
dt_image_t *img)
static int _check_forward_matrix(Exiv2::ExifData &exifData,
dt_image_t *img)
{
Exiv2::ExifData::const_iterator pos;
dt_mark_colormatrix_invalid(&img->dng_forward_matrix[0]);
Expand Down Expand Up @@ -1202,7 +1202,7 @@ static void _check_forward_matrix(Exiv2::ExifData &exifData,
// We only want a valid forward matrix if we got an illu and matrix are good
const gboolean has_forward_illuminant = sel_illu >= 0 && sel_illu < 3 && has_FM[sel_illu];
if(!has_forward_illuminant)
return;
return sel_illu;

// CameraToXYZ = ForwardMatrix * Inverse(AnalogBalance * CameraCalibration)
// (white balance D is applied later, upstream, via temperature.iop's wb_coeffs)
Expand All @@ -1226,7 +1226,52 @@ static void _check_forward_matrix(Exiv2::ExifData &exifData,
illu[2] ? ", [3] " : "", illu[2] ? _illu_to_str(illu[2]) : "" );
_print_matrix_data("img forward matrix", 0, img->dng_forward_matrix);
_print_matrix_data(has_CC[sel_illu] ? "calibration matrix" : "ident calibration matrix", 0, CC[sel_illu]);
return sel_illu;
}
return sel_illu;
}

static void _check_profile_look_table(Exiv2::ExifData &exifData,
dt_image_t *img,
const int sel_illu)
{
g_free(img->profile_hsm_data);
img->profile_hsm_data = NULL;
img->profile_hsm_hue_div = img->profile_hsm_sat_div = img->profile_hsm_val_div = 0;
Exiv2::ExifData::const_iterator dims_pos =
exifData.findKey(Exiv2::ExifKey("Exif.Image.ProfileHueSatMapDims"));
if(dims_pos != exifData.end() && dims_pos->count() == 3)
{
const auto hue_div = dims_pos->toLong(0);
const auto sat_div = dims_pos->toLong(1);
const auto val_div = dims_pos->toLong(2);
if(hue_div >= 1 && sat_div >= 2 && val_div >= 1
&& hue_div <= G_MAXINT / 3 / sat_div / val_div)
{
const int n_entries = hue_div * sat_div * val_div * 3;
const char *keys[] = {
"Exif.Image.ProfileHueSatMapData1",
"Exif.Image.ProfileHueSatMapData2",
#if EXIV2_TEST_VERSION(0,27,4)
"Exif.Image.ProfileHueSatMapData3"
#endif
};
const int index = sel_illu >= 0 && sel_illu < (int)G_N_ELEMENTS(keys) ? sel_illu : 0;
Exiv2::ExifData::const_iterator pos = exifData.findKey(Exiv2::ExifKey(keys[index]));
if(pos != exifData.end() && (int)pos->count() == n_entries)
{
img->profile_hsm_data = (float *)g_malloc_n(n_entries, sizeof(float));
for(int i = 0; i < n_entries; i++)
img->profile_hsm_data[i] = pos->toFloat(i);
img->profile_hsm_hue_div = hue_div;
img->profile_hsm_sat_div = sat_div;
img->profile_hsm_val_div = val_div;
dt_print(DT_DEBUG_IMAGEIO, "[exif] found ProfileHueSatMapData%d (%dx%dx%d)",
index + 1, img->profile_hsm_hue_div, img->profile_hsm_sat_div, img->profile_hsm_val_div);
}
}
}

}

static gboolean _check_dng_opcodes(Exiv2::ExifData &exifData,
Expand Down Expand Up @@ -1682,7 +1727,8 @@ void dt_exif_img_check_additional_tags(dt_image_t *img,
_check_dng_opcodes(exifData, img);
_check_lens_correction_data(exifData, img);
_check_linear_response_limit(exifData, img);
_check_forward_matrix(exifData, img);
const int sel_illu = _check_forward_matrix(exifData, img);
_check_profile_look_table(exifData, img, sel_illu);
_check_highlight_preservation(exifData, img);
_check_shading_compensation(exifData, img);
}
Expand Down Expand Up @@ -3298,7 +3344,6 @@ int dt_exif_read_blob(uint8_t **buf,
"Exif.Image.ProfileHueSatMapDims",
"Exif.Image.ProfileHueSatMapData1",
"Exif.Image.ProfileHueSatMapData2",
"Exif.Image.ProfileToneCurve",
"Exif.Image.ProfileEmbedPolicy",
"Exif.Image.ProfileCopyright",
"Exif.Image.ForwardMatrix1",
Expand Down
2 changes: 2 additions & 0 deletions src/common/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,8 @@ void dt_image_init(dt_image_t *img)
img->raw_white_point = 16384; // 2^14
dt_mark_colormatrix_invalid(&img->d65_color_matrix[0]);
dt_mark_colormatrix_invalid(&img->dng_forward_matrix[0]);
img->profile_hsm_data = NULL;
img->profile_hsm_hue_div = img->profile_hsm_sat_div = img->profile_hsm_val_div = 0;
img->profile = NULL;
img->profile_size = 0;
img->colorspace = DT_IMAGE_COLORSPACE_NONE;
Expand Down
4 changes: 4 additions & 0 deletions src/common/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ typedef struct dt_image_t

float d65_color_matrix[9]; // the 3x3 matrix embedded in some DNGs
float dng_forward_matrix[9]; // the 3x3 forward matrix supplied in some DNG files
float *profile_hsm_data; // hue_div * sat_div * val_div * 3 floats, owned by the struct
int profile_hsm_hue_div;
int profile_hsm_sat_div;
int profile_hsm_val_div;
uint8_t *profile; // embedded profile, for example from JPEGs
uint32_t profile_size;
dt_image_colorspace_t colorspace; // the colorspace that is
Expand Down
4 changes: 4 additions & 0 deletions src/common/image_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ static void _image_cache_allocate(void *data,
g_free(img->profile);
img->profile = NULL;
img->profile_size = 0;
g_free(img->profile_hsm_data);
img->profile_hsm_data = NULL;
img->profile_hsm_hue_div = img->profile_hsm_sat_div = img->profile_hsm_val_div = 0;
img->colorspace = sqlite3_column_int(stmt, 23);
img->version = sqlite3_column_int(stmt, 24);
img->raw_black_level = sqlite3_column_int(stmt, 25);
Expand Down Expand Up @@ -205,6 +208,7 @@ static void _image_cache_deallocate(void *data, dt_cache_entry_t *entry)
{
dt_image_t *img = entry->data;
g_free(img->profile);
g_free(img->profile_hsm_data);
g_list_free_full(img->dng_gain_maps, g_free);
g_free(img);
entry->data = NULL;
Expand Down
6 changes: 6 additions & 0 deletions src/common/iop_order.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const dt_iop_order_entry_t legacy_order[] = {
{ {25.0f }, "profile_gamma", 0},
{ {26.0f }, "hazeremoval", 0},
{ {27.0f }, "colorin", 0},
{ {27.1f }, "dng_look", 0},
{ {27.5f }, "channelmixerrgb", 0},
{ {27.5f }, "contrastntexture", 0},
{ {27.5f }, "diffuse", 0},
Expand Down Expand Up @@ -221,6 +222,7 @@ const dt_iop_order_entry_t v30_order[] = {
{ {26.0f }, "profile_gamma", 0},
{ {27.0f }, "equalizer", 0},
{ {28.0f }, "colorin", 0},
{ {28.1f }, "dng_look", 0},
{ {28.5f }, "channelmixerrgb", 0},
{ {28.5f }, "contrastntexture", 0},
{ {28.5f }, "diffuse", 0},
Expand Down Expand Up @@ -344,6 +346,7 @@ const dt_iop_order_entry_t v50_order[] = {
{ {26.0f }, "profile_gamma", 0},
{ {27.0f }, "equalizer", 0},
{ {28.0f }, "colorin", 0},
{ {28.1f }, "dng_look", 0},
{ {28.5f }, "channelmixerrgb", 0},
{ {28.5f }, "contrastntexture", 0},
{ {28.5f }, "diffuse", 0},
Expand Down Expand Up @@ -441,6 +444,7 @@ const dt_iop_order_entry_t v30_jpg_order[] = {
{ { 8.5f }, "demosaicscale", 0 },
// all the modules between [8.5; 28] expect linear RGB, so they need to be moved after colorin
{ { 28.0f }, "colorin", 0 },
{ { 28.0f }, "dng_look", 0 },
// moved modules : (copy-pasted in the same order)
{ { 28.0f }, "denoiseprofile", 0},
{ { 28.0f }, "bilateral", 0},
Expand Down Expand Up @@ -567,6 +571,7 @@ const dt_iop_order_entry_t v50_jpg_order[] = {
{ { 8.5f }, "demosaicscale", 0 },
// all the modules between [8.5; 28] expect linear RGB, so they need to be moved after colorin
{ { 28.0f }, "colorin", 0 },
{ { 28.0f }, "dng_look", 0 },
// moved modules : (copy-pasted in the same order)
{ { 28.0f }, "denoiseprofile", 0},
{ { 28.0f }, "bilateral", 0},
Expand Down Expand Up @@ -767,6 +772,7 @@ void dt_ioppr_migrate_legacy_iop_order_list(GList *iop_order_list)
_insert_before_after(iop_order_list, "highlights", "rasterfile", TRUE);
_insert_before_after(iop_order_list, "demosaic", "demosaicscale", FALSE);
_insert_before_after(iop_order_list, "colorbalance", "colorharmonizer", TRUE);
_insert_before_after(iop_order_list, "colorin", "dng_look", FALSE);
}

static dt_iop_order_t _ioppr_get_default_iop_order_version(const dt_imgid_t imgid)
Expand Down
6 changes: 4 additions & 2 deletions src/common/iop_profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -937,8 +937,10 @@ dt_ioppr_set_pipe_input_profile_info(struct dt_develop_t *dev,
dt_image_cache_write_release_info(wimg, DT_IMAGE_CACHE_RELAXED, NULL);
}

if(ptype >= DT_COLORSPACE_EMBEDDED_ICC
&& ptype <= DT_COLORSPACE_ALTERNATE_MATRIX)
if((ptype >= DT_COLORSPACE_EMBEDDED_ICC
&& ptype <= DT_COLORSPACE_ALTERNATE_MATRIX)
|| ptype == DT_COLORSPACE_FORWARD_MATRIX
|| ptype == DT_COLORSPACE_DNG_LOOK)
{
/* We have a camera input matrix, these are not generated from files but in colorin,
* so we need to fetch and replace them from somewhere.
Expand Down
4 changes: 4 additions & 0 deletions src/common/mipmap_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,8 @@ void dt_mipmap_cache_get_with_caller(dt_mipmap_buffer_t *buf,
dt_image_t DT_ALIGNED_ARRAY buffered_image;
const dt_image_t *cimg = dt_image_cache_get(imgid, 'r');
buffered_image = *cimg;
buffered_image.profile_hsm_data = NULL;
buffered_image.profile_hsm_hue_div = buffered_image.profile_hsm_sat_div = buffered_image.profile_hsm_val_div = 0;
// dt_image_t *img = dt_image_cache_write_get(cimg);
// dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED);
dt_image_cache_read_release(cimg);
Expand All @@ -1010,6 +1012,7 @@ void dt_mipmap_cache_get_with_caller(dt_mipmap_buffer_t *buf,
{
// swap back new image data:
dt_image_t *img = dt_image_cache_get(imgid, 'w');
g_free(img->profile_hsm_data);
*img = buffered_image;
img->load_status = DT_IMAGEIO_OK;
// dt_print(DT_DEBUG_ALWAYS, "[mipmap read get] initializing full buffer img %u with %u %u -> %d %d (%p)",
Expand All @@ -1019,6 +1022,7 @@ void dt_mipmap_cache_get_with_caller(dt_mipmap_buffer_t *buf,
}
else
{
g_free(buffered_image.profile_hsm_data);
dt_print(DT_DEBUG_PIPE, "[mipmap read get] error loading ID=%d", imgid);
//
// we can only return a zero dimension buffer if the buffer
Expand Down
1 change: 1 addition & 0 deletions src/iop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ add_iop(equalizer "equalizer.c")
add_iop(rgbcurve "rgbcurve.c")
add_iop(colorbalance "colorbalance.c" DEFAULT_VISIBLE)
add_iop(colorin "colorin.c" DEFAULT_VISIBLE)
add_iop(dng_look "dng_look.c")
add_iop(colorout "colorout.c")
add_iop(colorchecker "colorchecker.c")
add_iop(clipping "clipping.c" DEFAULT_VISIBLE)
Expand Down
20 changes: 19 additions & 1 deletion src/iop/colorin.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,16 @@ static void _profile_changed(GtkWidget *widget, dt_iop_module_t *self)
dt_colorspaces_color_profile_t *pp = prof->data;
if(pp->in_pos == pos)
{
const gboolean old_look = p->type == DT_COLORSPACE_FORWARD_MATRIX
|| p->type == DT_COLORSPACE_DNG_LOOK;
const gboolean new_look = pp->type == DT_COLORSPACE_FORWARD_MATRIX
|| pp->type == DT_COLORSPACE_DNG_LOOK;
p->type = pp->type;
memcpy(p->filename, pp->filename, sizeof(p->filename));
dt_dev_add_history_item(darktable.develop, self, TRUE);
// top-only sync would leave dng_look's enablement stale on the other pipes
if(old_look != new_look)
dt_dev_pipe_synch_all(self->dev);

DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_CONTROL_PROFILE_USER_CHANGED,
DT_COLORSPACES_PROFILE_TYPE_INPUT);
Expand Down Expand Up @@ -1384,7 +1391,7 @@ void commit_params(dt_iop_module_t *self,
else
type = DT_COLORSPACE_EMBEDDED_MATRIX;
}
if(type == DT_COLORSPACE_EMBEDDED_MATRIX)
if(type == DT_COLORSPACE_EMBEDDED_MATRIX || type == DT_COLORSPACE_DNG_LOOK)
{
// embedded matrix, hopefully D65
const dt_image_t *cimg = dt_image_cache_get(pipe->image.id, 'r');
Expand Down Expand Up @@ -1964,6 +1971,7 @@ static void update_profile_list(dt_iop_module_t *self)
// some file formats like jpeg can have an embedded color profile
// currently we only support jpeg, j2k, tiff and png
const dt_image_t *cimg = dt_image_cache_get(self->dev->image_storage.id, 'r');
const gboolean has_dng_look = cimg && cimg->profile_hsm_data;
if(cimg && cimg->profile)
{
dt_colorspaces_color_profile_t *prof = calloc(1, sizeof(dt_colorspaces_color_profile_t));
Expand All @@ -1983,6 +1991,16 @@ static void update_profile_list(dt_iop_module_t *self)
prof->type = DT_COLORSPACE_EMBEDDED_MATRIX;
g->image_profiles = g_list_append(g->image_profiles, prof);
prof->in_pos = ++pos;

if(!dt_is_valid_colormatrix(self->dev->image_storage.dng_forward_matrix[0]) && has_dng_look)
{
prof = calloc(1, sizeof(dt_colorspaces_color_profile_t));
g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_DNG_LOOK, ""),
sizeof(prof->name));
prof->type = DT_COLORSPACE_DNG_LOOK;
g->image_profiles = g_list_append(g->image_profiles, prof);
prof->in_pos = ++pos;
}
}

// use the DNG forward matrix if present -- gives the "as intended by
Expand Down
Loading
Loading