Skip to content

Commit 49aee0c

Browse files
committed
Add support for extracting, storing, and filtering on Fujifilm Film Modes
Fujifilm cameras of the X and GF series have support for so-called Film Simulation Modes. These are said to mimic the look of certain types of analogue film. I have wished for the ability to filter on film sim mode for quite a while. In addition, I would like to, in the future, add specific dtstyles for the various modes and allow to apply them by default via apply_camera_style. This commits provides the foundation for that. It adds the ability to filter by and view the film mode in the UI. It also exports the film mode to Lua, so that apply_camera_style could in the future use that.
1 parent 394d89e commit 49aee0c

File tree

12 files changed

+121
-29
lines changed

12 files changed

+121
-29
lines changed

src/common/collection.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ const char *dt_collection_name_untranslated(const dt_collection_properties_t pro
659659
return N_("exposure program");
660660
case DT_COLLECTION_PROP_METERING_MODE:
661661
return N_("metering mode");
662+
case DT_COLLECTION_PROP_FILM_MODE:
663+
return N_("film mode");
662664
case DT_COLLECTION_PROP_LAST:
663665
return NULL;
664666
default:
@@ -1828,6 +1830,30 @@ static gchar *get_query_string(const dt_collection_properties_t property, const
18281830
dt_util_str_cat(&query, ")");
18291831
break;
18301832

1833+
case DT_COLLECTION_PROP_FILM_MODE: // metering mode
1834+
query = g_strdup("(");
1835+
// handle the possibility of multiple values
1836+
elems = _strsplit_quotes(escaped_text, ",", -1);
1837+
for(int i = 0; i < g_strv_length(elems); i++)
1838+
{
1839+
if(!g_strcmp0(elems[i], _("unnamed")))
1840+
{
1841+
dt_util_str_cat(&query,
1842+
"%sfilm_mode_id IN (SELECT id FROM main.film_mode WHERE name IS NULL OR TRIM(name)='')",
1843+
i > 0 ? " OR " : "");
1844+
}
1845+
else
1846+
{
1847+
gchar *film_mode = _add_wildcards(elems[i]);
1848+
dt_util_str_cat(&query, "%sfilm_mode_id IN (SELECT id FROM main.film_mode WHERE name LIKE '%s')",
1849+
i > 0 ? " OR " : "", film_mode);
1850+
g_free(film_mode);
1851+
}
1852+
}
1853+
g_strfreev(elems);
1854+
dt_util_str_cat(&query, ")");
1855+
break;
1856+
18311857
case DT_COLLECTION_PROP_GROUP_ID: // group id
18321858
query = g_strdup("(");
18331859
// handle the possibility of multiple values
@@ -2605,15 +2631,11 @@ void dt_collection_update_query(const dt_collection_t *collection,
26052631
snprintf(confname, sizeof(confname), "plugins/lighttable/collect/mode%1d", i);
26062632
const int mode = dt_conf_get_int(confname);
26072633

2608-
if(*text
2609-
&& g_strcmp0(text, _("unnamed")) != 0
2610-
&& (property == DT_COLLECTION_PROP_CAMERA
2611-
|| property == DT_COLLECTION_PROP_LENS
2612-
|| property == DT_COLLECTION_PROP_WHITEBALANCE
2613-
|| property == DT_COLLECTION_PROP_FLASH
2614-
|| property == DT_COLLECTION_PROP_EXPOSURE_PROGRAM
2615-
|| property == DT_COLLECTION_PROP_METERING_MODE
2616-
|| property == DT_COLLECTION_PROP_GROUP_ID))
2634+
if(*text && g_strcmp0(text, _("unnamed")) != 0
2635+
&& (property == DT_COLLECTION_PROP_CAMERA || property == DT_COLLECTION_PROP_LENS
2636+
|| property == DT_COLLECTION_PROP_WHITEBALANCE || property == DT_COLLECTION_PROP_FLASH
2637+
|| property == DT_COLLECTION_PROP_EXPOSURE_PROGRAM || property == DT_COLLECTION_PROP_METERING_MODE
2638+
|| property == DT_COLLECTION_PROP_FILM_MODE || property == DT_COLLECTION_PROP_GROUP_ID))
26172639
{
26182640
gchar *text_quoted = g_strdup_printf("\"%s\"", text);
26192641
g_free(text);

src/common/collection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ typedef enum dt_collection_properties_t
121121

122122
// all new collection types need to be added before DT_COLLECTION_PROP_LAST,
123123
// which separates actual collection types from special flag values
124+
DT_COLLECTION_PROP_FILM_MODE,
124125
DT_COLLECTION_PROP_LAST,
125126

126127
DT_COLLECTION_PROP_UNDEF,

src/common/database.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
#define LAST_FULL_DATABASE_VERSION_DATA 10
5252

5353
// You HAVE TO bump THESE versions whenever you add an update branches to _upgrade_*_schema_step()!
54-
#define CURRENT_DATABASE_VERSION_LIBRARY 57
54+
#define CURRENT_DATABASE_VERSION_LIBRARY 58
5555
#define CURRENT_DATABASE_VERSION_DATA 13
5656

5757
#define USE_NESTED_TRANSACTIONS
@@ -2967,6 +2967,21 @@ static int _upgrade_library_schema_step(dt_database_t *db,
29672967
"[init] can't add `flash_tagvalue' column to images table in database\n");
29682968
new_version = 57;
29692969
}
2970+
else if(version == 57)
2971+
{
2972+
2973+
TRY_EXEC("CREATE TABLE film_mode"
2974+
" (id INTEGER PRIMARY KEY AUTOINCREMENT,"
2975+
" name VARCHAR)",
2976+
"can't create table film_mode");
2977+
TRY_EXEC("CREATE UNIQUE INDEX film_mode_name ON film_mode (name)",
2978+
"can't create index `film_mode_name' on table `film_mode'");
2979+
2980+
TRY_EXEC("ALTER TABLE main.images ADD COLUMN film_mode_id INTEGER REFERENCES film_mode (id) ON DELETE "
2981+
"RESTRICT ON UPDATE CASCADE",
2982+
"[init] can't add `film_mode' column to images table in database\n");
2983+
new_version = 58;
2984+
}
29702985
else
29712986
new_version = version; // should be the fallback so that calling code sees that we are in an infinite loop
29722987

src/common/exif.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,21 @@ static bool _exif_decode_exif_data(dt_image_t *img, Exiv2::ExifData &exifData)
23352335
}
23362336
};
23372337

2338+
if(FIND_EXIF_TAG("Exif.Fujifilm.FilmMode"))
2339+
{
2340+
const int value = pos->toLong();
2341+
_exif_value_str(value, img->exif_film_mode, sizeof(img->exif_film_mode), pos, exifData);
2342+
}
2343+
else if(FIND_EXIF_TAG("Exif.Fujifilm.Color"))
2344+
{
2345+
// Exif.Fujifilm.Color contains the monochrome mode (sepia, normal b&w,
2346+
// color filters, acros) if FilmMode is not set.
2347+
// In the camera UI, those are all in the same menu, so it makes sense to
2348+
// merge them into the same tag in darktable.
2349+
const int value = pos->toLong();
2350+
_exif_value_str(value, img->exif_film_mode, sizeof(img->exif_film_mode), pos, exifData);
2351+
}
2352+
23382353
img->exif_inited = TRUE;
23392354
return true;
23402355
}

