From 287c16a54900bd065ed927f06d8754f3bd602fee Mon Sep 17 00:00:00 2001 From: Mario Zimmermann Date: Fri, 31 Jul 2026 19:54:20 +0200 Subject: [PATCH 1/4] add image dimension filter --- src/common/collection.c | 18 ++++++++++++++++-- src/common/collection.h | 5 +++-- src/libs/filtering.c | 4 ++++ src/libs/filters/misc.c | 27 ++++++++++++++++++++++++++- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/common/collection.c b/src/common/collection.c index db6cc11df846..800c39e2eafb 100644 --- a/src/common/collection.c +++ b/src/common/collection.c @@ -656,6 +656,8 @@ const char *dt_collection_name_untranslated(const dt_collection_properties_t pro return N_("group"); case DT_COLLECTION_PROP_DUPLICATES: return N_("duplicates"); + case DT_COLLECTION_PROP_DIMENSIONS: + return N_("image dimensions"); case DT_COLLECTION_PROP_LOCAL_COPY: return N_("local copy"); case DT_COLLECTION_PROP_MODULE: @@ -1600,10 +1602,22 @@ static gchar *get_query_string(const dt_collection_properties_t property, const ("(mi.version > (SELECT MIN(version) FROM main.images" " WHERE film_id = mi.film_id AND filename = mi.filename)) "); } - else // by default, we select all the images + break; + + case DT_COLLECTION_PROP_DIMENSIONS: // image dimensions + query = g_strdup("("); + // handle the possibility of multiple values + elems = _strsplit_quotes(escaped_text, ",", -1); + for(int i = 0; i < g_strv_length(elems); i++) { - query = g_strdup("1 = 1"); + gchar *dims = _add_wildcards(elems[i]); + dt_util_str_cat(&query, + "%smi.width || 'x' || mi.height LIKE '%%%s%%'", + i>0?" OR ":"", dims); + g_free(dims); } + g_strfreev(elems); + dt_util_str_cat(&query, ")"); break; case DT_COLLECTION_PROP_ASPECT_RATIO: // aspect ratio diff --git a/src/common/collection.h b/src/common/collection.h index f9965163e2a5..ef96924f5ff4 100644 --- a/src/common/collection.h +++ b/src/common/collection.h @@ -119,10 +119,11 @@ typedef enum dt_collection_properties_t DT_COLLECTION_PROP_EXPOSURE_BIAS, - DT_COLLECTION_PROP_DUPLICATES, - DT_COLLECTION_PROP_MONTH, + DT_COLLECTION_PROP_DUPLICATES, + DT_COLLECTION_PROP_DIMENSIONS, + // all new collection types need to be added before DT_COLLECTION_PROP_LAST, // which separates actual collection types from special flag values DT_COLLECTION_PROP_LAST, diff --git a/src/libs/filtering.c b/src/libs/filtering.c index 978a4d869d08..4a372428a183 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -242,6 +242,7 @@ static _filter_t filters[] { DT_COLLECTION_PROP_EXPOSURE_BIAS, _exposure_bias_widget_init, _exposure_bias_update }, { DT_COLLECTION_PROP_GROUP_ID, _misc_widget_init, _misc_update }, { DT_COLLECTION_PROP_DUPLICATES, _duplicates_widget_init, _duplicates_update }, + { DT_COLLECTION_PROP_DIMENSIONS, _misc_widget_init, _misc_update }, { DT_COLLECTION_PROP_LOCAL_COPY, _local_copy_widget_init, _local_copy_update }, { DT_COLLECTION_PROP_HISTORY, _history_widget_init, _history_update }, { DT_COLLECTION_PROP_ORDER, _module_order_widget_init, _module_order_update }, @@ -921,6 +922,7 @@ static gboolean _rule_show_popup(GtkWidget *widget, dt_lib_filtering_rule_t *rul ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_FLASH); ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_EXPOSURE_PROGRAM); ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_METERING_MODE); + ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_DIMENSIONS); _popup_add_item(spop, _("darktable"), 0, TRUE, NULL, NULL, self, 0.0); ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_GROUP_ID); @@ -982,6 +984,7 @@ static void _populate_rules_combo(GtkWidget *w) ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_FLASH); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_EXPOSURE_PROGRAM); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_METERING_MODE); + ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_DIMENSIONS); dt_bauhaus_combobox_add_section(w, _("darktable")); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_GROUP_ID); @@ -1648,6 +1651,7 @@ static void _topbar_populate_rules_combo(GtkWidget *w, dt_lib_filtering_t *d) ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_FLASH); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_EXPOSURE_PROGRAM); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_METERING_MODE); + ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_DIMENSIONS); // if we have not added any entry, remove the section if(nb == dt_bauhaus_combobox_length(w)) dt_bauhaus_combobox_remove_at(w, nb - 1); diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index 2b6172bc932d..227a87ad2c98 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2024 darktable developers. + Copyright (C) 2024-2026 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 @@ -20,6 +20,7 @@ This file implements the necessary routines for all text baseed filters for the filtering module */ +#include "common/collection.h" typedef struct _widgets_misc_t { dt_lib_filtering_rule_t *rule; @@ -113,6 +114,10 @@ void _misc_tree_update(_widgets_misc_t *misc) table = g_strdup("metering_mode"); tooltip = g_strdup(_("no metering mode defined")); } + else if(misc->prop == DT_COLLECTION_PROP_DIMENSIONS) + { + tooltip = g_strdup(_("no image dimensions defined")); + } // SQL if(misc->prop == DT_COLLECTION_PROP_CAMERA) @@ -155,6 +160,18 @@ void _misc_tree_update(_widgets_misc_t *misc) d->last_where_ext); // clang-format on } + else if(misc->prop == DT_COLLECTION_PROP_DIMENSIONS) + { + // clang-format off + g_snprintf(query, sizeof(query), + "SELECT mi.width || 'x' || mi.height AS dim, COUNT(*) AS count" + " FROM main.images AS mi" + " WHERE %s" + " GROUP BY dim" + " ORDER BY dim", + d->last_where_ext); + // clang-format on + } else // white balance, flash, exposure program, metering mode { // clang-format off @@ -449,6 +466,14 @@ static void _misc_widget_init(dt_lib_filtering_rule_t *rule, "multiple values can be separated by ','\n" "\nright-click to get existing group ids")); } + else if(prop == DT_COLLECTION_PROP_DIMENSIONS) + { + name = g_strdup(_("image dimensions")); + tooltip = g_strdup(_("enter the image dimensions to search.\n" + "use the format widthxheight, i.e. 6000x4000.\n" + "multiple values can be separated by ','\n" + "\nright-click to get existing image dimensions")); + } gtk_entry_set_placeholder_text(GTK_ENTRY(misc->name), name); gtk_widget_set_tooltip_text(misc->name, tooltip); From 18a47d956d060a12b11eb22b3728ffc43b9f43c4 Mon Sep 17 00:00:00 2001 From: Mario Zimmermann Date: Sat, 1 Aug 2026 19:23:52 +0200 Subject: [PATCH 2/4] ensure collection enum order --- src/common/collection.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/collection.h b/src/common/collection.h index ef96924f5ff4..d0f54315db3e 100644 --- a/src/common/collection.h +++ b/src/common/collection.h @@ -119,9 +119,10 @@ typedef enum dt_collection_properties_t DT_COLLECTION_PROP_EXPOSURE_BIAS, + DT_COLLECTION_PROP_DUPLICATES, + DT_COLLECTION_PROP_MONTH, - DT_COLLECTION_PROP_DUPLICATES, DT_COLLECTION_PROP_DIMENSIONS, // all new collection types need to be added before DT_COLLECTION_PROP_LAST, From 7634e33b7f132bf48723dca3930a4f816d5e3c2e Mon Sep 17 00:00:00 2001 From: Mario Zimmermann Date: Sun, 2 Aug 2026 14:55:19 +0200 Subject: [PATCH 3/4] improve image dimension filter tooltip --- src/libs/filters/misc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index 227a87ad2c98..94558b966b2a 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -470,7 +470,10 @@ static void _misc_widget_init(dt_lib_filtering_rule_t *rule, { name = g_strdup(_("image dimensions")); tooltip = g_strdup(_("enter the image dimensions to search.\n" - "use the format widthxheight, i.e. 6000x4000.\n" + "use the format widthxheight, i.e.\n" + "'6000x4000' for a full match,\n" + "'6000x' for width only,\n" + "'x4000' for height only.\n" "multiple values can be separated by ','\n" "\nright-click to get existing image dimensions")); } From 7f488bebe75bc9b94aec056edfaa05c3c583a6b4 Mon Sep 17 00:00:00 2001 From: Mario Zimmermann Date: Mon, 3 Aug 2026 07:50:19 +0200 Subject: [PATCH 4/4] add missing collection filter types to lua --- src/libs/collect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/collect.c b/src/libs/collect.c index e0306005bd89..0d2127f1bc77 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -4369,7 +4369,9 @@ void init(struct dt_lib_module_t *self) luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_LOCAL_COPY); luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_MODULE); luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_ORDER); + luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_DUPLICATES); luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_MONTH); + luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_DIMENSIONS); } #endif #undef MAX_RULES