src/common/image.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,15 +1318,15 @@ static dt_imgid_t _image_duplicate_with_version_ext(const dt_imgid_t imgid,
13181318
" orientation, longitude, latitude, altitude, color_matrix,"
13191319
" colorspace, version, max_version,"
13201320
" history_end, position, aspect_ratio, exposure_bias, import_timestamp,"
1321-
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue)"
1321+
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue, film_mode_id)"
13221322
" SELECT NULL, group_id, film_id, width, height, filename,"
13231323
" maker_id, model_id, camera_id, lens_id,"
13241324
" exposure, aperture, iso, focal_length, focus_distance, datetime_taken,"
13251325
" flags, output_width, output_height, crop, raw_parameters,"
13261326
" raw_black, raw_maximum, orientation,"
13271327
" longitude, latitude, altitude, color_matrix, colorspace, NULL, NULL, 0, ?1,"
13281328
" aspect_ratio, exposure_bias, import_timestamp,"
1329-
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue"
1329+
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue, film_mode_id"
13301330
" FROM main.images WHERE id = ?2",
13311331
-1, &stmt, NULL);
13321332
// clang-format on
@@ -2141,6 +2141,7 @@ void dt_image_init(dt_image_t *img)
21412141
memset(img->exif_flash, 0, sizeof(img->exif_flash));
21422142
memset(img->exif_exposure_program, 0, sizeof(img->exif_exposure_program));
21432143
memset(img->exif_metering_mode, 0, sizeof(img->exif_metering_mode));
2144+
memset(img->exif_film_mode, 0, sizeof(img->exif_metering_mode));
21442145
memset(&img->exif_datetime_taken, 0, sizeof(img->exif_datetime_taken));
21452146
memset(img->camera_maker, 0, sizeof(img->camera_maker));
21462147
memset(img->camera_model, 0, sizeof(img->camera_model));
@@ -2548,15 +2549,15 @@ dt_imgid_t dt_image_copy_rename(const dt_imgid_t imgid,
25482549
" raw_black, raw_maximum, orientation,"
25492550
" longitude, latitude, altitude, color_matrix, colorspace, version, max_version,"
25502551
" position, aspect_ratio, exposure_bias,"
2551-
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue)"
2552+
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue, film_mode_id)"
25522553
" SELECT NULL, group_id, ?1 as film_id, width, height, ?2 as filename,"
25532554
" maker_id, model_id, lens_id,"
25542555
" exposure, aperture, iso, focal_length, focus_distance, datetime_taken,"
25552556
" flags, width, height, crop, raw_parameters, raw_black, raw_maximum,"
25562557
" orientation, longitude, latitude, altitude,"
25572558
" color_matrix, colorspace, -1, -1,"
25582559
" ?3, aspect_ratio, exposure_bias,"
2559-
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue"
2560+
" whitebalance_id, flash_id, exposure_program_id, metering_mode_id, flash_tagvalue, film_mode_id"
25602561
" FROM main.images"
25612562
" WHERE id = ?4",
25622563
-1, &stmt, NULL);
@@ -3349,6 +3350,11 @@ int32_t dt_image_get_metering_mode_id(const char *name)
33493350
return _image_get_set_name_id("metering_mode", name);
33503351
}
33513352

3353+
int32_t dt_image_get_film_mode_id(const char *name)
3354+
{
3355+
return _image_get_set_name_id("film_mode", name);
3356+
}
3357+
33523358
int32_t dt_image_get_camera_id(const char *maker, const char *model)
33533359
{
33543360
sqlite3_stmt *stmt;

src/common/image.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ typedef struct dt_image_t
271271
char exif_flash[64];
272272
char exif_exposure_program[64];
273273
char exif_metering_mode[64];
274+
char exif_film_mode[64];
274275
GTimeSpan exif_datetime_taken;
275276

276277
dt_image_correction_type_t exif_correction_type;
@@ -636,6 +637,7 @@ int32_t dt_image_get_whitebalance_id(const char *name);
636637
int32_t dt_image_get_flash_id(const char *name);
637638
int32_t dt_image_get_exposure_program_id(const char *name);
638639
int32_t dt_image_get_metering_mode_id(const char *name);
640+
int32_t dt_image_get_film_mode_id(const char *name);
639641
int32_t dt_image_get_camera_id(const char *maker, const char *model);
640642

641643
G_END_DECLS

src/common/image_cache.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static void _image_cache_allocate(void *data,
4949
" raw_black, raw_maximum, aspect_ratio, exposure_bias,"
5050
" import_timestamp, change_timestamp, export_timestamp, print_timestamp,"
5151
" output_width, output_height, cm.maker, cm.model, cm.alias,"
52-
" wb.name, fl.name, ep.name, mm.name, flash_tagvalue"
52+
" wb.name, fl.name, ep.name, mm.name, flash_tagvalue, fm.name"
5353
" FROM main.images AS mi"
5454
" LEFT JOIN main.cameras AS cm ON cm.id = mi.camera_id"
5555
" LEFT JOIN main.makers AS mk ON mk.id = mi.maker_id"
@@ -59,6 +59,7 @@ static void _image_cache_allocate(void *data,
5959
" LEFT JOIN main.flash AS fl ON fl.id = mi.flash_id"
6060
" LEFT JOIN main.exposure_program AS ep ON ep.id = mi.exposure_program_id"
6161
" LEFT JOIN main.metering_mode AS mm ON mm.id = mi.metering_mode_id"
62+
" LEFT JOIN main.film_mode AS fm ON fm.id = mi.film_mode_id"
6263
" WHERE mi.id = ?1",
6364
-1, &stmt, NULL);
6465
// clang-format on
@@ -155,6 +156,8 @@ static void _image_cache_allocate(void *data,
155156
if(str) g_strlcpy(img->exif_metering_mode, str, sizeof(img->exif_metering_mode));
156157

157158
img->exif_flash_tagvalue = sqlite3_column_int(stmt, 42);
159+
str = (char *)sqlite3_column_text(stmt, 43);
160+
if(str) g_strlcpy(img->exif_film_mode, str, sizeof(img->exif_film_mode));
158161

159162
dt_color_harmony_get(entry->key, &img->color_harmony_guide);
160163

@@ -345,7 +348,8 @@ void dt_image_cache_write_release_info(dt_image_t *img,
345348
" import_timestamp = ?28, change_timestamp = ?29, export_timestamp = ?30,"
346349
" print_timestamp = ?31, output_width = ?32, output_height = ?33,"
347350
" whitebalance_id = ?36, flash_id = ?37,"
348-
" exposure_program_id = ?38, metering_mode_id = ?39, flash_tagvalue = ?41"
351+
" exposure_program_id = ?38, metering_mode_id = ?39, flash_tagvalue = ?41,"
352+
" film_mode_id = ?42"
349353
" WHERE id = ?40",
350354
-1, &stmt, NULL);
351355

@@ -356,6 +360,7 @@ void dt_image_cache_write_release_info(dt_image_t *img,
356360
const int32_t flash_id = dt_image_get_flash_id(img->exif_flash);
357361
const int32_t exposure_program_id = dt_image_get_exposure_program_id(img->exif_exposure_program);
358362
const int32_t metering_mode_id = dt_image_get_metering_mode_id(img->exif_metering_mode);
363+
const int32_t film_mode_id = dt_image_get_film_mode_id(img->exif_film_mode);
359364

360365
// also make sure we update the camera_id and possibly the associated data
361366
// in cameras table.
@@ -412,6 +417,7 @@ void dt_image_cache_write_release_info(dt_image_t *img,
412417
DT_DEBUG_SQLITE3_BIND_INT(stmt, 39, metering_mode_id);
413418
DT_DEBUG_SQLITE3_BIND_INT(stmt, 40, img->id);
414419
DT_DEBUG_SQLITE3_BIND_INT(stmt, 41, img->exif_flash_tagvalue);
420+
DT_DEBUG_SQLITE3_BIND_INT(stmt, 42, film_mode_id);
415421

416422
const int rc = sqlite3_step(stmt);
417423
if(rc != SQLITE_DONE)

src/libs/collect.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,19 @@ static void _list_view(dt_lib_collect_rule_t *dr)
21042104
// clang-format on
21052105
break;
21062106

2107+
case DT_COLLECTION_PROP_FILM_MODE: // lens
2108+
// clang-format off
2109+
g_snprintf(query, sizeof(query),
2110+
"SELECT fm.name AS film_mode, 1, COUNT(*) AS count"
2111+
" FROM main.images AS mi, main.film_mode AS fm"
2112+
" WHERE mi.film_mode_id = fm.id"
2113+
" AND %s"
2114+
" GROUP BY LOWER(film_mode)"
2115+
" ORDER BY LOWER(film_mode) %s", where_ext,
2116+
sort_descending ? "DESC" : "ASC");
2117+
// clang-format on
2118+
break;
2119+
21072120
case DT_COLLECTION_PROP_FILENAME: // filename
21082121
// clang-format off
21092122
g_snprintf(query, sizeof(query),
@@ -2375,17 +2388,12 @@ static void _list_view(dt_lib_collect_rule_t *dr)
23752388

23762389
// if needed, we restrict the tree to matching entries
23772390
if(dr->typing
2378-
&& (property == DT_COLLECTION_PROP_CAMERA
2379-
|| property == DT_COLLECTION_PROP_FILENAME
2380-
|| property == DT_COLLECTION_PROP_FILMROLL
2381-
|| property == DT_COLLECTION_PROP_LENS
2382-
|| property == DT_COLLECTION_PROP_APERTURE
2383-
|| property == DT_COLLECTION_PROP_FOCAL_LENGTH
2384-
|| property == DT_COLLECTION_PROP_ISO
2385-
|| property == DT_COLLECTION_PROP_MODULE
2386-
|| property == DT_COLLECTION_PROP_ORDER
2387-
|| property == DT_COLLECTION_PROP_RATING
2388-
|| property >= DT_COLLECTION_PROP_METADATA_OFFSET))
2391+
&& (property == DT_COLLECTION_PROP_CAMERA || property == DT_COLLECTION_PROP_FILENAME
2392+
|| property == DT_COLLECTION_PROP_FILMROLL || property == DT_COLLECTION_PROP_LENS
2393+
|| property == DT_COLLECTION_PROP_APERTURE || property == DT_COLLECTION_PROP_FOCAL_LENGTH
2394+
|| property == DT_COLLECTION_PROP_ISO || property == DT_COLLECTION_PROP_MODULE
2395+
|| property == DT_COLLECTION_PROP_ORDER || property == DT_COLLECTION_PROP_RATING
2396+
|| property >= DT_COLLECTION_PROP_METADATA_OFFSET || property == DT_COLLECTION_PROP_FILM_MODE))
23892397
{
23902398
gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->text)), -1);
23912399
if(g_str_has_suffix(needle, "%"))
@@ -3360,6 +3368,7 @@ static void _populate_collect_combo(GtkWidget *w)
33603368
ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_FLASH);
33613369
ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_EXPOSURE_PROGRAM);
33623370
ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_METERING_MODE);
3371+
ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_FILM_MODE);
33633372

33643373
dt_bauhaus_combobox_add_section(w, _("darktable"));
33653374
ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_GROUP_ID);
@@ -4004,6 +4013,7 @@ void init(struct dt_lib_module_t *self)
40044013
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_ASPECT_RATIO);
40054014
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_EXPOSURE);
40064015
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_EXPOSURE_BIAS);
4016+
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_FILM_MODE);
40074017
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_FILENAME);
40084018
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_GEOTAGGING);
40094019
luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_LOCAL_COPY);

src/libs/filtering.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ static _filter_t filters[]
248248
{ DT_COLLECTION_PROP_WHITEBALANCE, _misc_widget_init, _misc_update },
249249
{ DT_COLLECTION_PROP_FLASH, _misc_widget_init, _misc_update },
250250
{ DT_COLLECTION_PROP_EXPOSURE_PROGRAM, _misc_widget_init, _misc_update },
251-
{ DT_COLLECTION_PROP_METERING_MODE, _misc_widget_init, _misc_update } };
251+
{ DT_COLLECTION_PROP_METERING_MODE, _misc_widget_init, _misc_update },
252+
{ DT_COLLECTION_PROP_FILM_MODE, _misc_widget_init, _misc_update } };
252253

253254
static _filter_t *_filters_get(const dt_collection_properties_t prop)
254255
{

src/libs/filters/misc.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ void _misc_tree_update(_widgets_misc_t *misc)
113113
table = g_strdup("metering_mode");
114114
tooltip = g_strdup(_("no metering mode defined"));
115115
}
116+
else if(misc->prop == DT_COLLECTION_PROP_FILM_MODE)
117+
{
118+
table = g_strdup("film_mode");
119+
tooltip = g_strdup(_("no film mode defined"));
120+
}
116121

117122
// SQL
118123
if(misc->prop == DT_COLLECTION_PROP_CAMERA)

0 commit comments

Comments
 (0)