From c360fd7e2c2a1de0e318d185533f9789dc84a9c4 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 6 May 2019 09:27:44 +0200 Subject: [PATCH 001/110] Use exiv2 for metadata handling --- .gitignore | 1 - CMakeLists.txt | 23 +- clean.bat | 4 - rtengine/CMakeLists.txt | 6 +- rtengine/dcp.cc | 437 +++- rtengine/dfmanager.cc | 2 +- rtengine/dynamicprofile.cc | 2 +- rtengine/ffmanager.cc | 2 +- rtengine/histmatching.cc | 6 +- rtengine/imagedata.cc | 1543 ++++---------- rtengine/imagedata.h | 110 +- rtengine/imageio.cc | 434 +--- rtengine/imageio.h | 30 +- rtengine/improccoordinator.cc | 21 +- rtengine/improcfun.cc | 5 +- rtengine/iptcpairs.h | 49 - rtengine/previewimage.cc | 3 +- rtengine/procparams.cc | 69 +- rtengine/procparams.h | 86 +- rtengine/rawimagesource.cc | 3 +- rtengine/rawmetadatalocation.h | 41 - rtengine/rtengine.h | 73 +- rtengine/rtthumbnail.cc | 57 +- rtengine/rtthumbnail.h | 6 +- rtengine/simpleprocess.cc | 23 +- rtexif/CMakeLists.txt | 17 - rtexif/canonattribs.cc | 2078 ------------------- rtexif/fujiattribs.cc | 316 --- rtexif/kodakattribs.cc | 165 -- rtexif/nikonattribs.cc | 1271 ------------ rtexif/olympusattribs.cc | 846 -------- rtexif/panasonicattribs.cc | 142 -- rtexif/pentaxattribs.cc | 2219 -------------------- rtexif/rtexif.cc | 3488 -------------------------------- rtexif/rtexif.h | 690 ------- rtexif/sonyminoltaattribs.cc | 2640 ------------------------ rtexif/stdattribs.cc | 931 --------- rtgui/CMakeLists.txt | 2 +- rtgui/cacheimagedata.cc | 4 - rtgui/cacheimagedata.h | 42 +- rtgui/editorpanel.cc | 14 +- rtgui/exifpanel.cc | 567 ++---- rtgui/exifpanel.h | 54 +- rtgui/iptcpanel.cc | 140 +- rtgui/resize.cc | 1 + rtgui/shcselector.cc | 1 + rtgui/thumbnail.cc | 111 +- rtgui/thumbnail.h | 2 +- tools/generateRtexifUpdates | 92 - 49 files changed, 1359 insertions(+), 17510 deletions(-) delete mode 100644 rtengine/iptcpairs.h delete mode 100644 rtengine/rawmetadatalocation.h delete mode 100644 rtexif/CMakeLists.txt delete mode 100644 rtexif/canonattribs.cc delete mode 100644 rtexif/fujiattribs.cc delete mode 100644 rtexif/kodakattribs.cc delete mode 100644 rtexif/nikonattribs.cc delete mode 100644 rtexif/olympusattribs.cc delete mode 100644 rtexif/panasonicattribs.cc delete mode 100644 rtexif/pentaxattribs.cc delete mode 100644 rtexif/rtexif.cc delete mode 100644 rtexif/rtexif.h delete mode 100644 rtexif/sonyminoltaattribs.cc delete mode 100644 rtexif/stdattribs.cc delete mode 100755 tools/generateRtexifUpdates diff --git a/.gitignore b/.gitignore index 21ebf986a..331bf634f 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ Release rtdata/rawtherapee.desktop rtengine/librtengine.a -rtexif/librtexif.a rtgui/config.h rtgui/version.h rtgui/rawtherapee diff --git a/CMakeLists.txt b/CMakeLists.txt index f13231586..c907824c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -318,6 +318,24 @@ pkg_check_modules (SIGC REQUIRED sigc++-2.0>=2.3.1) pkg_check_modules (LENSFUN REQUIRED lensfun>=0.2) pkg_check_modules (RSVG REQUIRED librsvg-2.0>=2.40) +# Require exiv2 >= 0.24 to make sure everything we need is available +#find_package(Exiv2 0.24 REQUIRED) +pkg_check_modules(EXIV2 REQUIRED exiv2>=0.24) +#include_directories(SYSTEM ${Exiv2_INCLUDE_DIRS}) +#list(APPEND LIBS ${EXIV2_LIBRARIES}) +add_definitions(${EXIV2_DEFINITIONS}) +set(_exiv2_libs ${EXIV2_LIBRARIES}) +set(EXIV2_LIBRARIES "") +foreach(l ${_exiv2_libs}) + set(_el "_el-NOTFOUND") + if(EXIV2_LIBRARY_DIRS) + find_library(_el ${l} PATHS ${EXIV2_LIBRARY_DIRS} NO_DEFAULT_PATH) + else() + find_library(_el ${l} PATHS ${EXIV2_LIBRARY_DIRS}) + endif() + set(EXIV2_LIBRARIES ${EXIV2_LIBRARIES} ${_el}) +endforeach() + if(WIN32) add_definitions(-DWIN32) add_definitions(-D_WIN32) @@ -333,7 +351,6 @@ endif() pkg_check_modules(LCMS REQUIRED lcms2>=2.6) pkg_check_modules(EXPAT REQUIRED expat>=2.1) pkg_check_modules(FFTW3F REQUIRED fftw3f) -pkg_check_modules(IPTCDATA REQUIRED libiptcdata) pkg_check_modules(TIFF REQUIRED libtiff-4>=4.0.4) find_package(JPEG REQUIRED) find_package(PNG REQUIRED) @@ -398,6 +415,7 @@ if(OPENMP_FOUND) set(CMAKE_REQUIRED_INCLUDES ${FFTW3F_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES) foreach(l ${FFTW3F_LIBRARIES}) + set(_f "_f-NOTFOUND") find_library(_f ${l} PATHS ${FFTW3F_LIBRARY_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${_f}) endforeach() @@ -538,11 +556,13 @@ foreach(l ${LENSFUN_LIBRARIES}) # the NO_DEFAULT_PATH is to make sure we find the lensfun version we # want, and not the system's one (e.g. if we have a custom version # installed in a non-standard location) + set(_l "_l-NOTFOUND") find_library(_l ${l} PATHS ${LENSFUN_LIBRARY_DIRS} NO_DEFAULT_PATH) else() # LENSFUN_LIBRARY_DIRS can be empty if lensfun is installed in the # default path. In this case, adding NO_DEFAULT_PATH would make # find_library fail... + set(_l "_l-NOTFOUND") find_library(_l ${l}) endif() set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${_l}) @@ -557,7 +577,6 @@ int main() }" LENSFUN_HAS_LOAD_DIRECTORY) -add_subdirectory(rtexif) add_subdirectory(rtengine) add_subdirectory(rtgui) add_subdirectory(rtdata) diff --git a/clean.bat b/clean.bat index 6a549821e..52e77f954 100644 --- a/clean.bat +++ b/clean.bat @@ -4,24 +4,20 @@ del .\install_manifest.txt rmdir /s /q .\CMakeFiles rmdir /s /q .\rtengine\CMakeFiles -rmdir /s /q .\rtexif\CMakeFiles rmdir /s /q .\rtgui\CMakeFiles rmdir /s /q .\rtdata\CMakeFiles del .\cmake_* del .\rtengine\cmake_* -del .\rtexif\cmake_* del .\rtgui\cmake_* del .\rtdata\cmake_* del .\Makefile del .\rtengine\Makefile -del .\rtexif\Makefile del .\rtgui\Makefile del .\rtdata\Makefile del .\rtengine\librtengine.so del .\rtengine\librtengine.a del .\rtgui\rawtherapee -del .\rtexif\librtexif.so del .\rtexif\librtexif.a diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index a1037f5a3..4f4dd1beb 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -11,9 +11,10 @@ include_directories(${EXTRA_INCDIR} ${LCMS_INCLUDE_DIRS} ${LENSFUN_INCLUDE_DIRS} ${RSVG_INCLUDE_DIRS} + ${EXIV2_INCLUDE_DIRS} ) -link_directories("${PROJECT_SOURCE_DIR}/rtexif" +link_directories( ${EXPAT_LIBRARY_DIRS} ${EXTRA_LIBDIR} ${FFTW3F_LIBRARY_DIRS} @@ -170,7 +171,7 @@ endif() set_target_properties(rtengine PROPERTIES COMPILE_FLAGS "${RTENGINE_CXX_FLAGS}") -target_link_libraries(rtengine rtexif +target_link_libraries(rtengine ${EXPAT_LIBRARIES} ${EXTRA_LIB} ${FFTW3F_LIBRARIES} @@ -186,6 +187,7 @@ target_link_libraries(rtengine rtexif ${ZLIB_LIBRARIES} ${LENSFUN_LIBRARIES} ${RSVG_LIBRARIES} + ${EXIV2_LIBRARIES} ) install(FILES ${CAMCONSTSFILE} DESTINATION "${DATADIR}" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 1c99b682c..0f5b32d34 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -39,10 +39,8 @@ extern const Settings* settings; } using namespace rtengine; -using namespace rtexif; -namespace -{ +namespace { // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here @@ -444,7 +442,308 @@ std::map getAliases(const Glib::ustring& profile_dir) return res; } -} + +class DCPMetadata { + enum TagType { + INVALID = 0, + BYTE = 1, + ASCII = 2, + SHORT = 3, + LONG = 4, + RATIONAL = 5, + SBYTE = 6, + UNDEFINED = 7, + SSHORT = 8, + SLONG = 9, + SRATIONAL = 10, + FLOAT = 11, + DOUBLE = 12 + }; + + enum ByteOrder { + UNKNOWN = 0, + INTEL = 0x4949, + MOTOROLA = 0x4D4D + }; + +public: + explicit DCPMetadata(FILE *file): order_(UNKNOWN), file_(file) {} + + bool parse() + { + int offset = 0; + FILE *f = file_; + + if (!f) { +#ifndef NDEBUG + std::cerr << "ERROR : no file opened !" << std::endl; +#endif + return false; + } + setlocale(LC_NUMERIC, "C"); // to set decimal point in sscanf + + // read tiff header + fseek(f, 0, SEEK_SET); + unsigned short bo; + fread(&bo, 1, 2, f); + order_ = ByteOrder(int(bo)); + + get2(f, order_); + if (!offset) { + offset = get4(f, order_); + } + + // seek to IFD + fseek(f, offset, SEEK_SET); + + // first read the IFD directory + int numtags = get2(f, order_); + + if (numtags <= 0 || numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit + return false; + } + + int base = 0; + for (int i = 0; i < numtags; i++) { + Tag t; + if (parse_tag(t, f, base, order_)) { + tags_[t.id] = std::move(t); + } + } + + return true; + } + + bool find(int id) const + { + return tags_.find(id) != tags_.end(); + } + + std::string toString(int id) + { + auto it = tags_.find(id); + if (it != tags_.end()) { + auto &t = it->second; + if (t.type == ASCII) { + std::ostringstream buf; + unsigned char *value = &(t.value[0]); + buf << value; + return buf.str(); + } + } + return ""; + } + + int toInt(int id, int ofs=0, TagType astype=INVALID) + { + auto it = tags_.find(id); + if (it == tags_.end()) { + return 0; + } + + auto &t = it->second; + int a; + unsigned char *value = &(t.value[0]); + + if (astype == INVALID) { + astype = t.type; + } + + switch (astype) { + case SBYTE: + return reinterpret_cast(value)[ofs]; + + case BYTE: + return value[ofs]; + + case SSHORT: + return int2_to_signed(sget2(value + ofs, order_)); + + case SHORT: + return sget2(value + ofs, order_); + + case SLONG: + case LONG: + return sget4 (value + ofs, order_); + + case SRATIONAL: + case RATIONAL: + a = sget4(value + ofs + 4, order_); + return a == 0 ? 0 : int(sget4(value + ofs, order_)) / a; + + case FLOAT: + return toDouble(id, ofs); + + default: + return 0; + } + } + + int toShort(int id, int ofs=0) + { + return toInt(id, ofs, SHORT); + } + + double toDouble(int id, int ofs=0) + { + auto it = tags_.find(id); + if (it == tags_.end()) { + return 0.0; + } + + auto &t = it->second; + + union IntFloat { + uint32_t i; + float f; + } conv; + + int ud, dd; + unsigned char *value = &(t.value[0]); + + switch (t.type) { + case SBYTE: + return int((reinterpret_cast (value))[ofs]); + + case BYTE: + return int(value[ofs]); + + case SSHORT: + return int2_to_signed(sget2(value + ofs, order_)); + + case SHORT: + return sget2(value + ofs, order_); + + case SLONG: + case LONG: + return sget4(value + ofs, order_); + + case SRATIONAL: + case RATIONAL: + ud = sget4(value + ofs, order_); + dd = sget4(value + ofs + 4, order_); + return (dd ? double(ud)/double(dd) : 0.0); + + case FLOAT: + conv.i = sget4(value + ofs, order_); + return conv.f; // IEEE FLOATs are already C format, they just need a recast + + default: + return 0.; + } + } + + unsigned int getCount(int id) + { + auto it = tags_.find(id); + if (it != tags_.end()) { + return it->second.count; + } + return 0; + } + +private: + static unsigned short sget2(unsigned char *s, ByteOrder order) + { + if (order == INTEL) { + return s[0] | s[1] << 8; + } else { + return s[0] << 8 | s[1]; + } + } + + static int sget4(unsigned char *s, ByteOrder order) + { + if (order == INTEL) { + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + } else { + return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; + } + } + + static unsigned short get2(FILE* f, ByteOrder order) + { + unsigned char str[2] = { 0xff, 0xff }; + fread (str, 1, 2, f); + return sget2(str, order); + } + + static int get4(FILE *f, ByteOrder order) + { + unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff }; + fread (str, 1, 4, f); + return sget4 (str, order); + } + + static short int int2_to_signed(short unsigned int i) + { + union { + short unsigned int i; + short int s; + } u; + u.i = i; + return u.s; + } + + static int getTypeSize(TagType type) + { + return ("11124811248484"[type < 14 ? type : 0] - '0'); + } + + struct Tag { + int id; + std::vector value; + TagType type; + unsigned int count; + + Tag(): id(0), value(), type(INVALID), count(0) {} + }; + + bool parse_tag(Tag &t, FILE *f, int base, ByteOrder order) + { + t.id = get2(f, order); + t.type = (TagType)get2(f, order); + t.count = get4(f, order); + + if (!t.count) { + t.count = 1; + } + + // filter out invalid tags + // note the large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, + // (only a small part of it will actually be parsed though) + if ((int)t.type < 1 || (int)t.type > 12 || t.count > 10 * 1024 * 1024) { + t.type = INVALID; + return false; + } + + // store next Tag's position in file + int save = ftell(f) + 4; + + // load value field (possibly seek before) + int valuesize = t.count * getTypeSize(t.type); + + if (valuesize > 4) { + fseek(f, get4(f, order) + base, SEEK_SET); + } + + // read value + t.value.resize(valuesize + 1); + auto readSize = fread(&(t.value[0]), 1, valuesize, f); + t.value[readSize] = '\0'; + + // seek back to the saved position + fseek(f, save, SEEK_SET); + return true; + } + + std::unordered_map tags_; + ByteOrder order_; + FILE *file_; +}; + +} // namespace + struct DCPProfile::ApplyState::Data { float pro_photo[3][3]; @@ -478,7 +777,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : delta_info.hue_step = delta_info.val_step = look_info.hue_step = look_info.val_step = 0; constexpr int tiff_float_size = 4; - enum class TagKey : int { + enum TagKey { COLOR_MATRIX_1 = 50721, COLOR_MATRIX_2 = 50722, PROFILE_HUE_SAT_MAP_DIMS = 50937, @@ -764,54 +1063,48 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : return; } - ExifManager exifManager(file, nullptr, true); - exifManager.parseTIFF(false); - std::unique_ptr tagDir(exifManager.roots.at(0)); + DCPMetadata md(file); + if (!md.parse()) { + printf ("Unable to load DCP profile '%s' !", filename.c_str()); + return; + } - Tag* tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_1)); light_source_1 = - tag - ? tag->toInt(0, rtexif::SHORT) - : -1; - tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_2)); + md.find(CALIBRATION_ILLUMINANT_1) ? + md.toShort(CALIBRATION_ILLUMINANT_1) : + -1; light_source_2 = - tag - ? tag->toInt(0, rtexif::SHORT) - : -1; + md.find(CALIBRATION_ILLUMINANT_2) ? + md.toShort(CALIBRATION_ILLUMINANT_2) : + -1; temperature_1 = calibrationIlluminantToTemperature(light_source_1); temperature_2 = calibrationIlluminantToTemperature(light_source_2); - const bool has_second_hue_sat = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_2)); // Some profiles have two matrices, but just one huesat + const bool has_second_hue_sat = md.find(PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat // Fetch Forward Matrices, if any - tag = tagDir->getTag(toUnderlying(TagKey::FORWARD_MATRIX_1)); - - if (tag) { - has_forward_matrix_1 = true; + has_forward_matrix_1 = md.find(FORWARD_MATRIX_1); + if (has_forward_matrix_1) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_1[row][col] = tag->toDouble((col + row * 3) * 8); + forward_matrix_1[row][col] = md.toDouble(FORWARD_MATRIX_1, (col + row * 3) * 8); } } } - tag = tagDir->getTag(toUnderlying(TagKey::FORWARD_MATRIX_2)); - - if (tag) { - has_forward_matrix_2 = true; + has_forward_matrix_2 = md.find(FORWARD_MATRIX_2); + if (has_forward_matrix_2) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_2[row][col] = tag->toDouble((col + row * 3) * 8); + forward_matrix_2[row][col] = md.toDouble(FORWARD_MATRIX_2, (col + row * 3) * 8); } } } // Color Matrix (one is always there) - tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_1)); - - if (!tag) { + if (!md.find(COLOR_MATRIX_1)) { std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; fclose(file); return; @@ -821,29 +1114,24 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - color_matrix_1[row][col] = tag->toDouble((col + row * 3) * 8); + color_matrix_1[row][col] = md.toDouble(COLOR_MATRIX_1, (col + row * 3) * 8); } } - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DIMS)); + if (md.find(PROFILE_LOOK_TABLE_DIMS)) { + look_info.hue_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 0); + look_info.sat_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 4); + look_info.val_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 8); - if (tag) { - look_info.hue_divisions = tag->toInt(0); - look_info.sat_divisions = tag->toInt(4); - look_info.val_divisions = tag->toInt(8); - - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_ENCODING)); - look_info.srgb_gamma = tag && tag->toInt(0); - - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DATA)); - look_info.array_count = tag->getCount() / 3; + look_info.srgb_gamma = md.find(PROFILE_LOOK_TABLE_ENCODING) && md.toInt(PROFILE_LOOK_TABLE_ENCODING); + look_info.array_count = md.getCount(PROFILE_LOOK_TABLE_DATA) / 3; look_table.resize(look_info.array_count); for (unsigned int i = 0; i < look_info.array_count; i++) { - look_table[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); - look_table[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); - look_table[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); + look_table[i].hue_shift = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); + look_table[i].sat_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); + look_table[i].val_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); } // Precalculated constants for table application @@ -860,25 +1148,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step; } - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DIMS)); + if (md.find(PROFILE_HUE_SAT_MAP_DIMS)) { + delta_info.hue_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 0); + delta_info.sat_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 4); + delta_info.val_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 8); - if (tag) { - delta_info.hue_divisions = tag->toInt(0); - delta_info.sat_divisions = tag->toInt(4); - delta_info.val_divisions = tag->toInt(8); - - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_ENCODING)); - delta_info.srgb_gamma = tag && tag->toInt(0); - - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_1)); - delta_info.array_count = tag->getCount() / 3; + delta_info.srgb_gamma = md.find(PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(PROFILE_HUE_SAT_MAP_ENCODING); + delta_info.array_count = md.getCount(PROFILE_HUE_SAT_MAP_DATA_1) / 3; deltas_1.resize(delta_info.array_count); for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_1[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); - deltas_1[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); - deltas_1[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); + deltas_1[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); + deltas_1[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); + deltas_1[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); } delta_info.pc.h_scale = @@ -898,13 +1181,13 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Second matrix has_color_matrix_2 = true; - tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_2)); + bool cm2 = md.find(COLOR_MATRIX_2); for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { color_matrix_2[row][col] = - tag - ? tag->toDouble((col + row * 3) * 8) + cm2 + ? md.toDouble(COLOR_MATRIX_2, (col + row * 3) * 8) : color_matrix_1[row][col]; } } @@ -914,27 +1197,21 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : deltas_2.resize(delta_info.array_count); // Saturation maps. Need to be unwinded. - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_2)); - for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_2[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); - deltas_2[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); - deltas_2[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); + deltas_2[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); + deltas_2[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); + deltas_2[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); } } } - tag = tagDir->getTag(toUnderlying(TagKey::BASELINE_EXPOSURE_OFFSET)); - - if (tag) { - has_baseline_exposure_offset = true; - baseline_exposure_offset = tag->toDouble(); + has_baseline_exposure_offset = md.find(BASELINE_EXPOSURE_OFFSET); + if (has_baseline_exposure_offset) { + baseline_exposure_offset = md.toDouble(BASELINE_EXPOSURE_OFFSET); } // Read tone curve points, if any, but disable to RTs own profiles - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_TONE_CURVE)); - - if (tag) { + if (md.find(PROFILE_TONE_CURVE)) { std::vector curve_points = { static_cast(DCT_Spline) // The first value is the curve type }; @@ -942,9 +1219,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Push back each X/Y coordinates in a loop bool curve_is_linear = true; - for (int i = 0; i < tag->getCount(); i += 2) { - const double x = tag->toDouble((i + 0) * tiff_float_size); - const double y = tag->toDouble((i + 1) * tiff_float_size); + for (unsigned int i = 0, n = md.getCount(PROFILE_TONE_CURVE); i < n; i += 2) { + const double x = md.toDouble(PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); + const double y = md.toDouble(PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); if (x != y) { curve_is_linear = false; @@ -960,9 +1237,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tone_curve.Set(DiagonalCurve(curve_points, CURVES_MIN_POLY_POINTS)); } } else { - tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_TONE_COPYRIGHT)); - - if (tag && tag->valueToString().find("Adobe Systems") != std::string::npos) { + if (md.find(PROFILE_TONE_COPYRIGHT) && md.toString(PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { // An Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that std::vector curve_points = { static_cast(DCT_Spline) diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 5f1035a8e..34475f545 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -383,7 +383,7 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) return &(iter->second); } - FramesData idata(filename, std::unique_ptr(new RawMetaDataLocation(ri.get_exifBase(), ri.get_ciffBase(), ri.get_ciffLen())), true); + FramesData idata(filename); /* Files are added in the map, divided by same maker/model,ISO and shutter*/ std::string key(dfInfo::key(((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(), idata.getISOSpeed(), idata.getShutterSpeed())); iter = dfList.find(key); diff --git a/rtengine/dynamicprofile.cc b/rtengine/dynamicprofile.cc index 7b7f2a517..7939936e9 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -81,7 +81,7 @@ bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im) const && expcomp (im->getExpComp()) && camera (im->getCamera()) && lens (im->getLens()) - && imagetype(im->getImageType(0))); + && imagetype(im->getImageType())); } namespace diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index 6b0302d1e..89b5c7154 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -332,7 +332,7 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) return &(iter->second); } - FramesData idata(filename, std::unique_ptr(new RawMetaDataLocation(ri.get_exifBase(), ri.get_ciffBase(), ri.get_ciffLen())), true); + FramesData idata(filename); /* Files are added in the map, divided by same maker/model,lens and aperture*/ std::string key(ffInfo::key(idata.getMake(), idata.getModel(), idata.getLens(), idata.getFocalLen(), idata.getFNumber())); iter = ffList.find(key); diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index e48f2017a..5a17ab6ec 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -278,10 +278,9 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st std::unique_ptr source; { - RawMetaDataLocation rml; eSensorType sensor_type; int w, h; - std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true, true)); + std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), sensor_type, w, h, 1, false, true, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: no thumbnail found, generating a neutral curve" << std::endl; @@ -310,11 +309,10 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st std::unique_ptr target; { - RawMetaDataLocation rml; eSensorType sensor_type; double scale; int w = fw / skip, h = fh / skip; - std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, false, true)); + std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), sensor_type, w, h, 1, false, false, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 4e38c612a..e0f6b50a3 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -20,69 +20,78 @@ #include #include #include +#include #include "imagedata.h" -#include "iptcpairs.h" #include "imagesource.h" #include "rt_math.h" -#include "procparams.h" - #pragma GCC diagnostic warning "-Wextra" #define PRINT_HDR_PS_DETECTION 0 using namespace rtengine; -extern "C" IptcData *iptc_data_new_from_jpeg_file (FILE* infile); -namespace -{ +// namespace { -Glib::ustring to_utf8 (const std::string& str) +// Glib::ustring to_utf8 (const std::string& str) +// { +// try { +// return Glib::locale_to_utf8 (str); +// } catch (Glib::Error&) { +// return Glib::convert_with_fallback (str, "UTF-8", "ISO-8859-1", "?"); +// } +// } + +// } // namespace + + +namespace rtengine { + +extern const Settings *settings; + +Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname) { - try { - return Glib::locale_to_utf8 (str); - } catch (Glib::Error&) { - return Glib::convert_with_fallback (str, "UTF-8", "ISO-8859-1", "?"); - } +#ifdef EXV_UNICODE_PATH + auto *ws = g_utf8_to_utf16(fname.c_str(), -1, NULL, NULL, NULL); + std::wstring wfname(ws); + g_free(ws); + auto image = Exiv2::ImageFactory::open(wfname); +#else + auto image = Exiv2::ImageFactory::open(fname); +#endif + return image; } -template -T getFromFrame( - const std::vector>& frames, - std::size_t frame, - const std::function& function -) +} // namespace rtengine + + + +FramesMetaData* FramesMetaData::fromFile (const Glib::ustring& fname) { - if (frame < frames.size()) { - return function(*frames[frame]); - } - if (!frames.empty()) { - return function(*frames[0]); - } - return {}; + return new FramesData(fname); } -} - -FramesMetaData* FramesMetaData::fromFile (const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) +FramesData::FramesData(const Glib::ustring &fname): + ok_(false), + fname_(fname), + dcrawFrameCount(0), + time(), + timeStamp(), + iso_speed(0), + aperture(0.), + focal_len(0.), + focal_len35mm(0.), + focus_dist(0.f), + shutter(0.), + expcomp(0.), + make("Unknown"), + model("Unknown"), + orientation("Unknown"), + lens("Unknown"), + sampleFormat(IIOSF_UNKNOWN), + isPixelShift(false), + isHDR(false) { - return new FramesData (fname, std::move(rml), firstFrameOnly); -} - -FrameData::FrameData (rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir) - : frameRootDir(frameRootDir_), iptc(nullptr), time(), timeStamp(), iso_speed(0), aperture(0.), focal_len(0.), focal_len35mm(0.), focus_dist(0.f), - shutter(0.), expcomp(0.), make("Unknown"), model("Unknown"), orientation("Unknown"), lens("Unknown"), - sampleFormat(IIOSF_UNKNOWN), isPixelShift(false), isHDR(false) -{ - memset (&time, 0, sizeof(time)); - - if (!frameRootDir) { - return; - } - - rtexif::Tag* tag; - rtexif::TagDirectory* newFrameRootDir = frameRootDir; - memset(&time, 0, sizeof(time)); timeStamp = 0; iso_speed = 0; @@ -98,1082 +107,476 @@ FrameData::FrameData (rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* orientation.clear(); lens.clear(); - tag = newFrameRootDir->findTag("Make"); - if (!tag) { - newFrameRootDir = rootDir; - tag = newFrameRootDir->findTag("Make"); - if (!tag) { - // For some raw files (like Canon's CR2 files), the metadata are contained in the first root directory - newFrameRootDir = firstRootDir; - tag = newFrameRootDir->findTag("Make"); + try { + auto image = open_exiv2(fname); + image->readMetadata(); + auto &exif = image->exifData(); + ok_ = true; + + // taken and adapted from darktable (src/common/exif.cc) +/* + This file is part of darktable, + copyright (c) 2009--2013 johannes hanika. + copyright (c) 2011 henrik andersson. + copyright (c) 2012-2017 tobias ellinghaus. + + 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 . + */ + + Exiv2::ExifData::const_iterator pos; + + const auto find_exif_tag = + [&](const std::string &name) -> bool + { + pos = exif.findKey(Exiv2::ExifKey(name)); + return (pos != exif.end() && pos->size()); + }; + + const auto find_tag = + [&](decltype(Exiv2::make) func) -> bool + { + pos = func(exif); + return pos != exif.end() && pos->size(); + }; + + /* List of tag names taken from exiv2's printSummary() in actions.cpp */ + + if (find_tag(Exiv2::make)) { + make = pos->print(&exif); } - } - if (tag) { - make = tag->valueToString(); - // Same dcraw treatment - for (const auto& corp : { - "Canon", - "NIKON", - "EPSON", - "KODAK", - "Kodak", - "OLYMPUS", - "PENTAX", - "RICOH", - "MINOLTA", - "Minolta", - "Konica", - "CASIO", - "Sinar", - "Phase One", - "SAMSUNG", - "Mamiya", - "MOTOROLA", - "Leaf", - "Panasonic" - }) { - if (make.find(corp) != std::string::npos) { // Simplify company names - make = corp; - break; + + if (find_tag(Exiv2::model)) { + model = pos->print(&exif); + } + + if (make.size() > 0) { + for (const auto& corp : { + "Canon", + "NIKON", + "EPSON", + "KODAK", + "Kodak", + "OLYMPUS", + "PENTAX", + "RICOH", + "MINOLTA", + "Minolta", + "Konica", + "CASIO", + "Sinar", + "Phase One", + "SAMSUNG", + "Mamiya", + "MOTOROLA", + "Leaf", + "Panasonic" + }) { + if (make.find(corp) != std::string::npos) { // Simplify company names + make = corp; + break; + } } - } - + } make.erase(make.find_last_not_of(' ') + 1); - } - - tag = newFrameRootDir->findTagUpward("Model"); - if (tag) { - model = tag->valueToString(); - } - - if (!model.empty()) { - std::string::size_type i = 0; - - if ( - make.find("KODAK") != std::string::npos - && ( - (i = model.find(" DIGITAL CAMERA")) != std::string::npos - || (i = model.find(" Digital Camera")) != std::string::npos - || (i = model.find("FILE VERSION")) != std::string::npos - ) - ) { - model.resize(i); - } - model.erase(model.find_last_not_of(' ') + 1); - if (!strncasecmp(model.c_str(), make.c_str(), make.size())) { - if (model.size() >= make.size() && model[make.size()] == ' ') { - model.erase(0, make.size() + 1); + if (make.length() > 0 && model.find(make + " ") == 0) { + model = model.substr(make.length() + 1); + } + + if (find_tag(Exiv2::exposureTime)) { + shutter = pos->toFloat(); + } + + if (find_tag(Exiv2::fNumber)) { + aperture = pos->toFloat(); + } + + /* Read ISO speed - Nikon happens to return a pair for Lo and Hi modes */ + if (find_tag(Exiv2::isoSpeed)) { + // if standard exif iso tag, use the old way of interpreting the return value to be more regression-save + if (strcmp(pos->key().c_str(), "Exif.Photo.ISOSpeedRatings") == 0) { + int isofield = pos->count() > 1 ? 1 : 0; + iso_speed = pos->toFloat(isofield); + } else { + std::string str = pos->print(); + iso_speed = std::atof(str.c_str()); + } + } + // some newer cameras support iso settings that exceed the 16 bit of exif's ISOSpeedRatings + if (iso_speed == 65535 || iso_speed == 0) { + if (find_exif_tag("Exif.PentaxDng.ISO") || find_exif_tag("Exif.Pentax.ISO")) { + std::string str = pos->print(); + iso_speed = std::atof(str.c_str()); + } else if((!g_strcmp0(make.c_str(), "SONY") || !g_strcmp0(make.c_str(), "Canon")) + && find_exif_tag("Exif.Photo.RecommendedExposureIndex")) { + iso_speed = pos->toFloat(); } } - if (model.find( "Digital Camera ") != std::string::npos) { - model.erase(0, 15); - } - } else { - model = "Unknown"; - } - - if (model == "Unknown") { - tag = newFrameRootDir->findTag("UniqueCameraModel"); - if (tag) { - model = tag->valueToString(); - } - } - - tag = newFrameRootDir->findTagUpward("Orientation"); - if (tag) { - orientation = tag->valueToString (); - } - - tag = newFrameRootDir->findTagUpward("MakerNote"); - rtexif::TagDirectory* mnote = nullptr; - if (tag) { - mnote = tag->getDirectory(); - } - - rtexif::TagDirectory* exif = nullptr; - tag = newFrameRootDir->findTagUpward("Exif"); - if (tag) { - exif = tag->getDirectory (); - } - - if (exif) { - - // standard exif tags - if ((tag = exif->getTag ("ShutterSpeedValue"))) { - shutter = tag->toDouble (); - } - - if ((tag = exif->getTag ("ExposureTime"))) { - shutter = tag->toDouble (); - } - - if ((tag = exif->getTag ("ApertureValue"))) { - aperture = tag->toDouble (); - } - - if ((tag = exif->getTag ("FNumber"))) { - aperture = tag->toDouble (); - } - - if ((tag = exif->getTag ("ExposureBiasValue"))) { - expcomp = tag->toDouble (); - } - - if ((tag = exif->getTag ("FocalLength"))) { - focal_len = tag->toDouble (); - } - - if ((tag = exif->getTag ("FocalLengthIn35mmFilm"))) { - focal_len35mm = tag->toDouble (); - } - - // Focus distance from EXIF or XMP. MakerNote ones are scattered and partly encrypted - int num = -3, denom = -3; - - // First try, official EXIF. Set by Adobe on some DNGs - tag = exif->getTag("SubjectDistance"); - - if (tag) { - int num, denom; - tag->toRational(num, denom); - } else { - // Second try, XMP data - char sXMPVal[64]; - - if (newFrameRootDir->getXMPTagValue("aux:ApproximateFocusDistance", sXMPVal)) { - sscanf(sXMPVal, "%d/%d", &num, &denom); + if (find_tag(Exiv2::focalLength)) { + // This works around a bug in exiv2 the developers refuse to fix + // For details see http://dev.exiv2.org/issues/1083 + if (pos->key() == "Exif.Canon.FocalLength" && pos->count() == 4) { + focal_len = pos->toFloat(1); + } else { + focal_len = pos->toFloat(); } } - if (num != -3) { - if ((denom == 1 && num >= 10000) || num < 0 || denom < 0) { - focus_dist = 10000; // infinity - } else if (denom > 0) { - focus_dist = (float)num / denom; - } + if (find_exif_tag("Exif.Photo.FocalLengthIn35mmFilm")) { + focal_len35mm = pos->toFloat(); } - if ((tag = exif->getTag ("ISOSpeedRatings"))) { - iso_speed = tag->toDouble (); + if (find_tag(Exiv2::subjectDistance)) { + focus_dist = (0.01 * pow(10, pos->toFloat() / 40)); + } + + if (find_tag(Exiv2::orientation)) { + orientation = pos->print(&exif); } - if ((tag = exif->findTag("DateTimeOriginal", true))) { - if (sscanf ((const char*)tag->getValue(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { - time.tm_year -= 1900; - time.tm_mon -= 1; - time.tm_isdst = -1; - timeStamp = mktime(&time); - } + if (find_tag(Exiv2::lensName)) { + lens = pos->print(&exif); + } + if (lens.empty()) { + lens = "Unknown"; } - tag = exif->findTag ("SerialNumber"); - - if(!tag) { - tag = exif->findTag ("InternalSerialNumber"); + std::string datetime_taken; + if (find_exif_tag("Exif.Image.DateTimeOriginal")) { + datetime_taken = pos->print(&exif); + } else if(find_exif_tag("Exif.Photo.DateTimeOriginal")) { + datetime_taken = pos->print(&exif); + } + if (sscanf(datetime_taken.c_str(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { + time.tm_year -= 1900; + time.tm_mon -= 1; + time.tm_isdst = -1; + timeStamp = mktime(&time); } - if (tag) { - serial = tag->valueToString(); + if (find_exif_tag("Exif.Image.ExposureBiasValue")) { + expcomp = pos->toFloat(); } - // guess lens... - lens = "Unknown"; + // ----------------------- + // Special file type detection (HDR, PixelShift) + // ------------------------ + uint16 bitspersample = 0, samplesperpixel = 0, sampleformat = 0, photometric = 0, compression = 0; + auto bps = exif.findKey(Exiv2::ExifKey("Exif.Image.BitsPerSample")); + auto spp = exif.findKey(Exiv2::ExifKey("Exif.Image.SamplesPerPixel")); + auto sf = exif.findKey(Exiv2::ExifKey("Exif.Image.SampleFormat")); + auto pi = exif.findKey(Exiv2::ExifKey("Exif.Image.PhotometricInterpretation")); + auto c = exif.findKey(Exiv2::ExifKey("Exif.Image.Compression")); - // Sometimes (e.g. DNG) EXIF already contains lens data - - if(!make.compare (0, 8, "FUJIFILM")) { - if(exif->getTag ("LensModel")) { - lens = exif->getTag ("LensModel")->valueToString (); - } - } else if(!make.compare (0, 4, "SONY")) { - if (iso_speed == 65535 || iso_speed == 0) { - rtexif::Tag* isoTag = exif->getTag ("RecommendedExposureIndex"); - - if(isoTag) { - iso_speed = isoTag->toDouble(); - } - } - - } - - if (lens == "Unknown") { - const auto lens_from_make_and_model = - [this, exif]() -> bool - { - if (!exif) { - return false; - } - - const rtexif::Tag* const lens_model = exif->getTag(0xA434); - - if (lens_model) { - const rtexif::Tag* const lens_make = exif->getTag(0xA433); - const std::string make = - lens_make - ? lens_make->valueToString() - : std::string(); - const std::string model = lens_model->valueToString(); - - if (!model.empty()) { - lens = make; - - if (!lens.empty()) { - lens += ' '; - } - - lens += model; - - return true; - } - } - - return false; - }; - - if (mnote) { - - if (!make.compare (0, 5, "NIKON")) { - // ISO at max value supported, check manufacturer specific - if (iso_speed == 65535 || iso_speed == 0) { - rtexif::Tag* isoTag = mnote->getTagP("ISOInfo/ISO"); - - if (isoTag) { - iso_speed = isoTag->toInt(); - } - } - - bool lensOk = false; - - if (mnote->getTag ("LensData")) { - std::string ldata = mnote->getTag ("LensData")->valueToString (); - size_t pos; - - if (ldata.size() > 10 && (pos = ldata.find ("Lens = ")) != Glib::ustring::npos) { - lens = ldata.substr (pos + 7); - - if (lens.compare (0, 7, "Unknown")) { - lensOk = true; - } else { - size_t pos = lens.find("$FL$"); // is there a placeholder for focallength? - - if(pos != Glib::ustring::npos) { // then fill in focallength - lens = lens.replace(pos, 4, exif->getTag ("FocalLength")->valueToString ()); - - if(mnote->getTag ("LensType")) { - std::string ltype = mnote->getTag ("LensType")->valueToString (); - - if(ltype.find("MF = Yes") != Glib::ustring::npos) { // check, whether it's a MF lens, should be always - lens = lens.replace(0, 7, "MF"); - } - - lensOk = true; - } - } - } - // If MakeNotes are vague, fall back to Exif LensMake and LensModel if set - // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#LensType - if (lens == "Manual Lens No CPU") { - lens_from_make_and_model(); - } - } - } - - if (!lensOk && mnote->getTag ("Lens")) { - std::string ldata = mnote->getTag ("Lens")->valueToString (); - size_t i = 0, j = 0; - double n[4] = {0.0}; - - for (int m = 0; m < 4; m++) { - while (i < ldata.size() && ldata[i] != '/') { - i++; - } - - int nom = atoi(ldata.substr(j, i).c_str()); - j = i + 1; - i++; - - while (i < ldata.size() && ldata[i] != ',') { - i++; - } - - int den = atoi(ldata.substr(j, i).c_str()); - j = i + 2; - i += 2; - n[m] = (double) nom / std::max(den,1); - } - - std::ostringstream str; - - if (n[0] == n[1]) { - str << "Unknown " << n[0] << "mm F/" << n[2]; - } else if (n[2] == n[3]) { - str << "Unknown " << n[0] << "-" << n[1] << "mm F/" << n[2]; - } else { - str << "Unknown " << n[0] << "-" << n[1] << "mm F/" << n[2] << "-" << n[3]; - } - - lens = str.str(); - - // Look whether it's MF or AF - if(mnote->getTag ("LensType")) { - std::string ltype = mnote->getTag ("LensType")->valueToString (); - - if(ltype.find("MF = Yes") != Glib::ustring::npos) { // check, whether it's a MF lens - lens = lens.replace(0, 7, "MF"); // replace 'Unknwon' with 'MF' - } else { - lens = lens.replace(0, 7, "AF"); // replace 'Unknwon' with 'AF' - } - } - } - } else if (!make.compare (0, 5, "Canon")) { - // ISO at max value supported, check manufacturer specific - if (iso_speed == 65535 || iso_speed == 0) { - rtexif::Tag* baseIsoTag = mnote->getTagP("CanonShotInfo/BaseISO"); - - if (baseIsoTag) { - iso_speed = baseIsoTag->toInt(); - } - } - - int found = false; - // canon EXIF have a string for lens model - rtexif::Tag *lt = mnote->getTag("LensType"); - - if ( lt ) { - if (lt->toInt()) { - std::string ldata = lt->valueToString (); - - if (ldata.size() > 1) { - found = true; - lens = "Canon " + ldata; - } - } else { - found = lens_from_make_and_model(); - } - } - - const std::string::size_type first_space_pos = lens.find(' '); - const std::string::size_type remaining_size = - first_space_pos != std::string::npos - ? lens.size() - first_space_pos - : 0; - - if( !found || remaining_size < 7U ) { - lt = mnote->findTag("LensID"); - - if ( lt ) { - std::string ldata = lt->valueToString (); - - if (ldata.size() > 1) { - lens = ldata; - } - } - } - } else if (!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX"))) { - // ISO at max value supported, check manufacturer specific - if (iso_speed == 65535 || iso_speed == 0) { - rtexif::Tag* baseIsoTag = mnote->getTag("ISO"); - if (baseIsoTag) { - std::string isoData = baseIsoTag->valueToString(); - if (isoData.size() > 1) { - iso_speed = stoi(isoData); - } - } - } - if (mnote->getTag ("LensType")) { - lens = mnote->getTag ("LensType")->valueToString(); - // If MakeNotes are vague, fall back to Exif LensMake and LensModel if set - // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html#LensType - if (lens == "M-42 or No Lens" || lens == "K or M Lens" || lens == "A Series Lens" || lens == "Sigma") { - lens_from_make_and_model(); - } - } else { - lens_from_make_and_model(); - } - - // Try to get the FocalLength from the LensInfo structure, where length below 10mm will be correctly set - rtexif::Tag* flt = mnote->getTagP ("LensInfo/FocalLength"); - - if (flt) { - // Don't replace Exif focal_len if Makernotes focal_len is 0 - if (flt->toDouble() > 0) { - focal_len = flt->toDouble (); - } - } else if ((flt = mnote->getTagP ("FocalLength"))) { - rtexif::Tag* flt = mnote->getTag ("FocalLength"); - focal_len = flt->toDouble (); - } - - if (mnote->getTag ("FocalLengthIn35mmFilm")) { - focal_len35mm = mnote->getTag ("FocalLengthIn35mmFilm")->toDouble (); - } - } else if (mnote && (!make.compare (0, 4, "SONY") || !make.compare (0, 6, "KONICA"))) { - if (mnote->getTag ("LensID")) { - lens = mnote->getTag ("LensID")->valueToString (); - if (lens == "Unknown") { - lens_from_make_and_model(); - } - } - } else if (!make.compare (0, 7, "OLYMPUS")) { - if (mnote->getTag ("Equipment")) { - rtexif::TagDirectory* eq = mnote->getTag ("Equipment")->getDirectory (); - - if (eq->getTag ("LensType")) { - lens = eq->getTag ("LensType")->valueToString (); - } - } - if (lens == "Unknown") { - lens_from_make_and_model(); - } - } else if (mnote && !make.compare (0, 9, "Panasonic")) { - if (mnote->getTag ("LensType")) { - std::string panalens = mnote->getTag("LensType")->valueToString(); - - if (panalens.find("LUMIX") != Glib::ustring::npos) { - lens = "Panasonic " + panalens; - } - else { - lens = panalens; - } - } - } - } else if (exif->getTag ("DNGLensInfo")) { - lens = exif->getTag ("DNGLensInfo")->valueToString (); - } else if (!lens_from_make_and_model() && exif->getTag ("LensInfo")) { - lens = exif->getTag ("LensInfo")->valueToString (); - } - } - } - - rtexif::Tag* t = newFrameRootDir->getTag(0x83BB); - if (t) { - iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); - } - - - // ----------------------- Special file type detection (HDR, PixelShift) ------------------------ - - - uint16 bitspersample = 0, samplesperpixel = 0, sampleformat = 0, photometric = 0, compression = 0; - const rtexif::Tag* const bps = frameRootDir->findTag("BitsPerSample"); - const rtexif::Tag* const spp = frameRootDir->findTag("SamplesPerPixel"); - const rtexif::Tag* const sf = frameRootDir->findTag("SampleFormat"); - const rtexif::Tag* const pi = frameRootDir->findTag("PhotometricInterpretation"); - const rtexif::Tag* const c = frameRootDir->findTag("Compression"); - - if (mnote && (!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX")))) { - const rtexif::Tag* const hdr = mnote->findTag("HDR"); - if (hdr) { - if (hdr->toInt() > 0) { - isHDR = true; -#if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> \"HDR\" tag found\n"); -#endif - } - } else { - const rtexif::Tag* const dm = mnote->findTag("DriveMode"); - if (dm) { - char buffer[60]; - dm->toString(buffer, 3); - buffer[3] = 0; - if (!strcmp(buffer, "HDR")) { + if ((!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX")))) { +// if (find_exif_tag("Exif.Pentax.HDR") && pos->toLong() > 0) { +// isHDR = true; +// #if PRINT_HDR_PS_DETECTION +// printf("HDR detected ! -> \"HDR\" tag found\n"); +// #endif +// } else + if (find_exif_tag("Exif.Pentax.DriveMode")) { + std::string buf = pos->toString(3); + buf[3] = 0; + if (!strcmp(buf.c_str(), "HDR")) { isHDR = true; #if PRINT_HDR_PS_DETECTION printf("HDR detected ! -> DriveMode = \"HDR\"\n"); #endif } } - } - if (!isHDR) { - const rtexif::Tag* const q = mnote->findTag("Quality"); - if (q && (q->toInt() == 7 || q->toInt() == 8)) { + if (!isHDR && find_exif_tag("Exif.Pentax.Quality") && + (pos->toLong() == 7 || pos->toLong() == 8)) { isPixelShift = true; #if PRINT_HDR_PS_DETECTION printf("PixelShift detected ! -> \"Quality\" = 7\n"); #endif } } - } - sampleFormat = IIOSF_UNKNOWN; + sampleFormat = IIOSF_UNKNOWN; - if (!sf) - /* - * WARNING: This is a dirty hack! - * We assume that files which doesn't contain the TIFFTAG_SAMPLEFORMAT tag - * (which is the case with uncompressed TIFFs produced by RT!) are RGB files, - * but that may be not true. --- Hombre - */ - { - sampleformat = SAMPLEFORMAT_UINT; - } else { - sampleformat = sf->toInt(); - } - - if ( - !bps - || !spp - || !pi - ) { - return; - } - - bitspersample = bps->toInt(); - samplesperpixel = spp->toInt(); - - photometric = pi->toInt(); - if (photometric == PHOTOMETRIC_LOGLUV) { - if (!c) { - compression = COMPRESSION_NONE; + if (sf == exif.end()) + /* + * WARNING: This is a dirty hack! + * We assume that files which doesn't contain the TIFFTAG_SAMPLEFORMAT tag + * (which is the case with uncompressed TIFFs produced by RT!) are RGB files, + * but that may be not true. --- Hombre + */ + { + sampleformat = SAMPLEFORMAT_UINT; } else { - compression = c->toInt(); + sampleformat = sf->toLong(); } - } - if (photometric == PHOTOMETRIC_RGB || photometric == PHOTOMETRIC_MINISBLACK) { - if (sampleformat == SAMPLEFORMAT_INT || sampleformat == SAMPLEFORMAT_UINT) { - if (bitspersample == 8) { - sampleFormat = IIOSF_UNSIGNED_CHAR; - } else if (bitspersample <= 16) { - sampleFormat = IIOSF_UNSIGNED_SHORT; - } - } else if (sampleformat == SAMPLEFORMAT_IEEEFP) { - if (bitspersample==16) { - sampleFormat = IIOSF_FLOAT16; - isHDR = true; -#if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d (16-bit)\n", sampleFormat); -#endif - } - else if (bitspersample == 24) { - sampleFormat = IIOSF_FLOAT24; - isHDR = true; -#if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d (24-bit)\n", sampleFormat); -#endif - } - else if (bitspersample == 32) { - sampleFormat = IIOSF_FLOAT32; - isHDR = true; -#if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d (32-bit)\n", sampleFormat); -#endif + if (bps == exif.end() || spp == exif.end() || pi == exif.end()) { + return; + } + + bitspersample = bps->toLong(); + samplesperpixel = spp->toLong(); + + photometric = pi->toLong(); + if (photometric == PHOTOMETRIC_LOGLUV) { + if (c == exif.end()) { + compression = COMPRESSION_NONE; + } else { + compression = c->toLong(); } } - } else if (photometric == PHOTOMETRIC_CFA) { - if (sampleformat == SAMPLEFORMAT_IEEEFP) { - if (bitspersample == 16) { - sampleFormat = IIOSF_FLOAT16; - isHDR = true; + + if (photometric == PHOTOMETRIC_RGB || photometric == PHOTOMETRIC_MINISBLACK) { + if (sampleformat == SAMPLEFORMAT_INT || sampleformat == SAMPLEFORMAT_UINT) { + if (bitspersample == 8) { + sampleFormat = IIOSF_UNSIGNED_CHAR; + } else if (bitspersample <= 16) { + sampleFormat = IIOSF_UNSIGNED_SHORT; + } + } else if (sampleformat == SAMPLEFORMAT_IEEEFP) { + if (bitspersample==16) { + sampleFormat = IIOSF_FLOAT16; + isHDR = true; #if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d (16-bit)\n", sampleFormat); + printf("HDR detected ! -> sampleFormat = %d (16-bit)\n", sampleFormat); #endif - } - else if (bitspersample == 24) { - sampleFormat = IIOSF_FLOAT24; - isHDR = true; + } + else if (bitspersample == 24) { + sampleFormat = IIOSF_FLOAT24; + isHDR = true; #if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d (24-bit)\n", sampleFormat); + printf("HDR detected ! -> sampleFormat = %d (24-bit)\n", sampleFormat); #endif - } - else if (bitspersample == 32) { - sampleFormat = IIOSF_FLOAT32; - isHDR = true; + } + else if (bitspersample == 32) { + sampleFormat = IIOSF_FLOAT32; + isHDR = true; #if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d (32-bit)\n", sampleFormat); -#endif - } - } else if (sampleformat == SAMPLEFORMAT_INT || sampleformat == SAMPLEFORMAT_UINT) { - if (bitspersample == 8) { // shouldn't occur... - sampleFormat = IIOSF_UNSIGNED_CHAR; - } else if (bitspersample <= 16) { - sampleFormat = IIOSF_UNSIGNED_SHORT; - } - } - } else if (photometric == 34892 || photometric == 32892 /* Linear RAW (see DNG spec ; 32892 seem to be a flaw from Sony's ARQ files) */) { - if (sampleformat == SAMPLEFORMAT_IEEEFP) { - sampleFormat = IIOSF_FLOAT32; - isHDR = true; -#if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d\n", sampleFormat); -#endif - } else if (sampleformat == SAMPLEFORMAT_INT || sampleformat == SAMPLEFORMAT_UINT) { - if (bitspersample == 8) { // shouldn't occur... - sampleFormat = IIOSF_UNSIGNED_CHAR; - } else if (bitspersample <= 16) { - sampleFormat = IIOSF_UNSIGNED_SHORT; - if (mnote && (!make.compare (0, 4, "SONY")) && bitspersample >= 12 && samplesperpixel == 4) { - isPixelShift = true; -#if PRINT_HDR_PS_DETECTION - printf("PixelShift detected ! -> \"Make\" = SONY, bitsPerPixel > 8, samplesPerPixel == 4\n"); + printf("HDR detected ! -> sampleFormat = %d (32-bit)\n", sampleFormat); #endif } } - } - } else if (photometric == PHOTOMETRIC_LOGLUV) { - if (compression == COMPRESSION_SGILOG24) { - sampleFormat = IIOSF_LOGLUV24; - isHDR = true; + } else if (photometric == PHOTOMETRIC_CFA) { + if (sampleformat == SAMPLEFORMAT_IEEEFP) { + if (bitspersample == 16) { + sampleFormat = IIOSF_FLOAT16; + isHDR = true; #if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d\n", sampleFormat); + printf("HDR detected ! -> sampleFormat = %d (16-bit)\n", sampleFormat); #endif - } else if (compression == COMPRESSION_SGILOG) { - sampleFormat = IIOSF_LOGLUV32; - isHDR = true; + } + else if (bitspersample == 24) { + sampleFormat = IIOSF_FLOAT24; + isHDR = true; #if PRINT_HDR_PS_DETECTION - printf("HDR detected ! -> sampleFormat = %d\n", sampleFormat); + printf("HDR detected ! -> sampleFormat = %d (24-bit)\n", sampleFormat); #endif + } + else if (bitspersample == 32) { + sampleFormat = IIOSF_FLOAT32; + isHDR = true; +#if PRINT_HDR_PS_DETECTION + printf("HDR detected ! -> sampleFormat = %d (32-bit)\n", sampleFormat); +#endif + } + } else if (sampleformat == SAMPLEFORMAT_INT || sampleformat == SAMPLEFORMAT_UINT) { + if (bitspersample == 8) { // shouldn't occur... + sampleFormat = IIOSF_UNSIGNED_CHAR; + } else if (bitspersample <= 16) { + sampleFormat = IIOSF_UNSIGNED_SHORT; + } + } + } else if (photometric == 34892 || photometric == 32892 /* Linear RAW (see DNG spec ; 32892 seem to be a flaw from Sony's ARQ files) */) { + if (sampleformat == SAMPLEFORMAT_IEEEFP) { + sampleFormat = IIOSF_FLOAT32; + isHDR = true; +#if PRINT_HDR_PS_DETECTION + printf("HDR detected ! -> sampleFormat = %d\n", sampleFormat); +#endif + } else if (sampleformat == SAMPLEFORMAT_INT || sampleformat == SAMPLEFORMAT_UINT) { + if (bitspersample == 8) { // shouldn't occur... + sampleFormat = IIOSF_UNSIGNED_CHAR; + } else if (bitspersample <= 16) { + sampleFormat = IIOSF_UNSIGNED_SHORT; + if (find_exif_tag("Exif.Photo.MakerNote") && (!make.compare (0, 4, "SONY")) && bitspersample >= 12 && samplesperpixel == 4) { + isPixelShift = true; +#if PRINT_HDR_PS_DETECTION + printf("PixelShift detected ! -> \"Make\" = SONY, bitsPerPixel > 8, samplesPerPixel == 4\n"); +#endif + } + } + } + } else if (photometric == PHOTOMETRIC_LOGLUV) { + if (compression == COMPRESSION_SGILOG24) { + sampleFormat = IIOSF_LOGLUV24; + isHDR = true; +#if PRINT_HDR_PS_DETECTION + printf("HDR detected ! -> sampleFormat = %d\n", sampleFormat); +#endif + } else if (compression == COMPRESSION_SGILOG) { + sampleFormat = IIOSF_LOGLUV32; + isHDR = true; +#if PRINT_HDR_PS_DETECTION + printf("HDR detected ! -> sampleFormat = %d\n", sampleFormat); +#endif + } } - } -} - -FrameData::~FrameData () -{ - - if (iptc) { - iptc_data_free (iptc); - } -} - -procparams::IPTCPairs FrameData::getIPTCData () const -{ - return getIPTCData(iptc); -} - -procparams::IPTCPairs FrameData::getIPTCData (IptcData* iptc_) -{ - - procparams::IPTCPairs iptcc; - - if (!iptc_) { - return iptcc; - } - - unsigned char buffer[2100]; - - for (int i = 0; i < 16; i++) { - IptcDataSet* ds = iptc_data_get_next_dataset (iptc_, nullptr, IPTC_RECORD_APP_2, strTags[i].tag); - - if (ds) { - iptc_dataset_get_data (ds, buffer, 2100); - std::vector icValues; - icValues.push_back (to_utf8((char*)buffer)); - - iptcc[strTags[i].field] = icValues; - iptc_dataset_unref (ds); + } catch(Exiv2::AnyError &e) { + if (settings->verbose) { + std::cerr << "EXIV2 ERROR: " << e.what() << std::endl; } + ok_ = false; } - - IptcDataSet* ds = nullptr; - std::vector keywords; - - while ((ds = iptc_data_get_next_dataset (iptc_, ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS))) { - iptc_dataset_get_data (ds, buffer, 2100); - keywords.push_back (to_utf8((char*)buffer)); - } - - iptcc["Keywords"] = keywords; - ds = nullptr; - std::vector suppCategories; - - while ((ds = iptc_data_get_next_dataset (iptc_, ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY))) { - iptc_dataset_get_data (ds, buffer, 2100); - suppCategories.push_back (to_utf8((char*)buffer)); - iptc_dataset_unref (ds); - } - - iptcc["SupplementalCategories"] = suppCategories; - return iptcc; } -bool FrameData::getPixelShift () const +bool FramesData::getPixelShift() const { return isPixelShift; } -bool FrameData::getHDR () const + + +bool FramesData::getHDR() const { return isHDR; } -std::string FrameData::getImageType () const + + +std::string FramesData::getImageType() const { return isPixelShift ? "PS" : isHDR ? "HDR" : "STD"; } -IIOSampleFormat FrameData::getSampleFormat () const + + +IIOSampleFormat FramesData::getSampleFormat() const { return sampleFormat; } -rtexif::TagDirectory* FrameData::getExifData () const + + +bool FramesData::hasExif() const { - return frameRootDir; + return ok_; } -bool FrameData::hasExif () const -{ - return frameRootDir && frameRootDir->getCount(); -} -bool FrameData::hasIPTC () const -{ - return iptc; -} -tm FrameData::getDateTime () const + + +tm FramesData::getDateTime() const { return time; } -time_t FrameData::getDateTimeAsTS () const + + +time_t FramesData::getDateTimeAsTS() const { return timeStamp; } -int FrameData::getISOSpeed () const + + +int FramesData::getISOSpeed() const { return iso_speed; } -double FrameData::getFNumber () const + + +double FramesData::getFNumber() const { return aperture; } -double FrameData::getFocalLen () const + + +double FramesData::getFocalLen() const { return focal_len; } -double FrameData::getFocalLen35mm () const + + +double FramesData::getFocalLen35mm() const { return focal_len35mm; } -float FrameData::getFocusDist () const + + +float FramesData::getFocusDist() const { return focus_dist; } -double FrameData::getShutterSpeed () const + + +double FramesData::getShutterSpeed() const { return shutter; } -double FrameData::getExpComp () const + + +double FramesData::getExpComp() const { return expcomp; } -std::string FrameData::getMake () const + + +std::string FramesData::getMake() const { return make; } -std::string FrameData::getModel () const + + +std::string FramesData::getModel() const { return model; } -std::string FrameData::getLens () const + + +std::string FramesData::getLens() const { return lens; } -std::string FrameData::getSerialNumber () const + + +std::string FramesData::getSerialNumber() const { return serial; } -std::string FrameData::getOrientation () const + + +std::string FramesData::getOrientation() const { return orientation; } - -void FramesData::setDCRawFrameCount (unsigned int frameCount) +void FramesData::setDCRawFrameCount(unsigned int frameCount) { dcrawFrameCount = frameCount; } -unsigned int FramesData::getRootCount () const +unsigned int FramesData::getFrameCount() const { - return roots.size(); + return dcrawFrameCount ? dcrawFrameCount : 1; } -unsigned int FramesData::getFrameCount () const + +Glib::ustring FramesData::getFileName() const { - return dcrawFrameCount ? dcrawFrameCount : frames.size(); + return fname_; } -bool FramesData::getPixelShift () const -{ - // So far only Pentax and Sony provide multi-frame Pixel Shift files. - // Only the first frame contains the Pixel Shift tag - // If more brand have to be supported, this rule may need - // to evolve - - return frames.empty() ? false : frames.at(0)->getPixelShift (); -} -bool FramesData::getHDR (unsigned int frame) const -{ - // So far only Pentax provides multi-frame HDR file. - // Only the first frame contains the HDR tag - // If more brand have to be supported, this rule may need - // to evolve - - return frames.empty() || frame >= frames.size() ? false : frames.at(0)->getHDR (); -} - -std::string FramesData::getImageType (unsigned int frame) const -{ - return frames.empty() || frame >= frames.size() ? "STD" : frames.at(0)->getImageType(); -} - -IIOSampleFormat FramesData::getSampleFormat (unsigned int frame) const -{ - return frames.empty() || frame >= frames.size() ? IIOSF_UNKNOWN : frames.at(frame)->getSampleFormat (); -} - -rtexif::TagDirectory* FramesData::getFrameExifData (unsigned int frame) const -{ - return frames.empty() || frame >= frames.size() ? nullptr : frames.at(frame)->getExifData (); -} - -rtexif::TagDirectory* FramesData::getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const -{ - rtexif::TagDirectory *td = nullptr; - if (frames.empty()) { - return nullptr; - } - if (imgSource && rawParams) { - eSensorType sensorType = imgSource->getSensorType(); - unsigned int imgNum = 0; - if (sensorType == ST_BAYER) { - imgNum = rtengine::LIM(rawParams->bayersensor.imageNum, 0, frames.size() - 1); - /* - // might exist someday ? - } else if (sensorType == ST_FUJI_XTRANS) { - imgNum = rtengine::LIM(rawParams->xtranssensor.imageNum, 0, frames.size() - 1); - } else if (sensorType == ST_NONE && !imgSource->isRAW()) { - // standard image multiframe support should come here (when implemented in GUI) - */ - } - - td = getFrameExifData (imgNum); - rtexif::Tag* makeTag; - if (td && (makeTag = td->findTag("Make", true))) { - td = makeTag->getParent(); - } else { - td = getRootExifData(0); - } - } - return td; -} - -rtexif::TagDirectory* FramesData::getRootExifData (unsigned int root) const -{ - return roots.empty() || root >= roots.size() ? nullptr : roots.at(root); -} - -procparams::IPTCPairs FramesData::getIPTCData (unsigned int frame) const -{ - if (frame < frames.size() && frames.at(frame)->hasIPTC()) { - return frames.at(frame)->getIPTCData(); - } else { - if (iptc) { - return FrameData::getIPTCData(iptc); - } else { - procparams::IPTCPairs emptyPairs; - return emptyPairs; - } - } -} - -bool FramesData::hasExif(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.hasExif(); - } - ); -} - -bool FramesData::hasIPTC(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.hasIPTC(); - } - ); -} - -tm FramesData::getDateTime(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getDateTime(); - } - ); -} - -time_t FramesData::getDateTimeAsTS(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getDateTimeAsTS(); - } - ); -} - -int FramesData::getISOSpeed(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getISOSpeed(); - } - ); -} - -double FramesData::getFNumber(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getFNumber(); - } - ); -} - -double FramesData::getFocalLen(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getFocalLen(); - } - ); -} - -double FramesData::getFocalLen35mm(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getFocalLen35mm(); - } - ); -} - -float FramesData::getFocusDist(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getFocusDist(); - } - ); -} - -double FramesData::getShutterSpeed(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getShutterSpeed(); - } - ); -} - -double FramesData::getExpComp(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getExpComp(); - } - ); -} - -std::string FramesData::getMake(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getMake(); - } - ); -} - -std::string FramesData::getModel(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getModel(); - } - ); -} - -std::string FramesData::getLens(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getLens(); - } - ); -} - -std::string FramesData::getSerialNumber(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getSerialNumber(); - } - ); -} - -std::string FramesData::getOrientation(unsigned int frame) const -{ - return getFromFrame( - frames, - frame, - [](const FrameData& frame_data) - { - return frame_data.getOrientation(); - } - ); -} - - //------inherited functions--------------// -std::string FramesMetaData::apertureToString (double aperture) +std::string FramesMetaData::apertureToString(double aperture) { char buffer[256]; @@ -1181,7 +584,7 @@ std::string FramesMetaData::apertureToString (double aperture) return buffer; } -std::string FramesMetaData::shutterToString (double shutter) +std::string FramesMetaData::shutterToString(double shutter) { char buffer[256]; @@ -1195,7 +598,7 @@ std::string FramesMetaData::shutterToString (double shutter) return buffer; } -std::string FramesMetaData::expcompToString (double expcomp, bool maskZeroexpcomp) +std::string FramesMetaData::expcompToString(double expcomp, bool maskZeroexpcomp) { char buffer[256]; @@ -1213,9 +616,8 @@ std::string FramesMetaData::expcompToString (double expcomp, bool maskZeroexpcom } } -double FramesMetaData::shutterFromString (std::string s) +double FramesMetaData::shutterFromString(std::string s) { - size_t i = s.find_first_of ('/'); if (i == std::string::npos) { @@ -1225,158 +627,9 @@ double FramesMetaData::shutterFromString (std::string s) } } -double FramesMetaData::apertureFromString (std::string s) +double FramesMetaData::apertureFromString(std::string s) { - return atof (s.c_str()); + return atof(s.c_str()); } -extern "C" { - -#include -#include - - struct _IptcDataPrivate { - unsigned int ref_count; - - IptcLog *log; - IptcMem *mem; - }; - - IptcData * - iptc_data_new_from_jpeg_file (FILE *infile) - { - IptcData *d; - unsigned char * buf; - int buf_len = 256 * 256; - int len, offset; - unsigned int iptc_len; - - if (!infile) { - return nullptr; - } - - d = iptc_data_new (); - - if (!d) { - return nullptr; - } - - buf = (unsigned char*)iptc_mem_alloc (d->priv->mem, buf_len); - - if (!buf) { - iptc_data_unref (d); - return nullptr; - } - - len = iptc_jpeg_read_ps3 (infile, buf, buf_len); - - if (len <= 0) { - goto failure; - } - - offset = iptc_jpeg_ps3_find_iptc (buf, len, &iptc_len); - - if (offset <= 0) { - goto failure; - } - - iptc_data_load (d, buf + offset, iptc_len); - - iptc_mem_free (d->priv->mem, buf); - return d; - -failure: - iptc_mem_free (d->priv->mem, buf); - iptc_data_unref (d); - return nullptr; - } - -} - -FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) : - iptc(nullptr), dcrawFrameCount (0) -{ - if (rml && (rml->exifBase >= 0 || rml->ciffBase >= 0)) { - FILE* f = g_fopen (fname.c_str (), "rb"); - - if (f) { - rtexif::ExifManager exifManager (f, std::move(rml), firstFrameOnly); - if (exifManager.f && exifManager.rml) { - if (exifManager.rml->exifBase >= 0) { - exifManager.parseRaw (); - } else if (exifManager.rml->ciffBase >= 0) { - exifManager.parseCIFF (); - } - } - - // copying roots - roots = exifManager.roots; - - // creating FrameData - for (auto currFrame : exifManager.frames) { - frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); - } - for (auto currRoot : roots) { - rtexif::Tag* t = currRoot->getTag(0x83BB); - - if (t && !iptc) { - iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); - break; - } - } - - fclose (f); - } - } else if (hasJpegExtension(fname)) { - FILE* f = g_fopen (fname.c_str (), "rb"); - - if (f) { - rtexif::ExifManager exifManager (f, std::move(rml), true); - if (exifManager.f) { - exifManager.parseJPEG (); - roots = exifManager.roots; - for (auto currFrame : exifManager.frames) { - frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); - } - rewind (exifManager.f); // Not sure this is necessary - iptc = iptc_data_new_from_jpeg_file (exifManager.f); - } - fclose (f); - } - } else if (hasTiffExtension(fname)) { - FILE* f = g_fopen (fname.c_str (), "rb"); - - if (f) { - rtexif::ExifManager exifManager (f, std::move(rml), firstFrameOnly); - - exifManager.parseTIFF(); - roots = exifManager.roots; - - // creating FrameData - for (auto currFrame : exifManager.frames) { - frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); - } - for (auto currRoot : roots) { - rtexif::Tag* t = currRoot->getTag(0x83BB); - - if (t && !iptc) { - iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); - break; - } - } - fclose (f); - } - } -} - -FramesData::~FramesData () -{ - for (auto currRoot : roots) { - delete currRoot; - } - - if (iptc) { - iptc_data_free (iptc); - } -} diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index c6889e653..6f2147277 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -24,20 +24,20 @@ #include "rawimage.h" #include #include -#include "../rtexif/rtexif.h" -#include +#include #include "rtengine.h" namespace rtengine { -class FrameData -{ +Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname); -protected: - rtexif::TagDirectory* frameRootDir; - IptcData* iptc; +class FramesData : public FramesMetaData { +private: + bool ok_; + Glib::ustring fname_; + unsigned int dcrawFrameCount; struct tm time; time_t timeStamp; int iso_speed; @@ -50,82 +50,34 @@ protected: std::string orientation; std::string lens; IIOSampleFormat sampleFormat; - - // each frame has the knowledge of "being an" - // or "being part of an" HDR or PS image bool isPixelShift; bool isHDR; - + public: + FramesData (const Glib::ustring& fname); - FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir); - virtual ~FrameData (); - - bool getPixelShift () const; - bool getHDR () const; - std::string getImageType () const; - IIOSampleFormat getSampleFormat () const; - rtexif::TagDirectory* getExifData () const; - procparams::IPTCPairs getIPTCData () const; - static procparams::IPTCPairs getIPTCData (IptcData* iptc_); - bool hasExif () const; - bool hasIPTC () const; - tm getDateTime () const; - time_t getDateTimeAsTS () const; - int getISOSpeed () const; - double getFNumber () const; - double getFocalLen () const; - double getFocalLen35mm () const; - float getFocusDist () const; - double getShutterSpeed () const; - double getExpComp () const; - std::string getMake () const; - std::string getModel () const; - std::string getLens () const; - std::string getSerialNumber () const; - std::string getOrientation () const; -}; - -class FramesData : public FramesMetaData { -private: - // frame's root IFD, can be a file root IFD or a SUB-IFD - std::vector> frames; - // root IFD in the file - std::vector roots; - IptcData* iptc; - unsigned int dcrawFrameCount; - -public: - FramesData (const Glib::ustring& fname, std::unique_ptr rml = nullptr, bool firstFrameOnly = false); - ~FramesData () override; - - void setDCRawFrameCount (unsigned int frameCount); - unsigned int getRootCount () const override; - unsigned int getFrameCount () const override; - bool getPixelShift () const override; - bool getHDR (unsigned int frame = 0) const override; - std::string getImageType (unsigned int frame) const override; - IIOSampleFormat getSampleFormat (unsigned int frame = 0) const override; - rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const override; - rtexif::TagDirectory* getRootExifData (unsigned int root = 0) const override; - rtexif::TagDirectory* getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const override; - procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const override; - bool hasExif (unsigned int frame = 0) const override; - bool hasIPTC (unsigned int frame = 0) const override; - tm getDateTime (unsigned int frame = 0) const override; - time_t getDateTimeAsTS (unsigned int frame = 0) const override; - int getISOSpeed (unsigned int frame = 0) const override; - double getFNumber (unsigned int frame = 0) const override; - double getFocalLen (unsigned int frame = 0) const override; - double getFocalLen35mm (unsigned int frame = 0) const override; - float getFocusDist (unsigned int frame = 0) const override; - double getShutterSpeed (unsigned int frame = 0) const override; - double getExpComp (unsigned int frame = 0) const override; - std::string getMake (unsigned int frame = 0) const override; - std::string getModel (unsigned int frame = 0) const override; - std::string getLens (unsigned int frame = 0) const override; - std::string getSerialNumber (unsigned int frame = 0) const; - std::string getOrientation (unsigned int frame = 0) const override; + void setDCRawFrameCount(unsigned int frameCount); + unsigned int getFrameCount() const override; + bool getPixelShift() const override; + bool getHDR() const override; + std::string getImageType() const override; + IIOSampleFormat getSampleFormat() const override; + bool hasExif() const override; + tm getDateTime() const override; + time_t getDateTimeAsTS() const override; + int getISOSpeed() const override; + double getFNumber() const override; + double getFocalLen() const override; + double getFocalLen35mm() const override; + float getFocusDist() const override; + double getShutterSpeed() const override; + double getExpComp() const override; + std::string getMake() const override; + std::string getModel() const override; + std::string getLens() const override; + std::string getSerialNumber() const; + std::string getOrientation() const override; + Glib::ustring getFileName() const override; }; diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index f1fa8dbef..f7d95b2df 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -24,7 +24,6 @@ #include #include #include -#include #include "rt_math.h" #include "procparams.h" #include "../rtgui/options.h" @@ -37,9 +36,10 @@ #endif #include "imageio.h" -#include "iptcpairs.h" +//#include "iptcpairs.h" #include "iccjpeg.h" #include "color.h" +#include "imagedata.h" #include "jpeg.h" @@ -80,97 +80,6 @@ FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname) Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."}; -// For only copying the raw input data -void ImageIO::setMetadata (const rtexif::TagDirectory* eroot) -{ - if (exifRoot != nullptr) { - delete exifRoot; - exifRoot = nullptr; - } - - if (eroot) { - rtexif::TagDirectory* td = ((rtexif::TagDirectory*)eroot)->clone (nullptr); - - // make IPTC and XMP pass through - td->keepTag(0x83bb); // IPTC - td->keepTag(0x02bc); // XMP - - exifRoot = td; - } -} - -// For merging with RT specific data -void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc) -{ - - // store exif info - exifChange->clear(); - *exifChange = exif; - - if (exifRoot != nullptr) { - delete exifRoot; - exifRoot = nullptr; - } - - if (eroot) { - exifRoot = ((rtexif::TagDirectory*)eroot)->clone (nullptr); - } - - if (iptc != nullptr) { - iptc_data_free (iptc); - iptc = nullptr; - } - - // build iptc structures for libiptcdata - if (iptcc.empty()) { - return; - } - - iptc = iptc_data_new (); - - const unsigned char utf8Esc[] = {0x1B, '%', 'G'}; - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_OBJECT_ENV, IPTC_TAG_CHARACTER_SET); - iptc_dataset_set_data (ds, utf8Esc, 3, IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - - for (rtengine::procparams::IPTCPairs::const_iterator i = iptcc.begin(); i != iptcc.end(); ++i) { - if (i->first == "Keywords" && !(i->second.empty())) { - for (unsigned int j = 0; j < i->second.size(); j++) { - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS); - iptc_dataset_set_data (ds, (unsigned char*)i->second.at(j).c_str(), min(static_cast(64), i->second.at(j).bytes()), IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - } - - continue; - } else if (i->first == "SupplementalCategories" && !(i->second.empty())) { - for (unsigned int j = 0; j < i->second.size(); j++) { - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY); - iptc_dataset_set_data (ds, (unsigned char*)i->second.at(j).c_str(), min(static_cast(32), i->second.at(j).bytes()), IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - } - - continue; - } - - for (int j = 0; j < 16; j++) - if (i->first == strTags[j].field && !(i->second.empty())) { - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag); - iptc_dataset_set_data (ds, (unsigned char*)i->second.at(0).c_str(), min(strTags[j].size, i->second.at(0).bytes()), IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - } - } - - iptc_data_sort (iptc); -} - void ImageIO::setOutputProfile (const char* pdata, int plen) { @@ -194,9 +103,6 @@ ImageIO::ImageIO() : loadedProfileData(nullptr), loadedProfileDataJpg(false), loadedProfileLength(0), - exifChange(new procparams::ExifPairs), - iptc(nullptr), - exifRoot(nullptr), sampleFormat(IIOSF_UNKNOWN), sampleArrangement(IIOSA_UNKNOWN) { @@ -210,7 +116,7 @@ ImageIO::~ImageIO () } deleteLoadedProfileData(); - delete exifRoot; + // delete exifRoot; delete [] profileData; } @@ -919,76 +825,6 @@ int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool s } -namespace { - -// Taken from Darktable -- src/imageio/format/png.c -// -/* Write EXIF data to PNG file. - * Code copied from DigiKam's libs/dimg/loaders/pngloader.cpp. - * The EXIF embedding is defined by ImageMagicK. - * It is documented in the ExifTool page: - * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html - * - * ..and in turn copied from ufraw. thanks to udi and colleagues - * for making useful code much more readable and discoverable ;) - */ - -void PNGwriteRawProfile(png_struct *ping, png_info *ping_info, const char *profile_type, guint8 *profile_data, png_uint_32 length) -{ - png_textp text; - long i; - guint8 *sp; - png_charp dp; - png_uint_32 allocated_length, description_length; - - const guint8 hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - text = static_cast(png_malloc(ping, sizeof(png_text))); - description_length = strlen(profile_type); - allocated_length = length * 2 + (length >> 5) + 20 + description_length; - - text[0].text = static_cast(png_malloc(ping, allocated_length)); - text[0].key = static_cast(png_malloc(ping, 80)); - text[0].key[0] = '\0'; - - g_strlcat(text[0].key, "Raw profile type ", 80); - g_strlcat(text[0].key, profile_type, 80); - - sp = profile_data; - dp = text[0].text; - *dp++ = '\n'; - - g_strlcpy(dp, profile_type, allocated_length); - - dp += description_length; - *dp++ = '\n'; - *dp = '\0'; - - g_snprintf(dp, allocated_length - strlen(text[0].text), "%8lu ", static_cast(length)); - - dp += 8; - - for(i = 0; i < long(length); i++) - { - if(i % 36 == 0) *dp++ = '\n'; - - *(dp++) = hex[((*sp >> 4) & 0x0f)]; - *(dp++) = hex[((*sp++) & 0x0f)]; - } - - *dp++ = '\n'; - *dp = '\0'; - text[0].text_length = (dp - text[0].text); - text[0].compression = -1; - - if(text[0].text_length <= allocated_length) png_set_text(ping, ping_info, text, 1); - - png_free(ping, text[0].text); - png_free(ping, text[0].key); - png_free(ping, text); -} - -} // namespace - int ImageIO::savePNG (const Glib::ustring &fname, int bps) const { if (getWidth() < 1 || getHeight() < 1) { @@ -1060,30 +896,6 @@ int ImageIO::savePNG (const Glib::ustring &fname, int bps) const png_set_iCCP(png, info, const_cast("icc"), 0, profdata, profileLength); } - { - // buffer for the exif and iptc - unsigned int bufferSize; - unsigned char* buffer = nullptr; // buffer will be allocated in createTIFFHeader - unsigned char* iptcdata = nullptr; - unsigned int iptclen = 0; - - if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) { - iptc_data_free_buf (iptc, iptcdata); - iptcdata = nullptr; - } - - int size = rtexif::ExifManager::createPNGMarker(exifRoot, *exifChange, width, height, bps, (char*)iptcdata, iptclen, buffer, bufferSize); - - if (iptcdata) { - iptc_data_free_buf (iptc, iptcdata); - } - if (buffer && size) { - PNGwriteRawProfile(png, info, "exif", buffer, size); - delete[] buffer; - } - } - - int rowlen = width * 3 * bps / 8; unsigned char *row = new unsigned char [rowlen]; @@ -1117,6 +929,11 @@ int ImageIO::savePNG (const Glib::ustring &fname, int bps) const delete [] row; fclose (file); + if (!saveMetadata(fname)) { + g_remove(fname.c_str()); + return IMIO_CANNOTWRITEFILE; + } + if (pl) { pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); @@ -1216,49 +1033,6 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con jpeg_start_compress(&cinfo, TRUE); - // buffer for exif and iptc markers - unsigned char* buffer = new unsigned char[165535]; //FIXME: no buffer size check so it can be overflowed in createJPEGMarker() for large tags, and then software will crash - unsigned int size; - - // assemble and write exif marker - if (exifRoot) { - int size = rtexif::ExifManager::createJPEGMarker (exifRoot, *exifChange, cinfo.image_width, cinfo.image_height, buffer); - - if (size > 0 && size < 65530) { - jpeg_write_marker(&cinfo, JPEG_APP0 + 1, buffer, size); - } - } - - // assemble and write iptc marker - if (iptc) { - unsigned char* iptcdata; - bool error = false; - - if (iptc_data_save (iptc, &iptcdata, &size)) { - if (iptcdata) { - iptc_data_free_buf (iptc, iptcdata); - } - - error = true; - } - - int bytes = 0; - - if (!error && (bytes = iptc_jpeg_ps3_save_iptc (nullptr, 0, iptcdata, size, buffer, 65532)) < 0) { - error = true; - } - - if (iptcdata) { - iptc_data_free_buf (iptc, iptcdata); - } - - if (!error) { - jpeg_write_marker(&cinfo, JPEG_APP0 + 13, buffer, bytes); - } - } - - delete [] buffer; - // write icc profile to the output if (profileData) { write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength); @@ -1310,6 +1084,11 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con fclose (file); + if (!saveMetadata(fname)) { + g_remove(fname.c_str()); + return IMIO_CANNOTWRITEFILE; + } + if (pl) { pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); @@ -1336,7 +1115,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u unsigned char* linebuffer = new unsigned char[lineWidth]; // little hack to get libTiff to use proper byte order (see TIFFClienOpen()): - const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb"); + const char *mode = "w"; #ifdef WIN32 FILE *file = g_fopen_withBinaryAndLock (fname); int fileno = _fileno(file); @@ -1344,7 +1123,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode); #else TIFF* out = TIFFOpen(fname.c_str(), mode); - int fileno = TIFFFileno (out); + // int fileno = TIFFFileno (out); #endif if (!out) { @@ -1357,113 +1136,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u pl->setProgress (0.0); } - bool applyExifPatch = false; - - if (exifRoot) { - rtexif::TagDirectory* cl = (const_cast (exifRoot))->clone (nullptr); - - // ------------------ remove some unknown top level tags which produce warnings when opening a tiff (might be useless) ----------------- - - rtexif::Tag *removeTag = cl->getTag (0x9003); - - if (removeTag) { - removeTag->setKeep (false); - } - - removeTag = cl->getTag (0x9211); - - if (removeTag) { - removeTag->setKeep (false); - } - - // ------------------ Apply list of change ----------------- - - for (auto currExifChange : *exifChange) { - cl->applyChange (currExifChange.first, currExifChange.second); - } - - rtexif::Tag *tag = cl->getTag (TIFFTAG_EXIFIFD); - - if (tag && tag->isDirectory()) { - rtexif::TagDirectory *exif = tag->getDirectory(); - - if (exif) { - int exif_size = exif->calculateSize(); - unsigned char *buffer = new unsigned char[exif_size + 8]; - // TIFFOpen writes out the header and sets file pointer at position 8 - - exif->write (8, buffer); - - write (fileno, buffer + 8, exif_size); - - delete [] buffer; - // let libtiff know that scanlines or any other following stuff should go - // at a different offset: - TIFFSetWriteOffset (out, exif_size + 8); - TIFFSetField (out, TIFFTAG_EXIFIFD, 8); - applyExifPatch = true; - } - } - - //TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed. - - if ((tag = cl->getTag (TIFFTAG_MODEL)) != nullptr) { - TIFFSetField (out, TIFFTAG_MODEL, tag->getValue()); - } - - if ((tag = cl->getTag (TIFFTAG_MAKE)) != nullptr) { - TIFFSetField (out, TIFFTAG_MAKE, tag->getValue()); - } - - if ((tag = cl->getTag (TIFFTAG_DATETIME)) != nullptr) { - TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue()); - } - - if ((tag = cl->getTag (TIFFTAG_ARTIST)) != nullptr) { - TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue()); - } - - if ((tag = cl->getTag (TIFFTAG_COPYRIGHT)) != nullptr) { - TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue()); - } - - delete cl; - } - - unsigned char* iptcdata = nullptr; - unsigned int iptclen = 0; - - if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen)) { - if (iptcdata) { - iptc_data_free_buf (iptc, iptcdata); - iptcdata = nullptr; - } - } - -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA; -#else - bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL; -#endif - if (iptcdata) { - rtexif::Tag iptcTag(nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData")); - iptcTag.initLongArray((char*)iptcdata, iptclen); - if (needsReverse) { - unsigned char *ptr = iptcTag.getValue(); - for (int a = 0; a < iptcTag.getCount(); ++a) { - unsigned char cc; - cc = ptr[3]; - ptr[3] = ptr[0]; - ptr[0] = cc; - cc = ptr[2]; - ptr[2] = ptr[1]; - ptr[1] = cc; - ptr += 4; - } - } - TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag.getCount(), (long*)iptcTag.getValue()); - iptc_data_free_buf (iptc, iptcdata); - } + bool needsReverse = false; TIFFSetField (out, TIFFTAG_SOFTWARE, "RawTherapee " RTVERSION); TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width); @@ -1523,38 +1196,6 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u writeOk = false; } - /************************************************************************************************************ - * - * Hombre: This is a dirty hack to update the Exif tag data type to 0x0004 so that Windows can understand it. - * libtiff will set this data type to 0x000d and doesn't provide any mechanism to update it before - * dumping to the file. - * - */ - if (applyExifPatch) { - unsigned char b[10]; - uint16 tagCount = 0; - lseek(fileno, 4, SEEK_SET); - read(fileno, b, 4); - uint32 ifd0Offset = rtexif::sget4(b, exifRoot->getOrder()); - lseek(fileno, ifd0Offset, SEEK_SET); - read(fileno, b, 2); - tagCount = rtexif::sget2(b, exifRoot->getOrder()); - for (size_t i = 0; i < tagCount ; ++i) { - uint16 tagID = 0; - read(fileno, b, 2); - tagID = rtexif::sget2(b, exifRoot->getOrder()); - if (tagID == 0x8769) { - rtexif::sset2(4, b, exifRoot->getOrder()); - write(fileno, b, 2); - break; - } else { - read(fileno, b, 10); - } - } - } - /************************************************************************************************************/ - - TIFFClose (out); #ifdef WIN32 fclose (file); @@ -1562,6 +1203,10 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u delete [] linebuffer; + if (!saveMetadata(fname)) { + writeOk = false; + } + if (pl) { pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); @@ -1692,3 +1337,42 @@ void ImageIO::deleteLoadedProfileData( ) loadedProfileData = nullptr; } + + +bool ImageIO::saveMetadata(const Glib::ustring &fname) const +{ + if (metadataInfo.filename().empty()) { + return true; + } + + try { + auto src = open_exiv2(metadataInfo.filename()); + auto dst = open_exiv2(fname); + src->readMetadata(); + dst->setMetadata(*src); + dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; + for (auto &p : metadataInfo.exif()) { + try { + dst->exifData()[p.first] = p.second; + } catch (Exiv2::AnyError &exc) {} + } + for (auto &p : metadataInfo.iptc()) { + try { + auto &v = p.second; + if (v.size() >= 1) { + dst->iptcData()[p.first] = v[0]; + for (size_t j = 1; j < v.size(); ++j) { + Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); + d.setValue(v[j]); + dst->iptcData().add(d); + } + } + } catch (Exiv2::AnyError &exc) {} + } + dst->writeMetadata(); + return true; + } catch (Exiv2::AnyError &exc) { + std::cout << "EXIF ERROR: " << exc.what() << std::endl; + return false; + } +} diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 05a11655a..0bdb7d43a 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -31,13 +31,12 @@ #include #include -#include #include "rtengine.h" #include "imageformat.h" -#include "../rtexif/rtexif.h" #include "imagedimensions.h" #include "iimage.h" #include "colortemp.h" +#include "procparams.h" namespace rtengine { @@ -45,6 +44,24 @@ namespace rtengine class ProgressListener; class Imagefloat; +class MetadataInfo { +public: + explicit MetadataInfo(const Glib::ustring &src=Glib::ustring()): + src_(src) {} + + const Glib::ustring &filename() const { return src_; } + + const rtengine::procparams::ExifPairs &exif() const { return exif_; } + const rtengine::procparams::IPTCPairs &iptc() const { return iptc_; } + void setExif(const rtengine::procparams::ExifPairs &exif) { exif_ = exif; } + void setIptc(const rtengine::procparams::IPTCPairs &iptc) { iptc_ = iptc; } + +private: + Glib::ustring src_; + rtengine::procparams::ExifPairs exif_; + rtengine::procparams::IPTCPairs iptc_; +}; + class ImageIO : virtual public ImageDatas { @@ -56,12 +73,10 @@ protected: char* loadedProfileData; bool loadedProfileDataJpg; int loadedProfileLength; - const std::unique_ptr exifChange; - IptcData* iptc; - const rtexif::TagDirectory* exifRoot; MyMutex imutex; IIOSampleFormat sampleFormat; IIOSampleArrangement sampleArrangement; + MetadataInfo metadataInfo; private: void deleteLoadedProfileData( ); @@ -103,10 +118,11 @@ public: cmsHPROFILE getEmbeddedProfile () const; void getEmbeddedProfileData (int& length, unsigned char*& pdata) const; - void setMetadata (const rtexif::TagDirectory* eroot); - void setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc); + void setMetadata(const MetadataInfo &info) { metadataInfo = info; } void setOutputProfile (const char* pdata, int plen); + bool saveMetadata(const Glib::ustring &fname) const; + MyMutex& mutex (); }; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ec047f853..079c5cb48 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -876,20 +876,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) customColCurve1, customColCurve2, customColCurve3, 1); const FramesMetaData* metaData = imgsrc->getMetaData(); - int imgNum = 0; - - if (imgsrc->isRAW()) { - if (imgsrc->getSensorType() == ST_BAYER) { - imgNum = rtengine::LIM(params->raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); - } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { - //imgNum = rtengine::LIM(params->raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); - } - } - - float fnum = metaData->getFNumber(imgNum); // F number - float fiso = metaData->getISOSpeed(imgNum) ; // ISO - float fspeed = metaData->getShutterSpeed(imgNum) ; // Speed - double fcomp = metaData->getExpComp(imgNum); // Compensation +/- + float fnum = metaData->getFNumber(); // F number + float fiso = metaData->getISOSpeed() ; // ISO + float fspeed = metaData->getShutterSpeed() ; // Speed + double fcomp = metaData->getExpComp(); // Compensation +/- double adap; if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong @@ -1413,7 +1403,8 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a im = tempImage; } - im->setMetadata(imgsrc->getMetaData()->getRootExifData()); + // im->setMetadata(imgsrc->getMetaData()->getRootExifData()); + im->setMetadata(MetadataInfo(imgsrc->getFileName())); im->saveTIFF(fname, 16, false, true); delete im; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index d215833d3..8dd57e74d 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5656,18 +5656,17 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_size) { if (fname != "") { - rtengine::RawMetaDataLocation ri; int w_raw = -1, h_raw = thumb_size; int w_thumb = -1, h_thumb = thumb_size; eSensorType sensorType = rtengine::ST_NONE; - Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, w_thumb, h_thumb, 1, FALSE); + Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, sensorType, w_thumb, h_thumb, 1, FALSE); if (!thumb) { return 0.0; } - Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, w_raw, h_raw, 1, 1.0, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, sensorType, w_raw, h_raw, 1, 1.0, FALSE); if (!raw) { delete thumb; diff --git a/rtengine/iptcpairs.h b/rtengine/iptcpairs.h deleted file mode 100644 index e0b34180f..000000000 --- a/rtengine/iptcpairs.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _IPTCPAIRS_ -#define _IPTCPAIRS_ - - -struct IptcPair { - IptcTag tag; - size_t size; - Glib::ustring field; -}; - -const IptcPair strTags[] = { - {IPTC_TAG_CAPTION, 2000, "Caption"}, - {IPTC_TAG_WRITER_EDITOR, 32, "CaptionWriter"}, - {IPTC_TAG_HEADLINE, 256, "Headline"}, - {IPTC_TAG_SPECIAL_INSTRUCTIONS, 256, "Instructions"}, - {IPTC_TAG_CATEGORY, 3, "Category"}, - {IPTC_TAG_BYLINE, 32, "Creator"}, - {IPTC_TAG_BYLINE_TITLE, 32, "CreatorJobTitle"}, - {IPTC_TAG_CREDIT, 32, "Credit"}, - {IPTC_TAG_SOURCE, 32, "Source"}, - {IPTC_TAG_COPYRIGHT_NOTICE, 128, "Copyright"}, - {IPTC_TAG_CITY, 32, "City"}, - {IPTC_TAG_STATE, 32, "Province"}, - {IPTC_TAG_COUNTRY_NAME, 64, "Country"}, - {IPTC_TAG_OBJECT_NAME, 64, "Title"}, - {IPTC_TAG_ORIG_TRANS_REF, 32, "TransReference"}, - {IPTC_TAG_DATE_CREATED, 8, "DateCreated"} -}; - -#endif - diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index e62a1adea..944e2e0ce 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -60,9 +60,8 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext data = tpp->getImage8Data(); } } else { - rtengine::RawMetaDataLocation ri; eSensorType sensorType = rtengine::ST_NONE; - tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, width, height, 1, true, true); + tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, sensorType, width, height, 1, true, true); if (tpp) { data = tpp->getImage8Data(); diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 6d914bb27..f9daead22 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -295,7 +295,36 @@ bool saveToKeyfile( return false; } -} + +const std::map exif_keys = { + {"Copyright", "Exif.Image.Copyright"}, + {"Artist", "Exif.Image.Artist"}, + {"ImageDescription", "Exif.Image.ImageDescription"}, + {"Exif.UserComment", "Exif.Photo.UserComment"} +}; + +const std::map iptc_keys = { + {"Title", "Iptc.Application2.ObjectName"}, + {"Category", "Iptc.Application2.Category"}, + {"SupplementalCategories", "Iptc.Application2.SuppCategory"}, + {"Keywords", "Iptc.Application2.Keywords"}, + {"Instructions", "Iptc.Application2.SpecialInstructions"}, + {"DateCreated", "Iptc.Application2.DateCreated"}, + {"Creator", "Iptc.Application2.Byline"}, + {"CreatorJobTitle", "Iptc.Application2.BylineTitle"}, + {"City", "Iptc.Application2.City"}, + {"Province", "Iptc.Application2.ProvinceState"}, + {"Country", "Iptc.Application2.CountryName"}, + {"TransReference", "Iptc.Application2.TransmissionReference"}, + {"Headline", "Iptc.Application2.Headline"}, + {"Credit", "Iptc.Application2.Credit"}, + {"Source", "Iptc.Application2.Source"}, + {"Copyright", "Iptc.Application2.Copyright"}, + {"Caption", "Iptc.Application2.Caption"}, + {"CaptionWriter", "Iptc.Application2.Writer"} +}; + +} // namespace namespace rtengine { @@ -3568,16 +3597,30 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // EXIF change list if (!pedited || pedited->exif) { + std::map m; + for (auto &p : exif_keys) { + m[p.second] = p.first; + } for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); ++i) { - keyFile.set_string("Exif", i->first, i->second); + auto it = m.find(i->first); + if (it != m.end()) { + keyFile.set_string("Exif", it->second, i->second); + } } } // IPTC change list if (!pedited || pedited->iptc) { + std::map m; + for (auto &p : iptc_keys) { + m[p.second] = p.first; + } for (IPTCPairs::const_iterator i = iptc.begin(); i != iptc.end(); ++i) { - Glib::ArrayHandle values = i->second; - keyFile.set_string_list("IPTC", i->first, values); + auto it = m.find(i->first); + if (it != m.end()) { + Glib::ArrayHandle values = i->second; + keyFile.set_string_list("IPTC", it->second, values); + } } } @@ -5120,10 +5163,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Exif")) { for (const auto& key : keyFile.get_keys("Exif")) { - exif[key] = keyFile.get_string("Exif", key); + auto it = exif_keys.find(key); + if (it != exif_keys.end()) { + exif[it->second] = keyFile.get_string("Exif", key); - if (pedited) { - pedited->exif = true; + if (pedited) { + pedited->exif = true; + } } } } @@ -5143,7 +5189,12 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("IPTC")) { for (const auto& key : keyFile.get_keys("IPTC")) { // does this key already exist? - const IPTCPairs::iterator element = iptc.find(key); + auto it = iptc_keys.find(key); + if (it == iptc_keys.end()) { + continue; + } + auto kk = it->second; + const IPTCPairs::iterator element = iptc.find(kk); if (element != iptc.end()) { // it already exist so we cleanup the values @@ -5152,7 +5203,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) // TODO: look out if merging Keywords and SupplementalCategories from the procparams chain would be interesting for (const auto& currLoadedTagValue : keyFile.get_string_list("IPTC", key)) { - iptc[key].push_back(currLoadedTagValue); + iptc[kk].push_back(currLoadedTagValue); } if (pedited) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0982fda48..951b02b1a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1075,90 +1075,8 @@ struct MetaDataParams { }; -/** - * Minimal wrapper allowing forward declaration for representing a key/value for the exif metadata information - */ -class ExifPairs final -{ -public: - using const_iterator = std::map::const_iterator; - - const_iterator begin() const - { - return pairs.begin(); - } - - const_iterator end() const - { - return pairs.end(); - } - - void clear() - { - pairs.clear(); - } - - Glib::ustring& operator[](const Glib::ustring& key) - { - return pairs[key]; - } - - bool operator ==(const ExifPairs& other) const - { - return pairs == other.pairs; - } - -private: - std::map pairs; -}; - -/** - * The IPTC key/value pairs - */ -class IPTCPairs final -{ -public: - using iterator = std::map>::iterator; - using const_iterator = std::map>::const_iterator; - - iterator find(const Glib::ustring& key) - { - return pairs.find(key); - } - - const_iterator begin() const - { - return pairs.begin(); - } - - const_iterator end() const - { - return pairs.end(); - } - - bool empty() const - { - return pairs.empty(); - } - - void clear() - { - pairs.clear(); - } - - std::vector& operator[](const Glib::ustring& key) - { - return pairs[key]; - } - - bool operator ==(const IPTCPairs& other) const - { - return pairs == other.pairs; - } - -private: - std::map> pairs; -}; +typedef std::map ExifPairs; +typedef std::map> IPTCPairs; struct WaveletParams { std::vector ccwcurve; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 0f0d31c40..5efb3249c 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1693,8 +1693,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) // Load complete Exif information - std::unique_ptr rml(new RawMetaDataLocation (ri->get_exifBase(), ri->get_ciffBase(), ri->get_ciffLen())); - idata = new FramesData (fname, std::move(rml)); + idata = new FramesData (fname); idata->setDCRawFrameCount (numFrames); green(W, H); diff --git a/rtengine/rawmetadatalocation.h b/rtengine/rawmetadatalocation.h deleted file mode 100644 index de6c6a0d7..000000000 --- a/rtengine/rawmetadatalocation.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _RAWMETADATALOCATION_ -#define _RAWMETADATALOCATION_ - -namespace rtengine -{ - -class RawMetaDataLocation { - -public: - int exifBase; - int ciffBase; - int ciffLength; - - RawMetaDataLocation () : exifBase(-1), ciffBase(-1), ciffLength(-1) {} - explicit RawMetaDataLocation (int exifBase) : exifBase(exifBase), ciffBase(-1), ciffLength(-1) {} - RawMetaDataLocation (int ciffBase, int ciffLength) : exifBase(-1), ciffBase(ciffBase), ciffLength(ciffLength) {} - RawMetaDataLocation (int exifBase, int ciffBase, int ciffLength) : exifBase(exifBase), ciffBase(ciffBase), ciffLength(ciffLength) {} -}; - -} - -#endif - diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 6264d43ae..b6b7402f9 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -26,8 +26,6 @@ #include #include #include -#include "../rtexif/rtexif.h" -#include "rawmetadatalocation.h" #include "iimage.h" #include "utils.h" #include "../rtgui/threadutils.h" @@ -49,14 +47,15 @@ enum RenderingIntent : int; namespace procparams { -class ProcParams; -class IPTCPairs; +typedef std::map ExifPairs; +typedef std::map> IPTCPairs; struct RAWParams; struct ColorManagementParams; struct CropParams; enum class ToneCurveMode : int; +class ProcParams; } @@ -73,76 +72,54 @@ class FramesMetaData { public: - /** @return Returns the number of root Metadata */ - virtual unsigned int getRootCount () const = 0; /** @return Returns the number of frame contained in the file based on Metadata */ - virtual unsigned int getFrameCount () const = 0; + virtual unsigned int getFrameCount() const = 0; /** Checks the availability of exif metadata tags. * @return Returns true if image contains exif metadata tags */ - virtual bool hasExif (unsigned int frame = 0) const = 0; - /** Returns the directory of exif metadata tags. - * @param root root number in the metadata tree - * @return The directory of exif metadata tags */ - virtual rtexif::TagDirectory* getRootExifData (unsigned int root = 0) const = 0; - /** Returns the directory of exif metadata tags. - * @param frame frame number in the metadata tree - * @return The directory of exif metadata tags */ - virtual rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const = 0; - /** Returns the directory of exif metadata tags containing at least the 'Make' tag for the requested frame. - * If no usable metadata exist in the frame, send back the best TagDirectory describing the frame content. - * @param imgSource rawimage that we want the metadata from - * @param rawParams RawParams to select the frame number - * @return The directory of exif metadata tags containing at least the 'Make' tag */ - virtual rtexif::TagDirectory* getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const = 0; - /** Checks the availability of IPTC tags. - * @return Returns true if image contains IPTC tags */ - virtual bool hasIPTC (unsigned int frame = 0) const = 0; - /** Returns the directory of IPTC tags. - * @return The directory of IPTC tags */ - virtual procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const = 0; + virtual bool hasExif() const = 0; /** @return a struct containing the date and time of the image */ - virtual tm getDateTime (unsigned int frame = 0) const = 0; + virtual tm getDateTime() const = 0; /** @return a timestamp containing the date and time of the image */ - virtual time_t getDateTimeAsTS(unsigned int frame = 0) const = 0; + virtual time_t getDateTimeAsTS() const = 0; /** @return the ISO of the image */ - virtual int getISOSpeed (unsigned int frame = 0) const = 0; + virtual int getISOSpeed() const = 0; /** @return the F number of the image */ - virtual double getFNumber (unsigned int frame = 0) const = 0; + virtual double getFNumber() const = 0; /** @return the focal length used at the exposure */ - virtual double getFocalLen (unsigned int frame = 0) const = 0; + virtual double getFocalLen() const = 0; /** @return the focal length in 35mm used at the exposure */ - virtual double getFocalLen35mm (unsigned int frame = 0) const = 0; + virtual double getFocalLen35mm() const = 0; /** @return the focus distance in meters, 0=unknown, 10000=infinity */ - virtual float getFocusDist (unsigned int frame = 0) const = 0; + virtual float getFocusDist() const = 0; /** @return the shutter speed */ - virtual double getShutterSpeed (unsigned int frame = 0) const = 0; + virtual double getShutterSpeed() const = 0; /** @return the exposure compensation */ - virtual double getExpComp (unsigned int frame = 0) const = 0; + virtual double getExpComp() const = 0; /** @return the maker of the camera */ - virtual std::string getMake (unsigned int frame = 0) const = 0; + virtual std::string getMake() const = 0; /** @return the model of the camera */ - virtual std::string getModel (unsigned int frame = 0) const = 0; + virtual std::string getModel() const = 0; - std::string getCamera (unsigned int frame = 0) const + std::string getCamera() const { - return getMake(frame) + " " + getModel(frame); + return getMake() + " " + getModel(); } /** @return the lens on the camera */ - virtual std::string getLens (unsigned int frame = 0) const = 0; + virtual std::string getLens() const = 0; /** @return the orientation of the image */ - virtual std::string getOrientation (unsigned int frame = 0) const = 0; + virtual std::string getOrientation() const = 0; /** @return true if the file is a PixelShift shot (Pentax and Sony bodies) */ virtual bool getPixelShift () const = 0; /** @return false: not an HDR file ; true: single or multi-frame HDR file (e.g. Pentax HDR raw file or 32 bit float DNG file or Log compressed) */ - virtual bool getHDR (unsigned int frame = 0) const = 0; + virtual bool getHDR() const = 0; /** @return false: not an HDR file ; true: single or multi-frame HDR file (e.g. Pentax HDR raw file or 32 bit float DNG file or Log compressed) */ - virtual std::string getImageType (unsigned int frame) const = 0; + virtual std::string getImageType() const = 0; /** @return the sample format based on MetaData */ - virtual IIOSampleFormat getSampleFormat (unsigned int frame = 0) const = 0; + virtual IIOSampleFormat getSampleFormat() const = 0; /** Functions to convert between floating point and string representation of shutter and aperture */ static std::string apertureToString (double aperture); @@ -163,7 +140,9 @@ public: * Use it only for raw files. In caseof jpgs and tiffs pass a NULL pointer. * @param firstFrameOnly must be true to get the MetaData of the first frame only, e.g. for a PixelShift file. * @return The metadata */ - static FramesMetaData* fromFile (const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly = false); + static FramesMetaData* fromFile (const Glib::ustring& fname); + + virtual Glib::ustring getFileName() const = 0; }; /** This listener interface is used to indicate the progress of time consuming operations */ diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 1ee09dcf3..a3c9ec6ba 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -312,7 +312,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, namespace { -Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml, eSensorType &sensorType, int &w, int &h) +Image8 *load_inspector_mode(const Glib::ustring &fname, eSensorType &sensorType, int &w, int &h) { BENCHFUN @@ -368,7 +368,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml } // namespace -Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode, bool forHistogramMatching) +Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode, bool forHistogramMatching) { Thumbnail* tpp = new Thumbnail (); tpp->isRaw = 1; @@ -378,7 +378,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL tpp->colorMatrix[2][2] = 1.0; if (inspectorMode && !forHistogramMatching && settings->thumbnail_inspector_mode == Settings::ThumbnailInspectorMode::RAW) { - Image8 *img = load_inspector_mode(fname, rml, sensorType, w, h); + Image8 *img = load_inspector_mode(fname, sensorType, w, h); if (!img) { delete tpp; return nullptr; @@ -403,10 +403,6 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL sensorType = ri->getSensorType(); - rml.exifBase = ri->get_exifBase(); - rml.ciffBase = ri->get_ciffBase(); - rml.ciffLength = ri->get_ciffLen(); - Image8* img = new Image8 (); // No sample format detection occurred earlier, so we set them here, // as they are mandatory for the setScanline method @@ -447,7 +443,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL delete img; delete ri; - img = load_inspector_mode(fname, rml, sensorType, w, h); + img = load_inspector_mode(fname, sensorType, w, h); if (!img) { delete tpp; return nullptr; @@ -513,28 +509,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL #define FISBLUE(filter,row,col) \ ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2 || !filter) -RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) -{ - RawMetaDataLocation rml; - rml.exifBase = -1; - rml.ciffBase = -1; - rml.ciffLength = -1; - - RawImage ri (fname); - unsigned int imageNum = 0; - - int r = ri.loadRaw (false, imageNum); - - if ( !r ) { - rml.exifBase = ri.get_exifBase(); - rml.ciffBase = ri.get_ciffBase(); - rml.ciffLength = ri.get_ciffLen(); - } - - return rml; -} - -Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching) +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching) { RawImage *ri = new RawImage (fname); unsigned int tempImageNum = 0; @@ -572,10 +547,6 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati ri->pre_interpolate(); - rml.exifBase = ri->get_exifBase(); - rml.ciffBase = ri->get_ciffBase(); - rml.ciffLength = ri->get_ciffLen(); - tpp->camwbRed = tpp->redMultiplier / pre_mul[0]; //ri->get_pre_mul(0); tpp->camwbGreen = tpp->greenMultiplier / pre_mul[1]; //ri->get_pre_mul(1); tpp->camwbBlue = tpp->blueMultiplier / pre_mul[2]; //ri->get_pre_mul(2); @@ -1084,19 +1055,11 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int // Full thumbnail processing, second stage if complete profile exists IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& myscale, bool forMonitor, bool forHistogramMatching) { - unsigned int imgNum = 0; - if (isRaw) { - if (sensorType == ST_BAYER) { - imgNum = rtengine::LIM(params.raw.bayersensor.imageNum, 0, metadata->getFrameCount() - 1); - } else if (sensorType == ST_FUJI_XTRANS) { - //imgNum = rtengine::LIM(params.raw.xtranssensor.imageNum, 0, metadata->getFrameCount() - 1) - } - } - std::string camName = metadata->getCamera(imgNum); - float shutter = metadata->getShutterSpeed(imgNum); - float fnumber = metadata->getFNumber(imgNum); - float iso = metadata->getISOSpeed(imgNum); - float fcomp = metadata->getExpComp(imgNum); + std::string camName = metadata->getCamera(); + float shutter = metadata->getShutterSpeed(); + float fnumber = metadata->getFNumber(); + float iso = metadata->getISOSpeed(); + float fcomp = metadata->getExpComp(); // check if the WB's equalizer value has changed if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4)) { diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index df33b892d..a2839e83d 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -19,7 +19,6 @@ #ifndef _THUMBPROCESSINGPARAMETERS_ #define _THUMBPROCESSINGPARAMETERS_ -#include "rawmetadatalocation.h" #include #include #include "image8.h" @@ -82,10 +81,9 @@ public: int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio); void getDimensions (int& w, int& h, double& scaleFac); - static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching = false); + static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching = false); static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false); - static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname); void getCamWB (double& temp, double& green); void getAutoWB (double& temp, double& green, double equal, double tempBias); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index ff2b234a3..64edc5c17 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1151,16 +1151,10 @@ private: if (params.colorappearance.enabled) { double adap; - int imgNum = 0; - if (imgsrc->getSensorType() == ST_BAYER) { - imgNum = params.raw.bayersensor.imageNum; - } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { - //imgNum = params.raw.xtranssensor.imageNum; - } - float fnum = imgsrc->getMetaData()->getFNumber (imgNum); // F number - float fiso = imgsrc->getMetaData()->getISOSpeed (imgNum) ; // ISO - float fspeed = imgsrc->getMetaData()->getShutterSpeed (imgNum) ; //speed - float fcomp = imgsrc->getMetaData()->getExpComp (imgNum); //compensation + - + float fnum = imgsrc->getMetaData()->getFNumber (); // F number + float fiso = imgsrc->getMetaData()->getISOSpeed () ; // ISO + float fspeed = imgsrc->getMetaData()->getShutterSpeed () ; //speed + float fcomp = imgsrc->getMetaData()->getExpComp (); //compensation + - if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { adap = 2000.; @@ -1295,15 +1289,20 @@ private: readyImg = tempImage; } + MetadataInfo info(imgsrc->getFileName()); switch (params.metadata.mode) { case MetaDataParams::TUNNEL: // Sending back the whole first root, which won't necessarily be the selected frame number // and may contain subframe depending on initial raw's hierarchy - readyImg->setMetadata (ii->getMetaData()->getRootExifData ()); + // readyImg->setMetadata (ii->getMetaData()->getRootExifData ()); + readyImg->setMetadata(info); break; case MetaDataParams::EDIT: + info.setExif(params.exif); + info.setIptc(params.iptc); + readyImg->setMetadata(info); // ask for the correct frame number, but may contain subframe depending on initial raw's hierarchy - readyImg->setMetadata (ii->getMetaData()->getBestExifData(imgsrc, ¶ms.raw), params.exif, params.iptc); + // readyImg->setMetadata (ii->getMetaData()->getBestExifData(imgsrc, ¶ms.raw), params.exif, params.iptc); break; default: // case MetaDataParams::STRIP // nothing to do diff --git a/rtexif/CMakeLists.txt b/rtexif/CMakeLists.txt deleted file mode 100644 index 9747b03fb..000000000 --- a/rtexif/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_library(rtexif rtexif.cc stdattribs.cc nikonattribs.cc canonattribs.cc pentaxattribs.cc fujiattribs.cc sonyminoltaattribs.cc olympusattribs.cc kodakattribs.cc panasonicattribs.cc) -add_dependencies(rtexif UpdateInfo) - -if(WIN32) - include_directories(${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS}) - link_directories(. "${PROJECT_SOURCE_DIR}/rtexif" ${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} ${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${LENSFUN_LIBRARY_DIRS}) -else() - set_target_properties(rtexif PROPERTIES COMPILE_FLAGS " -fPIC") - include_directories(${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS}) - link_directories(${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} ${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${LENSFUN_LIBRARY_DIRS}) -endif() - -include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}") - -if(BUILD_SHARED_LIBS) - install(TARGETS rtexif DESTINATION ${LIBDIR}) -endif() diff --git a/rtexif/canonattribs.cc b/rtexif/canonattribs.cc deleted file mode 100644 index 2dcbdd96f..000000000 --- a/rtexif/canonattribs.cc +++ /dev/null @@ -1,2078 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _CANONATTRIBS_ -#define _CANONATTRIBS_ - -#include -#include - -#include "rtexif.h" - -using namespace std; - -namespace rtexif -{ - -class CAOnOffInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - int n = t->toInt(); - - if ( n == 0 ) { - return "OFF"; - } else if ( n == 1) { - return "ON"; - } else { - return "undef"; - } - } -}; -CAOnOffInterpreter caOnOffInterpreter; - -class CAIntSerNumInterpreter : public Interpreter -{ -public: - CAIntSerNumInterpreter () {} - std::string toString (const Tag* t) const override - { - return ""; - } -}; - -CAIntSerNumInterpreter caIntSerNumInterpreter; - -class CAApertureInterpreter : public Interpreter -{ -public: - CAApertureInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double v = pow (2.0, t->toDouble() / 64.0); - - if ( v < 0. || v > 1000.) { - return "undef"; - } - - sprintf (buffer, "%.1f", v ); - return buffer; - } -}; -CAApertureInterpreter caApertureInterpreter; - -class CAMacroModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAMacroModeInterpreter() - { - choices[1] = "Macro"; - choices[2] = "Normal"; - } -}; -CAMacroModeInterpreter caMacroModeInterpreter; - -class CASelfTimerInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - int sec = t->toInt (0, SHORT); - - if ( !sec ) { - return "OFF"; - } - - char buffer[32]; - sprintf (buffer, "%.1fs %s", sec / 10., (sec & 0x4000) ? ",Custom" : ""); - return buffer; - } -}; -CASelfTimerInterpreter caSelfTimerInterpreter; - -class CAQualityInterpreter : public ChoiceInterpreter<> -{ -public: - CAQualityInterpreter() - { - choices[1] = "Economy"; - choices[2] = "Normal"; - choices[3] = "Fine"; - choices[4] = "RAW"; - choices[5] = "Superfine"; - } -}; -CAQualityInterpreter caQualityInterpreter; - -class CAFlashModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAFlashModeInterpreter() - { - choices[0] = "Off"; - choices[1] = "Auto"; - choices[2] = "On"; - choices[3] = "Red-eye reduction"; - choices[4] = "Slow-sync"; - choices[5] = "Red-eye reduction (Auto)"; - choices[6] = "Red-eye reduction (On)"; - choices[16] = "External flash"; - } -}; -CAFlashModeInterpreter caFlashModeInterpreter; - -class CAContinuousDriveInterpreter : public ChoiceInterpreter<> -{ -public: - CAContinuousDriveInterpreter() - { - choices[0] = "Single"; - choices[1] = "Continuous"; - choices[2] = "Movie"; - choices[3] = "Continuous, Speed Priority"; - choices[4] = "Continuous, Low"; - choices[5] = "Continuous, High"; - choices[6] = "Silent Single"; - choices[9] = "Single, Silent"; - choices[10] = "Continuous, Silent"; - } -}; -CAContinuousDriveInterpreter caContinuousDriveInterpreter; - -class CAFocusModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAFocusModeInterpreter() - { - choices[0] = "One-shot AF"; - choices[1] = "AI Servo AF"; - choices[2] = "AI Focus AF"; - choices[3] = "Manual Focus (3)"; - choices[4] = "Single"; - choices[5] = "Continuous"; - choices[6] = "Manual Focus (6)"; - choices[16] = "Pan Focus"; - choices[256] = "AF + MF"; - choices[512] = "Movie Snap Focus"; - choices[519] = "Movie Servo AF"; - } -}; -CAFocusModeInterpreter caFocusModeInterpreter; - -class CARecordModeInterpreter : public ChoiceInterpreter<> -{ -public: - CARecordModeInterpreter() - { - choices[1] = "JPEG"; - choices[2] = "CRW+THM"; - choices[3] = "AVI+THM"; - choices[4] = "TIF"; - choices[5] = "TIF+JPEG"; - choices[6] = "CR2"; - choices[7] = "CR2+JPEG"; - choices[9] = "MOV"; - choices[10] = "MP4"; - } -}; -CARecordModeInterpreter caRecordModeInterpreter; - -class CAImageSizeInterpreter : public ChoiceInterpreter<> -{ -public: - CAImageSizeInterpreter () - { - choices[0] = "Large"; - choices[1] = "Medium"; - choices[2] = "Small"; - choices[5] = "Medium 1"; - choices[6] = "Medium 2"; - choices[7] = "Medium 3"; - choices[8] = "Postcard"; - choices[9] = "Widescreen"; - choices[10] = "Medium Widescreen"; - choices[14] = "Small 1"; - choices[15] = "Small 2"; - choices[16] = "Small 3"; - choices[128] = "640x480 Movie"; - choices[129] = "Medium Movie"; - choices[130] = "Small Movie"; - choices[137] = "1280x720 Movie"; - choices[142] = "1920x1080 Movie"; - } -}; -CAImageSizeInterpreter caImageSizeInterpreter; - -class CAEasyModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAEasyModeInterpreter () - { - choices[0] = "Full auto"; - choices[1] = "Manual"; - choices[2] = "Landscape"; - choices[3] = "Fast shutter"; - choices[4] = "Slow shutter"; - choices[5] = "Night"; - choices[6] = "Gray Scale"; - choices[7] = "Sepia"; - choices[8] = "Portrait"; - choices[9] = "Sports"; - choices[10] = "Macro"; - choices[11] = "Black & White"; - choices[12] = "Pan focus"; - choices[13] = "Vivid"; - choices[14] = "Neutral"; - choices[15] = "Flash Off"; - choices[16] = "Long Shutter"; - choices[17] = "Super Macro"; - choices[18] = "Foliage"; - choices[19] = "Indoor"; - choices[20] = "Fireworks"; - choices[21] = "Beach"; - choices[22] = "Underwater"; - choices[23] = "Snow"; - choices[24] = "Kids & Pets"; - choices[25] = "Night Snapshot"; - choices[26] = "Digital Macro"; - choices[27] = "My Colors"; - choices[28] = "Movie Snap"; - choices[29] = "Super Macro 2"; - choices[30] = "Color Accent"; - choices[31] = "Color Swap"; - choices[32] = "Aquarium"; - choices[33] = "ISO 3200"; - choices[34] = "ISO 6400"; - choices[35] = "Creative Light Effect"; - choices[36] = "Easy"; - choices[37] = "Quick Shot"; - choices[38] = "Creative Auto"; - choices[39] = "Zoom Blur"; - choices[40] = "Low Light"; - choices[41] = "Nostalgic"; - choices[42] = "Super Vivid"; - choices[43] = "Poster Effect"; - choices[44] = "Face Self-timer"; - choices[45] = "Smile"; - choices[46] = "Wink Self-timer"; - choices[47] = "Fisheye Effect"; - choices[48] = "Miniature Effect"; - choices[49] = "High-speed Burst"; - choices[50] = "Best Image Selection"; - choices[51] = "High Dynamic Range"; - choices[52] = "Handheld Night Scene"; - choices[53] = "Movie Digest"; - choices[54] = "Live View Control"; - choices[55] = "Discreet"; - choices[56] = "Blur Reduction"; - choices[57] = "Monochrome"; - choices[58] = "Toy Camera Effect"; - choices[59] = "Scene Intelligent Auto"; - choices[60] = "High-speed Burst HQ"; - choices[61] = "Smooth Skin"; - choices[62] = "Soft Focus"; - choices[257] = "Spotlight"; - choices[258] = "Night 2"; - choices[259] = "Night+"; - choices[260] = "Super Night"; - choices[261] = "Sunset"; - choices[263] = "Night Scene"; - choices[264] = "Surface"; - choices[265] = "Low Light 2"; - } -}; -CAEasyModeInterpreter caEasyModeInterpreter; - -class CADigitalZoomInterpreter : public ChoiceInterpreter<> -{ -public: - CADigitalZoomInterpreter() - { - choices[0] = "None"; - choices[1] = "2x"; - choices[2] = "4x"; - choices[3] = "Other"; - } -}; -CADigitalZoomInterpreter caDigitalZoomInterpreter; - -class CAMeteringModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAMeteringModeInterpreter() - { - choices[0] = "Default"; - choices[1] = "Spot"; - choices[2] = "Average"; - choices[3] = "Evaluative"; - choices[4] = "Partial"; - choices[5] = "Center-weighted average"; - } -}; -CAMeteringModeInterpreter caMeteringModeInterpreter; - -class CAFocusRangeInterpreter : public ChoiceInterpreter<> -{ -public: - CAFocusRangeInterpreter() - { - choices[0] = "Manual"; - choices[1] = "Auto"; - choices[2] = "Not Known"; - choices[3] = "Macro"; - choices[4] = "Very Close"; - choices[5] = "Close"; - choices[6] = "Middle Range"; - choices[7] = "Far Range"; - choices[8] = "Pan Focus"; - choices[9] = "Super Macro"; - choices[10] = "Infinity"; - } -}; -CAFocusRangeInterpreter caFocusRangeInterpreter; - -class CAAFPointInterpreter : public ChoiceInterpreter<> -{ -public: - CAAFPointInterpreter() - { - choices[0x2005] = "Manual AF point selection "; - choices[0x3000] = "None (MF)"; - choices[0x3001] = "Auto AF point selection "; - choices[0x3002] = "Right "; - choices[0x3003] = "Center "; - choices[0x3004] = "Left "; - choices[0x4001] = "Auto AF point selection "; - choices[0x4006] = "Face Detect"; - } -}; -CAAFPointInterpreter caAFPointInterpreter; - -class CAExposureModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAExposureModeInterpreter() - { - choices[0] = "Easy"; - choices[1] = "Program AE"; - choices[2] = "Shutter speed priority AE"; - choices[3] = "Aperture-priority AE"; - choices[4] = "Manual"; - choices[5] = "Depth-of-field AE"; - choices[6] = "M-Dep"; - choices[7] = "Bulb"; - } -}; -CAExposureModeInterpreter caExposureModeInterpreter; - -class CAFlashBitsInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - std::ostringstream s; - unsigned bits = t->toInt (0, SHORT); - - if ( bits & 0x0001 ) { - s << "Manual "; - } - - if ( bits & 0x0002 ) { - s << "TTL "; - } - - if ( bits & 0x0004 ) { - s << "A-TTL "; - } - - if ( bits & 0x0008 ) { - s << "E-TTL "; - } - - if ( bits & 0x0010 ) { - s << "FP sync enabled "; - } - - if ( bits & 0x0080 ) { - s << "2nd curtain "; - } - - if ( bits & 0x0800 ) { - s << "FP sync used "; - } - - if ( bits & 0x2000 ) { - s << "Built-in "; - } - - if ( bits & 0x4000 ) { - s << "External "; - } - - return s.str(); - } -}; -CAFlashBitsInterpreter caFlashBitsInterpreter; - -class CAFocusContinuousInterpreter : public ChoiceInterpreter<> -{ -public: - CAFocusContinuousInterpreter() - { - choices[0] = "Single"; - choices[1] = "Continuous"; - choices[8] = "Manual"; - } -}; -CAFocusContinuousInterpreter caFocusContinuousInterpreter; - -class CAAESettingsInterpreter : public ChoiceInterpreter<> -{ -public: - CAAESettingsInterpreter() - { - choices[0] = "Normal AE"; - choices[1] = "Exposure Compensation"; - choices[2] = "AE Lock"; - choices[3] = "AE Lock + Exposure Comp."; - choices[4] = "No AE"; - } -}; -CAAESettingsInterpreter caAESettingsInterpreter; - -class CAStabilizationInterpreter : public ChoiceInterpreter<> -{ -public: - CAStabilizationInterpreter() - { - choices[0] = "Off"; - choices[1] = "On"; - choices[2] = "Shoot Only"; - choices[3] = "Panning"; - choices[4] = "Dynamic"; - choices[256] = "Off (2)"; - choices[257] = "On (2)"; - choices[258] = "Shoot Only (2)"; - choices[259] = "Panning (2)"; - choices[260] = "Dynamic (2)"; - } -}; -CAStabilizationInterpreter caStabilizationInterpreter; - -class CASpotMeteringInterpreter : public ChoiceInterpreter<> -{ -public: - CASpotMeteringInterpreter() - { - choices[0] = "Center"; - choices[1] = "AF Point"; - } -}; -CASpotMeteringInterpreter caSpotMeteringInterpreter; - -class CAPhotoEffectInterpreter : public ChoiceInterpreter<> -{ -public: - CAPhotoEffectInterpreter() - { - choices[0] = "Off"; - choices[1] = "Vivid"; - choices[2] = "Neutral"; - choices[3] = "Smooth"; - choices[4] = "Sepia"; - choices[5] = "B&W"; - choices[6] = "Custom"; - choices[100] = "My Color Data"; - } -}; -CAPhotoEffectInterpreter caPhotoEffectInterpreter; - -class CAManualFlashInterpreter : public ChoiceInterpreter<> -{ -public: - CAManualFlashInterpreter() - { - choices[0] = "N/A"; - choices[0x500] = "Full"; - choices[0x502] = "Medium"; - choices[0x504] = "Low"; - choices[0x7fff] = "N/A"; - } -}; -CAManualFlashInterpreter caManualFlashInterpreter; - -class CARAWQualityInterpreter : public ChoiceInterpreter<> -{ -public: - CARAWQualityInterpreter() - { - choices[0] = "N/A"; - choices[1] = "sRAW1 (mRAW)"; - choices[2] = "sRAW2 (sRAW)"; - } -}; -CARAWQualityInterpreter caRAWQualityInterpreter; - -class CAFocalInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - Tag *unitTag = t->getParent()->getRoot()->findTag ("FocalUnits"); - double v = unitTag ? unitTag->toDouble() : 1.; - v = (v > 0. ? t->toDouble() / v : t->toDouble()); - - if ( v < 0. || v > 1000000.) { - return "undef"; - } - - char buffer[32]; - sprintf (buffer, "%.1f", v ); - return buffer; - } -}; -CAFocalInterpreter caFocalInterpreter; - -class CALensInterpreter : public IntLensInterpreter< int > -{ -public: - CALensInterpreter () - { - choices = { - {1, "Canon EF 50mm f/1.8"}, - {2, "Canon EF 28mm f/2.8"}, - {3, "Canon EF 135mm f/2.8 Soft"}, - {4, "Canon EF 35-105mm f/3.5-4.5 or Sigma Lens"}, - {4, "Sigma UC Zoom 35-135mm f/4-5.6"}, - {5, "Canon EF 35-70mm f/3.5-4.5"}, - {6, "Canon EF 28-70mm f/3.5-4.5 or Sigma or Tokina Lens"}, - {6, "Sigma 18-50mm f/3.5-5.6 DC"}, - {6, "Sigma 18-125mm f/3.5-5.6 DC IF ASP"}, - {6, "Tokina AF 193-2 19-35mm f/3.5-4.5"}, - {6, "Sigma 28-80mm f/3.5-5.6 II Macro"}, - {6, "Sigma 28-300mm f/3.5-6.3 DG Macro"}, - {7, "Canon EF 100-300mm f/5.6L"}, - {8, "Canon EF 100-300mm f/5.6 or Sigma or Tokina Lens"}, - {8, "Sigma 70-300mm f/4-5.6 [APO] DG Macro"}, - {8, "Tokina AT-X 242 AF 24-200mm f/3.5-5.6"}, - {9, "Canon EF 70-210mm f/4"}, - {9, "Sigma 55-200mm f/4-5.6 DC"}, - {10, "Canon EF 50mm f/2.5 Macro or Sigma Lens"}, - {10, "Sigma 50mm f/2.8 EX"}, - {10, "Sigma 28mm f/1.8"}, - {10, "Sigma 105mm f/2.8 Macro EX"}, - {10, "Sigma 70mm f/2.8 EX DG Macro EF"}, - {11, "Canon EF 35mm f/2"}, - {13, "Canon EF 15mm f/2.8 Fisheye"}, - {14, "Canon EF 50-200mm f/3.5-4.5L"}, - {15, "Canon EF 50-200mm f/3.5-4.5"}, - {16, "Canon EF 35-135mm f/3.5-4.5"}, - {17, "Canon EF 35-70mm f/3.5-4.5A"}, - {18, "Canon EF 28-70mm f/3.5-4.5"}, - {20, "Canon EF 100-200mm f/4.5A"}, - {21, "Canon EF 80-200mm f/2.8L"}, - {22, "Canon EF 20-35mm f/2.8L or Tokina Lens"}, - {22, "Tokina AT-X 280 AF Pro 28-80mm f/2.8 Aspherical"}, - {23, "Canon EF 35-105mm f/3.5-4.5"}, - {24, "Canon EF 35-80mm f/4-5.6 Power Zoom"}, - {25, "Canon EF 35-80mm f/4-5.6 Power Zoom"}, - {26, "Canon EF 100mm f/2.8 Macro or Other Lens"}, - {26, "Cosina 100mm f/3.5 Macro AF"}, - {26, "Tamron SP AF 90mm f/2.8 Di Macro"}, - {26, "Tamron SP AF 180mm f/3.5 Di Macro"}, - {26, "Carl Zeiss Planar T* 50mm f/1.4"}, - {27, "Canon EF 35-80mm f/4-5.6"}, - {28, "Canon EF 80-200mm f/4.5-5.6 or Tamron Lens"}, - {28, "Tamron SP AF 28-105mm f/2.8 LD Aspherical IF"}, - {28, "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro"}, - {28, "Tamron AF 70-300mm f/4-5.6 Di LD 1:2 Macro"}, - {28, "Tamron AF Aspherical 28-200mm f/3.8-5.6"}, - {29, "Canon EF 50mm f/1.8 II"}, - {30, "Canon EF 35-105mm f/4.5-5.6"}, - {31, "Canon EF 75-300mm f/4-5.6 or Tamron Lens"}, - {31, "Tamron SP AF 300mm f/2.8 LD IF"}, - {32, "Canon EF 24mm f/2.8 or Sigma Lens"}, - {32, "Sigma 15mm f/2.8 EX Fisheye"}, - {33, "Voigtlander or Carl Zeiss Lens"}, - {33, "Voigtlander Ultron 40mm f/2 SLII Aspherical"}, - {33, "Voigtlander Color Skopar 20mm f/3.5 SLII Aspherical"}, - {33, "Voigtlander APO-Lanthar 90mm f/3.5 SLII Close Focus"}, - {33, "Carl Zeiss Distagon T* 15mm f/2.8 ZE"}, - {33, "Carl Zeiss Distagon T* 18mm f/3.5 ZE"}, - {33, "Carl Zeiss Distagon T* 21mm f/2.8 ZE"}, - {33, "Carl Zeiss Distagon T* 25mm f/2 ZE"}, - {33, "Carl Zeiss Distagon T* 28mm f/2 ZE"}, - {33, "Carl Zeiss Distagon T* 35mm f/2 ZE"}, - {33, "Carl Zeiss Distagon T* 35mm f/1.4 ZE"}, - {33, "Carl Zeiss Planar T* 50mm f/1.4 ZE"}, - {33, "Carl Zeiss Makro-Planar T* 50mm f/2 ZE"}, - {33, "Carl Zeiss Makro-Planar T* 100mm f/2 ZE"}, - {33, "Carl Zeiss Apo-Sonnar T* 135mm f/2 ZE"}, - {35, "Canon EF 35-80mm f/4-5.6"}, - {36, "Canon EF 38-76mm f/4.5-5.6"}, - {37, "Canon EF 35-80mm f/4-5.6 or Tamron Lens"}, - {37, "Tamron 70-200mm f/2.8 Di LD IF Macro"}, - {37, "Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20"}, - {37, "Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical [IF]"}, - {37, "Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical [IF] Macro"}, - {38, "Canon EF 80-200mm f/4.5-5.6"}, - {39, "Canon EF 75-300mm f/4-5.6"}, - {40, "Canon EF 28-80mm f/3.5-5.6"}, - {41, "Canon EF 28-90mm f/4-5.6"}, - {42, "Canon EF 28-200mm f/3.5-5.6 or Tamron Lens"}, - {42, "Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20"}, - {43, "Canon EF 28-105mm f/4-5.6"}, - {44, "Canon EF 90-300mm f/4.5-5.6"}, - {45, "Canon EF-S 18-55mm f/3.5-5.6 [II]"}, - {46, "Canon EF 28-90mm f/4-5.6"}, - {47, "Zeiss Milvus 35mm f/2 or 50mm f/2"}, - {47, "Zeiss Milvus 50mm f/2 Makro"}, - {48, "Canon EF-S 18-55mm f/3.5-5.6 IS"}, - {49, "Canon EF-S 55-250mm f/4-5.6 IS"}, - {50, "Canon EF-S 18-200mm f/3.5-5.6 IS"}, - {51, "Canon EF-S 18-135mm f/3.5-5.6 IS"}, - {52, "Canon EF-S 18-55mm f/3.5-5.6 IS II"}, - {53, "Canon EF-S 18-55mm f/3.5-5.6 III"}, - {54, "Canon EF-S 55-250mm f/4-5.6 IS II"}, - {60, "Irix 11mm f/4"}, - {80, "Canon TS-E 50mm f/2.8L Macro"}, - {81, "Canon TS-E 90mm f/2.8L Macro"}, - {82, "Canon TS-E 135mm f/4L Macro"}, - {94, "Canon TS-E 17mm f/4L"}, - {95, "Canon TS-E 24mm f/3.5L II"}, - {103, "Samyang AF 14mm f/2.8 EF or Rokinon Lens"}, - {103, "Rokinon SP 14mm f/2.4"}, - {103, "Rokinon AF 14mm f/2.8 EF"}, - {124, "Canon MP-E 65mm f/2.8 1-5x Macro Photo"}, - {125, "Canon TS-E 24mm f/3.5L"}, - {126, "Canon TS-E 45mm f/2.8"}, - {127, "Canon TS-E 90mm f/2.8"}, - {129, "Canon EF 300mm f/2.8L USM"}, - {130, "Canon EF 50mm f/1.0L USM"}, - {131, "Canon EF 28-80mm f/2.8-4L USM or Sigma Lens"}, - {131, "Sigma 8mm f/3.5 EX DG Circular Fisheye"}, - {131, "Sigma 17-35mm f/2.8-4 EX DG Aspherical HSM"}, - {131, "Sigma 17-70mm f/2.8-4.5 DC Macro"}, - {131, "Sigma APO 50-150mm f/2.8 [II] EX DC HSM"}, - {131, "Sigma APO 120-300mm f/2.8 EX DG HSM"}, - {131, "Sigma 4.5mm f/2.8 EX DC HSM Circular Fisheye"}, - {131, "Sigma 70-200mm f/2.8 APO EX HSM"}, - {132, "Canon EF 1200mm f/5.6L USM"}, - {134, "Canon EF 600mm f/4L IS USM"}, - {135, "Canon EF 200mm f/1.8L USM"}, - {136, "Canon EF 300mm f/2.8L USM"}, - {137, "Canon EF 85mm f/1.2L USM or Sigma or Tamron Lens"}, - {137, "Sigma 18-50mm f/2.8-4.5 DC OS HSM"}, - {137, "Sigma 50-200mm f/4-5.6 DC OS HSM"}, - {137, "Sigma 18-250mm f/3.5-6.3 DC OS HSM"}, - {137, "Sigma 24-70mm f/2.8 IF EX DG HSM"}, - {137, "Sigma 18-125mm f/3.8-5.6 DC OS HSM"}, - {137, "Sigma 17-70mm f/2.8-4 DC Macro OS HSM | C"}, - {137, "Sigma 17-50mm f/2.8 OS HSM"}, - {137, "Sigma 18-200mm f/3.5-6.3 DC OS HSM [II]"}, - {137, "Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD"}, - {137, "Sigma 8-16mm f/4.5-5.6 DC HSM"}, - {137, "Tamron SP 17-50mm f/2.8 XR Di II VC"}, - {137, "Tamron SP 60mm f/2 Macro Di II"}, - {137, "Sigma 10-20mm f/3.5 EX DC HSM"}, - {137, "Tamron SP 24-70mm f/2.8 Di VC USD"}, - {137, "Sigma 18-35mm f/1.8 DC HSM"}, - {137, "Sigma 12-24mm f/4.5-5.6 DG HSM II"}, - {138, "Canon EF 28-80mm f/2.8-4L"}, - {139, "Canon EF 400mm f/2.8L USM"}, - {140, "Canon EF 500mm f/4.5L USM"}, - {141, "Canon EF 500mm f/4.5L USM"}, - {142, "Canon EF 300mm f/2.8L IS USM"}, - {143, "Canon EF 500mm f/4L IS USM or Sigma Lens"}, - {143, "Sigma 17-70mm f/2.8-4 DC Macro OS HSM"}, - {144, "Canon EF 35-135mm f/4-5.6 USM"}, - {145, "Canon EF 100-300mm f/4.5-5.6 USM"}, - {146, "Canon EF 70-210mm f/3.5-4.5 USM"}, - {147, "Canon EF 35-135mm f/4-5.6 USM"}, - {148, "Canon EF 28-80mm f/3.5-5.6 USM"}, - {149, "Canon EF 100mm f/2 USM"}, - {150, "Canon EF 14mm f/2.8L USM or Sigma Lens"}, - {150, "Sigma 20mm EX f/1.8"}, - {150, "Sigma 30mm f/1.4 DC HSM"}, - {150, "Sigma 24mm f/1.8 DG Macro EX"}, - {150, "Sigma 28mm f/1.8 DG Macro EX"}, - {151, "Canon EF 200mm f/2.8L USM"}, - {152, "Canon EF 300mm f/4L IS USM or Sigma Lens"}, - {152, "Sigma 12-24mm f/4.5-5.6 EX DG ASPHERICAL HSM"}, - {152, "Sigma 14mm f/2.8 EX Aspherical HSM"}, - {152, "Sigma 10-20mm f/4-5.6"}, - {152, "Sigma 100-300mm f/4"}, - {153, "Canon EF 35-350mm f/3.5-5.6L USM or Sigma or Tamron Lens"}, - {153, "Sigma 50-500mm f/4-6.3 APO HSM EX"}, - {153, "Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical [IF] Macro"}, - {153, "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical [IF] Macro Model A14"}, - {153, "Tamron 18-250mm f/3.5-6.3 Di II LD Aspherical [IF] Macro"}, - {154, "Canon EF 20mm f/2.8 USM or Zeiss Lens"}, - {154, "Zeiss Milvus 21mm f/2.8"}, - {155, "Canon EF 85mm f/1.8 USM"}, - {156, "Canon EF 28-105mm f/3.5-4.5 USM or Tamron Lens"}, - {156, "Tamron SP 70-300mm f/4-5.6 Di VC USD"}, - {156, "Tamron SP AF 28-105mm f/2.8 LD Aspherical IF"}, - {160, "Canon EF 20-35mm f/3.5-4.5 USM or Tamron or Tokina Lens"}, - {160, "Tamron AF 19-35mm f/3.5-4.5"}, - {160, "Tokina AT-X 124 AF Pro DX 12-24mm f/4"}, - {160, "Tokina AT-X 107 AF DX 10-17mm f/3.5-4.5 Fisheye"}, - {160, "Tokina AT-X 116 AF Pro DX 11-16mm f/2.8"}, - {160, "Tokina AT-X 11-20 F2.8 PRO DX Aspherical 11-20mm f/2.8"}, - {161, "Canon EF 28-70mm f/2.8L USM or Other Lens"}, - {161, "Sigma 24-70mm f/2.8 EX"}, - {161, "Sigma 28-70mm f/2.8 EX"}, - {161, "Sigma 24-60mm f/2.8 EX DG"}, - {161, "Tamron AF 17-50mm f/2.8 Di-II LD Aspherical"}, - {161, "Tamron 90mm f/2.8"}, - {161, "Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical IF"}, - {161, "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro"}, - {161, "Tokina AT-X 24-70mm f/2.8 PRO FX (IF)"}, - {162, "Canon EF 200mm f/2.8L USM"}, - {163, "Canon EF 300mm f/4L"}, - {164, "Canon EF 400mm f/5.6L"}, - {165, "Canon EF 70-200mm f/2.8L USM"}, - {166, "Canon EF 70-200mm f/2.8L USM + 1.4x"}, - {167, "Canon EF 70-200mm f/2.8L USM + 2x"}, - {168, "Canon EF 28mm f/1.8 USM or Sigma Lens"}, - {168, "Sigma 50-100mm f/1.8 DC HSM | A"}, - {169, "Canon EF 17-35mm f/2.8L USM or Sigma Lens"}, - {169, "Sigma 18-200mm f/3.5-6.3 DC OS"}, - {169, "Sigma 15-30mm f/3.5-4.5 EX DG Aspherical"}, - {169, "Sigma 18-50mm f/2.8 Macro"}, - {169, "Sigma 50mm f/1.4 EX DG HSM"}, - {169, "Sigma 85mm f/1.4 EX DG HSM"}, - {169, "Sigma 30mm f/1.4 EX DC HSM"}, - {169, "Sigma 35mm f/1.4 DG HSM"}, - {169, "Sigma 35mm f/1.5 FF High-Speed Prime | 017"}, - {170, "Canon EF 200mm f/2.8L II USM"}, - {171, "Canon EF 300mm f/4L USM"}, - {172, "Canon EF 400mm f/5.6L USM or Sigma Lens"}, - {172, "Sigma 150-600mm f/5-6.3 DG OS HSM | S"}, - {173, "Canon EF 180mm Macro f/3.5L USM or Sigma Lens"}, - {173, "Sigma 180mm EX HSM Macro f/3.5"}, - {173, "Sigma APO Macro 150mm f/2.8 EX DG HSM"}, - {174, "Canon EF 135mm f/2L USM or Other Lens"}, - {174, "Sigma 70-200mm f/2.8 EX DG APO OS HSM"}, - {174, "Sigma 50-500mm f/4.5-6.3 APO DG OS HSM"}, - {174, "Sigma 150-500mm f/5-6.3 APO DG OS HSM"}, - {174, "Zeiss Milvus 100mm f/2 Makro"}, - {175, "Canon EF 400mm f/2.8L USM"}, - {176, "Canon EF 24-85mm f/3.5-4.5 USM"}, - {177, "Canon EF 300mm f/4L IS USM"}, - {178, "Canon EF 28-135mm f/3.5-5.6 IS"}, - {179, "Canon EF 24mm f/1.4L USM"}, - {180, "Canon EF 35mm f/1.4L USM or Other Lens"}, - {180, "Sigma 50mm f/1.4 DG HSM | A"}, - {180, "Sigma 24mm f/1.4 DG HSM | A"}, - {180, "Zeiss Milvus 50mm f/1.4"}, - {180, "Zeiss Milvus 85mm f/1.4"}, - {180, "Zeiss Otus 28mm f/1.4 ZE"}, - {180, "Sigma 24mm f/1.5 FF High-Speed Prime | 017"}, - {180, "Sigma 50mm f/1.5 FF High-Speed Prime | 017"}, - {180, "Sigma 85mm f/1.5 FF High-Speed Prime | 017"}, - {181, "Canon EF 100-400mm f/4.5-5.6L IS USM + 1.4x or Sigma Lens"}, - {181, "Sigma 150-600mm f/5-6.3 DG OS HSM | S + 1.4x"}, - {182, "Canon EF 100-400mm f/4.5-5.6L IS USM + 2x or Sigma Lens"}, - {182, "Sigma 150-600mm f/5-6.3 DG OS HSM | S + 2x"}, - {183, "Canon EF 100-400mm f/4.5-5.6L IS USM or Sigma Lens"}, - {183, "Sigma 150mm f/2.8 EX DG OS HSM APO Macro"}, - {183, "Sigma 105mm f/2.8 EX DG OS HSM Macro"}, - {183, "Sigma 180mm f/2.8 EX DG OS HSM APO Macro"}, - {183, "Sigma 150-600mm f/5-6.3 DG OS HSM | C"}, - {183, "Sigma 150-600mm f/5-6.3 DG OS HSM | S"}, - {183, "Sigma 100-400mm f/5-6.3 DG OS HSM"}, - {183, "Sigma 180mm f/3.5 APO Macro EX DG IF HSM"}, - {184, "Canon EF 400mm f/2.8L USM + 2x"}, - {185, "Canon EF 600mm f/4L IS USM"}, - {186, "Canon EF 70-200mm f/4L USM"}, - {187, "Canon EF 70-200mm f/4L USM + 1.4x"}, - {188, "Canon EF 70-200mm f/4L USM + 2x"}, - {189, "Canon EF 70-200mm f/4L USM + 2.8x"}, - {190, "Canon EF 100mm f/2.8 Macro USM"}, - {191, "Canon EF 400mm f/4 DO IS or Sigma Lens"}, - {191, "Sigma 500mm f/4 DG OS HSM"}, - {193, "Canon EF 35-80mm f/4-5.6 USM"}, - {194, "Canon EF 80-200mm f/4.5-5.6 USM"}, - {195, "Canon EF 35-105mm f/4.5-5.6 USM"}, - {196, "Canon EF 75-300mm f/4-5.6 USM"}, - {197, "Canon EF 75-300mm f/4-5.6 IS USM or Sigma Lens"}, - {197, "Sigma 18-300mm f/3.5-6.3 DC Macro OS HS"}, - {198, "Canon EF 50mm f/1.4 USM or Zeiss Lens"}, - {198, "Zeiss Otus 55mm f/1.4 ZE"}, - {198, "Zeiss Otus 85mm f/1.4 ZE"}, - {198, "Zeiss Milvus 25mm f/1.4"}, - {199, "Canon EF 28-80mm f/3.5-5.6 USM"}, - {200, "Canon EF 75-300mm f/4-5.6 USM"}, - {201, "Canon EF 28-80mm f/3.5-5.6 USM"}, - {202, "Canon EF 28-80mm f/3.5-5.6 USM IV"}, - {208, "Canon EF 22-55mm f/4-5.6 USM"}, - {209, "Canon EF 55-200mm f/4.5-5.6"}, - {210, "Canon EF 28-90mm f/4-5.6 USM"}, - {211, "Canon EF 28-200mm f/3.5-5.6 USM"}, - {212, "Canon EF 28-105mm f/4-5.6 USM"}, - {213, "Canon EF 90-300mm f/4.5-5.6 USM or Tamron Lens"}, - {213, "Tamron SP 150-600mm f/5-6.3 Di VC USD"}, - {213, "Tamron 16-300mm f/3.5-6.3 Di II VC PZD Macro"}, - {213, "Tamron SP 35mm f/1.8 Di VC USD"}, - {213, "Tamron SP 45mm f/1.8 Di VC USD"}, - {214, "Canon EF-S 18-55mm f/3.5-5.6 USM"}, - {215, "Canon EF 55-200mm f/4.5-5.6 II USM"}, - {217, "Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD"}, - {224, "Canon EF 70-200mm f/2.8L IS USM"}, - {225, "Canon EF 70-200mm f/2.8L IS USM + 1.4x"}, - {226, "Canon EF 70-200mm f/2.8L IS USM + 2x"}, - {227, "Canon EF 70-200mm f/2.8L IS USM + 2.8x"}, - {228, "Canon EF 28-105mm f/3.5-4.5 USM"}, - {229, "Canon EF 16-35mm f/2.8L USM"}, - {230, "Canon EF 24-70mm f/2.8L USM"}, - {231, "Canon EF 17-40mm f/4L USM"}, - {232, "Canon EF 70-300mm f/4.5-5.6 DO IS USM"}, - {233, "Canon EF 28-300mm f/3.5-5.6L IS USM"}, - {234, "Canon EF-S 17-85mm f/4-5.6 IS USM or Tokina Lens"}, - {234, "Tokina AT-X 12-28 PRO DX 12-28mm f/4"}, - {235, "Canon EF-S 10-22mm f/3.5-4.5 USM"}, - {236, "Canon EF-S 60mm f/2.8 Macro USM"}, - {237, "Canon EF 24-105mm f/4L IS USM"}, - {238, "Canon EF 70-300mm f/4-5.6 IS USM"}, - {239, "Canon EF 85mm f/1.2L II USM or Rokinon Lens"}, - {239, "Rokinon SP 85mm f/1.2"}, - {240, "Canon EF-S 17-55mm f/2.8 IS USM or Sigma Lens"}, - {240, "Sigma 17-50mm f/2.8 EX DC OS HSM"}, - {241, "Canon EF 50mm f/1.2L USM"}, - {242, "Canon EF 70-200mm f/4L IS USM"}, - {243, "Canon EF 70-200mm f/4L IS USM + 1.4x"}, - {244, "Canon EF 70-200mm f/4L IS USM + 2x"}, - {245, "Canon EF 70-200mm f/4L IS USM + 2.8x"}, - {246, "Canon EF 16-35mm f/2.8L II USM"}, - {247, "Canon EF 14mm f/2.8L II USM"}, - {248, "Canon EF 200mm f/2L IS USM or Sigma Lens"}, - {248, "Sigma 24-35mm f/2 DG HSM | A"}, - {248, "Sigma 135mm f/2 FF High-Speed Prime | 017"}, - {248, "Sigma 24-35mm f/2.2 FF Zoom | 017"}, - {249, "Canon EF 800mm f/5.6L IS USM"}, - {250, "Canon EF 24mm f/1.4L II USM or Sigma Lens"}, - {250, "Sigma 20mm f/1.4 DG HSM | A"}, - {250, "Sigma 20mm f/1.5 FF High-Speed Prime | 017"}, - {251, "Canon EF 70-200mm f/2.8L IS II USM"}, - {252, "Canon EF 70-200mm f/2.8L IS II USM + 1.4x"}, - {253, "Canon EF 70-200mm f/2.8L IS II USM + 2x"}, - {254, "Canon EF 100mm f/2.8L Macro IS USM"}, - {255, "Sigma 24-105mm f/4 DG OS HSM | A or Other Sigma Lens"}, - {255, "Sigma 180mm f/2.8 EX DG OS HSM APO Macro"}, - {368, "Sigma 14-24mm f/2.8 DG HSM | A or other Sigma Lens"}, - {368, "Sigma 20mm f/1.4 DG HSM | A"}, - {368, "Sigma 50mm f/1.4 DG HSM | A"}, - {368, "Sigma 40mm f/1.4 DG HSM | A"}, - {368, "Sigma 60-600mm f/4.5-6.3 DG OS HSM | S"}, - {488, "Canon EF-S 15-85mm f/3.5-5.6 IS USM"}, - {489, "Canon EF 70-300mm f/4-5.6L IS USM"}, - {490, "Canon EF 8-15mm f/4L Fisheye USM"}, - {491, "Canon EF 300mm f/2.8L IS II USM or Tamron Lens"}, - {491, "Tamron SP 70-200mm f/2.8 Di VC USD G2 (A025)"}, - {491, "Tamron 18-400mm f/3.5-6.3 Di II VC HLD (B028)"}, - {491, "Tamron 100-400mm f/4.5-6.3 Di VC USD (A035)"}, - {491, "Tamron 70-210mm f/4 Di VC USD (A034)"}, - {491, "Tamron 70-210mm f/4 Di VC USD (A034) + 1.4x"}, - {491, "Tamron SP 24-70mm f/2.8 Di VC USD G2 (A032)"}, - {492, "Canon EF 400mm f/2.8L IS II USM"}, - {493, "Canon EF 500mm f/4L IS II USM or EF 24-105mm f4L IS USM"}, - {493, "Canon EF 24-105mm f/4L IS USM"}, - {494, "Canon EF 600mm f/4L IS II USM"}, - {495, "Canon EF 24-70mm f/2.8L II USM or Sigma Lens"}, - {495, "Sigma 24-70mm F2.8 DG OS HSM | A"}, - {496, "Canon EF 200-400mm f/4L IS USM"}, - {499, "Canon EF 200-400mm f/4L IS USM + 1.4x"}, - {502, "Canon EF 28mm f/2.8 IS USM or Tamron Lens"}, - {502, "Tamron 35mm f/1.8 Di VC USD (F012)"}, - {503, "Canon EF 24mm f/2.8 IS USM"}, - {504, "Canon EF 24-70mm f/4L IS USM"}, - {505, "Canon EF 35mm f/2 IS USM"}, - {506, "Canon EF 400mm f/4 DO IS II USM"}, - {507, "Canon EF 16-35mm f/4L IS USM"}, - {508, "Canon EF 11-24mm f/4L USM or Tamron Lens"}, - {508, "Tamron 10-24mm f/3.5-4.5 Di II VC HLD"}, - {747, "Canon EF 100-400mm f/4.5-5.6L IS II USM or Tamron Lens"}, - {747, "Tamron SP 150-600mm f/5-6.3 Di VC USD G2"}, - {748, "Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x or Tamron Lens"}, - {748, "Tamron 100-400mm f/4.5-6.3 Di VC USD A035E + 1.4x"}, - {748, "Tamron 70-210mm f/4 Di VC USD (A034) + 2x"}, - {749, "Tamron 100-400mm f/4.5-6.3 Di VC USD A035E + 2x"}, - {750, "Canon EF 35mm f/1.4L II USM"}, - {751, "Canon EF 16-35mm f/2.8L III USM"}, - {752, "Canon EF 24-105mm f/4L IS II USM"}, - {753, "Canon EF 85mm f/1.4L IS USM"}, - {754, "Canon EF 70-200mm f/4L IS II USM"}, - {757, "Canon EF 400mm f/2.8L IS III USM"}, - {758, "Canon EF 600mm f/4L IS III USM"}, - {1136, "Sigma 24-70mm f/2.8 DG OS HSM | Art 017"}, - {4142, "Canon EF-S 18-135mm f/3.5-5.6 IS STM"}, - {4143, "Canon EF-M 18-55mm f/3.5-5.6 IS STM or Tamron Lens"}, - {4143, "Tamron 18-200mm f/3.5-6.3 Di III VC"}, - {4144, "Canon EF 40mm f/2.8 STM"}, - {4145, "Canon EF-M 22mm f/2 STM"}, - {4146, "Canon EF-S 18-55mm f/3.5-5.6 IS STM"}, - {4147, "Canon EF-M 11-22mm f/4-5.6 IS STM"}, - {4148, "Canon EF-S 55-250mm f/4-5.6 IS STM"}, - {4149, "Canon EF-M 55-200mm f/4.5-6.3 IS STM"}, - {4150, "Canon EF-S 10-18mm f/4.5-5.6 IS STM"}, - {4152, "Canon EF 24-105mm f/3.5-5.6 IS STM"}, - {4153, "Canon EF-M 15-45mm f/3.5-6.3 IS STM"}, - {4154, "Canon EF-S 24mm f/2.8 STM"}, - {4155, "Canon EF-M 28mm f/3.5 Macro IS STM"}, - {4156, "Canon EF 50mm f/1.8 STM"}, - {4157, "Canon EF-M 18-150mm 1:3.5-6.3 IS STM"}, - {4158, "Canon EF-S 18-55mm f/4-5.6 IS STM"}, - {4159, "Canon EF-M 32mm f/1.4 STM"}, - {4160, "Canon EF-S 35mm f/2.8 Macro IS STM"}, - {36910, "Canon EF 70-300mm f/4-5.6 IS II USM"}, - {36912, "Canon EF-S 18-135mm f/3.5-5.6 IS USM"}, - {61182, "Canon RF 35mm F1.8 Macro IS STM or other Canon RF Lens"}, - {61182, "Canon RF 50mm F1.2 L USM"}, - {61182, "Canon RF 24-105mm F4 L IS USM"}, - {61182, "Canon RF 28-70mm F2 L USM"}, - {61491, "Canon CN-E 14mm T3.1 L F"}, - {61492, "Canon CN-E 24mm T1.5 L F"}, - {61494, "Canon CN-E 85mm T1.3 L F"}, - {61495, "Canon CN-E 135mm T2.2 L F"}, - {61496, "Canon CN-E 35mm T1.5 L F"}, - {65535, "n/a"} - }; - } - - std::string toString (const Tag* t) const override - { - int lensID = t->toInt(); - - it_t r; - size_t nFound = choices.count ( lensID ); - - if (1 == nFound) { - r = choices.find ( lensID ); - return r->second; - } - - Tag *apertureTag = t->getParent()->getRoot()->findTag ("MaxAperture"); - Tag *focalLengthTag = t->getParent()->getRoot()->findTag ("FocalLength"); - Tag *focalLengthMaxTag = t->getParent()->getRoot()->findTag ("LongFocal"); - Tag *focalLengthMinTag = t->getParent()->getRoot()->findTag ("ShortFocal"); - Tag *unitTag = t->getParent()->getRoot()->findTag ("FocalUnits"); - double maxApertureAtFocal = 0.; - double focalLength = 0.; - double focalLengthMin = 0.; - double focalLengthMax = 0.; - - if ( apertureTag ) { - maxApertureAtFocal = pow (2.0, apertureTag->toDouble() / 64.0); - } - - if ( unitTag ) { - double unit = unitTag->toDouble(); - - if ( unit == 0. ) { - unit = 1; - } - - if ( focalLengthTag ) { - focalLength = focalLengthTag->toDouble(); - } - - if ( focalLengthMinTag ) { - focalLengthMin = focalLengthMinTag->toDouble() / unit; - } - - if ( focalLengthMaxTag ) { - focalLengthMax = focalLengthMaxTag->toDouble() / unit; - } - } - - std::ostringstream s; - s << "Unknown "; - - if (focalLengthMin > 0.) { - s << focalLengthMin; - } - - if (focalLengthMax > 0. && focalLengthMax != focalLengthMin) { - s << "-" << focalLengthMax; - } - - if (focalLengthMin > 0.) { - s << "mm"; - } - - s << " (" << lensID << ")"; - - if (0 == nFound) { - return s.str(); - } - - double deltaMin = 1000.; - - std::string bestMatch (s.str()); - std::ostringstream candidates; - - for (r = choices.lower_bound (lensID); r != choices.upper_bound (lensID); r++) { - double a1, a2, f1, f2, dif; - - if ( !extractLensInfo ( r->second, f1, f2, a1, a2) ) { - continue; - } - - if ( f1 == 0. || a1 == 0.) { - continue; - } - - if ( focalLength < f1 - .5 || focalLength > f2 + 0.5 ) { - continue; - } - - if ( focalLengthMin > 0. && fabs (f1 - focalLengthMin) > 0.5 ) { - continue; - } - - if ( focalLengthMax > 0. && fabs (f2 - focalLengthMax) > 0.5 ) { - continue; - } - - if ( maxApertureAtFocal > 0.1) { - double lensAperture; - - if ( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 + 0.15) { - continue; - } - - if ( a1 == a2 || f1 == f2) { - lensAperture = a1; - } else { - lensAperture = exp ( log (a1) + (log (a2) - log (a1)) / (log (f2) - log (f1)) * (log (focalLength) - log (f1)) ); - } - - dif = abs (lensAperture - maxApertureAtFocal); - } else { - dif = 0; - } - - if ( dif < deltaMin ) { - deltaMin = dif; - bestMatch = r->second; - } - - if ( dif < 0.15) { - if ( candidates.tellp() ) { - candidates << "\n or " << r->second; - } else { - candidates << r->second; - } - } - - } - - if ( !candidates.tellp() ) { - return bestMatch; - } else { - return candidates.str(); - } - } -}; -CALensInterpreter caLensInterpreter; - -class CAFocalTypeInterpreter : public ChoiceInterpreter<> -{ -public: - CAFocalTypeInterpreter() - { - choices[0] = "Fixed"; - choices[1] = "Fixed"; - choices[2] = "Zoom"; - } -}; -CAFocalTypeInterpreter caFocalTypeInterpreter; - -class CAFocalPlaneInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - int val = t->toInt(); - - if ( val < 40 ) { - return "undef"; - } - - char buffer[32]; - sprintf (buffer, "%.2fmm", val * 25.4 / 1000); - return buffer; - } -}; -CAFocalPlaneInterpreter caFocalPlaneInterpreter; - -class CAExposureTimeInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - char buffer[32]; - double d = pow (2, - t->toInt() / 32.0); - sprintf (buffer, "%.3f", d); - return buffer; - } -}; -CAExposureTimeInterpreter caExposureTimeInterpreter; - -class CAEVInterpreter : public Interpreter -{ - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%.1f", t->toDouble() / 32.0 ); - return buffer; - } -}; -CAEVInterpreter caEVInterpreter; - -class CABaseISOInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - char buffer[32]; - int a = t->toInt(); - sprintf (buffer, "%d", a); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = Interpreter::toInt (t, ofs); - - if (a > 1) { - double i = pow (2., double (a) / 32. - 4.) * 50.; - return i; - } else { - return 0.; - } - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - int a = Interpreter::toInt (t, ofs, astype); - - if (a > 1) { - int i = int (double (powf (2.f, float (a) / 32.f - 4.f)) * 50.f + 0.5f); - return i; - } else { - return 0; - } - } -}; -CABaseISOInterpreter caBaseISOInterpreter; - -class CAToneCurveInterpreter : public ChoiceInterpreter<> -{ -public: - CAToneCurveInterpreter() - { - choices[0] = "Standard"; - choices[1] = "Manual"; - choices[2] = "Custom"; - } -}; -CAToneCurveInterpreter caToneCurveInterpreter; - -class CASharpnessFrequencyInterpreter : public ChoiceInterpreter<> -{ -public: - CASharpnessFrequencyInterpreter() - { - choices[0] = "N/A"; - choices[1] = "Lowest"; - choices[2] = "Low"; - choices[3] = "Standard"; - choices[4] = "High"; - choices[5] = "Highest"; - } -}; -CASharpnessFrequencyInterpreter caSharpnessFrequencyInterpreter; - -class CAWhiteBalanceInterpreter : public ChoiceInterpreter<> -{ -public: - CAWhiteBalanceInterpreter() - { - choices[0] = "Auto"; - choices[1] = "Daylight"; - choices[2] = "Cloudy"; - choices[3] = "Tungsten"; - choices[4] = "Fluorescent"; - choices[5] = "Flash"; - choices[6] = "Custom"; - choices[7] = "Black & White"; - choices[8] = "Shade"; - choices[9] = "Manual Temperature (Kelvin)"; - choices[10] = "PC Set1"; - choices[11] = "PC Set2"; - choices[12] = "PC Set3"; - choices[14] = "Daylight Fluorescent"; - choices[15] = "Custom 1"; - choices[16] = "Custom 2"; - choices[17] = "Underwater"; - choices[18] = "Custom 3"; - choices[19] = "Custom 4"; - choices[20] = "PC Set4"; - choices[21] = "PC Set5"; - choices[23] = "Auto (ambience priority)"; - } -}; -CAWhiteBalanceInterpreter caWhiteBalanceInterpreter; - -class CAPictureStyleInterpreter : public ChoiceInterpreter<> -{ -public: - CAPictureStyleInterpreter() - { - choices[0] = "None"; - choices[1] = "Standard"; - choices[2] = "Portrait"; - choices[3] = "High Saturation"; - choices[4] = "Adobe RGB"; - choices[5] = "Low Saturation"; - choices[6] = "CM Set 1"; - choices[7] = "CM Set 2"; - choices[0x21] = "User Def. 1"; - choices[0x22] = "User Def. 2"; - choices[0x23] = "User Def. 3"; - choices[0x41] = "PC 1"; - choices[0x42] = "PC 2"; - choices[0x43] = "PC 3"; - choices[0x81] = "Standard"; - choices[0x82] = "Portrait"; - choices[0x83] = "Landscape"; - choices[0x84] = "Neutral"; - choices[0x85] = "Faithful"; - choices[0x86] = "Monochrome"; - choices[0x87] = "Auto"; - choices[0x88] = "Fine Detail"; - } -}; -CAPictureStyleInterpreter caPictureStyleInterpreter; - -class CASlowShutterInterpreter : public ChoiceInterpreter<> -{ -public: - CASlowShutterInterpreter() - { - choices[0] = "Off"; - choices[1] = "Night Scene"; - choices[2] = "On"; - choices[3] = "None"; - } -}; -CASlowShutterInterpreter caSlowShutterInterpreter; - -class CAFlashGuideNumberInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - int n = t->toInt(); - - if ( n == -1) { - return "undef"; - } - - char buffer[32]; - sprintf (buffer, "%.0f", n / 32. ); - return buffer; - } -}; -CAFlashGuideNumberInterpreter caFlashGuideNumberInterpreter; - -class CAAFPointsInFocusInterpreter : public ChoiceInterpreter<> -{ -public: - CAAFPointsInFocusInterpreter() - { - choices[0x3000] = "None (MF)"; - choices[0x3001] = "Right"; - choices[0x3002] = "Center"; - choices[0x3003] = "Center+Right"; - choices[0x3004] = "Left"; - choices[0x3005] = "Left+Right"; - choices[0x3006] = "Left+Center"; - choices[0x3007] = "All"; - } -}; -CAAFPointsInFocusInterpreter caAFPointsInFocusInterpreter; - -class CAAutoExposureBracketingInterpreter : public ChoiceInterpreter -{ -public: - CAAutoExposureBracketingInterpreter() - { - choices[-1] = "On "; - choices[0] = "Off "; - choices[1] = "On (shot 1)"; - choices[2] = "On (shot 2)"; - choices[3] = "On (shot 3)"; - } -}; -CAAutoExposureBracketingInterpreter caAutoExposureBracketingInterpreter; - -class CAControModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAControModeInterpreter() - { - choices[0] = "n/a"; - choices[1] = "Camera Local Control"; - choices[3] = "Computer Remote Control"; - } -}; -CAControModeInterpreter caControModeInterpreter; - -class CAFocusDistanceInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%.2f", t->toDouble() / 100 ); - return buffer; - } -}; -CAFocusDistanceInterpreter caFocusDistanceInterpreter; - -class CAMeasuredEVInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%.1f", t->toDouble() / 8 - 6 ); - return buffer; - } -}; -CAMeasuredEVInterpreter caMeasuredEVInterpreter; - -class CACameraTypeInterpreter : public ChoiceInterpreter<> -{ -public: - CACameraTypeInterpreter() - { - choices[248] = "EOS High-end"; - choices[250] = "Compact"; - choices[252] = "EOS Mid-range"; - choices[255] = "DV Camera"; - } -}; -CACameraTypeInterpreter caCameraTypeInterpreter; - -class CAAutoRotateInterpreter : public ChoiceInterpreter -{ -public: - CAAutoRotateInterpreter() - { - choices[-1] = "Rotated by Software"; - choices[0] = "None"; - choices[1] = "Rotate 90 CW"; - choices[2] = "Rotate 180"; - choices[3] = "Rotate 270 CW"; - } -}; -CAAutoRotateInterpreter caAutoRotateInterpreter; - -class CABracketModeInterpreter : public ChoiceInterpreter<> -{ -public: - CABracketModeInterpreter() - { - choices[0] = "Off"; - choices[1] = "AEB"; - choices[2] = "FEB"; - choices[3] = "ISO"; - choices[4] = "WB"; - } -}; -CABracketModeInterpreter caBracketModeInterpreter; - -class CARAWJpegQualityInterpreter : public ChoiceInterpreter<> -{ -public: - CARAWJpegQualityInterpreter() - { - choices[1] = "Economy"; - choices[2] = "Normal"; - choices[3] = "Fine"; - choices[4] = "RAW"; - choices[5] = "Superfine"; - choices[130] = "Normal Movie"; - choices[131] = "Movie (2)"; - } -}; -CARAWJpegQualityInterpreter caRAWJpegQualityInterpreter; - -class CAJpegSizeInterpreter : public ChoiceInterpreter<> -{ -public: - CAJpegSizeInterpreter() - { - choices[0] = "Large"; - choices[1] = "Medium"; - choices[2] = "Small"; - choices[5] = "Medium 1"; - choices[6] = "Medium 2"; - choices[7] = "Medium 3"; - choices[8] = "Postcard"; - choices[9] = "Widescreen"; - choices[10] = "Medium Widescreen"; - choices[14] = "Small 1"; - choices[15] = "Small 2"; - choices[16] = "Small 3"; - choices[128] = "640x480 Movie"; - choices[129] = "Medium Movie"; - choices[130] = "Small Movie"; - choices[137] = "1280x720 Movie"; - choices[142] = "1920x1080 Movie"; - } -}; -CAJpegSizeInterpreter caJpegSizeInterpreter; - -class CAWBBracketModeInterpreter : public ChoiceInterpreter<> -{ -public: - CAWBBracketModeInterpreter() - { - choices[0] = "Off"; - choices[1] = "On (shift AB)"; - choices[2] = "On (shift GM)"; - } -}; -CAWBBracketModeInterpreter caWBBracketModeInterpreter; - -class CAFilterEffectInterpreter : public ChoiceInterpreter<> -{ -public: - CAFilterEffectInterpreter() - { - choices[0] = "None"; - choices[1] = "Yellow"; - choices[2] = "Orange"; - choices[3] = "Red"; - choices[4] = "Green"; - } -}; -CAFilterEffectInterpreter caFilterEffectInterpreter; - -class CAToningEffectInterpreter : public ChoiceInterpreter<> -{ -public: - CAToningEffectInterpreter() - { - choices[0] = "None"; - choices[1] = "Sepia"; - choices[2] = "Blue"; - choices[3] = "Purple"; - choices[4] = "Green"; - } -}; -CAToningEffectInterpreter caToningEffectInterpreter; - -class CAFileNumberInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - unsigned long val = t->toInt (0, LONG); - char buffer[32]; - sprintf (buffer, "%ld", ((val & 0xffc0) >> 6) * 10000 + ((val >> 16) & 0xff) + ((val & 0x3f) << 8) ); - return buffer; - } -}; -CAFileNumberInterpreter caFileNumberInterpreter; - -// CanonModelID -class CAModelIDInterpreter : public ChoiceInterpreter<> -{ -public: - CAModelIDInterpreter () - { - choices[1042] = "EOS M50 / Kiss M"; - choices[2049] = "PowerShot SX740 HS"; - choices[2053] = "PowerShot SX70 HS"; - choices[16842752] = "PowerShot A30"; - choices[17039360] = "PowerShot S300 / Digital IXUS 300 / IXY Digital 300"; - choices[17170432] = "PowerShot A20"; - choices[17301504] = "PowerShot A10"; - choices[17367040] = "PowerShot S110 / Digital IXUS v / IXY Digital 200"; - choices[17825792] = "PowerShot G2"; - choices[17891328] = "PowerShot S40"; - choices[17956864] = "PowerShot S30"; - choices[18022400] = "PowerShot A40"; - choices[18087936] = "EOS D30"; - choices[18153472] = "PowerShot A100"; - choices[18219008] = "PowerShot S200 / Digital IXUS v2 / IXY Digital 200a"; - choices[18284544] = "PowerShot A200"; - choices[18350080] = "PowerShot S330 / Digital IXUS 330 / IXY Digital 300a"; - choices[18415616] = "PowerShot G3"; - choices[18939904] = "PowerShot S45"; - choices[19070976] = "PowerShot SD100 / Digital IXUS II / IXY Digital 30"; - choices[19136512] = "PowerShot S230 / Digital IXUS v3 / IXY Digital 320"; - choices[19202048] = "PowerShot A70"; - choices[19267584] = "PowerShot A60"; - choices[19333120] = "PowerShot S400 / Digital IXUS 400 / IXY Digital 400"; - choices[19464192] = "PowerShot G5"; - choices[19922944] = "PowerShot A300"; - choices[19988480] = "PowerShot S50"; - choices[20185088] = "PowerShot A80"; - choices[20250624] = "PowerShot SD10 / Digital IXUS i / IXY Digital L"; - choices[20316160] = "PowerShot S1 IS"; - choices[20381696] = "PowerShot Pro1"; - choices[20447232] = "PowerShot S70"; - choices[20512768] = "PowerShot S60"; - choices[20971520] = "PowerShot G6"; - choices[21037056] = "PowerShot S500 / Digital IXUS 500 / IXY Digital 500"; - choices[21102592] = "PowerShot A75"; - choices[21233664] = "PowerShot SD110 / Digital IXUS IIs / IXY Digital 30a"; - choices[21299200] = "PowerShot A400"; - choices[21430272] = "PowerShot A310"; - choices[21561344] = "PowerShot A85"; - choices[22151168] = "PowerShot S410 / Digital IXUS 430 / IXY Digital 450"; - choices[22216704] = "PowerShot A95"; - choices[22282240] = "PowerShot SD300 / Digital IXUS 40 / IXY Digital 50"; - choices[22347776] = "PowerShot SD200 / Digital IXUS 30 / IXY Digital 40"; - choices[22413312] = "PowerShot A520"; - choices[22478848] = "PowerShot A510"; - choices[22609920] = "PowerShot SD20 / Digital IXUS i5 / IXY Digital L2"; - choices[23330816] = "PowerShot S2 IS"; - choices[23396352] = "PowerShot SD430 / Digital IXUS Wireless / IXY Digital Wireless"; - choices[23461888] = "PowerShot SD500 / Digital IXUS 700 / IXY Digital 600"; - choices[23494656] = "EOS D60"; - choices[24117248] = "PowerShot SD30 / Digital IXUS i Zoom / IXY Digital L3"; - choices[24379392] = "PowerShot A430"; - choices[24444928] = "PowerShot A410"; - choices[24510464] = "PowerShot S80"; - choices[24641536] = "PowerShot A620"; - choices[24707072] = "PowerShot A610"; - choices[25165824] = "PowerShot SD630 / Digital IXUS 65 / IXY Digital 80"; - choices[25231360] = "PowerShot SD450 / Digital IXUS 55 / IXY Digital 60"; - choices[25296896] = "PowerShot TX1"; - choices[25624576] = "PowerShot SD400 / Digital IXUS 50 / IXY Digital 55"; - choices[25690112] = "PowerShot A420"; - choices[25755648] = "PowerShot SD900 / Digital IXUS 900 Ti / IXY Digital 1000"; - choices[26214400] = "PowerShot SD550 / Digital IXUS 750 / IXY Digital 700"; - choices[26345472] = "PowerShot A700"; - choices[26476544] = "PowerShot SD700 IS / Digital IXUS 800 IS / IXY Digital 800 IS"; - choices[26542080] = "PowerShot S3 IS"; - choices[26607616] = "PowerShot A540"; - choices[26673152] = "PowerShot SD600 / Digital IXUS 60 / IXY Digital 70"; - choices[26738688] = "PowerShot G7"; - choices[26804224] = "PowerShot A530"; - choices[33554432] = "PowerShot SD800 IS / Digital IXUS 850 IS / IXY Digital 900 IS"; - choices[33619968] = "PowerShot SD40 / Digital IXUS i7 / IXY Digital L4"; - choices[33685504] = "PowerShot A710 IS"; - choices[33751040] = "PowerShot A640"; - choices[33816576] = "PowerShot A630"; - choices[34144256] = "PowerShot S5 IS"; - choices[34603008] = "PowerShot A460"; - choices[34734080] = "PowerShot SD850 IS / Digital IXUS 950 IS / IXY Digital 810 IS"; - choices[34799616] = "PowerShot A570 IS"; - choices[34865152] = "PowerShot A560"; - choices[34930688] = "PowerShot SD750 / Digital IXUS 75 / IXY Digital 90"; - choices[34996224] = "PowerShot SD1000 / Digital IXUS 70 / IXY Digital 10"; - choices[35127296] = "PowerShot A550"; - choices[35192832] = "PowerShot A450"; - choices[35848192] = "PowerShot G9"; - choices[35913728] = "PowerShot A650 IS"; - choices[36044800] = "PowerShot A720 IS"; - choices[36241408] = "PowerShot SX100 IS"; - choices[36700160] = "PowerShot SD950 IS / Digital IXUS 960 IS / IXY Digital 2000 IS"; - choices[36765696] = "PowerShot SD870 IS / Digital IXUS 860 IS / IXY Digital 910 IS"; - choices[36831232] = "PowerShot SD890 IS / Digital IXUS 970 IS / IXY Digital 820 IS"; - choices[37093376] = "PowerShot SD790 IS / Digital IXUS 90 IS / IXY Digital 95 IS"; - choices[37158912] = "PowerShot SD770 IS / Digital IXUS 85 IS / IXY Digital 25 IS"; - choices[37224448] = "PowerShot A590 IS"; - choices[37289984] = "PowerShot A580"; - choices[37879808] = "PowerShot A470"; - choices[37945344] = "PowerShot SD1100 IS / Digital IXUS 80 IS / IXY Digital 20 IS"; - choices[38141952] = "PowerShot SX1 IS"; - choices[38207488] = "PowerShot SX10 IS"; - choices[38273024] = "PowerShot A1000 IS"; - choices[38338560] = "PowerShot G10"; - choices[38862848] = "PowerShot A2000 IS"; - choices[38928384] = "PowerShot SX110 IS"; - choices[38993920] = "PowerShot SD990 IS / Digital IXUS 980 IS / IXY Digital 3000 IS"; - choices[39059456] = "PowerShot SD880 IS / Digital IXUS 870 IS / IXY Digital 920 IS"; - choices[39124992] = "PowerShot E1"; - choices[39190528] = "PowerShot D10"; - choices[39256064] = "PowerShot SD960 IS / Digital IXUS 110 IS / IXY Digital 510 IS"; - choices[39321600] = "PowerShot A2100 IS"; - choices[39387136] = "PowerShot A480"; - choices[39845888] = "PowerShot SX200 IS"; - choices[39911424] = "PowerShot SD970 IS / Digital IXUS 990 IS / IXY Digital 830 IS"; - choices[39976960] = "PowerShot SD780 IS / Digital IXUS 100 IS / IXY Digital 210 IS"; - choices[40042496] = "PowerShot A1100 IS"; - choices[40108032] = "PowerShot SD1200 IS / Digital IXUS 95 IS / IXY Digital 110 IS"; - choices[40894464] = "PowerShot G11"; - choices[40960000] = "PowerShot SX120 IS"; - choices[41025536] = "PowerShot S90"; - choices[41222144] = "PowerShot SX20 IS"; - choices[41287680] = "PowerShot SD980 IS / Digital IXUS 200 IS / IXY Digital 930 IS"; - choices[41353216] = "PowerShot SD940 IS / Digital IXUS 120 IS / IXY Digital 220 IS"; - choices[41943040] = "PowerShot A495"; - choices[42008576] = "PowerShot A490"; - choices[42074112] = "PowerShot A3100/A3150 IS"; - choices[42139648] = "PowerShot A3000 IS"; - choices[42205184] = "PowerShot SD1400 IS / IXUS 130 / IXY 400F"; - choices[42270720] = "PowerShot SD1300 IS / IXUS 105 / IXY 200F"; - choices[42336256] = "PowerShot SD3500 IS / IXUS 210 / IXY 10S"; - choices[42401792] = "PowerShot SX210 IS"; - choices[42467328] = "PowerShot SD4000 IS / IXUS 300 HS / IXY 30S"; - choices[42532864] = "PowerShot SD4500 IS / IXUS 1000 HS / IXY 50S"; - choices[43122688] = "PowerShot G12"; - choices[43188224] = "PowerShot SX30 IS"; - choices[43253760] = "PowerShot SX130 IS"; - choices[43319296] = "PowerShot S95"; - choices[43515904] = "PowerShot A3300 IS"; - choices[43581440] = "PowerShot A3200 IS"; - choices[50331648] = "PowerShot ELPH 500 HS / IXUS 310 HS / IXY 31S"; - choices[50397184] = "PowerShot Pro90 IS"; - choices[50397185] = "PowerShot A800"; - choices[50462720] = "PowerShot ELPH 100 HS / IXUS 115 HS / IXY 210F"; - choices[50528256] = "PowerShot SX230 HS"; - choices[50593792] = "PowerShot ELPH 300 HS / IXUS 220 HS / IXY 410F"; - choices[50659328] = "PowerShot A2200"; - choices[50724864] = "PowerShot A1200"; - choices[50790400] = "PowerShot SX220 HS"; - choices[50855936] = "PowerShot G1 X"; - choices[50921472] = "PowerShot SX150 IS"; - choices[51380224] = "PowerShot ELPH 510 HS / IXUS 1100 HS / IXY 51S"; - choices[51445760] = "PowerShot S100 (new)"; - choices[51511296] = "PowerShot ELPH 310 HS / IXUS 230 HS / IXY 600F"; - choices[51576832] = "PowerShot SX40 HS"; - choices[51642368] = "IXY 32S"; - choices[51773440] = "PowerShot A1300"; - choices[51838976] = "PowerShot A810"; - choices[51904512] = "PowerShot ELPH 320 HS / IXUS 240 HS / IXY 420F"; - choices[51970048] = "PowerShot ELPH 110 HS / IXUS 125 HS / IXY 220F"; - choices[52428800] = "PowerShot D20"; - choices[52494336] = "PowerShot A4000 IS"; - choices[52559872] = "PowerShot SX260 HS"; - choices[52625408] = "PowerShot SX240 HS"; - choices[52690944] = "PowerShot ELPH 530 HS / IXUS 510 HS / IXY 1"; - choices[52756480] = "PowerShot ELPH 520 HS / IXUS 500 HS / IXY 3"; - choices[52822016] = "PowerShot A3400 IS"; - choices[52887552] = "PowerShot A2400 IS"; - choices[52953088] = "PowerShot A2300"; - choices[53673984] = "PowerShot G15"; - choices[53739520] = "PowerShot SX50 HS"; - choices[53805056] = "PowerShot SX160 IS"; - choices[53870592] = "PowerShot S110 (new)"; - choices[53936128] = "PowerShot SX500 IS"; - choices[54001664] = "PowerShot N"; - choices[54067200] = "IXUS 245 HS / IXY 430F"; - choices[54525952] = "PowerShot SX280 HS"; - choices[54591488] = "PowerShot SX270 HS"; - choices[54657024] = "PowerShot A3500 IS"; - choices[54722560] = "PowerShot A2600"; - choices[54788096] = "PowerShot SX275 HS"; - choices[54853632] = "PowerShot A1400"; - choices[54919168] = "PowerShot ELPH 130 IS / IXUS 140 / IXY 110F"; - choices[54984704] = "PowerShot ELPH 115/120 IS / IXUS 132/135 / IXY 90F/100F"; - choices[55115776] = "PowerShot ELPH 330 HS / IXUS 255 HS / IXY 610F"; - choices[55640064] = "PowerShot A2500"; - choices[55836672] = "PowerShot G16"; - choices[55902208] = "PowerShot S120"; - choices[55967744] = "PowerShot SX170 IS"; - choices[56098816] = "PowerShot SX510 HS"; - choices[56164352] = "PowerShot S200 (new)"; - choices[56623104] = "IXY 620F"; - choices[56688640] = "PowerShot N100"; - choices[56885248] = "PowerShot G1 X Mark II"; - choices[56950784] = "PowerShot D30"; - choices[57016320] = "PowerShot SX700 HS"; - choices[57081856] = "PowerShot SX600 HS"; - choices[57147392] = "PowerShot ELPH 140 IS / IXUS 150 / IXY 130"; - choices[57212928] = "PowerShot ELPH 135 / IXUS 145 / IXY 120"; - choices[57671680] = "PowerShot ELPH 340 HS / IXUS 265 HS / IXY 630"; - choices[57737216] = "PowerShot ELPH 150 IS / IXUS 155 / IXY 140"; - choices[57933824] = "EOS M3"; - choices[57999360] = "PowerShot SX60 HS"; - choices[58064896] = "PowerShot SX520 HS"; - choices[58130432] = "PowerShot SX400 IS"; - choices[58195968] = "PowerShot G7 X"; - choices[58261504] = "PowerShot N2"; - choices[58720256] = "PowerShot SX530 HS"; - choices[58851328] = "PowerShot SX710 HS"; - choices[58916864] = "PowerShot SX610 HS"; - choices[58982400] = "EOS M10"; - choices[59047936] = "PowerShot G3 X"; - choices[59113472] = "PowerShot ELPH 165 HS / IXUS 165 / IXY 160"; - choices[59179008] = "PowerShot ELPH 160 / IXUS 160"; - choices[59244544] = "PowerShot ELPH 350 HS / IXUS 275 HS / IXY 640"; - choices[59310080] = "PowerShot ELPH 170 IS / IXUS 170"; - choices[59834368] = "PowerShot SX410 IS"; - choices[59965440] = "PowerShot G9 X"; - choices[60030976] = "EOS M5"; - choices[60096512] = "PowerShot G5 X"; - choices[60227584] = "PowerShot G7 X Mark II"; - choices[60293120] = "EOS M100"; - choices[60358656] = "PowerShot ELPH 360 HS / IXUS 285 HS / IXY 650"; - choices[67174400] = "PowerShot SX540 HS"; - choices[67239936] = "PowerShot SX420 IS"; - choices[67305472] = "PowerShot ELPH 190 IS / IXUS 180 / IXY 190"; - choices[67371008] = "PowerShot G1"; - choices[67371009] = "IXY 180"; - choices[67436544] = "PowerShot SX720 HS"; - choices[67502080] = "PowerShot SX620 HS"; - choices[67567616] = "EOS M6"; - choices[68157440] = "PowerShot G9 X Mark II"; - choices[68485120] = "PowerShot ELPH 185 / IXUS 185 / IXY 200"; - choices[68550656] = "PowerShot SX430 IS"; - choices[68616192] = "PowerShot SX730 HS"; - choices[68681728] = "PowerShot G1 X Mark III"; - choices[100925440] = "PowerShot S100 / Digital IXUS / IXY Digital"; - choices[1074255475] = "DC19/DC21/DC22"; - choices[1074255476] = "XH A1"; - choices[1074255477] = "HV10"; - choices[1074255478] = "MD130/MD140/MD150/MD160/ZR850"; - choices[1074255735] = "DC50"; - choices[1074255736] = "HV20"; - choices[1074255737] = "DC211"; - choices[1074255738] = "HG10"; - choices[1074255739] = "HR10"; - choices[1074255741] = "MD255/ZR950"; - choices[1074255900] = "HF11"; - choices[1074255992] = "HV30"; - choices[1074255996] = "XH A1S"; - choices[1074255998] = "DC301/DC310/DC311/DC320/DC330"; - choices[1074255999] = "FS100"; - choices[1074256000] = "HF10"; - choices[1074256002] = "HG20/HG21"; - choices[1074256165] = "HF21"; - choices[1074256166] = "HF S11"; - choices[1074256248] = "HV40"; - choices[1074256263] = "DC410/DC411/DC420"; - choices[1074256264] = "FS19/FS20/FS21/FS22/FS200"; - choices[1074256265] = "HF20/HF200"; - choices[1074256266] = "HF S10/S100"; - choices[1074256526] = "HF R10/R16/R17/R18/R100/R106"; - choices[1074256527] = "HF M30/M31/M36/M300/M306"; - choices[1074256528] = "HF S20/S21/S200"; - choices[1074256530] = "FS31/FS36/FS37/FS300/FS305/FS306/FS307"; - choices[1074257056] = "EOS C300"; - choices[1074257321] = "HF G25"; - choices[1074257844] = "XC10"; - choices[1074258371] = "EOS C200"; - choices[2147483649] = "EOS-1D"; - choices[2147484007] = "EOS-1DS"; - choices[2147484008] = "EOS 10D"; - choices[2147484009] = "EOS-1D Mark III"; - choices[2147484016] = "EOS Digital Rebel / 300D / Kiss Digital"; - choices[2147484020] = "EOS-1D Mark II"; - choices[2147484021] = "EOS 20D"; - choices[2147484022] = "EOS Digital Rebel XSi / 450D / Kiss X2"; - choices[2147484040] = "EOS-1Ds Mark II"; - choices[2147484041] = "EOS Digital Rebel XT / 350D / Kiss Digital N"; - choices[2147484048] = "EOS 40D"; - choices[2147484179] = "EOS 5D"; - choices[2147484181] = "EOS-1Ds Mark III"; - choices[2147484184] = "EOS 5D Mark II"; - choices[2147484185] = "WFT-E1"; - choices[2147484210] = "EOS-1D Mark II N"; - choices[2147484212] = "EOS 30D"; - choices[2147484214] = "EOS Digital Rebel XTi / 400D / Kiss Digital X"; - choices[2147484225] = "WFT-E2"; - choices[2147484230] = "WFT-E3"; - choices[2147484240] = "EOS 7D"; - choices[2147484242] = "EOS Rebel T1i / 500D / Kiss X3"; - choices[2147484244] = "EOS Rebel XS / 1000D / Kiss F"; - choices[2147484257] = "EOS 50D"; - choices[2147484265] = "EOS-1D X"; - choices[2147484272] = "EOS Rebel T2i / 550D / Kiss X4"; - choices[2147484273] = "WFT-E4"; - choices[2147484275] = "WFT-E5"; - choices[2147484289] = "EOS-1D Mark IV"; - choices[2147484293] = "EOS 5D Mark III"; - choices[2147484294] = "EOS Rebel T3i / 600D / Kiss X5"; - choices[2147484295] = "EOS 60D"; - choices[2147484296] = "EOS Rebel T3 / 1100D / Kiss X50"; - choices[2147484297] = "EOS 7D Mark II"; - choices[2147484311] = "WFT-E2 II"; - choices[2147484312] = "WFT-E4 II"; - choices[2147484417] = "EOS Rebel T4i / 650D / Kiss X6i"; - choices[2147484418] = "EOS 6D"; - choices[2147484452] = "EOS-1D C"; - choices[2147484453] = "EOS 70D"; - choices[2147484454] = "EOS Rebel T5i / 700D / Kiss X7i"; - choices[2147484455] = "EOS Rebel T5 / 1200D / Kiss X70 / Hi"; - choices[2147484456] = "EOS-1D X MARK II"; - choices[2147484465] = "EOS M"; - choices[2147484486] = "EOS Rebel SL1 / 100D / Kiss X7"; - choices[2147484487] = "EOS Rebel T6s / 760D / 8000D"; - choices[2147484489] = "EOS 5D Mark IV"; - choices[2147484496] = "EOS 80D"; - choices[2147484501] = "EOS M2"; - choices[2147484546] = "EOS 5DS"; - choices[2147484563] = "EOS Rebel T6i / 750D / Kiss X8i"; - choices[2147484673] = "EOS 5DS R"; - choices[2147484676] = "EOS Rebel T6 / 1300D / Kiss X80"; - choices[2147484677] = "EOS Rebel T7i / 800D / Kiss X9i"; - choices[2147484678] = "EOS 6D Mark II"; - choices[2147484680] = "EOS 77D / 9000D"; - choices[2147484695] = "EOS Rebel SL2 / 200D / Kiss X9"; - choices[2147484706] = "EOS Rebel T100 / 4000D / 3000D"; - choices[2147484708] = "EOR R"; - choices[2147484722] = "EOS Rebel T7 / 2000D / 1500D / Kiss X90"; - } -}; -CAModelIDInterpreter caModelIDInterpreter; - -class CAPanoramaDirectionInterpreter : public ChoiceInterpreter<> -{ -public: - CAPanoramaDirectionInterpreter() - { - choices[0] = "Left to Right"; - choices[1] = "Right to Left"; - choices[2] = "Bottom to Top"; - choices[3] = "Top to Bottom"; - choices[4] = "2x2 Matrix (Clockwise)"; - } -}; -CAPanoramaDirectionInterpreter caPanoramaDirectionInterpreter; - -class CAAspectRatioInterpreter : public ChoiceInterpreter<> -{ -public: - CAAspectRatioInterpreter() - { - choices[0] = "3:2"; - choices[1] = "1:1"; - choices[2] = "4:3"; - choices[7] = "16:9"; - choices[8] = "4:5"; - } - -}; -CAAspectRatioInterpreter caAspectRatioInterpreter; - -const TagAttrib canonCameraSettingsAttribs[] = { - {0, AC_WRITE, 0, nullptr, 1, AUTO, "MacroMode", &caMacroModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "SelfTimer", &caSelfTimerInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "Quality", &caQualityInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "CanonFlashMode", &caFlashModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "ContinuousDrive", &caContinuousDriveInterpreter}, - {0, AC_WRITE, 0, nullptr, 7, AUTO, "FocusMode", &caFocusModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "RecordMode", &caRecordModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "CanonImageSize", &caImageSizeInterpreter}, - {0, AC_WRITE, 0, nullptr, 11, AUTO, "EasyMode", &caEasyModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 12, AUTO, "DigitalZoom", &caDigitalZoomInterpreter}, - {0, AC_WRITE, 0, nullptr, 13, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 14, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 15, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 16, AUTO, "CameraISO", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "MeteringMode", &caMeteringModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 18, AUTO, "FocusRange", &caFocusRangeInterpreter}, - {0, AC_WRITE, 0, nullptr, 19, AUTO, "AFPoint", &caAFPointInterpreter}, - {0, AC_WRITE, 0, nullptr, 20, AUTO, "CanonExposureMode", &caExposureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 22, AUTO, "LensID", &caLensInterpreter}, - {0, AC_WRITE, 0, nullptr, 23, AUTO, "LongFocal", &caFocalInterpreter}, - {0, AC_WRITE, 0, nullptr, 24, AUTO, "ShortFocal", &caFocalInterpreter}, - {0, AC_WRITE, 0, nullptr, 25, AUTO, "FocalUnits", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 26, AUTO, "MaxAperture", &caApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 27, AUTO, "MinAperture", &caApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 28, AUTO, "FlashActivity", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 29, AUTO, "FlashBits", &caFlashBitsInterpreter}, - {0, AC_WRITE, 0, nullptr, 32, AUTO, "FocusContinuous", &caFocusContinuousInterpreter}, - {0, AC_WRITE, 0, nullptr, 33, AUTO, "AESetting", &caAESettingsInterpreter}, - {0, AC_WRITE, 0, nullptr, 34, AUTO, "ImageStabilization", &caStabilizationInterpreter}, - {0, AC_WRITE, 0, nullptr, 35, AUTO, "DisplayAperture", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 36, AUTO, "ZoomSourceWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 37, AUTO, "ZoomTargetWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 39, AUTO, "SpotMeteringMode", &caSpotMeteringInterpreter}, - {0, AC_WRITE, 0, nullptr, 40, AUTO, "PhotoEffect", &caPhotoEffectInterpreter}, - {0, AC_WRITE, 0, nullptr, 41, AUTO, "ManualFlashOutput", &caManualFlashInterpreter}, - {0, AC_WRITE, 0, nullptr, 42, AUTO, "ColorTone", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 46, AUTO, "SRAWQuality", &caRAWQualityInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib canonFocalLengthAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "FocalType", &caFocalTypeInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "FocalLength", &caFocalInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "FocalPlaneXSize", &caFocalPlaneInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "FocalPlaneYSize", &caFocalPlaneInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib canonShotInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 1, AUTO, "AutoISO", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "BaseISO", &caBaseISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "MeasuredEV", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "TargetAperture", &caApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "TargetExposureTime", &caExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 6, AUTO, "ExposureCompensation", &caEVInterpreter}, - {0, AC_WRITE, 0, nullptr, 7, AUTO, "WhiteBalance", &caWhiteBalanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 8, AUTO, "SlowShutter", &caSlowShutterInterpreter}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "SequenceNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "OpticalZoomCode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 13, AUTO, "FlashGuideNumber", &caFlashGuideNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 14, AUTO, "AFPointsInFocus", &caAFPointsInFocusInterpreter}, - {0, AC_WRITE, 0, nullptr, 15, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 16, AUTO, "AutoExposureBracketing", &caAutoExposureBracketingInterpreter}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "AEBBracketValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 18, AUTO, "ControlMode", &caControModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 21, AUTO, "FNumber", &caApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 22, AUTO, "ExposureTime", &caExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 23, AUTO, "MeasuredEV2", &caMeasuredEVInterpreter}, - {0, AC_WRITE, 0, nullptr, 24, AUTO, "BulbDuration", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 26, AUTO, "CameraType", &caCameraTypeInterpreter}, - {0, AC_WRITE, 0, nullptr, 27, AUTO, "AutoRotate", &caAutoRotateInterpreter}, - {0, AC_WRITE, 0, nullptr, 28, AUTO, "NDFilter", &caOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 29, AUTO, "Self-timer2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 33, AUTO, "FlashOutput", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr}, -}; - -const TagAttrib canonFileInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 1, AUTO, "FileNumber", &caFileNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "BracketMode", &caBracketModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "BracketValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "BracketShotNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 6, AUTO, "RawJpgQuality", &caRAWJpegQualityInterpreter}, - {0, AC_WRITE, 0, nullptr, 7, AUTO, "RawJpgSize", &caJpegSizeInterpreter}, - {0, AC_WRITE, 0, nullptr, 8, AUTO, "NoiseReduction", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "WBBracketMode", &caWBBracketModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 12, AUTO, "WBBracketValueAB", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 13, AUTO, "WBBracketValueGM", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 14, AUTO, "FilterEffect", &caFilterEffectInterpreter}, - {0, AC_WRITE, 0, nullptr, 15, AUTO, "ToningEffect", &caToningEffectInterpreter}, - {0, AC_WRITE, 0, nullptr, 19, AUTO, "LiveViewShooting", &caOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 20, AUTO, "FocusDistanceUpper", &caFocusDistanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 21, AUTO, "FocusDistanceLower", &caFocusDistanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 25, AUTO, "FlashExposureLock", &caOnOffInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr}, -}; - -const TagAttrib canonProcessingInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ToneCurve", &caToneCurveInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "SharpnessFrequency", &caSharpnessFrequencyInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "SensorRedLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "SensorBlueLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 6, AUTO, "WhiteBalanceRed", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 7, AUTO, "WhiteBalanceBlue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 8, AUTO, "WhiteBalance", &caWhiteBalanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "PictureStyle", &caPictureStyleInterpreter}, - {0, AC_WRITE, 0, nullptr, 11, AUTO, "DigitalGain", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 12, AUTO, "WBShiftAB", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 13, AUTO, "WBShiftGM", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr}, -}; - -const TagAttrib canonPanoramaInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 2, AUTO, "PanoramaFrameNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "PanoramaDirection", &caPanoramaDirectionInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr}, -}; - -const TagAttrib canonCropInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "CropLeftMargin", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "CropRightMargin", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "CropTopMargin", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "CropBottomMargin", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr}, -}; - -const TagAttrib canonAspectInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "AspectRatio", &caAspectRatioInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "CroppedImageWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "CroppedImageHeight", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr}, -}; - -const TagAttrib canonMicroAdjustAttrib[] = { - {0, AC_WRITE, 0, nullptr, 1, AUTO, "AFMicroAdjActive", &caOnOffInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 2, AUTO, "", nullptr}, -}; - -const TagAttrib canonAttribs[] = { - {0, AC_WRITE, 0, canonCameraSettingsAttribs, 0x0001, AUTO, "CanonCameraSettings", &stdInterpreter}, - {0, AC_WRITE, 0, canonFocalLengthAttribs, 0x0002, AUTO, "CanonFocalLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "CanonFlashInfo", &stdInterpreter}, - {0, AC_WRITE, 0, canonShotInfoAttribs, 0x0004, AUTO, "CanonShotInfo", &stdInterpreter}, - {0, AC_WRITE, 0, canonPanoramaInfoAttribs, 0x0005, AUTO, "CanonPanorama", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "CanonImageType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "CanonFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0008, AUTO, "FileNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0009, AUTO, "OwnerName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000a, AUTO, "ColorInfoD30", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000c, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000d, AUTO, "CanonCameraInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000e, AUTO, "CanonFileLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000f, AUTO, "CustomFunctions", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0010, AUTO, "CanonModelID", &caModelIDInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0012, AUTO, "CanonAFInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0015, AUTO, "SerialNumberFormat", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001c, AUTO, "DateStampMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001d, AUTO, "MyColors", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001e, AUTO, "FirmwareRevision", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x0024, AUTO, "FaceDetect1", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x0025, AUTO, "FaceDetect2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0026, AUTO, "CanonAFInfo2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0083, AUTO, "OriginalDecisionData", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0090, AUTO, "CustomFunctions1D", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0091, AUTO, "PersonalFunctions", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0092, AUTO, "PersonalFunctionValues", &stdInterpreter}, - {0, AC_WRITE, 0, canonFileInfoAttribs, 0x0093, AUTO, "CanonFileInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0094, AUTO, "AFPointsInFocus1D", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0095, AUTO, "LensType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0096, AUTO, "InternalSerialNumber", &caIntSerNumInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0097, AUTO, "DustRemovalData", &stdInterpreter}, - {0, AC_WRITE, 0, canonCropInfoAttribs, 0x0098, AUTO, "CropInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0099, AUTO, "CustomFunctions2", &stdInterpreter}, - {0, AC_WRITE, 0, canonAspectInfoAttribs, 0x009a, AUTO, "AspectInfo", &stdInterpreter}, - {0, AC_WRITE, 0, canonProcessingInfoAttribs, 0x00a0, AUTO, "ProcessingInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a1, AUTO, "ToneCurveTable", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a2, AUTO, "SharpnessTable", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a3, AUTO, "SharpnessFreqTable", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a4, AUTO, "WhiteBalanceTable", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a9, AUTO, "ColorBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00aa, AUTO, "MeasuredColor", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00ae, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x00b0, AUTO, "CanonFlags", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00b1, AUTO, "ModifiedInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00b2, AUTO, "ToneCurveMatching", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00b3, AUTO, "WhiteBalanceMatching", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00b4, AUTO, "ColorSpace", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x00b6, AUTO, "PreviewImageInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00d0, AUTO, "VRDOffset", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00e0, AUTO, "SensorInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x4001, AUTO, "ColorBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x4002, AUTO, "UnknownBlock1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x4003, AUTO, "ColorInfo", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x4005, AUTO, "UnknownBlock2", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x4008, AUTO, "BlackLevel", &stdInterpreter}, - {1, AC_WRITE, 0, canonMicroAdjustAttrib, 0x4013, AUTO, "AFMicroAdj", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; -} -#endif - diff --git a/rtexif/fujiattribs.cc b/rtexif/fujiattribs.cc deleted file mode 100644 index 2e17a68f9..000000000 --- a/rtexif/fujiattribs.cc +++ /dev/null @@ -1,316 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _FUJIATTRIBS_ -#define _FUJIATTRIBS_ - -#include "rtexif.h" - -namespace rtexif -{ - -class FAOnOffInterpreter : public ChoiceInterpreter<> -{ -public: - FAOnOffInterpreter () - { - choices[0] = "Off"; - choices[1] = "On"; - } -}; -FAOnOffInterpreter faOnOffInterpreter; - -class FASharpnessInterpreter : public ChoiceInterpreter<> -{ -public: - FASharpnessInterpreter () - { - choices[1] = "Soft"; - choices[2] = "Soft2"; - choices[3] = "Normal"; - choices[4] = "Hard"; - choices[5] = "Hard2"; - choices[0x82] = "Medium Soft"; - choices[0x84] = "Medium Hard"; - choices[0x8000] = "Film Simulation"; - choices[0xffff] = "n/a"; - } -}; -FASharpnessInterpreter faSharpnessInterpreter; - -class FAWhiteBalanceInterpreter : public ChoiceInterpreter<> -{ -public: - FAWhiteBalanceInterpreter () - { - choices[0] = "Auto"; - choices[0x100] = "Daylight"; - choices[0x200] = "Cloudy"; - choices[0x300] = "Daylight Fluorescent"; - choices[0x301] = "Day White Fluorescent"; - choices[0x302] = "White Fluorescent"; - choices[0x303] = "Warm White Fluorescent"; - choices[0x304] = "Living Room Warm White Fluorescent"; - choices[0x400] = "Incandescent"; - choices[0x500] = "Flash"; - choices[0x600] = "Underwater"; - choices[0xf00] = "Custom"; - choices[0xf01] = "Custom2"; - choices[0xf02] = "Custom3"; - choices[0xf03] = "Custom4"; - choices[0xf04] = "Custom5"; - choices[0xff0] = "Kelvin"; - } -}; -FAWhiteBalanceInterpreter faWhiteBalanceInterpreter; - -class FASaturationInterpreter : public ChoiceInterpreter<> -{ -public: - FASaturationInterpreter () - { - choices[0] = "Normal"; - choices[128] = "Medium High"; - choices[256] = "High"; - choices[384] = "Medium Low"; - choices[512] = "Low"; - choices[768] = "None (B&W)"; - choices[769] = "B&W Red Filter"; - choices[770] = "B&W Yellow Filter"; - choices[771] = "B&W Green Filter"; - choices[784] = "B&W Sepia"; - choices[1024] = "Low 2"; - choices[1280] = "Acros"; - choices[1281] = "Acros Red Filter"; - choices[1282] = "Acros Yellow Filter"; - choices[1283] = "Acros Green Filter"; - choices[32768] = "Film Simulation"; - } -}; -FASaturationInterpreter faSaturationInterpreter; - -class FAContrastInterpreter : public ChoiceInterpreter<> -{ -public: - FAContrastInterpreter () - { - choices[0] = "Normal"; - choices[0x80] = "Medium High"; - choices[0x100] = "High"; - choices[0x180] = "Medium Low"; - choices[0x200] = "Low"; - choices[0x8000] = "Film Simulation"; - } -}; -FAContrastInterpreter faContrastInterpreter; - -class FAContrast2Interpreter : public ChoiceInterpreter<> -{ -public: - FAContrast2Interpreter () - { - choices[0] = "Normal"; - choices[0x100] = "High"; - choices[0x300] = "Low"; - } -}; -FAContrast2Interpreter faContrast2Interpreter; - -class FANoiseReductionInterpreter : public ChoiceInterpreter<> -{ -public: - FANoiseReductionInterpreter () - { - choices[0x40] = "Low"; - choices[0x80] = "Normal"; - choices[0x100] = "n/a"; - } -}; -FANoiseReductionInterpreter faNoiseReductionInterpreter; - -class FAFlashInterpreter : public ChoiceInterpreter<> -{ -public: - // FujiFlashMode - FAFlashInterpreter () - { - choices[0] = "Auto"; - choices[1] = "On"; - choices[2] = "Off"; - choices[3] = "Red-eye reduction"; - choices[4] = "External"; - } -}; -FAFlashInterpreter faFlashInterpreter; - -class FAFocusModeInterpreter : public ChoiceInterpreter<> -{ -public: - FAFocusModeInterpreter () - { - choices[0] = "Auto"; - choices[1] = "Manual"; - } -}; -FAFocusModeInterpreter faFocusModeInterpreter; - -class FAColorModeInterpreter : public ChoiceInterpreter<> -{ -public: - FAColorModeInterpreter () - { - choices[0] = "Standard"; - choices[0x10] = "Chrome"; - choices[0x30] = "B & W"; - } -}; -FAColorModeInterpreter faColorModeInterpreter; - -class FADynamicRangeInterpreter : public ChoiceInterpreter<> -{ -public: - FADynamicRangeInterpreter () - { - choices[1] = "Standard"; - choices[3] = "Wide"; - } -}; -FADynamicRangeInterpreter faDynamicRangeInterpreter; - -class FAFilmModeInterpreter : public ChoiceInterpreter<> -{ -public: - FAFilmModeInterpreter () - { - choices[0x0] = "F0/Standard (Provia)"; - choices[0x100] = "F1/Studio Portrait"; - choices[0x110] = "F1a/Studio Portrait Enhanced Saturation"; - choices[0x120] = "F1b/Studio Portrait Smooth Skin Tone (Astia)"; - choices[0x130] = "F1c/Studio Portrait Increased Sharpness"; - choices[0x200] = "F2/Fujichrome (Velvia)"; - choices[0x300] = "F3/Studio Portrait Ex"; - choices[0x400] = "F4/Velvia"; - choices[0x500] = "Pro Neg. Std"; - choices[0x501] = "Pro Neg. Hi"; - choices[0x600] = "Classic Chrome"; - } -}; -FAFilmModeInterpreter faFilmModeInterpreter; - -class FADRSettingInterpreter : public ChoiceInterpreter<> -{ -public: - // DynamicRangeSetting - FADRSettingInterpreter () - { - choices[0x0] = "Auto (100-400%)"; - choices[0x1] = "Manual"; - choices[0x100] = "Standard (100%)"; - choices[0x200] = "Wide1 (230%)"; - choices[0x201] = "Wide2 (400%)"; - choices[0x8000] = "Film Simulation"; - } -}; -FADRSettingInterpreter faDRSettingInterpreter; - -class FAPictureModeInterpreter : public ChoiceInterpreter<> -{ -public: - FAPictureModeInterpreter () - { - choices[0x0] = "Auto"; - choices[0x1] = "Portrait"; - choices[0x2] = "Landscape"; - choices[0x3] = "Macro"; - choices[0x4] = "Sports"; - choices[0x5] = "Night Scene"; - choices[0x6] = "Program AE"; - choices[0x7] = "Natural Light"; - choices[0x8] = "Anti-blur"; - choices[0x9] = "Beach & Snow"; - choices[0xa] = "Sunset"; - choices[0xb] = "Museum"; - choices[0xc] = "Party"; - choices[0xd] = "Flower"; - choices[0xe] = "Text"; - choices[0xf] = "Natural Light & Flash"; - choices[0x10] = "Beach"; - choices[0x11] = "Snow"; - choices[0x12] = "Fireworks"; - choices[0x13] = "Underwater"; - choices[0x14] = "Portrait with Skin Correction"; - choices[0x16] = "Panorama"; - choices[0x17] = "Night (tripod)"; - choices[0x18] = "Pro Low-light"; - choices[0x19] = "Pro Focus"; - choices[0x1a] = "Portrait 2"; - choices[0x1b] = "Dog Face Detection"; - choices[0x1c] = "Cat Face Detection"; - choices[0x40] = "Advanced Filter"; - choices[0x100] = "Aperture-priority AE"; - choices[0x200] = "Shutter speed priority AE"; - choices[0x300] = "Manual"; - } -}; -FAPictureModeInterpreter faPictureModeInterpreter; - - - -const TagAttrib fujiAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "Version", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0010, AUTO, "InternalSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1000, AUTO, "Quality", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1001, AUTO, "Sharpness", &faSharpnessInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1002, AUTO, "WhiteBalance", &faWhiteBalanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1003, AUTO, "Saturation", &faSaturationInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1004, AUTO, "Contrast", &faContrastInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1005, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1006, AUTO, "Contrast2", &faContrast2Interpreter}, - {0, AC_WRITE, 0, nullptr, 0x100a, AUTO, "WhiteBalanceFineTune", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100b, AUTO, "NoiseReduction", &faNoiseReductionInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1010, AUTO, "FujiFlashMode", &faFlashInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1011, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1020, AUTO, "Macro", &faOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1021, AUTO, "FocusMode", &faFocusModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1023, AUTO, "FocusPixel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1030, AUTO, "SlowSync", &faOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1031, AUTO, "PictureMode", &faPictureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1100, AUTO, "AutoBracketing", &faOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1101, AUTO, "SequenceNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1210, AUTO, "ColorMode", &faColorModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1300, AUTO, "BlurWarning", &faOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1301, AUTO, "FocusWarning", &faOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1302, AUTO, "ExposureWarning", &faOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1400, AUTO, "DynamicRange", &faDynamicRangeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1401, AUTO, "FilmMode", &faFilmModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1402, AUTO, "DynamicRangeSetting", &faDRSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1403, AUTO, "DevelopmentDynamicRange", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1404, AUTO, "MinFocalLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1405, AUTO, "MaxFocalLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1406, AUTO, "MaxApertureAtMinFocal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1407, AUTO, "MaxApertureAtMaxFocal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x140b, AUTO, "AutoDynamicRange", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x4100, AUTO, "FacesDetected", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8000, AUTO, "FileSource", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8002, AUTO, "OrderNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8003, AUTO, "FrameNumber", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; -} -#endif - diff --git a/rtexif/kodakattribs.cc b/rtexif/kodakattribs.cc deleted file mode 100644 index a9c168a70..000000000 --- a/rtexif/kodakattribs.cc +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of RawTherapee. - */ -#ifndef _KODAKATTRIBS_ -#define _KODAKATTRIBS_ - -#include -#include "rtexif.h" - -namespace rtexif -{ - - -void parseKodakIfdTextualInfo (Tag *textualInfo, Tag* exif_) -{ - // parse TextualInfo and copy values into corresponding standard Exif - if (textualInfo->getType() != ASCII) { - return; - } - - TagDirectory *exif = exif_->getDirectory(); - char *value = (char *)textualInfo->getValue(); - - char *p = value; - char *pc, *plf; - - while ((pc = strchr (p, ':')) != nullptr && (plf = strchr (pc, '\n')) != nullptr) { - while (*p == ' ') { - p++; - } - - size_t len = pc - p; - - while (len > 1 && p[len - 1] == ' ') { - len--; - } - - std::string key = std::string (p, len); - ++pc; - - while (*pc == ' ') { - pc++; - } - - len = plf - pc; - - while (len > 1 && pc[len - 1] == ' ') { - len--; - } - - std::string val = std::string (pc, len); - p = ++plf; - - // we pick out a few select tags here - Tag *t; - - if (key == "Lens") { - // Proback645 may have "Lens" but not "Focal Length" - float flen = atof (val.c_str()); - - if (flen != 0.0) { - t = new Tag (exif, lookupAttrib (exifAttribs, "FocalLength")); - t->initRational (flen * 32, 32); - exif->replaceTag (t); - } - } else if (key == "Focal Length") { - float flen = atof (val.c_str()); - - if (flen != 0.0) { - t = new Tag (exif, lookupAttrib (exifAttribs, "FocalLength")); - t->initRational (flen * 32, 32); - exif->replaceTag (t); - } - } else if (key == "Aperture") { - float aperture = atof (&val.c_str()[1]); - - if (aperture != 0.0) { - t = new Tag (exif, lookupAttrib (exifAttribs, "FNumber")); - t->initRational ((int) (aperture * 10), 10); - exif->replaceTag (t); - } - } else if (key == "Exposure Bias" || key == "Compensation") { - float bias = 0.0; - - if (val != "Off") { - bias = atof (val.c_str()); - } - - t = new Tag (exif, lookupAttrib (exifAttribs, "ExposureBiasValue")); - t->initRational ((int) (bias * 1000), 1000); - exif->replaceTag (t); - } else if (key == "ISO Speed") { - t = new Tag (exif, lookupAttrib (exifAttribs, "ISOSpeedRatings")); - t->initInt (atoi (val.c_str()), SHORT); - exif->replaceTag (t); - } else if (key == "Shutter") { - const char *p1 = strchr (val.c_str(), '/'); - int a, b; - - if (p1 == nullptr) { - a = atoi (val.c_str()); - b = 1; - } else { - a = atoi (val.c_str()); - b = atoi (&p1[1]); - } - t = new Tag (exif, lookupAttrib (exifAttribs, "ExposureTime")); - t->initRational (a, b); - exif->replaceTag (t); - - const float ssv = -log2 ((float)a / std::max((float)b, 0.0001f)); // convert to APEX value, avoid division by zero - t = new Tag (exif, lookupAttrib (exifAttribs, "ShutterSpeedValue")); - t->initRational (1000000 * ssv, 1000000); - exif->replaceTag (t); - } else if (key == "Flash Fired") { - t = new Tag (exif, lookupAttrib (exifAttribs, "Flash")); - - if (val == "No") { - t->initInt (0, SHORT); - } else { - // not sure if "Flash Fired" is only yes/no, only seen "No" in test pictures - t->initInt (1, SHORT); - } - - exif->replaceTag (t); - } else if (key == "White balance") { // yes should be small 'b' int 'balance'. - t = new Tag (exif, lookupAttrib (exifAttribs, "Flash")); - t->initInt ((val == "Auto") ? 0 : 1, SHORT); - exif->replaceTag (t); - } - } -} - -// table not complete, not all proprietary Kodak tags are known -const TagAttrib kodakIfdAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "UnknownEV?", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "ExposureValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03e9, AUTO, "OriginalFileName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03eb, AUTO, "SensorLeftBorder", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03ec, AUTO, "SensorTopBorder", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03ed, AUTO, "SensorImageWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03ee, AUTO, "SensorImageHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03f1, AUTO, "TextualInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03fc, AUTO, "WhiteBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03fd, AUTO, "Processing", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0401, AUTO, "Time", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0414, AUTO, "NCDFileInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0846, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0852, AUTO, "WB_RGBMul0", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0853, AUTO, "WB_RGBMul1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0854, AUTO, "WB_RGBMul2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0855, AUTO, "WB_RGBMul3", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x085c, AUTO, "WB_RGBCoeffs0", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x085d, AUTO, "WB_RGBCoeffs1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x085e, AUTO, "WB_RGBCoeffs2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x085f, AUTO, "WB_RGBCoeffs3", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0ce5, AUTO, "FirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1391, AUTO, "ToneCurveFileName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1784, AUTO, "ISO", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr } -}; - -} -#endif - diff --git a/rtexif/nikonattribs.cc b/rtexif/nikonattribs.cc deleted file mode 100644 index b2066150d..000000000 --- a/rtexif/nikonattribs.cc +++ /dev/null @@ -1,1271 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _NIKONATTRIBS_ -#define _NIKONATTRIBS_ - -#include -#include -#include -#include -#include "rtexif.h" - -using namespace std; - -namespace rtexif -{ - -class NAISOInterpreter : public Interpreter -{ -public: - NAISOInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%d", t->toInt (2)); - return buffer; - } -}; -NAISOInterpreter naISOInterpreter; - -class NAISOInfoISOInterpreter : public Interpreter -{ -public: - NAISOInfoISOInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - int a = t->toInt(); - sprintf (buffer, "%d", a); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->getValue()[ofs]; - - if (a > 1) { - double i = pow (2., double (a) / 12. - 5.) * 100.; - return i; - } else { - return 0.; - } - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - int a = t->getValue()[ofs]; - - if (a > 1) { - int i = int (double (powf (2.f, float (a) / 12.f - 5.f)) * 100.f + 0.5f); - return i; - } else { - return 0; - } - } -}; -NAISOInfoISOInterpreter naISOInfoISOInterpreter; - -class NAISOExpansionInterpreter : public Interpreter -{ -public: - NAISOExpansionInterpreter () {} - std::string toString (const Tag* t) const override - { - int a = t->toInt(); - - // unclear if this interpretation is correct! - switch (a) { - case 0x0: - return "Off"; - - case 0x101: - return "Hi 0.3"; - - case 0x102: - return "Hi 0.5"; - - case 0x103: - return "Hi 0.7"; - - case 0x104: - return "Hi 1.0"; - - case 0x105: - return "Hi 1.3"; - - case 0x106: - return "Hi 1.5"; - - case 0x107: - return "Hi 1.7"; - - case 0x108: - return "Hi 2.0"; - - case 0x201: - return "Lo 0.3"; - - case 0x202: - return "Lo 0.5"; - - case 0x203: - return "Lo 0.7"; - - case 0x204: - return "Lo 1.0"; - - default: { - char buffer[32]; - sprintf (buffer, "0x%04X", a); - return buffer; - } - } - } -}; -NAISOExpansionInterpreter naISOExpansionInterpreter; - -class NALensTypeInterpreter : public Interpreter -{ -public: - NALensTypeInterpreter () {} - std::string toString (const Tag* t) const override - { - int a = t->toInt(); - std::ostringstream str; - str << "MF = " << ((a & 1) ? "Yes" : "No") << std::endl; - str << "D = " << ((a & 2) ? "Yes" : "No") << std::endl; - str << "G = " << ((a & 4) ? "Yes" : "No") << std::endl; - str << "VR = " << ((a & 8) ? "Yes" : "No"); - return str.str(); - } -}; -NALensTypeInterpreter naLensTypeInterpreter; - -class NAFlashModeInterpreter : public ChoiceInterpreter<> -{ -public: - NAFlashModeInterpreter () - { - choices[0x0] = "Did Not Fire"; - choices[0x1] = "Fired, Manual"; - choices[0x3] = "Not Ready"; - choices[0x7] = "Fired, External"; - choices[0x8] = "Fired, Commander Mode"; - choices[0x9] = "Fired, TTL Mode"; - } -}; -NAFlashModeInterpreter naFlashModeInterpreter; - -class NAHiISONRInterpreter : public ChoiceInterpreter<> -{ -public: - // HighISONoiseReduction - NAHiISONRInterpreter () - { - choices[0x0] = "Off"; - choices[0x1] = "Minimal"; - choices[0x2] = "Low"; - choices[0x3] = "Medium Low"; - choices[0x4] = "Normal"; - choices[0x5] = "Medium High"; - choices[0x6] = "High"; - } -}; -NAHiISONRInterpreter naHiISONRInterpreter; - -class NAShootingModeInterpreter : public Interpreter -{ -public: - NAShootingModeInterpreter () {} - std::string toString (const Tag* t) const override - { - int a = t->toInt(); - std::ostringstream str; - str << "Continuous = " << ((a & 1) ? "Yes" : "No") << std::endl; - str << "Delay = " << ((a & 2) ? "Yes" : "No") << std::endl; - str << "PC Control = " << ((a & 4) ? "Yes" : "No") << std::endl; - str << "White-Balance Bracketing = " << ((a & 8) ? "Yes" : "No") << std::endl; - str << "Exposure Bracketing = " << ((a & 16) ? "Yes" : "No") << std::endl; - str << "Auto ISO = " << ((a & 32) ? "Yes" : "No") << std::endl; - str << "IR Control = " << ((a & 64) ? "Yes" : "No"); - return str.str(); - } -}; -NAShootingModeInterpreter naShootingModeInterpreter; - -class NAAFInfoInterpreter : public Interpreter -{ - std::map amchoices; - std::map afpchoices; -public: - // AFAreaMode - NAAFInfoInterpreter () - { - amchoices[0x0] = "Single Area"; - amchoices[0x1] = "Dynamic Area"; - amchoices[0x2] = "Dynamic Area (closest subject)"; - amchoices[0x3] = "Group Dynamic"; - amchoices[0x4] = "Single Area (wide)"; - amchoices[0x5] = "Dynamic Area (wide)"; - // AFPoint - afpchoices[0x0] = "Center"; - afpchoices[0x1] = "Top"; - afpchoices[0x2] = "Bottom"; - afpchoices[0x3] = "Mid-left"; - afpchoices[0x4] = "Mid-right"; - afpchoices[0x5] = "Upper-left"; - afpchoices[0x6] = "Upper-right"; - afpchoices[0x7] = "Lower-left"; - afpchoices[0x8] = "Lower-right"; - afpchoices[0x9] = "Far Left"; - afpchoices[0xa] = "Far Right"; - } - std::string toString (const Tag* t) const override - { - const auto get_from_choices = - [](const std::map& choices, int index) -> std::string - { - const std::map::const_iterator choice = choices.find(index); - - if (choice != choices.end()) { - return choice->second; - } - - return {}; - }; - - int am = t->toInt (0, BYTE); - int afp = t->toInt (1, BYTE); - int aff = t->toInt (2, SHORT); - std::ostringstream str; - str << "AFAreaMode = " << get_from_choices(amchoices, am) << std::endl; - str << "AFAreaMode = " << get_from_choices(afpchoices, afp) << std::endl; - - std::ostringstream af; - - if (aff & 1) - if (af.str() == "") { - af << "Center"; - } else { - af << ", Center"; - } else if (aff & 2) - if (af.str() == "") { - af << "Top"; - } else { - af << ", Top"; - } else if (aff & 4) - if (af.str() == "") { - af << "Bottom"; - } else { - af << ", Bottom"; - } else if (aff & 8) - if (af.str() == "") { - af << "Left"; - } else { - af << ", Left"; - } else if (aff & 16) - if (af.str() == "") { - af << "Right"; - } else { - af << ", Right"; - } else if (aff & 32) - if (af.str() == "") { - af << "Upper-left"; - } else { - af << ", Upper-left"; - } else if (aff & 64) - if (af.str() == "") { - af << "Upper-right"; - } else { - af << ", Upper-right"; - } else if (aff & 128) - if (af.str() == "") { - af << " Lower-left"; - } else { - af << ", Lower-left"; - } else if (aff & 256) - if (af.str() == "") { - af << "Lower-right"; - } else { - af << ", Lower-right"; - } else if (aff & 512) - if (af.str() == "") { - af << "Far Left"; - } else { - af << ", Far Left"; - } else if (aff & 1024) { - if (af.str() == "") { - af << "Far Right"; - } else { - af << ", Far Right"; - } - } - - str << "AFPointsInFocus = " << af.str(); - return str.str(); - } -}; -NAAFInfoInterpreter naAFInfoInterpreter; - -class NALensDataInterpreter : public Interpreter -{ - static const std::map lenses; - -public: - std::string toString (const Tag* t) const override - { - - static const unsigned char xlat[2][256] = { - { - 0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f, 0xc7, 0x7f, 0x3d, 0x3d, - 0x53, 0x59, 0xe3, 0xc7, 0xe9, 0x2f, 0x95, 0xa7, 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, 0xc7, 0x0d, - 0xdf, 0x07, 0xef, 0x71, 0x89, 0x3d, 0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, 0xc1, 0x65, 0x1f, - 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b, 0x47, 0x7f, 0x95, 0x35, 0xa7, 0x47, 0x4f, - 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61, 0xf1, 0x3d, 0xb3, 0x2b, 0x0d, 0x43, 0x89, 0xc1, - 0x9d, 0x9d, 0x89, 0x65, 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, 0x53, 0x97, 0xe5, 0xe9, 0x95, 0x17, - 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, 0xf1, 0x71, 0xa7, 0x53, 0xb5, 0x29, 0x89, - 0xe5, 0x2b, 0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5, 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, - 0xb3, 0x43, 0x53, 0x65, 0x1d, 0x49, 0xa3, 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b, - 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, 0x29, 0x43, 0x2b, 0x07, 0x1d, 0x95, 0x59, 0x59, 0x47, 0xfb, - 0xe5, 0xe9, 0x61, 0x47, 0x2f, 0x35, 0x7f, 0x17, 0x7f, 0xef, 0x7f, 0x95, 0x95, 0x71, 0xd3, 0xa3, - 0x0b, 0x71, 0xa3, 0xad, 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad, 0xe9, 0x2f, - 0x71, 0x65, 0xa3, 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47, 0x3b, 0x9d, 0xef, 0x35, - 0xa3, 0xbf, 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53, 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, - 0x2f, 0x11, 0xdf, 0x17, 0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5, - 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07, 0x6b, 0x25, 0x49, 0x95, 0x25, 0x49, 0x6d, 0x71, 0xc7 - }, - { - 0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17, 0x46, 0x7c, 0x29, 0x4c, - 0x4d, 0x03, 0xe9, 0x25, 0x68, 0x11, 0x86, 0xb3, 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, 0x26, 0x34, - 0x2a, 0xbe, 0x1e, 0x46, 0x14, 0x68, 0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, 0x5f, 0x1b, 0xad, - 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95, 0x9c, 0x66, 0xdc, 0xe7, 0x5d, 0x6c, 0x05, - 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f, 0x82, 0x4c, 0xc0, 0x68, 0x47, 0xa1, 0xbd, 0xee, - 0x39, 0x50, 0x56, 0x4a, 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, 0xca, 0x90, 0xca, 0x01, 0x42, 0x9d, - 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, 0xb3, 0x80, 0x34, 0xe5, 0x2c, 0xdc, 0x9b, - 0x3f, 0xca, 0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5, 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, - 0x3e, 0xd0, 0x5b, 0xa8, 0x87, 0x8c, 0x06, 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc, - 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, 0x9b, 0x45, 0xf1, 0xf0, 0xa3, 0x94, 0x3a, 0x12, 0x77, 0x33, - 0x4d, 0x44, 0x78, 0x28, 0x3c, 0x9e, 0xfd, 0x65, 0x57, 0x16, 0x94, 0x6b, 0xfb, 0x59, 0xd0, 0xc8, - 0x22, 0x36, 0xdb, 0xd2, 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26, 0xbb, 0xd6, - 0x59, 0x4d, 0xbf, 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e, 0xe0, 0x2f, 0xdc, 0x7c, - 0xbe, 0x57, 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8, 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, - 0x3b, 0x2d, 0xeb, 0x25, 0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb, - 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65, 0x7e, 0xb0, 0xdf, 0xaf, 0x4e, 0xb3, 0x61, 0x7f, 0x2f - } - }; - - int ver = (t->toInt (0, BYTE) - '0') * 1000 + (t->toInt (1, BYTE) - '0') * 100 + (t->toInt (2, BYTE) - '0') * 10 + (t->toInt (3, BYTE) - '0'); - - std::ostringstream ld; - ld << "Version = " << ver << std::endl; - - int lenstype = t->getParent()->getTag (0x0083)->toInt (0, BYTE); - - std::ostringstream lid; - lid.setf (std::ios_base::hex, std::ios_base::basefield); - lid.setf (std::ios_base::uppercase); - - Tag *modelTag = t->getParent()->getRoot()->findTag ("Model"); - std::string model ( modelTag ? modelTag->valueToString() : ""); - int lidoffs = 7; - bool d100 = false; - - if (model.substr (0, 10) == "NIKON D100" || model.substr (0, 9) == "NIKON D1X") { - lidoffs = 0; - d100 = true; - } else if ( ver < 204) { - lidoffs = 7; - d100 = false; - } else { - lidoffs = 8; - d100 = false; - } - - unsigned char buffer[16]; - - if (d100) { - memcpy (buffer, t->getValue() + 6, 7); - } else { - memcpy (buffer, t->getValue() + 4, 16); - } - - if (ver >= 201) { - const unsigned char* serval = t->getParent()->getTag (0x001d)->getValue (); - int serial = 0; - - for (int i = 0; serval[i]; i++) { - serial = serial * 10 + (isdigit (serval[i]) ? serval[i] - '0' : serval[i] % 10); - } - - const unsigned char* scval = t->getParent()->getTag (0x00a7)->getValue (); - int key = 0; - - for (int i = 0; i < 4; i++) { - key ^= scval[i]; - } - - unsigned char ci = xlat[0][serial & 0xff]; - unsigned char cj = xlat[1][key]; - unsigned char ck = 0x60; - - for (int i = 0; i < 16; i++) { - buffer[i] ^= (cj += ci * ck++); - } - } - - std::string EffectiveMaxApertureString = ""; - - if (!d100) { - int EffectiveMaxApertureValue; - - if ( ver < 204 ) { - ld << "ExitPupilPosition = " << (int) buffer[0] << std::endl; - ld << "AFAperture = " << (int) buffer[1] << std::endl; - ld << "FocusPosition = " << (int) buffer[4] << std::endl; - ld << "FocusDistance = " << (int) buffer[5] << std::endl; - ld << "FocalLength = " << (int) buffer[6] << std::endl; - EffectiveMaxApertureValue = (int) buffer[14]; - } else { - ld << "ExitPupilPosition = " << (int) buffer[0] << std::endl; - ld << "AFAperture = " << (int) buffer[1] << std::endl; - ld << "FocusPosition = " << (int) buffer[4] << std::endl; - ld << "FocusDistance = " << (int) buffer[6] << std::endl; - ld << "FocalLength = " << (int) buffer[7] << std::endl; - EffectiveMaxApertureValue = (int) buffer[15]; - } - - switch (EffectiveMaxApertureValue) { - case 0x8: - EffectiveMaxApertureString = "1.2"; - break; - - case 0xc: - EffectiveMaxApertureString = "1.4"; - break; - - case 0x14: - EffectiveMaxApertureString = "1.8"; - break; - - case 0x18: - EffectiveMaxApertureString = "2.0"; - break; - - case 0x20: - EffectiveMaxApertureString = "2.5"; - break; - - case 0x24: - EffectiveMaxApertureString = "2.8"; - break; - - case 0x2a: - EffectiveMaxApertureString = "3.3"; - break; - - case 0x2c: - EffectiveMaxApertureString = "3.5"; - break; - - case 0x30: - EffectiveMaxApertureString = "4.0"; - break; - - case 0x34: - EffectiveMaxApertureString = "4.5"; - break; - - case 0x38: - EffectiveMaxApertureString = "5.0"; - break; - - case 0x3c: - EffectiveMaxApertureString = "5.6"; - break; - - case 0x40: - EffectiveMaxApertureString = "6.3"; - break; - - case 0x44: - EffectiveMaxApertureString = "7.1"; - break; - - case 0x48: - EffectiveMaxApertureString = "8.0"; - break; - - case 0x4e: - EffectiveMaxApertureString = "9.5"; - break; - - case 0x54: - EffectiveMaxApertureString = "11.0"; - break; - - case 0x5a: - EffectiveMaxApertureString = "13.0"; - break; - - case 0x5e: - EffectiveMaxApertureString = "15.0"; - break; - - case 0x60: - EffectiveMaxApertureString = "16.0"; - break; - - case 0x66: - EffectiveMaxApertureString = "19.0"; - break; - - case 0x6c: - EffectiveMaxApertureString = "22.0"; - break; - - default : - EffectiveMaxApertureString = ""; - } - - ld << "EffectiveMaxAperture = " << EffectiveMaxApertureString << std::endl; - } - - for (int i = 0; i < 7; i++) { - lid << std::setw (2) << std::setfill ('0') << (int)buffer[lidoffs + i] << ' '; - } - - lid << std::setw (2) << std::setfill ('0') << lenstype; - - std::map::const_iterator r = lenses.find (lid.str()); - - if (r != lenses.end()) { - if (r == lenses.begin() && EffectiveMaxApertureString != "") { // first entry is for unchipped lenses - Tag *FLTag = t->getParent()->getRoot()->findTag ("FocalLength"); - ld << "Lens = MF "; - - if(FLTag) { - ld << FLTag->valueToString () << "mm"; - } else { - ld << "0mm"; - } - - ld << " f/" << EffectiveMaxApertureString; - } else { - ld << "Lens = " << r->second; - } - } else { - ld << "Lens = Unknown, ID=" << lid.str(); - } - - return ld.str(); - } - -}; -NALensDataInterpreter naLensDataInterpreter; -const std::map NALensDataInterpreter::lenses = { - /* - * The Nikon LensID is constructed as a Composite tag from the raw hex values of 8 other tags: - * LensIDNumber, LensFStops, MinFocalLength, MaxFocalLength, MaxApertureAtMinFocal, MaxApertureAtMaxFocal, MCUVersion and LensType, in that order. - */ - {"00 00 00 00 00 00 00 01", "Manual Lens No CPU"}, - {"00 00 00 00 00 00 E1 12", "TC-17E II"}, - {"00 00 00 00 00 00 F1 0C", "TC-14E [II] or Sigma APO Tele Converter 1.4x EX DG or Kenko Teleplus PRO 300 DG 1.4x"}, - {"00 00 00 00 00 00 F2 18", "TC-20E [II] or Sigma APO Tele Converter 2x EX DG or Kenko Teleplus PRO 300 DG 2.0x"}, - {"00 00 48 48 53 53 00 01", "Loreo 40mm f/11-22 3D Lens in a Cap 9005"}, - {"00 36 1C 2D 34 3C 00 06", "Tamron SP AF 11-18mm f/4.5-5.6 Di II LD Aspherical (IF) (A13)"}, - {"00 3C 1F 37 30 30 00 06", "Tokina AT-X 124 AF PRO DX (AF 12-24mm f/4)"}, - {"00 3C 2B 44 30 30 00 06", "Tokina AT-X 17-35 f/4 PRO FX (AF 17-35mm f/4)"}, - {"00 3C 5C 80 30 30 00 0E", "Tokina AT-X 70-200 f/4 FX VCM-S (AF 70-200mm f/4)"}, - {"00 3E 80 A0 38 3F 00 02", "Tamron SP AF 200-500mm f/5-6.3 Di LD (IF) (A08)"}, - {"00 3F 2D 80 2B 40 00 06", "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) (A14)"}, - {"00 3F 2D 80 2C 40 00 06", "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro (A14)"}, - {"00 3F 80 A0 38 3F 00 02", "Tamron SP AF 200-500mm f/5-6.3 Di (A08)"}, - {"00 40 11 11 2C 2C 00 00", "Samyang 8mm f/3.5 Fish-Eye"}, - {"00 40 18 2B 2C 34 00 06", "Tokina AT-X 107 AF DX Fisheye (AF 10-17mm f/3.5-4.5)"}, - {"00 40 2A 72 2C 3C 00 06", "Tokina AT-X 16.5-135 DX (AF 16.5-135mm f/3.5-5.6)"}, - {"00 40 2B 2B 2C 2C 00 02", "Tokina AT-X 17 AF PRO (AF 17mm f/3.5)"}, - {"00 40 2D 2D 2C 2C 00 00", "Carl Zeiss Distagon T* 3.5/18 ZF.2"}, - {"00 40 2D 80 2C 40 00 06", "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro (A14NII)"}, - {"00 40 2D 88 2C 40 00 06", "Tamron AF 18-250mm f/3.5-6.3 Di II LD Aspherical (IF) Macro (A18NII)"}, - {"00 40 2D 88 2C 40 62 06", "Tamron AF 18-250mm f/3.5-6.3 Di II LD Aspherical (IF) Macro (A18)"}, - {"00 40 31 31 2C 2C 00 00", "Voigtlander Color Skopar 20mm f/3.5 SLII Aspherical"}, - {"00 40 37 80 2C 3C 00 02", "Tokina AT-X 242 AF (AF 24-200mm f/3.5-5.6)"}, - {"00 40 64 64 2C 2C 00 00", "Voigtlander APO-Lanthar 90mm f/3.5 SLII Close Focus"}, - {"00 44 60 98 34 3C 00 02", "Tokina AT-X 840 D (AF 80-400mm f/4.5-5.6)"}, - {"00 47 10 10 24 24 00 00", "Fisheye Nikkor 8mm f/2.8 AiS"}, - {"00 47 25 25 24 24 00 02", "Tamron SP AF 14mm f/2.8 Aspherical (IF) (69E)"}, - {"00 47 3C 3C 24 24 00 00", "Nikkor 28mm f/2.8 AiS"}, - {"00 47 44 44 24 24 00 06", "Tokina AT-X M35 PRO DX (AF 35mm f/2.8 Macro)"}, - {"00 47 53 80 30 3C 00 06", "Tamron AF 55-200mm f/4-5.6 Di II LD (A15)"}, - {"00 48 1C 29 24 24 00 06", "Tokina AT-X 116 PRO DX (AF 11-16mm f/2.8)"}, - {"00 48 29 3C 24 24 00 06", "Tokina AT-X 16-28 AF PRO FX (AF 16-28mm f/2.8)"}, - {"00 48 29 50 24 24 00 06", "Tokina AT-X 165 PRO DX (AF 16-50mm f/2.8)"}, - {"00 48 32 32 24 24 00 00", "Carl Zeiss Distagon T* 2.8/21 ZF.2"}, - {"00 48 37 5C 24 24 00 06", "Tokina AT-X 24-70 f/2.8 PRO FX (AF 24-70mm f/2.8)"}, - {"00 48 3C 3C 24 24 00 00", "Voigtlander Color Skopar 28mm f/2.8 SL II"}, - {"00 48 3C 60 24 24 00 02", "Tokina AT-X 280 AF PRO (AF 28-80mm f/2.8)"}, - {"00 48 3C 6A 24 24 00 02", "Tamron SP AF 28-105mm f/2.8 LD Aspherical IF (176D)"}, - {"00 48 50 50 18 18 00 00", "Nikkor H 50mm f/2"}, - {"00 48 50 72 24 24 00 06", "Tokina AT-X 535 PRO DX (AF 50-135mm f/2.8)"}, - {"00 48 5C 80 30 30 00 0E", "Tokina AT-X 70-200 f/4 FX VCM-S (AF 70-200mm f/4)"}, - {"00 48 5C 8E 30 3C 00 06", "Tamron AF 70-300mm f/4-5.6 Di LD Macro 1:2 (A17NII)"}, - {"00 48 68 68 24 24 00 00", "Series E 100mm f/2.8"}, - {"00 48 80 80 30 30 00 00", "Nikkor 200mm f/4 AiS"}, - {"00 49 30 48 22 2B 00 02", "Tamron SP AF 20-40mm f/2.7-3.5 (166D)"}, - {"00 4C 6A 6A 20 20 00 00", "Nikkor 105mm f/2.5 AiS"}, - {"00 4C 7C 7C 2C 2C 00 02", "Tamron SP AF 180mm f/3.5 Di Model (B01)"}, - {"00 53 2B 50 24 24 00 06", "Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16)"}, - {"00 54 2B 50 24 24 00 06", "Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16NII)"}, - {"00 54 38 38 18 18 00 00", "Carl Zeiss Distagon T* 2/25 ZF.2"}, - {"00 54 3C 3C 18 18 00 00", "Carl Zeiss Distagon T* 2/28 ZF.2"}, - {"00 54 44 44 0C 0C 00 00", "Carl Zeiss Distagon T* 1.4/35 ZF.2"}, - {"00 54 44 44 18 18 00 00", "Carl Zeiss Distagon T* 2/35 ZF.2"}, - {"00 54 48 48 18 18 00 00", "Voigtlander Ultron 40mm f/2 SLII Aspherical"}, - {"00 54 50 50 0C 0C 00 00", "Carl Zeiss Planar T* 1.4/50 ZF.2"}, - {"00 54 50 50 18 18 00 00", "Carl Zeiss Makro-Planar T* 2/50 ZF.2"}, - {"00 54 53 53 0C 0C 00 00", "Zeiss Otus 1.4/55"}, - {"00 54 55 55 0C 0C 00 00", "Voigtlander Nokton 58mm f/1.4 SLII"}, - {"00 54 56 56 30 30 00 00", "Coastal Optical Systems 60mm 1:4 UV-VIS-IR Macro Apo"}, - {"00 54 62 62 0C 0C 00 00", "Carl Zeiss Planar T* 1.4/85 ZF.2"}, - {"00 54 68 68 18 18 00 00", "Carl Zeiss Makro-Planar T* 2/100 ZF.2"}, - {"00 54 68 68 24 24 00 02", "Tokina AT-X M100 AF PRO D (AF 100mm f/2.8 Macro)"}, - {"00 54 72 72 18 18 00 00", "Carl Zeiss Apo Sonnar T* 2/135 ZF.2"}, - {"00 54 8E 8E 24 24 00 02", "Tokina AT-X 300 AF PRO (AF 300mm f/2.8)"}, - {"00 57 50 50 14 14 00 00", "Nikkor 50mm f/1.8 AI"}, - {"00 58 64 64 20 20 00 00", "Soligor C/D Macro MC 90mm f/2.5"}, - {"01 00 00 00 00 00 02 00", "TC-16A"}, - {"01 00 00 00 00 00 08 00", "TC-16A"}, - {"01 54 62 62 0C 0C 00 00", "Zeiss Otus 1.4/85"}, - {"01 58 50 50 14 14 02 00", "AF Nikkor 50mm f/1.8"}, - {"01 58 50 50 14 14 05 00", "AF Nikkor 50mm f/1.8"}, - {"02 2F 98 98 3D 3D 02 00", "Sigma APO 400mm f/5.6"}, - {"02 34 A0 A0 44 44 02 00", "Sigma APO 500mm f/7.2"}, - {"02 37 5E 8E 35 3D 02 00", "Sigma 75-300mm f/4.5-5.6 APO"}, - {"02 37 A0 A0 34 34 02 00", "Sigma APO 500mm f/4.5"}, - {"02 3A 37 50 31 3D 02 00", "Sigma 24-50mm f/4-5.6 UC"}, - {"02 3A 5E 8E 32 3D 02 00", "Sigma 75-300mm f/4.0-5.6"}, - {"02 3B 44 61 30 3D 02 00", "Sigma 35-80mm f/4-5.6"}, - {"02 3C B0 B0 3C 3C 02 00", "Sigma APO 800mm f/5.6"}, - {"02 3F 24 24 2C 2C 02 00", "Sigma 14mm f/3.5"}, - {"02 3F 3C 5C 2D 35 02 00", "Sigma 28-70mm f/3.5-4.5 UC"}, - {"02 40 44 5C 2C 34 02 00", "Exakta AF 35-70mm 1:3.5-4.5 MC"}, - {"02 40 44 73 2B 36 02 00", "Sigma 35-135mm f/3.5-4.5 a"}, - {"02 40 5C 82 2C 35 02 00", "Sigma APO 70-210mm f/3.5-4.5"}, - {"02 42 44 5C 2A 34 02 00", "AF Zoom-Nikkor 35-70mm f/3.3-4.5"}, - {"02 42 44 5C 2A 34 08 00", "AF Zoom-Nikkor 35-70mm f/3.3-4.5"}, - {"02 46 37 37 25 25 02 00", "Sigma 24mm f/2.8 Super Wide II Macro"}, - {"02 46 3C 5C 25 25 02 00", "Sigma 28-70mm f/2.8"}, - {"02 46 5C 82 25 25 02 00", "Sigma 70-210mm f/2.8 APO"}, - {"02 48 50 50 24 24 02 00", "Sigma Macro 50mm f/2.8"}, - {"02 48 65 65 24 24 02 00", "Sigma Macro 90mm f/2.8"}, - {"03 43 5C 81 35 35 02 00", "Soligor AF C/D Zoom UMCS 70-210mm 1:4.5"}, - {"03 48 5C 81 30 30 02 00", "AF Zoom-Nikkor 70-210mm f/4"}, - {"04 48 3C 3C 24 24 03 00", "AF Nikkor 28mm f/2.8"}, - {"05 54 50 50 0C 0C 04 00", "AF Nikkor 50mm f/1.4"}, - {"06 3F 68 68 2C 2C 06 00", "Cosina AF 100mm f/3.5 Macro"}, - {"06 54 53 53 24 24 06 00", "AF Micro-Nikkor 55mm f/2.8"}, - {"07 36 3D 5F 2C 3C 03 00", "Cosina AF Zoom 28-80mm f/3.5-5.6 MC Macro"}, - {"07 3E 30 43 2D 35 03 00", "Soligor AF Zoom 19-35mm 1:3.5-4.5 MC"}, - {"07 40 2F 44 2C 34 03 02", "Tamron AF 19-35mm f/3.5-4.5 (A10)"}, - {"07 40 30 45 2D 35 03 02", "Tamron AF 19-35mm f/3.5-4.5 (A10)"}, - {"07 40 3C 5C 2C 35 03 00", "Tokina AF 270 II (AF 28-70mm f/3.5-4.5)"}, - {"07 40 3C 62 2C 34 03 00", "AF Zoom-Nikkor 28-85mm f/3.5-4.5"}, - {"07 46 2B 44 24 30 03 02", "Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical (IF) (A05)"}, - {"07 46 3D 6A 25 2F 03 00", "Cosina AF Zoom 28-105mm f/2.8-3.8 MC"}, - {"07 47 3C 5C 25 35 03 00", "Tokina AF 287 SD (AF 28-70mm f/2.8-4.5)"}, - {"07 48 3C 5C 24 24 03 00", "Tokina AT-X 287 AF (AF 28-70mm f/2.8)"}, - {"08 40 44 6A 2C 34 04 00", "AF Zoom-Nikkor 35-105mm f/3.5-4.5"}, - {"09 48 37 37 24 24 04 00", "AF Nikkor 24mm f/2.8"}, - {"0A 48 8E 8E 24 24 03 00", "AF Nikkor 300mm f/2.8 IF-ED"}, - {"0A 48 8E 8E 24 24 05 00", "AF Nikkor 300mm f/2.8 IF-ED N"}, - {"0B 3E 3D 7F 2F 3D 0E 00", "Tamron AF 28-200mm f/3.8-5.6 (71D)"}, - {"0B 3E 3D 7F 2F 3D 0E 02", "Tamron AF 28-200mm f/3.8-5.6D (171D)"}, - {"0B 48 7C 7C 24 24 05 00", "AF Nikkor 180mm f/2.8 IF-ED"}, - {"0D 40 44 72 2C 34 07 00", "AF Zoom-Nikkor 35-135mm f/3.5-4.5"}, - {"0E 48 5C 81 30 30 05 00", "AF Zoom-Nikkor 70-210mm f/4"}, - {"0E 4A 31 48 23 2D 0E 02", "Tamron SP AF 20-40mm f/2.7-3.5 (166D)"}, - {"0F 58 50 50 14 14 05 00", "AF Nikkor 50mm f/1.8 N"}, - {"10 3D 3C 60 2C 3C D2 02", "Tamron AF 28-80mm f/3.5-5.6 Aspherical (177D)"}, - {"10 48 8E 8E 30 30 08 00", "AF Nikkor 300mm f/4 IF-ED"}, - {"11 48 44 5C 24 24 08 00", "AF Zoom-Nikkor 35-70mm f/2.8"}, - {"11 48 44 5C 24 24 15 00", "AF Zoom-Nikkor 35-70mm f/2.8"}, - {"12 36 5C 81 35 3D 09 00", "Cosina AF Zoom 70-210mm f/4.5-5.6 MC Macro"}, - {"12 36 69 97 35 42 09 00", "Soligor AF Zoom 100-400mm 1:4.5-6.7 MC"}, - {"12 38 69 97 35 42 09 02", "Promaster Spectrum 7 100-400mm f/4.5-6.7"}, - {"12 39 5C 8E 34 3D 08 02", "Cosina AF Zoom 70-300mm f/4.5-5.6 MC Macro"}, - {"12 3B 68 8D 3D 43 09 02", "Cosina AF Zoom 100-300mm f/5.6-6.7 MC Macro"}, - {"12 3B 98 98 3D 3D 09 00", "Tokina AT-X 400 AF SD (AF 400mm f/5.6)"}, - {"12 3D 3C 80 2E 3C DF 02", "Tamron AF 28-200mm f/3.8-5.6 AF Aspherical LD (IF) (271D)"}, - {"12 44 5E 8E 34 3C 09 00", "Tokina AF 730 (AF 75-300mm f/4.5-5.6)"}, - {"12 48 5C 81 30 3C 09 00", "AF Nikkor 70-210mm f/4-5.6"}, - {"12 4A 5C 81 31 3D 09 00", "Soligor AF C/D Auto Zoom+Macro 70-210mm 1:4-5.6 UMCS"}, - {"13 42 37 50 2A 34 0B 00", "AF Zoom-Nikkor 24-50mm f/3.3-4.5"}, - {"14 48 60 80 24 24 0B 00", "AF Zoom-Nikkor 80-200mm f/2.8 ED"}, - {"14 48 68 8E 30 30 0B 00", "Tokina AT-X 340 AF (AF 100-300mm f/4)"}, - {"14 54 60 80 24 24 0B 00", "Tokina AT-X 828 AF (AF 80-200mm f/2.8)"}, - {"15 4C 62 62 14 14 0C 00", "AF Nikkor 85mm f/1.8"}, - {"17 3C A0 A0 30 30 0F 00", "Nikkor 500mm f/4 P ED IF"}, - {"17 3C A0 A0 30 30 11 00", "Nikkor 500mm f/4 P ED IF"}, - {"18 40 44 72 2C 34 0E 00", "AF Zoom-Nikkor 35-135mm f/3.5-4.5 N"}, - {"1A 54 44 44 18 18 11 00", "AF Nikkor 35mm f/2"}, - {"1B 44 5E 8E 34 3C 10 00", "AF Zoom-Nikkor 75-300mm f/4.5-5.6"}, - {"1C 48 30 30 24 24 12 00", "AF Nikkor 20mm f/2.8"}, - {"1D 42 44 5C 2A 34 12 00", "AF Zoom-Nikkor 35-70mm f/3.3-4.5 N"}, - {"1E 54 56 56 24 24 13 00", "AF Micro-Nikkor 60mm f/2.8"}, - {"1E 5D 64 64 20 20 13 00", "Tamron SP AF 90mm f/2.5 (52E)"}, - {"1F 54 6A 6A 24 24 14 00", "AF Micro-Nikkor 105mm f/2.8"}, - {"20 3C 80 98 3D 3D 1E 02", "Tamron AF 200-400mm f/5.6 LD IF (75D)"}, - {"20 48 60 80 24 24 15 00", "AF Zoom-Nikkor 80-200mm f/2.8 ED"}, - {"20 5A 64 64 20 20 14 00", "Tamron SP AF 90mm f/2.5 Macro (152E)"}, - {"21 40 3C 5C 2C 34 16 00", "AF Zoom-Nikkor 28-70mm f/3.5-4.5"}, - {"21 56 8E 8E 24 24 14 00", "Tamron SP AF 300mm f/2.8 LD-IF (60E)"}, - {"22 48 72 72 18 18 16 00", "AF DC-Nikkor 135mm f/2"}, - {"22 53 64 64 24 24 E0 02", "Tamron SP AF 90mm f/2.8 Macro 1:1 (72E)"}, - {"23 30 BE CA 3C 48 17 00", "Zoom-Nikkor 1200-1700mm f/5.6-8 P ED IF"}, - {"24 44 60 98 34 3C 1A 02", "Tokina AT-X 840 AF-II (AF 80-400mm f/4.5-5.6)"}, - {"24 48 60 80 24 24 1A 02", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, - {"24 54 60 80 24 24 1A 02", "Tokina AT-X 828 AF PRO (AF 80-200mm f/2.8)"}, - {"25 44 44 8E 34 42 1B 02", "Tokina AF 353 (AF 35-300mm f/4.5-6.7)"}, - {"25 48 3C 5C 24 24 1B 02", "Tokina AT-X 270 AF PRO II (AF 28-70mm f/2.6-2.8)"}, - {"25 48 3C 5C 24 24 1B 02", "Tokina AT-X 287 AF PRO SV (AF 28-70mm f/2.8)"}, - {"25 48 44 5C 24 24 1B 02", "AF Zoom-Nikkor 35-70mm f/2.8D"}, - {"25 48 44 5C 24 24 3A 02", "AF Zoom-Nikkor 35-70mm f/2.8D"}, - {"25 48 44 5C 24 24 52 02", "AF Zoom-Nikkor 35-70mm f/2.8D"}, - {"26 3C 54 80 30 3C 1C 06", "Sigma 55-200mm f/4-5.6 DC"}, - {"26 3C 5C 82 30 3C 1C 02", "Sigma 70-210mm f/4-5.6 UC-II"}, - {"26 3C 5C 8E 30 3C 1C 02", "Sigma 70-300mm f/4-5.6 DG Macro"}, - {"26 3C 98 98 3C 3C 1C 02", "Sigma APO Tele Macro 400mm f/5.6"}, - {"26 3D 3C 80 2F 3D 1C 02", "Sigma 28-300mm f/3.8-5.6 Aspherical"}, - {"26 3E 3C 6A 2E 3C 1C 02", "Sigma 28-105mm f/3.8-5.6 UC-III Aspherical IF"}, - {"26 40 27 3F 2C 34 1C 02", "Sigma 15-30mm f/3.5-4.5 EX DG Aspherical DF"}, - {"26 40 2D 44 2B 34 1C 02", "Sigma 18-35mm f/3.5-4.5 Aspherical"}, - {"26 40 2D 50 2C 3C 1C 06", "Sigma 18-50mm f/3.5-5.6 DC"}, - {"26 40 2D 70 2B 3C 1C 06", "Sigma 18-125mm f/3.5-5.6 DC"}, - {"26 40 2D 80 2C 40 1C 06", "Sigma 18-200mm f/3.5-6.3 DC"}, - {"26 40 37 5C 2C 3C 1C 02", "Sigma 24-70mm f/3.5-5.6 Aspherical HF"}, - {"26 40 3C 5C 2C 34 1C 02", "AF Zoom-Nikkor 28-70mm f/3.5-4.5D"}, - {"26 40 3C 60 2C 3C 1C 02", "Sigma 28-80mm f/3.5-5.6 Mini Zoom Macro II Aspherical"}, - {"26 40 3C 65 2C 3C 1C 02", "Sigma 28-90mm f/3.5-5.6 Macro"}, - {"26 40 3C 80 2B 3C 1C 02", "Sigma 28-200mm f/3.5-5.6 Compact Aspherical Hyperzoom Macro"}, - {"26 40 3C 80 2C 3C 1C 02", "Sigma 28-200mm f/3.5-5.6 Compact Aspherical Hyperzoom Macro"}, - {"26 40 3C 8E 2C 40 1C 02", "Sigma 28-300mm f/3.5-6.3 Macro"}, - {"26 40 7B A0 34 40 1C 02", "Sigma APO 170-500mm f/5-6.3 Aspherical RF"}, - {"26 41 3C 8E 2C 40 1C 02", "Sigma 28-300mm f/3.5-6.3 DG Macro"}, - {"26 44 73 98 34 3C 1C 02", "Sigma 135-400mm f/4.5-5.6 APO Aspherical"}, - {"26 48 11 11 30 30 1C 02", "Sigma 8mm f/4 EX Circular Fisheye"}, - {"26 48 27 27 24 24 1C 02", "Sigma 15mm f/2.8 EX Diagonal Fisheye"}, - {"26 48 2D 50 24 24 1C 06", "Sigma 18-50mm f/2.8 EX DC"}, - {"26 48 31 49 24 24 1C 02", "Sigma 20-40mm f/2.8"}, - {"26 48 37 56 24 24 1C 02", "Sigma 24-60mm f/2.8 EX DG"}, - {"26 48 3C 5C 24 24 1C 06", "Sigma 28-70mm f/2.8 EX DG"}, - {"26 48 3C 5C 24 30 1C 02", "Sigma 28-70mm f/2.8-4 DG"}, - {"26 48 3C 6A 24 30 1C 02", "Sigma 28-105mm f/2.8-4 Aspherical"}, - {"26 48 8E 8E 30 30 1C 02", "Sigma APO Tele Macro 300mm f/4"}, - {"26 54 2B 44 24 30 1C 02", "Sigma 17-35mm f/2.8-4 EX Aspherical"}, - {"26 54 37 5C 24 24 1C 02", "Sigma 24-70mm f/2.8 EX DG Macro"}, - {"26 54 37 73 24 34 1C 02", "Sigma 24-135mm f/2.8-4.5"}, - {"26 54 3C 5C 24 24 1C 02", "Sigma 28-70mm f/2.8 EX"}, - {"26 58 31 31 14 14 1C 02", "Sigma 20mm f/1.8 EX DG Aspherical RF"}, - {"26 58 37 37 14 14 1C 02", "Sigma 24mm f/1.8 EX DG Aspherical Macro"}, - {"26 58 3C 3C 14 14 1C 02", "Sigma 28mm f/1.8 EX DG Aspherical Macro"}, - {"27 48 8E 8E 24 24 1D 02", "AF-I Nikkor 300mm f/2.8D IF-ED"}, - {"27 48 8E 8E 24 24 E1 02", "AF-I Nikkor 300mm f/2.8D IF-ED + TC-17E"}, - {"27 48 8E 8E 24 24 F1 02", "AF-I Nikkor 300mm f/2.8D IF-ED + TC-14E"}, - {"27 48 8E 8E 24 24 F2 02", "AF-I Nikkor 300mm f/2.8D IF-ED + TC-20E"}, - {"27 48 8E 8E 30 30 1D 02", "Tokina AT-X 304 AF (AF 300mm f/4.0)"}, - {"27 54 8E 8E 24 24 1D 02", "Tamron SP AF 300mm f/2.8 LD-IF (360E)"}, - {"28 3C A6 A6 30 30 1D 02", "AF-I Nikkor 600mm f/4D IF-ED"}, - {"28 3C A6 A6 30 30 E1 02", "AF-I Nikkor 600mm f/4D IF-ED + TC-17E"}, - {"28 3C A6 A6 30 30 F1 02", "AF-I Nikkor 600mm f/4D IF-ED + TC-14E"}, - {"28 3C A6 A6 30 30 F2 02", "AF-I Nikkor 600mm f/4D IF-ED + TC-20E"}, - {"2A 54 3C 3C 0C 0C 26 02", "AF Nikkor 28mm f/1.4D"}, - {"2B 3C 44 60 30 3C 1F 02", "AF Zoom-Nikkor 35-80mm f/4-5.6D"}, - {"2C 48 6A 6A 18 18 27 02", "AF DC-Nikkor 105mm f/2D"}, - {"2D 48 80 80 30 30 21 02", "AF Micro-Nikkor 200mm f/4D IF-ED"}, - {"2E 48 5C 82 30 3C 22 02", "AF Nikkor 70-210mm f/4-5.6D"}, - {"2E 48 5C 82 30 3C 28 02", "AF Nikkor 70-210mm f/4-5.6D"}, - {"2F 40 30 44 2C 34 29 02", "Tokina AF 235 II (AF 20-35mm f/3.5-4.5)"}, - {"2F 40 30 44 2C 34 29 02", "Tokina AF 193 (AF 19-35mm f/3.5-4.5)"}, - {"2F 48 30 44 24 24 29 02", "AF Zoom-Nikkor 20-35mm f/2.8D IF"}, - {"2F 48 30 44 24 24 29 02", "Tokina AT-X 235 AF PRO (AF 20-35mm f/2.8)"}, - {"30 48 98 98 24 24 24 02", "AF-I Nikkor 400mm f/2.8D IF-ED"}, - {"30 48 98 98 24 24 E1 02", "AF-I Nikkor 400mm f/2.8D IF-ED + TC-17E"}, - {"30 48 98 98 24 24 F1 02", "AF-I Nikkor 400mm f/2.8D IF-ED + TC-14E"}, - {"30 48 98 98 24 24 F2 02", "AF-I Nikkor 400mm f/2.8D IF-ED + TC-20E"}, - {"31 54 56 56 24 24 25 02", "AF Micro-Nikkor 60mm f/2.8D"}, - {"32 53 64 64 24 24 35 02", "Tamron SP AF 90mm f/2.8 [Di] Macro 1:1 (172E/272E)"}, - {"32 54 50 50 24 24 35 02", "Sigma Macro 50mm f/2.8 EX DG"}, - {"32 54 6A 6A 24 24 35 02", "AF Micro-Nikkor 105mm f/2.8D"}, - {"32 54 6A 6A 24 24 35 02", "Sigma Macro 105mm f/2.8 EX DG"}, - {"33 48 2D 2D 24 24 31 02", "AF Nikkor 18mm f/2.8D"}, - {"33 54 3C 5E 24 24 62 02", "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical (IF) Macro (A09)"}, - {"34 48 29 29 24 24 32 02", "AF Fisheye Nikkor 16mm f/2.8D"}, - {"35 3C A0 A0 30 30 33 02", "AF-I Nikkor 500mm f/4D IF-ED"}, - {"35 3C A0 A0 30 30 E1 02", "AF-I Nikkor 500mm f/4D IF-ED + TC-17E"}, - {"35 3C A0 A0 30 30 F1 02", "AF-I Nikkor 500mm f/4D IF-ED + TC-14E"}, - {"35 3C A0 A0 30 30 F2 02", "AF-I Nikkor 500mm f/4D IF-ED + TC-20E"}, - {"36 48 37 37 24 24 34 02", "AF Nikkor 24mm f/2.8D"}, - {"37 48 30 30 24 24 36 02", "AF Nikkor 20mm f/2.8D"}, - {"38 4C 62 62 14 14 37 02", "AF Nikkor 85mm f/1.8D"}, - {"3A 40 3C 5C 2C 34 39 02", "AF Zoom-Nikkor 28-70mm f/3.5-4.5D"}, - {"3B 48 44 5C 24 24 3A 02", "AF Zoom-Nikkor 35-70mm f/2.8D N"}, - {"3C 48 60 80 24 24 3B 02", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, - {"3D 3C 44 60 30 3C 3E 02", "AF Zoom-Nikkor 35-80mm f/4-5.6D"}, - {"3E 48 3C 3C 24 24 3D 02", "AF Nikkor 28mm f/2.8D"}, - {"3F 40 44 6A 2C 34 45 02", "AF Zoom-Nikkor 35-105mm f/3.5-4.5D"}, - {"41 48 7C 7C 24 24 43 02", "AF Nikkor 180mm f/2.8D IF-ED"}, - {"42 54 44 44 18 18 44 02", "AF Nikkor 35mm f/2D"}, - {"43 54 50 50 0C 0C 46 02", "AF Nikkor 50mm f/1.4D"}, - {"44 44 60 80 34 3C 47 02", "AF Zoom-Nikkor 80-200mm f/4.5-5.6D"}, - {"45 3D 3C 60 2C 3C 48 02", "Tamron AF 28-80mm f/3.5-5.6 Aspherical (177D)"}, - {"45 40 3C 60 2C 3C 48 02", "AF Zoom-Nikkor 28-80mm f/3.5-5.6D"}, - {"45 41 37 72 2C 3C 48 02", "Tamron SP AF 24-135mm f/3.5-5.6 AD Aspherical (IF) Macro (190D)"}, - {"46 3C 44 60 30 3C 49 02", "AF Zoom-Nikkor 35-80mm f/4-5.6D N"}, - {"47 42 37 50 2A 34 4A 02", "AF Zoom-Nikkor 24-50mm f/3.3-4.5D"}, - {"48 38 1F 37 34 3C 4B 06", "Sigma 12-24mm f/4.5-5.6 EX DG Aspherical HSM"}, - {"48 3C 19 31 30 3C 4B 06", "Sigma 10-20mm f/4-5.6 EX DC HSM"}, - {"48 3C 50 A0 30 40 4B 02", "Sigma 50-500mm f/4-6.3 EX APO RF HSM"}, - {"48 3C 8E B0 3C 3C 4B 02", "Sigma APO 300-800mm f/5.6 EX DG HSM"}, - {"48 3C B0 B0 3C 3C 4B 02", "Sigma APO 800mm f/5.6 EX HSM"}, - {"48 44 A0 A0 34 34 4B 02", "Sigma APO 500mm f/4.5 EX HSM"}, - {"48 48 24 24 24 24 4B 02", "Sigma 14mm f/2.8 EX Aspherical HSM"}, - {"48 48 2B 44 24 30 4B 06", "Sigma 17-35mm f/2.8-4 EX DG Aspherical HSM"}, - {"48 48 68 8E 30 30 4B 02", "Sigma APO 100-300mm f/4 EX IF HSM"}, - {"48 48 76 76 24 24 4B 06", "Sigma APO Macro 150mm f/2.8 EX DG HSM"}, - {"48 48 8E 8E 24 24 4B 02", "AF-S Nikkor 300mm f/2.8D IF-ED"}, - {"48 48 8E 8E 24 24 E1 02", "AF-S Nikkor 300mm f/2.8D IF-ED + TC-17E"}, - {"48 48 8E 8E 24 24 F1 02", "AF-S Nikkor 300mm f/2.8D IF-ED + TC-14E"}, - {"48 48 8E 8E 24 24 F2 02", "AF-S Nikkor 300mm f/2.8D IF-ED + TC-20E"}, - {"48 4C 7C 7C 2C 2C 4B 02", "Sigma APO Macro 180mm f/3.5 EX DG HSM"}, - {"48 4C 7D 7D 2C 2C 4B 02", "Sigma APO Macro 180mm f/3.5 EX DG HSM"}, - {"48 54 3E 3E 0C 0C 4B 06", "Sigma 30mm f/1.4 EX DC HSM"}, - {"48 54 5C 80 24 24 4B 02", "Sigma 70-200mm f/2.8 EX APO IF HSM"}, - {"48 54 6F 8E 24 24 4B 02", "Sigma APO 120-300mm f/2.8 EX DG HSM"}, - {"48 54 8E 8E 24 24 4B 02", "Sigma APO 300mm f/2.8 EX DG HSM"}, - {"49 3C A6 A6 30 30 4C 02", "AF-S Nikkor 600mm f/4D IF-ED"}, - {"49 3C A6 A6 30 30 E1 02", "AF-S Nikkor 600mm f/4D IF-ED + TC-17E"}, - {"49 3C A6 A6 30 30 F1 02", "AF-S Nikkor 600mm f/4D IF-ED + TC-14E"}, - {"49 3C A6 A6 30 30 F2 02", "AF-S Nikkor 600mm f/4D IF-ED + TC-20E"}, - {"4A 40 11 11 2C 0C 4D 02", "Samyang 8mm f/3.5 Fish-Eye CS"}, - {"4A 48 1E 1E 24 0C 4D 02", "Samyang 12mm f/2.8 ED AS NCS Fish-Eye"}, - {"4A 48 24 24 24 0C 4D 02", "Samyang 10mm f/2.8 ED AS NCS CS"}, - {"4A 48 24 24 24 0C 4D 02", "Samyang AE 14mm f/2.8 ED AS IF UMC"}, - {"4A 4C 24 24 1E 6C 4D 06", "Samyang 14mm f/2.4 Premium"}, - {"4A 54 29 29 18 0C 4D 02", "Samyang 16mm f/2.0 ED AS UMC CS"}, - {"4A 54 62 62 0C 0C 4D 02", "AF Nikkor 85mm f/1.4D IF"}, - {"4A 60 36 36 0C 0C 4D 02", "Samyang 24mm f/1.4 ED AS UMC"}, - {"4A 60 44 44 0C 0C 4D 02", "Samyang 35mm f/1.4 AS UMC"}, - {"4A 60 62 62 0C 0C 4D 02", "Samyang AE 85mm f/1.4 AS IF UMC"}, - {"4B 3C A0 A0 30 30 4E 02", "AF-S Nikkor 500mm f/4D IF-ED"}, - {"4B 3C A0 A0 30 30 E1 02", "AF-S Nikkor 500mm f/4D IF-ED + TC-17E"}, - {"4B 3C A0 A0 30 30 F1 02", "AF-S Nikkor 500mm f/4D IF-ED + TC-14E"}, - {"4B 3C A0 A0 30 30 F2 02", "AF-S Nikkor 500mm f/4D IF-ED + TC-20E"}, - {"4C 40 37 6E 2C 3C 4F 02", "AF Zoom-Nikkor 24-120mm f/3.5-5.6D IF"}, - {"4D 3E 3C 80 2E 3C 62 02", "Tamron AF 28-200mm f/3.8-5.6 XR Aspherical (IF) Macro (A03N)"}, - {"4D 40 3C 80 2C 3C 62 02", "AF Zoom-Nikkor 28-200mm f/3.5-5.6D IF"}, - {"4D 41 3C 8E 2B 40 62 02", "Tamron AF 28-300mm f/3.5-6.3 XR Di LD Aspherical (IF) (A061)"}, - {"4D 41 3C 8E 2C 40 62 02", "Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical (IF) (185D)"}, - {"4E 48 72 72 18 18 51 02", "AF DC-Nikkor 135mm f/2D"}, - {"4F 40 37 5C 2C 3C 53 06", "IX-Nikkor 24-70mm f/3.5-5.6"}, - {"50 48 56 7C 30 3C 54 06", "IX-Nikkor 60-180mm f/4-5.6"}, - {"52 54 44 44 18 18 00 00", "Zeiss Milvus 35mm f/2"}, - {"53 48 60 80 24 24 57 02", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, - {"53 48 60 80 24 24 60 02", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, - {"53 54 50 50 0C 0C 00 00", "Zeiss Milvus 50mm f/1.4"}, - {"54 44 5C 7C 34 3C 58 02", "AF Zoom-Micro Nikkor 70-180mm f/4.5-5.6D ED"}, - {"54 44 5C 7C 34 3C 61 02", "AF Zoom-Micro Nikkor 70-180mm f/4.5-5.6D ED"}, - {"54 54 50 50 18 18 00 00", "Zeiss Milvus 50mm f/2 Macro"}, - {"55 54 62 62 0C 0C 00 00", "Zeiss Milvus 85mm f/1.4"}, - {"56 3C 5C 8E 30 3C 1C 02", "Sigma 70-300mm f/4-5.6 APO Macro Super II"}, - {"56 48 5C 8E 30 3C 5A 02", "AF Zoom-Nikkor 70-300mm f/4-5.6D ED"}, - {"56 54 68 68 18 18 00 00", "Zeiss Milvus 100mm f/2 Macro"}, - {"59 48 98 98 24 24 5D 02", "AF-S Nikkor 400mm f/2.8D IF-ED"}, - {"59 48 98 98 24 24 E1 02", "AF-S Nikkor 400mm f/2.8D IF-ED + TC-17E"}, - {"59 48 98 98 24 24 F1 02", "AF-S Nikkor 400mm f/2.8D IF-ED + TC-14E"}, - {"59 48 98 98 24 24 F2 02", "AF-S Nikkor 400mm f/2.8D IF-ED + TC-20E"}, - {"5A 3C 3E 56 30 3C 5E 06", "IX-Nikkor 30-60mm f/4-5.6"}, - {"5B 44 56 7C 34 3C 5F 06", "IX-Nikkor 60-180mm f/4.5-5.6"}, - {"5D 48 3C 5C 24 24 63 02", "AF-S Zoom-Nikkor 28-70mm f/2.8D IF-ED"}, - {"5E 48 60 80 24 24 64 02", "AF-S Zoom-Nikkor 80-200mm f/2.8D IF-ED"}, - {"5F 40 3C 6A 2C 34 65 02", "AF Zoom-Nikkor 28-105mm f/3.5-4.5D IF"}, - {"60 40 3C 60 2C 3C 66 02", "AF Zoom-Nikkor 28-80mm f/3.5-5.6D"}, - {"61 44 5E 86 34 3C 67 02", "AF Zoom-Nikkor 75-240mm f/4.5-5.6D"}, - {"63 48 2B 44 24 24 68 02", "AF-S Nikkor 17-35mm f/2.8D IF-ED"}, - {"64 00 62 62 24 24 6A 02", "PC Micro-Nikkor 85mm f/2.8D"}, - {"65 44 60 98 34 3C 6B 0A", "AF VR Zoom-Nikkor 80-400mm f/4.5-5.6D ED"}, - {"66 40 2D 44 2C 34 6C 02", "AF Zoom-Nikkor 18-35mm f/3.5-4.5D IF-ED"}, - {"67 48 37 62 24 30 6D 02", "AF Zoom-Nikkor 24-85mm f/2.8-4D IF"}, - {"67 54 37 5C 24 24 1C 02", "Sigma 24-70mm f/2.8 EX DG Macro"}, - {"68 42 3C 60 2A 3C 6E 06", "AF Zoom-Nikkor 28-80mm f/3.3-5.6G"}, - {"69 47 5C 8E 30 3C 00 02", "Tamron AF 70-300mm f/4-5.6 Di LD Macro 1:2 (A17N)"}, - {"69 48 5C 8E 30 3C 6F 02", "Tamron AF 70-300mm f/4-5.6 LD Macro 1:2 (572D/772D)"}, - {"69 48 5C 8E 30 3C 6F 06", "AF Zoom-Nikkor 70-300mm f/4-5.6G"}, - {"6A 48 8E 8E 30 30 70 02", "AF-S Nikkor 300mm f/4D IF-ED"}, - {"6B 48 24 24 24 24 71 02", "AF Nikkor ED 14mm f/2.8D"}, - {"6D 48 8E 8E 24 24 73 02", "AF-S Nikkor 300mm f/2.8D IF-ED II"}, - {"6E 48 98 98 24 24 74 02", "AF-S Nikkor 400mm f/2.8D IF-ED II"}, - {"6F 3C A0 A0 30 30 75 02", "AF-S Nikkor 500mm f/4D IF-ED II"}, - {"70 3C A6 A6 30 30 76 02", "AF-S Nikkor 600mm f/4D IF-ED II"}, - {"72 48 4C 4C 24 24 77 00", "Nikkor 45mm f/2.8 P"}, - {"74 40 37 62 2C 34 78 06", "AF-S Zoom-Nikkor 24-85mm f/3.5-4.5G IF-ED"}, - {"75 40 3C 68 2C 3C 79 06", "AF Zoom-Nikkor 28-100mm f/3.5-5.6G"}, - {"76 58 50 50 14 14 7A 02", "AF Nikkor 50mm f/1.8D"}, - {"77 44 60 98 34 3C 7B 0E", "Sigma 80-400mm f/4.5-5.6 APO DG D OS"}, - {"77 44 61 98 34 3C 7B 0E", "Sigma 80-400mm f/4.5-5.6 EX OS"}, - {"77 48 5C 80 24 24 7B 0E", "AF-S VR Zoom-Nikkor 70-200mm f/2.8G IF-ED"}, - {"78 40 37 6E 2C 3C 7C 0E", "AF-S VR Zoom-Nikkor 24-120mm f/3.5-5.6G IF-ED"}, - {"79 40 11 11 2C 2C 1C 06", "Sigma 8mm f/3.5 EX Circular Fisheye"}, - {"79 40 3C 80 2C 3C 7F 06", "AF Zoom-Nikkor 28-200mm f/3.5-5.6G IF-ED"}, - {"79 48 3C 5C 24 24 1C 06", "Sigma 28-70mm f/2.8 EX DG"}, - {"79 48 5C 5C 24 24 1C 06", "Sigma Macro 70mm f/2.8 EX DG"}, - {"79 54 31 31 0C 0C 4B 06", "Sigma 20mm f/1.4 DG HSM | A"}, - {"7A 3B 53 80 30 3C 4B 06", "Sigma 55-200mm f/4-5.6 DC HSM"}, - {"7A 3C 1F 37 30 30 7E 06", "AF-S DX Zoom-Nikkor 12-24mm f/4G IF-ED"}, - {"7A 3C 1F 37 30 30 7E 06", "Tokina AT-X 124 AF PRO DX II (AF 12-24mm f/4)"}, - {"7A 3C 1F 3C 30 30 7E 06", "Tokina AT-X 12-28 PRO DX (AF 12-28mm f/4)"}, - {"7A 40 2D 50 2C 3C 4B 06", "Sigma 18-50mm f/3.5-5.6 DC HSM"}, - {"7A 40 2D 80 2C 40 4B 0E", "Sigma 18-200mm f/3.5-6.3 DC OS HSM"}, - {"7A 47 2B 5C 24 34 4B 06", "Sigma 17-70mm f/2.8-4.5 DC Macro Asp. IF HSM"}, - {"7A 47 50 76 24 24 4B 06", "Sigma 50-150mm f/2.8 EX APO DC HSM"}, - {"7A 48 1C 29 24 24 7E 06", "Tokina AT-X 116 PRO DX II (AF 11-16mm f/2.8)"}, - {"7A 48 1C 30 24 24 7E 06", "Tokina AT-X 11-20 f/2.8 PRO DX (AF 11-20mm f/2.8)"}, - {"7A 48 2B 5C 24 34 4B 06", "Sigma 17-70mm f/2.8-4.5 DC Macro Asp. IF HSM"}, - {"7A 48 2D 50 24 24 4B 06", "Sigma 18-50mm f/2.8 EX DC Macro"}, - {"7A 48 5C 80 24 24 4B 06", "Sigma 70-200mm f/2.8 EX APO DG Macro HSM II"}, - {"7A 54 6E 8E 24 24 4B 02", "Sigma APO 120-300mm f/2.8 EX DG HSM"}, - {"7B 48 80 98 30 30 80 0E", "AF-S VR Zoom-Nikkor 200-400mm f/4G IF-ED"}, - {"7D 48 2B 53 24 24 82 06", "AF-S DX Zoom-Nikkor 17-55mm f/2.8G IF-ED"}, - {"7F 40 2D 5C 2C 34 84 06", "AF-S DX Zoom-Nikkor 18-70mm f/3.5-4.5G IF-ED"}, - {"7F 48 2B 5C 24 34 1C 06", "Sigma 17-70mm f/2.8-4.5 DC Macro Asp. IF"}, - {"7F 48 2D 50 24 24 1C 06", "Sigma 18-50mm f/2.8 EX DC Macro"}, - {"80 48 1A 1A 24 24 85 06", "AF DX Fisheye-Nikkor 10.5mm f/2.8G ED"}, - {"81 34 76 A6 38 40 4B 0E", "Sigma 150-600mm f/5-6.3 DG OS HSM | S"}, - {"81 54 80 80 18 18 86 0E", "AF-S VR Nikkor 200mm f/2G IF-ED"}, - {"82 34 76 A6 38 40 4B 0E", "Sigma 150-600mm f/5-6.3 DG OS HSM | C"}, - {"82 48 8E 8E 24 24 87 0E", "AF-S VR Nikkor 300mm f/2.8G IF-ED"}, - {"83 00 B0 B0 5A 5A 88 04", "FSA-L2, EDG 65, 800mm f/13 G"}, - {"88 54 50 50 0C 0C 4B 06", "Sigma 50mm f/1.4 DG HSM | A"}, - {"89 3C 53 80 30 3C 8B 06", "AF-S DX Zoom-Nikkor 55-200mm f/4-5.6G ED"}, - {"8A 3C 37 6A 30 30 4B 0E", "Sigma 24-105mm f/4 DG OS HSM"}, - {"8A 54 6A 6A 24 24 8C 0E", "AF-S VR Micro-Nikkor 105mm f/2.8G IF-ED"}, - {"8B 40 2D 80 2C 3C 8D 0E", "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED"}, - {"8B 40 2D 80 2C 3C FD 0E", "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED [II]"}, - {"8B 4C 2D 44 14 14 4B 06", "Sigma 18-35mm f/1.8 DC HSM"}, - {"8C 40 2D 53 2C 3C 8E 06", "AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G ED"}, - {"8D 44 5C 8E 34 3C 8F 0E", "AF-S VR Zoom-Nikkor 70-300mm f/4.5-5.6G IF-ED"}, - {"8D 48 6E 8E 24 24 4B 0E", "Sigma 120-300mm f/2.8 DG OS HSM Sports"}, - {"8E 3C 2B 5C 24 30 4B 0E", "Sigma 17-70mm f/2.8-4 DC Macro OS HSM | C"}, - {"8F 40 2D 72 2C 3C 91 06", "AF-S DX Zoom-Nikkor 18-135mm f/3.5-5.6G IF-ED"}, - {"8F 48 2B 50 24 24 4B 0E", "Sigma 17-50mm f/2.8 EX DC OS HSM"}, - {"90 3B 53 80 30 3C 92 0E", "AF-S DX VR Zoom-Nikkor 55-200mm f/4-5.6G IF-ED"}, - {"90 40 2D 80 2C 40 4B 0E", "Sigma 18-200mm f/3.5-6.3 II DC OS HSM"}, - {"91 54 44 44 0C 0C 4B 06", "Sigma 35mm f/1.4 DG HSM"}, - {"92 2C 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, - {"92 48 24 37 24 24 94 06", "AF-S Zoom-Nikkor 14-24mm f/2.8G ED"}, - {"93 48 37 5C 24 24 95 06", "AF-S Zoom-Nikkor 24-70mm f/2.8G ED"}, - {"94 40 2D 53 2C 3C 96 06", "AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G ED II"}, - {"94 48 7C 7C 24 24 4B 0E", "Sigma APO Macro 180mm f/2.8 EX DG OS HSM"}, - {"95 00 37 37 2C 2C 97 06", "PC-E Nikkor 24mm f/3.5D ED"}, - {"95 4C 37 37 2C 2C 97 02", "PC-E Nikkor 24mm f/3.5D ED"}, - {"96 38 1F 37 34 3C 4B 06", "Sigma 12-24mm f/4.5-5.6 II DG HSM"}, - {"96 48 98 98 24 24 98 0E", "AF-S VR Nikkor 400mm f/2.8G ED"}, - {"97 3C A0 A0 30 30 99 0E", "AF-S VR Nikkor 500mm f/4G ED"}, - {"97 48 6A 6A 24 24 4B 0E", "Sigma Macro 105mm f/2.8 EX DG OS HSM"}, - {"98 3C A6 A6 30 30 9A 0E", "AF-S VR Nikkor 600mm f/4G ED"}, - {"98 48 50 76 24 24 4B 0E", "Sigma 50-150mm f/2.8 EX APO DC OS HSM"}, - {"99 40 29 62 2C 3C 9B 0E", "AF-S DX VR Zoom-Nikkor 16-85mm f/3.5-5.6G ED"}, - {"99 48 76 76 24 24 4B 0E", "Sigma APO Macro 150mm f/2.8 EX DG OS HSM"}, - {"9A 40 2D 53 2C 3C 9C 0E", "AF-S DX VR Zoom-Nikkor 18-55mm f/3.5-5.6G"}, - {"9A 4C 50 50 14 14 9C 06", "Yongnuo YN50mm f/1.8N"}, - {"9B 00 4C 4C 24 24 9D 06", "PC-E Micro Nikkor 45mm f/2.8D ED"}, - {"9B 54 4C 4C 24 24 9D 02", "PC-E Micro Nikkor 45mm f/2.8D ED"}, - {"9B 54 62 62 0C 0C 4B 06", "Sigma 85mm f/1.4 EX DG HSM"}, - {"9C 48 5C 80 24 24 4B 0E", "Sigma 70-200mm f/2.8 EX DG OS HSM"}, - {"9C 54 56 56 24 24 9E 06", "AF-S Micro Nikkor 60mm f/2.8G ED"}, - {"9D 00 62 62 24 24 9F 06", "PC-E Micro Nikkor 85mm f/2.8D"}, - {"9D 48 2B 50 24 24 4B 0E", "Sigma 17-50mm f/2.8 EX DC OS HSM"}, - {"9D 54 62 62 24 24 9F 02", "PC-E Micro Nikkor 85mm f/2.8D"}, - {"9E 38 11 29 34 3C 4B 06", "Sigma 8-16mm f/4.5-5.6 DC HSM"}, - {"9E 40 2D 6A 2C 3C A0 0E", "AF-S DX VR Zoom-Nikkor 18-105mm f/3.5-5.6G ED"}, - {"9F 37 50 A0 34 40 4B 0E", "Sigma 50-500mm f/4.5-6.3 DG OS HSM"}, - {"9F 58 44 44 14 14 A1 06", "AF-S DX Nikkor 35mm f/1.8G"}, - {"A0 40 2D 53 2C 3C CA 0E", "AF-P DX Nikkor 18-55mm f/3.5-5.6G VR"}, - {"A0 40 2D 53 2C 3C CA 8E", "AF-P DX Nikkor 18-55mm f/3.5-5.6G"}, - {"A0 40 2D 74 2C 3C BB 0E", "AF-S DX Nikkor 18-140mm f/3.5-5.6G ED VR"}, - {"A0 48 2A 5C 24 30 4B 0E", "Sigma 17-70mm f/2.8-4 DC Macro OS HSM"}, - {"A0 54 50 50 0C 0C A2 06", "AF-S Nikkor 50mm f/1.4G"}, - {"A1 40 18 37 2C 34 A3 06", "AF-S DX Nikkor 10-24mm f/3.5-4.5G ED"}, - {"A1 41 19 31 2C 2C 4B 06", "Sigma 10-20mm f/3.5 EX DC HSM"}, - {"A1 54 55 55 0C 0C BC 06", "AF-S Nikkor 58mm f/1.4G"}, - {"A2 38 5C 8E 34 40 CD 86", "AF-P DX Nikkor 70-300mm f/4.5-6.3G VR"}, - {"A2 40 2D 53 2C 3C BD 0E", "AF-S DX Nikkor 18-55mm f/3.5-5.6G VR II"}, - {"A2 48 5C 80 24 24 A4 0E", "AF-S Nikkor 70-200mm f/2.8G ED VR II"}, - {"A3 38 5C 8E 34 40 CE 0E", "AF-P DX Nikkor 70-300mm f/4.5-6.3G ED"}, - {"A3 38 5C 8E 34 40 CE 8E", "AF-P DX Nikkor 70-300mm f/4.5-6.3G ED VR"}, - {"A3 3C 29 44 30 30 A5 0E", "AF-S Nikkor 16-35mm f/4G ED VR"}, - {"A3 3C 5C 8E 30 3C 4B 0E", "Sigma 70-300mm f/4-5.6 DG OS"}, - {"A4 40 2D 8E 2C 40 BF 0E", "AF-S DX Nikkor 18-300mm f/3.5-6.3G ED VR"}, - {"A4 47 2D 50 24 34 4B 0E", "Sigma 18-50mm f/2.8-4.5 DC OS HSM"}, - {"A4 48 5C 80 24 24 CF 0E", "AF-S Nikkor 70-200mm f/2.8E FL ED VR"}, - {"A4 48 5C 80 24 24 CF 4E", "AF-S Nikkor 70-200mm f/2.8E FL ED VR"}, - {"A4 54 37 37 0C 0C A6 06", "AF-S Nikkor 24mm f/1.4G ED"}, - {"A5 40 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC OS HSM"}, - {"A5 40 3C 8E 2C 3C A7 0E", "AF-S Nikkor 28-300mm f/3.5-5.6G ED VR"}, - {"A5 4C 44 44 14 14 C0 06", "AF-S Nikkor 35mm f/1.8G ED"}, - {"A5 54 6A 6A 0C 0C D0 06", "AF-S Nikkor 105mm f/1.4E ED"}, - {"A5 54 6A 6A 0C 0C D0 46", "AF-S Nikkor 105mm f/1.4E ED"}, - {"A6 48 2F 2F 30 30 D1 06", "PC Nikkor 19mm f/4E ED"}, - {"A6 48 2F 2F 30 30 D1 46", "PC Nikkor 19mm f/4E ED"}, - {"A6 48 37 5C 24 24 4B 06", "Sigma 24-70mm f/2.8 IF EX DG HSM"}, - {"A6 48 8E 8E 24 24 A8 0E", "AF-S Nikkor 300mm f/2.8G IF-ED VR II"}, - {"A6 48 98 98 24 24 C1 0E", "AF-S Nikkor 400mm f/2.8E FL ED VR"}, - {"A7 3C 53 80 30 3C C2 0E", "AF-S DX Nikkor 55-200mm f/4-5.6G ED VR II"}, - {"A7 40 11 26 2C 34 D2 06", "AF-S Fisheye Nikkor 8-15mm f/3.5-4.5E ED"}, - {"A7 40 11 26 2C 34 D2 46", "AF-S Fisheye Nikkor 8-15mm f/3.5-4.5E ED"}, - {"A7 49 80 A0 24 24 4B 06", "Sigma APO 200-500mm f/2.8 EX DG"}, - {"A7 4B 62 62 2C 2C A9 0E", "AF-S DX Micro Nikkor 85mm f/3.5G ED VR"}, - {"A8 38 18 30 34 3C D3 0E", "AF-P DX Nikkor 10-20mm f/4.5-5.6G VR"}, - {"A8 38 18 30 34 3C D3 8E", "AF-P DX Nikkor 10-20mm f/4.5-5.6G VR"}, - {"A8 48 80 98 30 30 AA 0E", "AF-S Zoom-Nikkor 200-400mm f/4G IF-ED VR II"}, - {"A8 48 8E 8E 30 30 C3 0E", "AF-S Nikkor 300mm f/4E PF ED VR"}, - {"A8 48 8E 8E 30 30 C3 4E", "AF-S Nikkor 300mm f/4E PF ED VR"}, - {"A9 48 7C 98 30 30 D4 0E", "AF-S Nikkor 180-400mm f/4E TC1.4 FL ED VR"}, - {"A9 48 7C 98 30 30 D4 4E", "AF-S Nikkor 180-400mm f/4E TC1.4 FL ED VR"}, - {"A9 4C 31 31 14 14 C4 06", "AF-S Nikkor 20mm f/1.8G ED"}, - {"A9 54 80 80 18 18 AB 0E", "AF-S Nikkor 200mm f/2G ED VR II"}, - {"AA 3C 37 6E 30 30 AC 0E", "AF-S Nikkor 24-120mm f/4G ED VR"}, - {"AA 48 37 5C 24 24 C5 0E", "AF-S Nikkor 24-70mm f/2.8E ED VR"}, - {"AA 48 37 5C 24 24 C5 4E", "AF-S Nikkor 24-70mm f/2.8E ED VR"}, - {"AA 48 88 A4 3C 3C D5 0E", "AF-S Nikkor 180-400mm f/4E TC1.4 FL ED VR + 1.4x TC"}, - {"AA 48 88 A4 3C 3C D5 4E", "AF-S Nikkor 180-400mm f/4E TC1.4 FL ED VR + 1.4x TC"}, - {"AB 3C A0 A0 30 30 C6 4E", "AF-S Nikkor 500mm f/4E FL ED VR"}, - {"AB 44 5C 8E 34 3C D6 0E", "AF-P Nikkor 70-300mm f/4.5-5.6E ED VR"}, - {"AB 44 5C 8E 34 3C D6 CE", "AF-P Nikkor 70-300mm f/4.5-5.6E ED VR"}, - {"AC 38 53 8E 34 3C AE 0E", "AF-S DX Nikkor 55-300mm f/4.5-5.6G ED VR"}, - {"AC 3C A6 A6 30 30 C7 4E", "AF-S Nikkor 600mm f/4E FL ED VR"}, - {"AC 54 3C 3C 0C 0C D7 06", "AF-S Nikkor 28mm f/1.4E ED"}, - {"AC 54 3C 3C 0C 0C D7 46", "AF-S Nikkor 28mm f/1.4E ED"}, - {"AD 3C 2D 8E 2C 3C AF 0E", "AF-S DX Nikkor 18-300mm f/3.5-5.6G ED VR"}, - {"AD 3C A0 A0 3C 3C D8 0E", "AF-S Nikkor 500mm f/5.6E PF ED VR"}, - {"AD 3C A0 A0 3C 3C D8 4E", "AF-S Nikkor 500mm f/5.6E PF ED VR"}, - {"AD 48 28 60 24 30 C8 0E", "AF-S DX Nikkor 16-80mm f/2.8-4E ED VR"}, - {"AD 48 28 60 24 30 C8 4E", "AF-S DX Nikkor 16-80mm f/2.8-4E ED VR"}, - {"AE 3C 80 A0 3C 3C C9 0E", "AF-S Nikkor 200-500mm f/5.6E ED VR"}, - {"AE 3C 80 A0 3C 3C C9 4E", "AF-S Nikkor 200-500mm f/5.6E ED VR"}, - {"AE 54 62 62 0C 0C B0 06", "AF-S Nikkor 85mm f/1.4G"}, - {"AF 4C 37 37 14 14 CC 06", "AF-S Nikkor 24mm f/1.8G ED"}, - {"AF 54 44 44 0C 0C B1 06", "AF-S Nikkor 35mm f/1.4G"}, - {"B0 4C 50 50 14 14 B2 06", "AF-S Nikkor 50mm f/1.8G"}, - {"B1 48 48 48 24 24 B3 06", "AF-S DX Micro Nikkor 40mm f/2.8G"}, - {"B2 48 5C 80 30 30 B4 0E", "AF-S Nikkor 70-200mm f/4G ED VR"}, - {"B3 4C 62 62 14 14 B5 06", "AF-S Nikkor 85mm f/1.8G"}, - {"B4 40 37 62 2C 34 B6 0E", "AF-S Zoom-Nikkor 24-85mm f/3.5-4.5G IF-ED VR"}, - {"B5 4C 3C 3C 14 14 B7 06", "AF-S Nikkor 28mm f/1.8G"}, - {"B6 3C B0 B0 3C 3C B8 0E", "AF-S VR Nikkor 800mm f/5.6E FL ED"}, - {"B6 3C B0 B0 3C 3C B8 4E", "AF-S VR Nikkor 800mm f/5.6E FL ED"}, - {"B6 48 37 56 24 24 1C 02", "Sigma 24-60mm f/2.8 EX DG"}, - {"B7 44 60 98 34 3C B9 0E", "AF-S Nikkor 80-400mm f/4.5-5.6G ED VR"}, - {"B8 40 2D 44 2C 34 BA 06", "AF-S Nikkor 18-35mm f/3.5-4.5G ED"}, - {"BF 3C 1B 1B 30 30 01 04", "Irix 11mm f/4 Firefly"}, - {"BF 4E 26 26 1E 1E 01 04", "Irix 15mm f/2.4 Firefly"}, - {"C1 48 24 37 24 24 4B 46", "Sigma 14-24mm f/2.8 DG HSM | A"}, - {"C2 4C 24 24 14 14 4B 06", "Sigma 14mm f/1.8 DG HSM | A"}, - {"C3 34 68 98 38 40 4B 4E", "Sigma 100-400mm f/5-6.3 DG OS HSM | C"}, - {"C8 54 62 62 0C 0C 4B 46", "Sigma 85mm f/1.4 DG HSM | A"}, - {"C9 48 37 5C 24 24 4B 4E", "Sigma 24-70mm f/2.8 DG OS HSM | A"}, - {"CA 48 27 3E 24 24 DF 4E", "Tamron SP 15-30mm f/2.8 Di VC USD G2 (A041)"}, - {"CB 3C 2B 44 24 31 DF 46", "Tamron 17-35mm f/2.8-4 Di OSD (A037)"}, - {"CC 4C 50 68 14 14 4B 06", "Sigma 50-100mm f/1.8 DC HSM | A"}, - {"CD 3D 2D 70 2E 3C 4B 0E", "Sigma 18-125mm f/3.8-5.6 DC OS HSM"}, - {"CE 34 76 A0 38 40 4B 0E", "Sigma 150-500mm f/5-6.3 DG OS APO HSM"}, - {"CE 47 37 5C 25 25 DF 4E", "Tamron SP 24-70mm f/2.8 Di VC USD G2 (A032)"}, - {"CF 38 6E 98 34 3C 4B 0E", "Sigma APO 120-400mm f/4.5-5.6 DG OS HSM"}, - {"CF 47 5C 8E 31 3D DF 0E", "Tamron SP 70-300mm f/4-5.6 Di VC USD (A030)"}, - {"DC 48 19 19 24 24 4B 06", "Sigma 10mm f/2.8 EX DC HSM Fisheye"}, - {"DE 54 50 50 0C 0C 4B 06", "Sigma 50mm f/1.4 EX DG HSM"}, - {"E0 3C 5C 8E 30 3C 4B 06", "Sigma 70-300mm f/4-5.6 APO DG Macro HSM"}, - {"E0 40 2D 98 2C 41 DF 4E", "Tamron AF 18-400mm f/3.5-6.3 Di II VC HLD (B028)"}, - {"E1 40 19 36 2C 35 DF 4E", "Tamron 10-24mm f/3.5-4.5 Di II VC HLD (B023)"}, - {"E1 58 37 37 14 14 1C 02", "Sigma 24mm f/1.8 EX DG Aspherical Macro"}, - {"E2 47 5C 80 24 24 DF 4E", "Tamron SP 70-200mm f/2.8 Di VC USD G2 (A025)"}, - {"E3 40 76 A6 38 40 DF 4E", "Tamron SP 150-600mm f/5-6.3 Di VC USD G2"}, - {"E3 54 50 50 24 24 35 02", "Sigma Macro 50mm f/2.8 EX DG"}, - {"E4 54 64 64 24 24 DF 0E", "Tamron SP 90mm f/2.8 Di VC USD Macro 1:1 (F017)"}, - {"E5 54 6A 6A 24 24 35 02", "Sigma Macro 105mm f/2.8 EX DG"}, - {"E6 40 2D 80 2C 40 DF 0E", "Tamron AF 18-200mm f/3.5-6.3 Di II VC (B018)"}, - {"E6 41 3C 8E 2C 40 1C 02", "Sigma 28-300mm f/3.5-6.3 DG Macro"}, - {"E7 4C 4C 4C 14 14 DF 0E", "Tamron SP 45mm f/1.8 Di VC USD (F013)"}, - {"E8 4C 44 44 14 14 DF 0E", "Tamron SP 35mm f/1.8 Di VC USD (F012)"}, - {"E9 48 27 3E 24 24 DF 0E", "Tamron SP 15-30mm f/2.8 Di VC USD (A012)"}, - {"E9 54 37 5C 24 24 1C 02", "Sigma 24-70mm f/2.8 EX DG Macro"}, - {"EA 40 29 8E 2C 40 DF 0E", "Tamron AF 16-300mm f/3.5-6.3 Di II VC PZD (B016)"}, - {"EA 48 27 27 24 24 1C 02", "Sigma 15mm f/2.8 EX Diagonal Fisheye"}, - {"EB 40 76 A6 38 40 DF 0E", "Tamron SP AF 150-600mm f/5-6.3 VC USD (A011)"}, - {"ED 40 2D 80 2C 40 4B 0E", "Sigma 18-200mm f/3.5-6.3 DC OS HSM"}, - {"EE 48 5C 80 24 24 4B 06", "Sigma 70-200mm f/2.8 EX APO DG Macro HSM II"}, - {"F0 38 1F 37 34 3C 4B 06", "Sigma 12-24mm f/4.5-5.6 EX DG Aspherical HSM"}, - {"F0 3F 2D 8A 2C 40 DF 0E", "Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD (B008)"}, - {"F1 44 A0 A0 34 34 4B 02", "Sigma APO 500mm f/4.5 EX DG HSM"}, - {"F1 47 5C 8E 30 3C DF 0E", "Tamron SP 70-300mm f/4-5.6 Di VC USD (A005)"}, - {"F3 48 68 8E 30 30 4B 02", "Sigma APO 100-300mm f/4 EX IF HSM"}, - {"F3 54 2B 50 24 24 84 0E", "Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical (IF) (B005)"}, - {"F4 54 56 56 18 18 84 06", "Tamron SP AF 60mm f/2.0 Di II Macro 1:1 (G005)"}, - {"F5 40 2C 8A 2C 40 40 0E", "Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical (IF) Macro (B003)"}, - {"F5 48 76 76 24 24 4B 06", "Sigma APO Macro 150mm f/2.8 EX DG HSM"}, - {"F6 3F 18 37 2C 34 84 06", "Tamron SP AF 10-24mm f/3.5-4.5 Di II LD Aspherical (IF) (B001)"}, - {"F6 3F 18 37 2C 34 DF 06", "Tamron SP AF 10-24mm f/3.5-4.5 Di II LD Aspherical (IF) (B001)"}, - {"F6 48 2D 50 24 24 4B 06", "Sigma 18-50mm f/2.8 EX DC Macro"}, - {"F7 53 5C 80 24 24 40 06", "Tamron SP AF 70-200mm f/2.8 Di LD (IF) Macro (A001)"}, - {"F7 53 5C 80 24 24 84 06", "Tamron SP AF 70-200mm f/2.8 Di LD (IF) Macro (A001)"}, - {"F8 54 3E 3E 0C 0C 4B 06", "Sigma 30mm f/1.4 EX DC HSM"}, - {"F8 54 64 64 24 24 DF 06", "Tamron SP AF 90mm f/2.8 Di Macro 1:1 (272NII)"}, - {"F8 55 64 64 24 24 84 06", "Tamron SP AF 90mm f/2.8 Di Macro 1:1 (272NII)"}, - {"F9 3C 19 31 30 3C 4B 06", "Sigma 10-20mm f/4-5.6 EX DC HSM"}, - {"F9 40 3C 8E 2C 40 40 0E", "Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical (IF) Macro (A20)"}, - {"FA 54 3C 5E 24 24 84 06", "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical (IF) Macro (A09NII)"}, - {"FA 54 3C 5E 24 24 DF 06", "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical (IF) Macro (A09NII)"}, - {"FA 54 6E 8E 24 24 4B 02", "Sigma APO 120-300mm f/2.8 EX DG HSM"}, - {"FB 54 2B 50 24 24 84 06", "Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16NII)"}, - {"FB 54 8E 8E 24 24 4B 02", "Sigma APO 300mm f/2.8 EX DG HSM"}, - {"FC 40 2D 80 2C 40 DF 06", "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro (A14NII)"}, - {"FD 47 50 76 24 24 4B 06", "Sigma 50-150mm f/2.8 EX APO DC HSM II"}, - {"FE 47 00 00 24 24 4B 06", "Sigma 4.5mm f/2.8 EX DC HSM Circular Fisheye"}, - {"FE 48 37 5C 24 24 DF 0E", "Tamron SP 24-70mm f/2.8 Di VC USD (A007)"}, - {"FE 53 5C 80 24 24 84 06", "Tamron SP AF 70-200mm f/2.8 Di LD (IF) Macro (A001)"}, - {"FE 54 5C 80 24 24 DF 0E", "Tamron SP 70-200mm f/2.8 Di VC USD (A009)"}, - {"FE 54 64 64 24 24 DF 0E", "Tamron SP 90mm f/2.8 Di VC USD Macro 1:1 (F004)"}, - {"FF 40 2D 80 2C 40 4B 06", "Sigma 18-200mm f/3.5-6.3 DC"}, - - // There are cases where one lens uses multiple IDs which change based on the focal length or aperture. - // These IDs cannot be listed using ExifTool, and so must be entered manually below. - // #4135 - - {"92 2B 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (210mm) - {"92 2C 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (185mm) - {"92 2D 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (155mm) - {"92 2E 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (130mm) - {"92 2F 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (105mm) - {"92 30 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (90mm) - {"92 32 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (75mm) - {"92 33 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (62mm) - {"92 35 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (52mm) - {"92 37 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (44mm) - {"92 39 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (38mm) - {"92 3A 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (32mm) - {"92 3E 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"}, // (22mm) - {"92 40 2D 88 2C 40 4B 0E", "Sigma 18-250mm f/3.5-6.3 DC Macro OS HSM"} // (18mm) -}; - -const TagAttrib nikonISOInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "ISO", &naISOInfoISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0004, SHORT, "ISOExpansion", &naISOExpansionInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "ISO2", &naISOInfoISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000a, SHORT, "ISOExpansion2", &naISOExpansionInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib nikon2Attribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0002, AUTO, "Unknown", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "Quality", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0004, AUTO, "ColorMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0005, AUTO, "ImageAdjustment", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "ISOSpeed", &naISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "WhiteBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0008, AUTO, "Focus", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0009, AUTO, "Unknown", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000a, AUTO, "DigitalZoom", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000b, AUTO, "AuxiliaryLens", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0f00, AUTO, "Unknown", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib nikon3Attribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "MakerNoteVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0002, AUTO, "ISOSpeed", &naISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "ColorMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0004, AUTO, "Quality", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0005, AUTO, "WhiteBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "FocusMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0008, AUTO, "FlashSetting", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0009, AUTO, "FlashType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000b, AUTO, "WhiteBalanceFineTune", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x000c, AUTO, "ColorBalance1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000d, AUTO, "ProgramShift", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000e, AUTO, "ExposureDifference", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000f, AUTO, "ISOSelection", &naISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0010, AUTO, "DataDump", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0011, AUTO, "NikonPreview", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0012, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0013, AUTO, "ISOSetting", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0016, AUTO, "ImageBoundary", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0018, AUTO, "FlashExposureBracketValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0019, AUTO, "ExposureBracketValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001a, AUTO, "ImageProcessing", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001b, AUTO, "CropHiSpeed", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001d, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001e, AUTO, "ColorSpace", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0020, AUTO, "ImageAuthentication", &stdInterpreter}, - {0, AC_WRITE, 0, nikonISOInfoAttribs, 0x0025, AUTO, "ISOInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0080, AUTO, "ImageAdjustment", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0081, AUTO, "ToneComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0082, AUTO, "AuxiliaryLens", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0083, AUTO, "LensType", &naLensTypeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0084, AUTO, "Lens", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0085, AUTO, "ManualFocusDistance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0086, AUTO, "DigitalZoom", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0087, AUTO, "FlashMode", &naFlashModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0088, AUTO, "AFInfo", &naAFInfoInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0089, AUTO, "ShootingMode", &naShootingModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008a, AUTO, "AutoBracketRelease", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008b, AUTO, "LensFStops", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008c, AUTO, "NEFCurve1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008d, AUTO, "ColorHue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008f, AUTO, "SceneMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0090, AUTO, "LightSource", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0091, AUTO, "ShotInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0092, AUTO, "HueAdjustment", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0094, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0095, AUTO, "NoiseReduction", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0096, AUTO, "NEFCurve2", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x0097, AUTO, "ColorBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0098, AUTO, "LensData", &naLensDataInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0099, AUTO, "RawImageCenter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x009a, AUTO, "SensorPixelSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a0, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a2, AUTO, "ImageDataSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a5, AUTO, "ImageCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a6, AUTO, "DeletedImageCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a7, AUTO, "ShutterCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a9, AUTO, "ImageOptimization", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00aa, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00ab, AUTO, "VariProgram", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00ac, AUTO, "ImageStabilization", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00ad, AUTO, "AFResponse", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00b0, AUTO, "MultiExposure", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00b1, AUTO, "HighISONoiseReduction", &naHiISONRInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0e00, AUTO, "PrintIM", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0x0e01, AUTO, "NikonCaptureData", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0x0e09, AUTO, "NikonCaptureVersion", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0x0e0e, AUTO, "NikonCaptureOffsets", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0x0e10, AUTO, "NikonScanIFD", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -} -#endif - diff --git a/rtexif/olympusattribs.cc b/rtexif/olympusattribs.cc deleted file mode 100644 index e42763e35..000000000 --- a/rtexif/olympusattribs.cc +++ /dev/null @@ -1,846 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _OLYMPUSATTRIBS_ -#define _OLYMPUSATTRIBS_ - -#include -#include -#include -#include - -#include "rtexif.h" - -namespace rtexif -{ - -class OLOnOffInterpreter : public Interpreter -{ -public: - OLOnOffInterpreter () {} - std::string toString (const Tag* t) const override - { - if (t->toInt() == 0) { - return "Off"; - } else { - return "On"; - } - } -}; -OLOnOffInterpreter olOnOffInterpreter; - -class OLYesNoInterpreter : public Interpreter -{ -public: - OLYesNoInterpreter () {} - std::string toString (const Tag* t) const override - { - if (t->toInt() == 0) { - return "No"; - } else { - return "Yes"; - } - } -}; -OLYesNoInterpreter olYesNoInterpreter; - -class OLApertureInterpreter : public Interpreter -{ -public: - OLApertureInterpreter () {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - str.precision (2); - str << pow (2, t->toInt() / 512.0); - return str.str(); - } -}; -OLApertureInterpreter olApertureInterpreter; - -class OLLensTypeInterpreter : public Interpreter -{ - std::map lenses; -public: - OLLensTypeInterpreter () - { - lenses["00 01 00"] = "Olympus Zuiko Digital ED 50mm f/2.0 Macro"; - lenses["00 01 01"] = "Olympus Zuiko Digital 40-150mm f/3.5-4.5"; - lenses["00 01 10"] = "Olympus M.Zuiko Digital ED 14-42mm f/3.5-5.6"; - lenses["00 02 00"] = "Olympus Zuiko Digital ED 150mm f/2.0"; - lenses["00 02 10"] = "Olympus M.Zuiko Digital 17mm f/2.8 Pancake"; - lenses["00 03 00"] = "Olympus Zuiko Digital ED 300mm f/2.8"; - lenses["00 03 10"] = "Olympus M.Zuiko Digital ED 14-150mm f/4.0-5.6 [II]"; - lenses["00 04 10"] = "Olympus M.Zuiko Digital ED 9-18mm f/4.0-5.6"; - lenses["00 05 00"] = "Olympus Zuiko Digital 14-54mm f/2.8-3.5"; - lenses["00 05 01"] = "Olympus Zuiko Digital Pro ED 90-250mm f/2.8"; - lenses["00 05 10"] = "Olympus M.Zuiko Digital ED 14-42mm f/3.5-5.6 L"; - lenses["00 06 00"] = "Olympus Zuiko Digital ED 50-200mm f/2.8-3.5"; - lenses["00 06 01"] = "Olympus Zuiko Digital ED 8mm f/3.5 Fisheye"; - lenses["00 06 10"] = "Olympus M.Zuiko Digital ED 40-150mm f/4.0-5.6"; - lenses["00 07 00"] = "Olympus Zuiko Digital 11-22mm f/2.8-3.5"; - lenses["00 07 01"] = "Olympus Zuiko Digital 18-180mm f/3.5-6.3"; - lenses["00 07 10"] = "Olympus M.Zuiko Digital ED 12mm f/2.0"; - lenses["00 08 01"] = "Olympus Zuiko Digital 70-300mm f/4.0-5.6"; - lenses["00 08 10"] = "Olympus M.Zuiko Digital ED 75-300mm f/4.8-6.7"; - lenses["00 09 10"] = "Olympus M.Zuiko Digital 14-42mm f/3.5-5.6 II"; - lenses["00 10 01"] = "Kenko Tokina Reflex 300mm f/6.3 MF Macro"; - lenses["00 10 10"] = "Olympus M.Zuiko Digital ED 12-50mm f/3.5-6.3 EZ"; - lenses["00 11 10"] = "Olympus M.Zuiko Digital 45mm f/1.8"; - lenses["00 12 10"] = "Olympus M.Zuiko Digital ED 60mm f/2.8 Macro"; - lenses["00 13 10"] = "Olympus M.Zuiko Digital 14-42mm f/3.5-5.6 II R"; - lenses["00 14 10"] = "Olympus M.Zuiko Digital ED 40-150mm f/4.0-5.6 R"; - lenses["00 15 00"] = "Olympus Zuiko Digital ED 7-14mm f/4.0"; - lenses["00 15 10"] = "Olympus M.Zuiko Digital ED 75mm f/1.8"; - lenses["00 16 10"] = "Olympus M.Zuiko Digital 17mm f/1.8"; - lenses["00 17 00"] = "Olympus Zuiko Digital Pro ED 35-100mm f/2.0"; - lenses["00 18 00"] = "Olympus Zuiko Digital 14-45mm f/3.5-5.6"; - lenses["00 18 10"] = "Olympus M.Zuiko Digital ED 75-300mm f/4.8-6.7 II"; - lenses["00 19 10"] = "Olympus M.Zuiko Digital ED 12-40mm f/2.8 Pro"; - lenses["00 20 00"] = "Olympus Zuiko Digital 35mm f/3.5 Macro"; - lenses["00 20 10"] = "Olympus M.Zuiko Digital ED 40-150mm f/2.8 Pro"; - lenses["00 21 10"] = "Olympus M.Zuiko Digital ED 14-42mm f/3.5-5.6 EZ"; - lenses["00 22 00"] = "Olympus Zuiko Digital 17.5-45mm f/3.5-5.6"; - lenses["00 22 10"] = "Olympus M.Zuiko Digital 25mm f/1.8"; - lenses["00 23 00"] = "Olympus Zuiko Digital ED 14-42mm f/3.5-5.6"; - lenses["00 23 10"] = "Olympus M.Zuiko Digital ED 7-14mm f/2.8 Pro"; - lenses["00 24 00"] = "Olympus Zuiko Digital ED 40-150mm f/4.0-5.6"; - lenses["00 24 10"] = "Olympus M.Zuiko Digital ED 300mm f/4.0 IS Pro"; - lenses["00 25 10"] = "Olympus M.Zuiko Digital ED 8mm f/1.8 Fisheye Pro"; - lenses["00 26 10"] = "Olympus M.Zuiko Digital ED 12-100mm f/4.0 IS Pro"; - lenses["00 27 10"] = "Olympus M.Zuiko Digital ED 30mm f/3.5 Macro"; - lenses["00 28 10"] = "Olympus M.Zuiko Digital ED 25mm f/1.2 Pro"; - lenses["00 29 10"] = "Olympus M.Zuiko Digital ED 17mm f/1.2 Pro"; - lenses["00 30 00"] = "Olympus Zuiko Digital ED 50-200mm f/2.8-3.5 SWD"; - lenses["00 30 10"] = "Olympus M.Zuiko Digital ED 45mm f/1.2 Pro"; - lenses["00 31 00"] = "Olympus Zuiko Digital ED 12-60mm f/2.8-4.0 SWD"; - lenses["00 32 00"] = "Olympus Zuiko Digital ED 14-35mm f/2.0 SWD"; - lenses["00 33 00"] = "Olympus Zuiko Digital 25mm f/2.8"; - lenses["00 34 00"] = "Olympus Zuiko Digital ED 9-18mm f/4.0-5.6"; - lenses["00 35 00"] = "Olympus Zuiko Digital 14-54mm f/2.8-3.5 II"; - lenses["01 01 00"] = "Sigma 18-50mm f/3.5-5.6 DC"; - lenses["01 01 10"] = "Sigma 30mm f/2.8 EX DN"; - lenses["01 02 00"] = "Sigma 55-200mm f/4.0-5.6 DC"; - lenses["01 02 10"] = "Sigma 19mm f/2.8 EX DN"; - lenses["01 03 00"] = "Sigma 18-125mm f/3.5-5.6 DC"; - lenses["01 03 10"] = "Sigma 30mm f/2.8 DN | A"; - lenses["01 04 00"] = "Sigma 18-125mm f/3.5-5.6 DC"; - lenses["01 04 10"] = "Sigma 19mm f/2.8 DN | A"; - lenses["01 05 00"] = "Sigma 30mm f/1.4 EX DC HSM"; - lenses["01 05 10"] = "Sigma 60mm f/2.8 DN | A"; - lenses["01 06 00"] = "Sigma APO 50-500mm f/4.0-6.3 EX DG HSM"; - lenses["01 06 10"] = "Sigma 30mm f/1.4 DC DN | C"; - lenses["01 07 00"] = "Sigma Macro 105mm f/2.8 EX DG"; - lenses["01 07 10"] = "Sigma 16mm f/1.4 DC DN | C (017)"; - lenses["01 08 00"] = "Sigma APO Macro 150mm f/2.8 EX DG HSM"; - lenses["01 09 00"] = "Sigma 18-50mm f/2.8 EX DC Macro"; - lenses["01 10 00"] = "Sigma 24mm f/1.8 EX DG Aspherical Macro"; - lenses["01 11 00"] = "Sigma APO 135-400mm f/4.5-5.6 DG"; - lenses["01 12 00"] = "Sigma APO 300-800mm f/5.6 EX DG HSM"; - lenses["01 13 00"] = "Sigma 30mm f/1.4 EX DC HSM"; - lenses["01 14 00"] = "Sigma APO 50-500mm f/4.0-6.3 EX DG HSM"; - lenses["01 15 00"] = "Sigma 10-20mm f/4.0-5.6 EX DC HSM"; - lenses["01 16 00"] = "Sigma APO 70-200mm f/2.8 II EX DG Macro HSM"; - lenses["01 17 00"] = "Sigma 50mm f/1.4 EX DG HSM"; - lenses["02 01 00"] = "Leica D Vario Elmarit 14-50mm f/2.8-3.5 Asph."; - lenses["02 01 10"] = "Lumix G Vario 14-45mm f/3.5-5.6 Asph. Mega OIS"; - lenses["02 02 00"] = "Leica D Summilux 25mm f/1.4 Asph."; - lenses["02 02 10"] = "Lumix G Vario 45-200mm f/4.0-5.6 Mega OIS"; - lenses["02 03 00"] = "Leica D Vario Elmar 14-50mm f/3.8-5.6 Asph. Mega OIS"; - lenses["02 03 01"] = "Leica D Vario Elmar 14-50mm f/3.8-5.6 Asph."; - lenses["02 03 10"] = "Lumix G Vario HD 14-140mm f/4.0-5.8 Asph. Mega OIS"; - lenses["02 04 00"] = "Leica D Vario Elmar 14-150mm f/3.5-5.6"; - lenses["02 04 10"] = "Lumix G Vario 7-14mm f/4.0 Asph."; - lenses["02 05 10"] = "Lumix G 20mm f/1.7 Asph."; - lenses["02 06 10"] = "Leica DG Macro-Elmarit 45mm f/2.8 Asph. Mega OIS"; - lenses["02 07 10"] = "Lumix G Vario 14-42mm f/3.5-5.6 Asph. Mega OIS"; - lenses["02 08 10"] = "Lumix G Fisheye 8mm f/3.5"; - lenses["02 09 10"] = "Lumix G Vario 100-300mm f/4.0-5.6 Mega OIS"; - lenses["02 10 10"] = "Lumix G 14mm f/2.5 Asph."; - lenses["02 11 10"] = "Lumix G 12.5mm f/12 3D"; - lenses["02 12 10"] = "Leica DG Summilux 25mm f/1.4 Asph."; - lenses["02 13 10"] = "Lumix G X Vario PZ 45-175mm f/4.0-5.6 Asph. Power OIS"; - lenses["02 14 10"] = "Lumix G X Vario PZ 14-42mm f/3.5-5.6 Asph. Power OIS"; - lenses["02 15 10"] = "Lumix G X Vario 12-35mm f/2.8 Asph. Power OIS"; - lenses["02 16 10"] = "Lumix G Vario 45-150mm f/4.0-5.6 Asph. Mega OIS"; - lenses["02 17 10"] = "Lumix G X Vario 35-100mm f/2.8 Power OIS"; - lenses["02 18 10"] = "Lumix G Vario 14-42mm f/3.5-5.6 II Asph. Mega OIS"; - lenses["02 19 10"] = "Lumix G Vario 14-140mm f/3.5-5.6 Asph. Power OIS"; - lenses["02 20 10"] = "Lumix G Vario 12-32mm f/3.5-5.6 Asph. Mega OIS"; - lenses["02 21 10"] = "Leica DG Nocticron 42.5mm f/1.2 Asph. Power OIS"; - lenses["02 22 10"] = "Leica DG Summilux 15mm f/1.7 Asph."; - lenses["02 23 10"] = "Lumix G Vario 35-100mm f/4.0-5.6 Asph. Mega OIS"; - lenses["02 24 10"] = "Lumix G Macro 30mm f/2.8 Asph. Mega OIS"; - lenses["02 25 10"] = "Lumix G 42.5mm f/1.7 Asph. Power OIS"; - lenses["02 26 10"] = "Lumix G 25mm f/1.7 Asph."; - lenses["02 27 10"] = "Leica DG Vario-Elmar 100-400mm f/4.0-6.3 Asph. Power OIS"; - lenses["02 28 10"] = "Lumix G Vario 12-60mm f/3.5-5.6 Asph. Power OIS"; - lenses["03 01 00"] = "Leica D Vario Elmarit 14-50mm f/2.8-3.5 Asph."; - lenses["03 02 00"] = "Leica D Summilux 25mm f/1.4 Asph."; - lenses["05 01 10"] = "Tamron 14-150mm f/3.5-5.8 Di III"; - } - std::string toString (const Tag* t) const override - { - std::ostringstream lid; - lid.setf (std::ios_base::hex, std::ios_base::basefield); - lid.setf (std::ios_base::uppercase); - lid << std::setw (2) << std::setfill ('0') << t->toInt (0) << ' '; //maker - lid << std::setw (2) << std::setfill ('0') << t->toInt (2) << ' '; //model - lid << std::setw (2) << std::setfill ('0') << t->toInt (3); // submodel - - std::map::const_iterator r = lenses.find (lid.str()); - - if (r != lenses.end()) { - return r->second; - } else { - return "Unknown"; - } - } -}; -OLLensTypeInterpreter olLensTypeInterpreter; - -class OLFlashTypeInterpreter : public ChoiceInterpreter<> -{ -public: - OLFlashTypeInterpreter () - { - choices[0] = "None"; - choices[2] = "Simple E-System"; - choices[3] = "E-System"; - } -}; -OLFlashTypeInterpreter olFlashTypeInterpreter; - -class OLExposureModeInterpreter : public ChoiceInterpreter<> -{ -public: - OLExposureModeInterpreter () - { - choices[1] = "Manual"; - choices[2] = "Program"; - choices[3] = "Aperture-priority AE"; - choices[4] = "Shutter speed priority AE"; - choices[5] = "Program-shift"; - } -}; -OLExposureModeInterpreter olExposureModeInterpreter; - -class OLMeteringModeInterpreter : public ChoiceInterpreter<> -{ -public: - OLMeteringModeInterpreter () - { - choices[2] = "Center-weighted average"; - choices[3] = "Spot"; - choices[5] = "ESP"; - choices[261] = "Pattern+AF"; - choices[515] = "Spot+Highlight control"; - choices[1027] = "Spot+Shadow control"; - } -}; -OLMeteringModeInterpreter olMeteringModeInterpreter; - -class OLFocusModeInterpreter : public ChoiceInterpreter<> -{ -public: - OLFocusModeInterpreter () - { - choices[0] = "Single AF"; - choices[1] = "Sequential shooting AF"; - choices[2] = "Continuous AF"; - choices[3] = "Multi AF"; - choices[4] = "Face detect"; - choices[10] = "MF"; - } -}; -OLFocusModeInterpreter olFocusModeInterpreter; - -class OLWhitebalance2Interpreter : public ChoiceInterpreter<> -{ -public: - OLWhitebalance2Interpreter () - { - choices[0] = "Auto"; - choices[1] = "Auto (Keep Warm Color Off)"; - choices[16] = "7500K (Fine Weather with Shade)"; - choices[17] = "6000K (Cloudy)"; - choices[18] = "5300K (Fine Weather)"; - choices[20] = "3000K (Tungsten light)"; - choices[21] = "3600K (Tungsten light-like)"; - choices[22] = "Auto Setup"; - choices[23] = "5500K (Flash)"; - choices[33] = "6600K (Daylight fluorescent)"; - choices[34] = "4500K (Neutral white fluorescent)"; - choices[35] = "4000K (Cool white fluorescent)"; - choices[36] = "White Fluorescent"; - choices[48] = "3600K (Tungsten light-like)"; - choices[67] = "Underwater"; - choices[256] = "One Touch WB 1"; - choices[257] = "One Touch WB 2"; - choices[258] = "One Touch WB 3"; - choices[259] = "One Touch WB 4"; - choices[512] = "Custom WB 1"; - choices[513] = "Custom WB 2"; - choices[514] = "Custom WB 3"; - choices[515] = "Custom WB 4"; - } -}; -OLWhitebalance2Interpreter olWhitebalance2Interpreter; - -class OLSceneModeInterpreter : public ChoiceInterpreter<> -{ -public: - OLSceneModeInterpreter () - { - choices[0] = "Standard"; - choices[6] = "Auto"; - choices[7] = "Sport"; - choices[8] = "Portrait"; - choices[9] = "Landscape+Portrait"; - choices[10] = "Landscape"; - choices[11] = "Night Scene"; - choices[12] = "Self Portrait"; - choices[13] = "Panorama"; - choices[14] = "2 in 1"; - choices[15] = "Movie"; - choices[16] = "Landscape+Portrait"; - choices[17] = "Night+Portrait"; - choices[18] = "Indoor"; - choices[19] = "Fireworks"; - choices[20] = "Sunset"; - choices[21] = "Beauty Skin"; - choices[22] = "Macro"; - choices[23] = "Super Macro"; - choices[24] = "Food"; - choices[25] = "Documents"; - choices[26] = "Museum"; - choices[27] = "Shoot & Select"; - choices[28] = "Beach & Snow"; - choices[29] = "Self Protrait+Timer"; - choices[30] = "Candle"; - choices[31] = "Available Light"; - choices[32] = "Behind Glass"; - choices[33] = "My Mode"; - choices[34] = "Pet"; - choices[35] = "Underwater Wide1"; - choices[36] = "Underwater Macro"; - choices[37] = "Shoot & Select1"; - choices[38] = "Shoot & Select2"; - choices[39] = "High Key"; - choices[40] = "Digital Image Stabilization"; - choices[41] = "Auction"; - choices[42] = "Beach"; - choices[43] = "Snow"; - choices[44] = "Underwater Wide2"; - choices[45] = "Low Key"; - choices[46] = "Children"; - choices[47] = "Vivid"; - choices[48] = "Nature Macro"; - choices[49] = "Underwater Snapshot"; - choices[50] = "Shooting Guide"; - choices[54] = "Face Portrait"; - choices[57] = "Bulb"; - choices[59] = "Smile Shot"; - choices[60] = "Quick Shutter"; - choices[63] = "Slow Shutter"; - choices[64] = "Bird Watching"; - choices[65] = "Multiple Exposure"; - choices[66] = "e-Portrait"; - choices[67] = "Soft Background Shot"; - choices[142] = "Hand-held Starlight"; - choices[154] = "HDR"; - } -}; -OLSceneModeInterpreter olSceneModeInterpreter; - -class OLPictureModeBWFilterInterpreter : public ChoiceInterpreter<> -{ -public: - OLPictureModeBWFilterInterpreter () - { - choices[0] = "n/a"; - choices[1] = "Neutral"; - choices[2] = "Yellow"; - choices[3] = "Orange"; - choices[4] = "Red"; - choices[5] = "Green"; - } -}; -OLPictureModeBWFilterInterpreter olPictureModeBWFilterInterpreter; - -class OLPictureModeToneInterpreter : public ChoiceInterpreter<> -{ -public: - OLPictureModeToneInterpreter () - { - choices[0] = "n/a"; - choices[1] = "Neutral"; - choices[2] = "Sepia"; - choices[3] = "Blue"; - choices[4] = "Purple"; - choices[5] = "Green"; - } -}; -OLPictureModeToneInterpreter olPictureModeToneInterpreter; - -class OLImageQuality2Interpreter : public ChoiceInterpreter<> -{ -public: - OLImageQuality2Interpreter () - { - choices[1] = "SQ"; - choices[2] = "HQ"; - choices[3] = "SHQ"; - choices[4] = "RAW"; - choices[5] = "SQ (5)"; - } -}; -OLImageQuality2Interpreter olImageQuality2Interpreter; - -class OLDevEngineInterpreter : public ChoiceInterpreter<> -{ -public: - // RawDevEngine - OLDevEngineInterpreter () - { - choices[0] = "High Speed"; - choices[1] = "High Function"; - choices[2] = "Advanced High Speed"; - choices[3] = "Advanced High Function"; - } -}; -OLDevEngineInterpreter olDevEngineInterpreter; - -class OLPictureModeInterpreter : public ChoiceInterpreter<> -{ -public: - OLPictureModeInterpreter () - { - choices[1] = "Vivid"; - choices[2] = "Natural"; - choices[3] = "Muted"; - choices[4] = "Portrait"; - choices[5] = "i-Enhance"; - choices[7] = "Color Creator"; - choices[9] = "Color Profile 1"; - choices[10] = "Color Profile 2"; - choices[11] = "Color Profile 3"; - choices[12] = "Monochrome Profile 1"; - choices[13] = "Monochrome Profile 2"; - choices[14] = "Monochrome Profile 3"; - choices[256] = "Monotone"; - choices[512] = "Sepia"; - } -}; -OLPictureModeInterpreter olPictureModeInterpreter; - -class OLColorSpaceInterpreter : public ChoiceInterpreter<> -{ -public: - OLColorSpaceInterpreter () - { - choices[0] = "sRGB"; - choices[1] = "Adobe RGB"; - choices[2] = "Pro Photo RGB"; - } -}; -OLColorSpaceInterpreter olColorSpaceInterpreter; - -class OLNoiseFilterInterpreter : public Interpreter -{ -public: - OLNoiseFilterInterpreter () {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0); - int b = t->toInt (2); - int c = t->toInt (4); - - if (a == -1 && b == -2 && c == 1) { - return "Low"; - } else if (a == -2 && b == -2 && c == 1) { - return "Off"; - } else if (a == 0 && b == -2 && c == 1) { - return "Standard"; - } else if (a == 1 && b == -2 && c == 1) { - return "High"; - } else { - return "Unknown"; - } - } -}; -OLNoiseFilterInterpreter olNoiseFilterInterpreter; - -class OLFlashModeInterpreter : public Interpreter -{ -public: - OLFlashModeInterpreter () {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - int a = t->toInt (); - str << "Flash Used = " << ((a & 1) ? "Yes" : "No") << std::endl; - str << "Fill-in = " << ((a & 2) ? "On" : "Off") << std::endl; - str << "Red-eye = " << ((a & 4) ? "On" : "Off") << std::endl; - str << "Slow-sync = " << ((a & 8) ? "On" : "Off") << std::endl; - str << "Forced On = " << ((a & 16) ? "On" : "Off") << std::endl; - str << "2nd Curtain = " << ((a & 32) ? "On" : "Off"); - return str.str(); - } -}; -OLFlashModeInterpreter olFlashModeInterpreter; - -class OLNoiseReductionInterpreter : public Interpreter -{ -public: - OLNoiseReductionInterpreter () {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - int a = t->toInt (); - str << "Noise Reduction = " << ((a & 1) ? "On" : "Off") << std::endl; - str << "Noise Filter = " << ((a & 2) ? "On" : "Off") << std::endl; - str << "Noise Filter (ISO Boost) = " << ((a & 4) ? "On" : "Off") << std::endl; - str << "Auto = " << ((a & 8) ? "On" : "Off"); - return str.str(); - } -}; -OLNoiseReductionInterpreter olNoiseReductionInterpreter; - -class OLFlashModelInterpreter : public ChoiceInterpreter<> -{ -public: - OLFlashModelInterpreter () - { - choices[0] = "None"; - choices[1] = "FL-20"; - choices[2] = "FL-50"; - choices[3] = "RF-11"; - choices[4] = "TF-22"; - choices[5] = "FL-36"; - choices[6] = "FL-50R"; - choices[7] = "FL-36R"; - choices[9] = "FL-14"; - choices[11] = "FL-600R"; - } -}; -OLFlashModelInterpreter olFlashModelInterpreter; - -const TagAttrib olyFocusInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "FocusInfoVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0209, AUTO, "AutoFocus", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0210, AUTO, "SceneDetect", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0211, AUTO, "SceneArea", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0212, AUTO, "SceneDetectData", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0300, AUTO, "ZoomStepCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0301, AUTO, "FocusStepCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0303, AUTO, "FocusStepInfinity", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0304, AUTO, "FocusStepNear", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0305, AUTO, "FocusDistance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0308, AUTO, "AFPoint", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1201, AUTO, "ExternalFlash", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1203, AUTO, "ExternalFlashGuideNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1204, AUTO, "ExternalFlashBounce", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1205, AUTO, "ExternalFlashZoom", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1208, AUTO, "InternalFlash", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1209, AUTO, "ManualFlash", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1500, AUTO, "SensorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1600, AUTO, "ImageStabilization", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib olyImageProcessingAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "ImageProcessingVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0100, AUTO, "WB_RBLevels", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0102, AUTO, "WB_RBLevels3000K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0103, AUTO, "WB_RBLevels3300K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "WB_RBLevels3600K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0105, AUTO, "WB_RBLevels3900K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0106, AUTO, "WB_RBLevels4000K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0107, AUTO, "WB_RBLevels4300K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0108, AUTO, "WB_RBLevels4500K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0109, AUTO, "WB_RBLevels4800K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010a, AUTO, "WB_RBLevels5300K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010b, AUTO, "WB_RBLevels6000K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010c, AUTO, "WB_RBLevels6600K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010d, AUTO, "WB_RBLevels7500K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010e, AUTO, "WB_RBLevelsCWB1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010f, AUTO, "WB_RBLevelsCWB2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0110, AUTO, "WB_RBLevelsCWB3", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0111, AUTO, "WB_RBLevelsCWB4", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0113, AUTO, "WB_GLevel3000K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0114, AUTO, "WB_GLevel3300K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0115, AUTO, "WB_GLevel3600K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0116, AUTO, "WB_GLevel3900K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0117, AUTO, "WB_GLevel4000K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0118, AUTO, "WB_GLevel4300K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0119, AUTO, "WB_GLevel4500K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x011a, AUTO, "WB_GLevel4800K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x011b, AUTO, "WB_GLevel5300K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x011c, AUTO, "WB_GLevel6000K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x011d, AUTO, "WB_GLevel6600K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x011e, AUTO, "WB_GLevel7500K", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x011f, AUTO, "WB_GLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0200, AUTO, "ColorMatrix", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0300, AUTO, "Enhancer", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0301, AUTO, "EnhancerValues", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0310, AUTO, "CoringFilter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0311, AUTO, "CoringValues", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0600, AUTO, "BlackLevel2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0610, AUTO, "GainBase", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0611, AUTO, "ValidBits", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0612, AUTO, "CropLeft", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0613, AUTO, "CropTop", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0614, AUTO, "CropWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0615, AUTO, "CropHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1010, AUTO, "NoiseReduction2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1011, AUTO, "DistortionCorrection2", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1012, AUTO, "ShadingCompensation2", &olOnOffInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x1103, AUTO, "UnknownBlock", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1200, AUTO, "FaceDetect", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1201, AUTO, "FaceDetectArea", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib olyRawDevelopmentAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "RawDevVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0100, AUTO, "RawDevExposureBiasValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0101, AUTO, "RawDevWhiteBalanceValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0102, AUTO, "RawDevWBFineAdjustment", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0103, AUTO, "RawDevGrayPoint", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "RawDevSaturationEmphasis", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0105, AUTO, "RawDevMemoryColorEmphasis", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0106, AUTO, "RawDevContrastValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0107, AUTO, "RawDevSharpnessValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0108, AUTO, "RawDevColorSpace", &olColorSpaceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0109, AUTO, "RawDevEngine", &olDevEngineInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010a, AUTO, "RawDevNoiseReduction", &olNoiseReductionInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010b, AUTO, "RawDevEditStatus", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010c, AUTO, "RawDevSettings", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib olyRawDevelopment2Attribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "RawDevVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0100, AUTO, "RawDevExposureBiasValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0101, AUTO, "RawDevWhiteBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0102, AUTO, "RawDevWhiteBalanceValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0103, AUTO, "RawDevWBFineAdjustment", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "RawDevGrayPoint", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0105, AUTO, "RawDevContrastValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0106, AUTO, "RawDevSharpnessValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0107, AUTO, "RawDevSaturationEmphasis", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0108, AUTO, "RawDevMemoryColorEmphasis", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0109, AUTO, "RawDevColorSpace", &olColorSpaceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010a, AUTO, "RawDevNoiseReduction", &olNoiseReductionInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010b, AUTO, "RawDevEngine", &olDevEngineInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010c, AUTO, "RawDevPictureMode", &olPictureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010d, AUTO, "RawDevPMSaturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010e, AUTO, "RawDevPMContrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010f, AUTO, "RawDevPMSharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0110, AUTO, "RawDevPM_BWFilter", &olPictureModeBWFilterInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0111, AUTO, "RawDevPMPictureTone", &olPictureModeToneInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0112, AUTO, "RawDevGradation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0113, AUTO, "RawDevSaturation3", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0119, AUTO, "RawDevAutoGradation", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0120, AUTO, "RawDevPMNoiseFilter", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib olyCameraSettingsAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "CameraSettingsVersion", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0100, AUTO, "PreviewImageValid", &olYesNoInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0101, AUTO, "PreviewImageStart", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0102, AUTO, "PreviewImageLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0200, AUTO, "ExposureMode", &olExposureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0201, AUTO, "AELock", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0202, AUTO, "MeteringMode", &olMeteringModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0300, AUTO, "MacroMode", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0301, AUTO, "FocusMode", &olFocusModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0302, AUTO, "FocusProcess", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0303, AUTO, "AFSearch", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0304, AUTO, "AFAreas", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0400, AUTO, "FlashMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0401, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0500, AUTO, "WhiteBalance2", &olWhitebalance2Interpreter}, - {0, AC_WRITE, 0, nullptr, 0x0501, AUTO, "WhiteBalanceTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0502, AUTO, "WhiteBalanceBracket", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0503, AUTO, "CustomSaturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0504, AUTO, "ModifiedSaturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0505, AUTO, "ContrastSetting", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0506, AUTO, "SharpnessSetting", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0507, AUTO, "ColorSpace", &olColorSpaceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0509, AUTO, "SceneMode", &olSceneModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x050a, AUTO, "NoiseReduction", &olNoiseReductionInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x050b, AUTO, "DistortionCorrection", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x050c, AUTO, "ShadingCompensation", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x050d, AUTO, "CompressionFactor", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x050f, AUTO, "Gradation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0520, AUTO, "PictureMode", &olPictureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0521, AUTO, "PictureModeSaturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0522, AUTO, "PictureModeHue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0523, AUTO, "PictureModeContrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0524, AUTO, "PictureModeSharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0525, AUTO, "PictureModeBWFilter", &olPictureModeBWFilterInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0526, AUTO, "PictureModeTone", &olPictureModeToneInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0527, AUTO, "NoiseFilter", &olNoiseFilterInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0600, AUTO, "DriveMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0601, AUTO, "PanoramaMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0603, AUTO, "ImageQuality2", &olImageQuality2Interpreter}, - {0, AC_WRITE, 0, nullptr, 0x0900, AUTO, "ManometerPressure", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0901, AUTO, "ManometerReading", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0902, AUTO, "ExtendedWBDetect", &olOnOffInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib olyEquipmentAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "EquipmentVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0100, AUTO, "CameraType2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0101, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0102, AUTO, "InternalSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0103, AUTO, "FocalPlaneDiagonal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "BodyFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0201, AUTO, "LensType", &olLensTypeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0202, AUTO, "LensSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0204, AUTO, "LensFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0205, AUTO, "MaxApertureAtMinFocal", &olApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0206, AUTO, "MaxApertureAtMaxFocal", &olApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0207, AUTO, "MinFocalLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0208, AUTO, "MaxFocalLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020a, AUTO, "MaxApertureAtCurrentFocal", &olApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020b, AUTO, "LensProperties", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0301, AUTO, "Extender", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0302, AUTO, "ExtenderSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0303, AUTO, "ExtenderModel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0304, AUTO, "ExtenderFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1000, AUTO, "FlashType", &olFlashTypeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1001, AUTO, "FlashModel", &olFlashModelInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1002, AUTO, "FlashFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1003, AUTO, "FlashSerialNumber", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib olympusAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "BodyFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0200, AUTO, "SpecialMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0201, AUTO, "Quality", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0202, AUTO, "Macro", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0203, AUTO, "BWMode", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0204, AUTO, "DigitalZoom", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0205, AUTO, "FocalPlaneDiagonal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0206, AUTO, "LensDistortionParams", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0207, AUTO, "CameraType", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0208, AUTO, "TextInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0209, AUTO, "CameraID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020b, AUTO, "EpsonImageWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020c, AUTO, "EpsonImageHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020d, AUTO, "EpsonSoftware", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0280, AUTO, "PreviewImage", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0300, AUTO, "PreCaptureFrames", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0301, AUTO, "WhiteBoard", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0302, AUTO, "OneTouchWB", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0303, AUTO, "WhiteBalanceBracket", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0304, AUTO, "WhiteBalanceBias", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0403, AUTO, "SceneMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0404, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0405, AUTO, "Firmware", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0e00, AUTO, "PrintIM", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0f00, AUTO, "DataDump", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0f01, AUTO, "DataDump2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1000, AUTO, "ShutterSpeedValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1001, AUTO, "ISOValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1002, AUTO, "ApertureValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1003, AUTO, "BrightnessValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1004, AUTO, "FlashMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1005, AUTO, "FlashDevice", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1006, AUTO, "ExposureCompensation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1007, AUTO, "SensorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1008, AUTO, "LensTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1009, AUTO, "LightCondition", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100a, AUTO, "FocusRange", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100b, AUTO, "FocusMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100c, AUTO, "ManualFocusDistance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100d, AUTO, "ZoomStepCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100e, AUTO, "FocusStepCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x100f, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1010, AUTO, "FlashChargeLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1011, AUTO, "ColorMatrix", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1012, AUTO, "BlackLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1013, AUTO, "ColorTemperatureBG", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1014, AUTO, "ColorTemperatureRG", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1015, AUTO, "WBMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1017, AUTO, "RedBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1018, AUTO, "BlueBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1019, AUTO, "ColorMatrixNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x101a, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x101b, AUTO, "ExternalFlashAE1_0", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x101c, AUTO, "ExternalFlashAE2_0", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x101d, AUTO, "InternalFlashAE1_0", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x101e, AUTO, "InternalFlashAE2_0", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x101f, AUTO, "ExternalFlashAE1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1020, AUTO, "ExternalFlashAE2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1021, AUTO, "InternalFlashAE1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1022, AUTO, "InternalFlashAE2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1023, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1024, AUTO, "InternalFlashTable", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1025, AUTO, "ExternalFlashGValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1026, AUTO, "ExternalFlashBounce", &olYesNoInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1027, AUTO, "ExternalFlashZoom", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1028, AUTO, "ExternalFlashMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1029, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x102a, AUTO, "SharpnessFactor", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x102b, AUTO, "ColorControl", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x102c, AUTO, "ValidBits", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x102d, AUTO, "CoringFilter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x102e, AUTO, "OlympusImageWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x102f, AUTO, "OlympusImageHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1030, AUTO, "SceneDetect", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1031, AUTO, "SceneArea", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1033, AUTO, "SceneDetectData", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1034, AUTO, "CompressionRatio", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x1035, AUTO, "PreviewImageValid", &olYesNoInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x1036, AUTO, "PreviewImageStart", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x1037, AUTO, "PreviewImageLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1038, AUTO, "AFResult", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x1039, AUTO, "CCDScanMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x103a, AUTO, "NoiseReduction", &olOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x103b, AUTO, "InfinityLensStep", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x103c, AUTO, "NearLensStep", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x103d, AUTO, "LightValueCenter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x103e, AUTO, "LightValuePeriphery", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x103f, AUTO, "FieldCount", &stdInterpreter}, - {0, AC_WRITE, 0, olyEquipmentAttribs, 0x2010, AUTO, "Equipment", &stdInterpreter}, - {0, AC_WRITE, 0, olyCameraSettingsAttribs, 0x2020, AUTO, "CameraSettings", &stdInterpreter}, - {0, AC_WRITE, 0, olyRawDevelopmentAttribs, 0x2030, AUTO, "RawDevelopment", &stdInterpreter}, - {0, AC_WRITE, 0, olyRawDevelopment2Attribs, 0x2031, AUTO, "RawDev2", &stdInterpreter}, - {0, AC_WRITE, 0, olyImageProcessingAttribs, 0x2040, AUTO, "ImageProcessing", &stdInterpreter}, - {0, AC_WRITE, 0, olyFocusInfoAttribs, 0x2050, AUTO, "FocusInfo", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2100, AUTO, "Olympus2100", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2300, AUTO, "Olympus2300", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2400, AUTO, "Olympus2400", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2500, AUTO, "Olympus2500", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2600, AUTO, "Olympus2600", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2700, AUTO, "Olympus2700", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2800, AUTO, "Olympus2800", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2900, AUTO, "Olympus2900", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x3000, AUTO, "RawInfo", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; -} -#endif - diff --git a/rtexif/panasonicattribs.cc b/rtexif/panasonicattribs.cc deleted file mode 100644 index 3062824cf..000000000 --- a/rtexif/panasonicattribs.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of RawTherapee. - */ -#ifndef _PANASONICATTRIBS_ -#define _PANASONICATTRIBS_ - -#include -#include "rtexif.h" - -namespace rtexif -{ - -// TODO: write interpreters - -const TagAttrib panasonicAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "Quality", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0002, AUTO, "FirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "WhiteBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "FocusMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000f, AUTO, "AFMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001a, AUTO, "ImageStabilization", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001c, AUTO, "Macro", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001f, AUTO, "ShootingMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0020, AUTO, "Audio", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0023, AUTO, "WhiteBalanceBias", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0024, AUTO, "FlashBias", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0025, AUTO, "InternalSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0026, AUTO, "ExifVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0028, AUTO, "ColorEffect", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0029, AUTO, "TimeSincePowerOn", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002a, AUTO, "BurstMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002b, AUTO, "SequenceNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002c, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002d, AUTO, "NoiseReduction", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002e, AUTO, "SelfTimer", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0030, AUTO, "Rotation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0031, AUTO, "AFAssistLamp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0032, AUTO, "ColorMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0033, AUTO, "BabyAge1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0034, AUTO, "OpticalZoomMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0035, AUTO, "ConversionLens", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0036, AUTO, "TravelDay", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0039, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003a, AUTO, "WorldTimeLocation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003b, AUTO, "TextStamp1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003c, AUTO, "ProgramISO", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003d, AUTO, "AdvancedSceneType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003e, AUTO, "TextStamp2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003f, AUTO, "FacesDetected", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0040, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0041, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0042, AUTO, "FilmMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0044, AUTO, "ColorTempKelvin", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0045, AUTO, "BracketSettings", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0046, AUTO, "WBAdjustAB", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0047, AUTO, "WBAdjustGM", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0048, AUTO, "FlashCurtain", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0049, AUTO, "LongShutterNoiseReduction", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x004b, AUTO, "ImageWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x004c, AUTO, "ImageHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x004d, AUTO, "AFPointPosition", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x004e, AUTO, "FaceDetInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0051, AUTO, "LensType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0052, AUTO, "LensSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0053, AUTO, "AccessoryType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0054, AUTO, "AccessorySerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0059, AUTO, "Transform1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x005d, AUTO, "IntelligentExposure", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0060, AUTO, "LensFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0061, AUTO, "FaceRecInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0062, AUTO, "FlashWarning", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0065, AUTO, "Title", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0066, AUTO, "BabyName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0067, AUTO, "Location", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0069, AUTO, "Country", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x006b, AUTO, "State", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x006d, AUTO, "City", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x006f, AUTO, "Landmark", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0070, AUTO, "IntelligentResolution", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0077, AUTO, "BurstSheed", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0079, AUTO, "IntelligentDRange", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x007c, AUTO, "ClearRetouch", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0080, AUTO, "City2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0086, AUTO, "ManometerPressure", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0089, AUTO, "PhotoStyle", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008a, AUTO, "ShadingCompensation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008c, AUTO, "AccelerometerZ", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008d, AUTO, "AccelerometerX", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008e, AUTO, "AccelerometerY", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008f, AUTO, "CameraOrientation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0090, AUTO, "RollAngle", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0091, AUTO, "PitchAngle", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0093, AUTO, "SweepPanoramaDirection", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0094, AUTO, "PanoramaFieldOfView", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0096, AUTO, "TimerRecording", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x009d, AUTO, "InternalNDFilter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x009e, AUTO, "HDR", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x009f, AUTO, "ShutterType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00a3, AUTO, "ClearRetouchValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x00ab, AUTO, "TouchAE", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0e00, AUTO, "PrintIM", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8000, AUTO, "MakerNoteVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8001, AUTO, "SceneMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8004, AUTO, "WBRedLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8005, AUTO, "WBGreenLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8006, AUTO, "WBBlueLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8007, AUTO, "FlashFired", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8008, AUTO, "TextStamp3", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8009, AUTO, "TextStamp4", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8010, AUTO, "BabyAge2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8012, AUTO, "Transform2", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr } -}; - -const TagAttrib panasonicRawAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "Version", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0002, AUTO, "SensorWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "SensorHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0004, AUTO, "SensorTopBorder", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0005, AUTO, "SensorLeftBorder", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "ImageHeight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "ImageWidth", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0011, AUTO, "RedBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0012, AUTO, "BlueBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0017, AUTO, "ISOSpeed", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0024, AUTO, "WBRedLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0025, AUTO, "WBGreenLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0026, AUTO, "WBBlueLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002e, AUTO, "PreviewImage", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010f, AUTO, "Make", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0110, AUTO, "Model", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0111, AUTO, "StripOffsets", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0112, AUTO, "Orientation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0116, AUTO, "RowsPerStrip", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0117, AUTO, "StripByteCounts", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0118, AUTO, "RawDataOffset", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr } -}; - -} -#endif - diff --git a/rtexif/pentaxattribs.cc b/rtexif/pentaxattribs.cc deleted file mode 100644 index 7e861d64f..000000000 --- a/rtexif/pentaxattribs.cc +++ /dev/null @@ -1,2219 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _PENTAXATTRIBS_ -#define _PENTAXATTRIBS_ - -#include -#include -#include /* memcpy() */ -#include -#include - -#include "rtexif.h" - -namespace rtexif -{ - - -class PAQualityInterpreter : public ChoiceInterpreter<> -{ -public: - PAQualityInterpreter () - { - choices[0] = "Good"; - choices[1] = "Better"; - choices[2] = "Best"; - choices[3] = "TIFF"; - choices[4] = "RAW"; - choices[5] = "Premium"; - choices[6] = "RAW (HDR enabled)"; - choices[7] = "RAW (pixel shift enabled)"; - choices[8] = "RAW (pixel shift handheld mode enabled)"; - choices[65535] = "n/a"; - } -}; -PAQualityInterpreter paQualityInterpreter; - -class PAOnOffInterpreter : public ChoiceInterpreter<> -{ -public: - PAOnOffInterpreter () - { - choices[0] = "Off"; - choices[1] = "On"; - } -}; -PAOnOffInterpreter paOnOffInterpreter; - -class PAShakeReductionInterpreter : public ChoiceInterpreter<> -{ -public: - PAShakeReductionInterpreter () - { - choices[ 0] = "Off"; - choices[ 1] = "On"; - choices[ 4] = "On (4)"; - choices[ 5] = "On but Disabled"; - choices[ 6] = "On (Video)"; - choices[ 7] = "On (7)"; - choices[ 15] = "On (15)"; - choices[ 39] = "On (mode 2)"; - choices[135] = "On (135)"; - choices[167] = "On (mode 1)"; - } -}; -PAShakeReductionInterpreter paShakeReductionInterpreter; - -class PAShakeReduction2Interpreter : public ChoiceInterpreter<> -{ -public: - // ShakeReduction - PAShakeReduction2Interpreter () - { - choices[ 0] = "Off"; - choices[ 1] = "On"; - choices[ 4] = "Off (AA simulation off)"; - choices[ 5] = "On but Disabled"; - choices[ 6] = "On (Video)"; - choices[ 7] = "On (AA simulation off)"; - choices[12] = "Off (AA simulation type 1)"; - choices[15] = "On (AA simulation type 1)"; - choices[20] = "Off (AA simulation type 2)"; - choices[23] = "On (AA simulation type 2)"; - } -}; -PAShakeReduction2Interpreter paShakeReduction2Interpreter; - -class PAPictureModeInterpreter : public ChoiceInterpreter<> -{ -public: - PAPictureModeInterpreter () - { - choices[0] = "Program"; - choices[1] = "Shutter Speed Priority"; - choices[2] = "Program AE"; - choices[3] = "Manual"; - choices[5] = "Portrait"; - choices[6] = "Landscape"; - choices[8] = "Sport"; - choices[9] = "Night Scene"; - choices[11] = "Soft"; - choices[12] = "Surf & Snow"; - choices[13] = "Candlelight"; - choices[14] = "Autumn"; - choices[15] = "Macro"; - choices[17] = "Fireworks"; - choices[18] = "Text"; - choices[19] = "Panorama"; - choices[20] = "3-D"; - choices[21] = "Black & White"; - choices[22] = "Sepia"; - choices[23] = "Red"; - choices[24] = "Pink"; - choices[25] = "Purple"; - choices[26] = "Blue"; - choices[27] = "Green"; - choices[28] = "Yellow"; - choices[30] = "Self Portrait"; - choices[31] = "Illustrations"; - choices[33] = "Digital Filter"; - choices[35] = "Night Scene Portrait"; - choices[37] = "Museum"; - choices[38] = "Food"; - choices[39] = "Underwater"; - choices[40] = "Green Mode"; - choices[49] = "Light Pet"; - choices[50] = "Dark Pet"; - choices[51] = "Medium Pet"; - choices[53] = "Underwater"; - choices[54] = "Candlelight"; - choices[55] = "Natural Skin Tone"; - choices[56] = "Synchro Sound Record"; - choices[58] = "Frame Composite"; - choices[59] = "Report"; - choices[60] = "Kids"; - choices[61] = "Blur Reduction"; - choices[63] = "Panorama 2"; - choices[65] = "Half-length Portrait"; - choices[66] = "Portrait 2"; - choices[74] = "Digital Microscope"; - choices[75] = "Blue Sky"; - choices[80] = "Miniature"; - choices[81] = "HDR"; - choices[83] = "Fisheye"; - choices[85] = "Digital Filter 4"; - choices[221] = "P"; - choices[255] = "PICT"; - } -}; -PAPictureModeInterpreter paPictureModeInterpreter; - -class PASceneModeInterpreter : public ChoiceInterpreter<> -{ -public: - PASceneModeInterpreter () - { - choices[0] = "Off"; - choices[1] = "HDR"; - choices[4] = "Auto PICT"; - choices[5] = "Portrait"; - choices[6] = "Landscape"; - choices[7] = "Macro"; - choices[8] = "Sport"; - choices[9] = "Night Scene Portrait"; - choices[10] = "No Flash"; - choices[11] = "Night Scene"; - choices[12] = "Surf & Snow"; - choices[14] = "Sunset"; - choices[15] = "Kids"; - choices[16] = "Pet"; - choices[17] = "Candlelight"; - choices[18] = "Museum"; - choices[20] = "Food"; - choices[21] = "Stage Lighting"; - choices[22] = "Night Snap"; - choices[25] = "Night Scene HDR"; - choices[26] = "Blue Sky"; - choices[27] = "Forest"; - choices[29] = "Backlight Silhouette"; - } -}; -PASceneModeInterpreter paSceneModeInterpreter; - -class PAAEProgramModeInterpreter : public ChoiceInterpreter<> -{ -public: - PAAEProgramModeInterpreter () - { - choices[0] = "M, P or TAv"; - choices[1] = "Av, B or X"; - choices[2] = "Tv"; - choices[3] = "Sv or Green Mode"; - choices[8] = "Hi-speed Program"; - choices[11] = "Hi-speed Program (P-Shift)"; - choices[16] = "DOF Program"; - choices[19] = "DOF Program (P-Shift)"; - choices[24] = "MTF Program"; - choices[27] = "MTF Program (P-Shift)"; - choices[35] = "Standard"; - choices[43] = "Portrait"; - choices[51] = "Landscape"; - choices[59] = "Macro"; - choices[67] = "Sport"; - choices[75] = "Night Scene Portrait"; - choices[83] = "No Flash"; - choices[91] = "Night Scene"; - choices[99] = "Surf & Snow"; - choices[104] = "Night Snap"; - choices[107] = "Text"; - choices[115] = "Sunset"; - choices[123] = "Kids"; - choices[131] = "Pet"; - choices[139] = "Candlelight"; - choices[144] = "SCN"; - choices[147] = "Museum"; - choices[160] = "Program"; - choices[184] = "Shallow DOF Program"; - choices[216] = "HDR"; - } -}; -PAAEProgramModeInterpreter paAEProgramModeInterpreter; - -class PAFlashModeInterpreter : public ChoiceInterpreter<> -{ -public: - PAFlashModeInterpreter () - { - choices[0] = "Auto, Did not fire"; - choices[1] = "Off, Did not fire"; - choices[2] = "On, Did not fire"; - choices[3] = "Auto, Did not fire, Red-eye reduction"; - choices[5] = "On, Did not fire, Wireless (Master)"; - choices[256] = "Auto, Fired"; - choices[258] = "On, Fired"; - choices[259] = "Auto, Fired, Red-eye reduction"; - choices[260] = "On, Red-eye reduction"; - choices[261] = "On, Wireless (Master)"; - choices[262] = "On, Wireless (Control)"; - choices[264] = "On, Soft"; - choices[265] = "On, Slow-sync"; - choices[266] = "On, Slow-sync, Red-eye reduction"; - choices[267] = "On, Trailing-curtain Sync"; - } -}; -PAFlashModeInterpreter paFlashModeInterpreter; - -class PAFocusModeInterpreter : public ChoiceInterpreter<> -{ -public: - PAFocusModeInterpreter () - { - choices[0] = "Normal"; - choices[1] = "Macro"; - choices[2] = "Infinity"; - choices[3] = "Manual"; - choices[4] = "Super Macro"; - choices[5] = "Pan Focus"; - choices[16] = "AF-S (Focus-priority)"; - choices[17] = "AF-C (Focus-priority)"; - choices[18] = "AF-A (Focus-priority)"; - choices[32] = "Contrast-detect (Focus-priority)"; - choices[33] = "Tracking Contrast-detect (Focus-priority)"; - choices[272] = "AF-S (Release-priority)"; - choices[273] = "AF-C (Release-priority)"; - choices[274] = "AF-A (Release-priority)"; - choices[288] = "Contrast-detect (Release-priority)"; - } -}; -PAFocusModeInterpreter paFocusModeInterpreter; - -class PAAFPointInterpreter : public ChoiceInterpreter<> -{ -public: - // AFPointSelected - PAAFPointInterpreter () - { - choices[0] = "None"; - choices[1] = "Upper-left"; - choices[2] = "Top"; - choices[3] = "Upper-right"; - choices[4] = "Left"; - choices[5] = "Mid-left"; - choices[6] = "Center"; - choices[7] = "Mid-right"; - choices[8] = "Right"; - choices[9] = "Lower-left"; - choices[10] = "Bottom"; - choices[11] = "Lower-right"; - choices[65531] = "AF Select"; - choices[65532] = "Face Detect AF"; - choices[65533] = "Automatic Tracking AF"; - choices[65534] = "Fixed Center"; - choices[65535] = "Auto"; - } -}; -PAAFPointInterpreter paAFPointInterpreter; - -class PAAFFocusInterpreter : public ChoiceInterpreter<> -{ -public: - // AFPointsInFocus - PAAFFocusInterpreter () - { - choices[0] = "Fixed Center or Multiple"; - choices[1] = "Top-left"; - choices[2] = "Top-center"; - choices[3] = "Top-right"; - choices[4] = "Left"; - choices[5] = "Center"; - choices[6] = "Right"; - choices[7] = "Bottom-left"; - choices[8] = "Bottom-center"; - choices[9] = "Bottom-right"; - choices[65535] = "None"; - } -}; -PAAFFocusInterpreter paAFFocusInterpreter; - -class PAISOInterpreter : public ChoiceInterpreter<> -{ -public: - PAISOInterpreter () - { - choices[3] = "50"; - choices[4] = "64"; - choices[5] = "80"; - choices[6] = "100"; - choices[7] = "125"; - choices[8] = "160"; - choices[9] = "200"; - choices[10] = "250"; - choices[11] = "320"; - choices[12] = "400"; - choices[13] = "500"; - choices[14] = "640"; - choices[15] = "800"; - choices[16] = "1000"; - choices[17] = "1250"; - choices[18] = "1600"; - choices[19] = "2000"; - choices[20] = "2500"; - choices[21] = "3200"; - choices[22] = "4000"; - choices[23] = "5000"; - choices[24] = "6400"; - choices[25] = "8000"; - choices[26] = "10000"; - choices[27] = "12800"; - choices[28] = "16000"; - choices[29] = "20000"; - choices[30] = "25600"; - choices[31] = "32000"; - choices[32] = "40000"; - choices[33] = "51200"; - choices[34] = "64000"; - choices[35] = "80000"; - choices[36] = "102400"; - choices[37] = "128000"; - choices[38] = "160000"; - choices[39] = "204800"; - choices[40] = "256000"; - choices[41] = "320000"; - choices[42] = "409600"; - choices[43] = "512000"; - choices[44] = "640000"; - choices[45] = "819200"; - choices[50] = "50"; - choices[100] = "100"; - choices[200] = "200"; - choices[258] = "50"; - choices[259] = "70"; - choices[260] = "100"; - choices[261] = "140"; - choices[262] = "200"; - choices[263] = "280"; - choices[264] = "400"; - choices[265] = "560"; - choices[266] = "800"; - choices[267] = "1100"; - choices[268] = "1600"; - choices[269] = "2200"; - choices[270] = "3200"; - choices[271] = "4500"; - choices[272] = "6400"; - choices[273] = "9000"; - choices[274] = "12800"; - choices[275] = "18000"; - choices[276] = "25600"; - choices[277] = "36000"; - choices[278] = "51200"; - choices[400] = "400"; - choices[800] = "800"; - choices[1600] = "1600"; - choices[3200] = "3200"; - } -}; -PAISOInterpreter paISOInterpreter; - -class PAFNumberInterpreter: public Interpreter -{ -public: - PAFNumberInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double v = t->toDouble() / 10; - - if ( v < 0. || v > 1000. ) { - return "undef"; - } - - sprintf (buffer, "%.1f", v ); - return buffer; - } -}; -PAFNumberInterpreter paFNumberInterpreter; - -class PAMeteringModeInterpreter : public ChoiceInterpreter<> -{ -public: - PAMeteringModeInterpreter () - { - choices[0] = "Multi-segment"; - choices[1] = "Center-weighted average"; - choices[2] = "Spot"; - } -}; -PAMeteringModeInterpreter paMeteringModeInterpreter; - -class PAWhiteBalanceInterpreter : public ChoiceInterpreter<> -{ -public: - PAWhiteBalanceInterpreter () - { - choices[0] = "Auto"; - choices[1] = "Daylight"; - choices[2] = "Shade"; - choices[3] = "Fluorescent"; - choices[4] = "Tungsten"; - choices[5] = "Manual"; - choices[6] = "Daylight Fluorescent"; - choices[7] = "Day White Fluorescent"; - choices[8] = "White Fluorescent"; - choices[9] = "Flash"; - choices[10] = "Cloudy"; - choices[11] = "Warm White Fluorescent"; - choices[14] = "Multi Auto"; - choices[15] = "Color Temperature Enhancement"; - choices[17] = "Kelvin"; - choices[65534] = "Unknown"; - choices[65535] = "User-Selected"; - } -}; -PAWhiteBalanceInterpreter paWhiteBalanceInterpreter; - -class PAWhiteBalanceModeInterpreter : public ChoiceInterpreter<> -{ -public: - PAWhiteBalanceModeInterpreter () - { - choices[1] = "Auto (Daylight)"; - choices[2] = "Auto (Shade)"; - choices[3] = "Auto (Flash)"; - choices[4] = "Auto (Tungsten)"; - choices[6] = "Auto (Daylight Fluorescent)"; - choices[7] = "Auto (Day White Fluorescent)"; - choices[8] = "Auto (White Fluorescent)"; - choices[10] = "Auto (Cloudy)"; - choices[65534] = "Unknown"; - choices[65535] = "User-Selected"; - } -}; -PAWhiteBalanceModeInterpreter paWhiteBalanceModeInterpreter; - -class PASaturationInterpreter : public ChoiceInterpreter<> -{ -public: - PASaturationInterpreter () - { - choices[0] = "-2 (low)"; - choices[1] = "0 (normal)"; - choices[2] = "+2 (high)"; - choices[3] = "-1 (med low)"; - choices[4] = "+1 (med high)"; - choices[5] = "-3 (very low)"; - choices[6] = "+3 (very high)"; - choices[7] = "-4 (minimum)"; - choices[8] = "+4 (maximum)"; - choices[65535] = "None"; - } -}; -PASaturationInterpreter paSaturationInterpreter; - -class PAContrastInterpreter : public ChoiceInterpreter<> -{ -public: - PAContrastInterpreter () - { - choices[0] = "-2 (low)"; - choices[1] = "0 (normal)"; - choices[2] = "+2 (high)"; - choices[3] = "-1 (med low)"; - choices[4] = "+1 (med high)"; - choices[5] = "-3 (very low)"; - choices[6] = "+3 (very high)"; - choices[7] = "-4 (minimum)"; - choices[8] = "+4 (maximum)"; - choices[65535] = "n/a"; - } -}; -PAContrastInterpreter paContrastInterpreter; - -class PASharpnessInterpreter : public ChoiceInterpreter<> -{ -public: - PASharpnessInterpreter () - { - choices[0] = "-2 (soft)"; - choices[1] = "0 (normal)"; - choices[2] = "+2 (hard)"; - choices[3] = "-1 (med soft)"; - choices[4] = "+1 (med hard)"; - choices[5] = "-3 (very soft)"; - choices[6] = "+3 (very hard)"; - choices[7] = "-4 (minimum)"; - choices[8] = "+4 (maximum)"; - } -}; -PASharpnessInterpreter paSharpnessInterpreter; - -class PAPictureModeInterpreter2: public ChoiceInterpreter<> -{ -public: - PAPictureModeInterpreter2() - { - choices[256 * 0 + 0] = "Program"; - choices[256 * 0 + 1] = "Hi-speed Program"; - choices[256 * 0 + 2] = "DOF Program"; - choices[256 * 0 + 3] = "MTF Program"; - choices[256 * 0 + 4] = "Standard"; - choices[256 * 0 + 5] = "Portrait"; - choices[256 * 0 + 6] = "Landscape"; - choices[256 * 0 + 7] = "Macro"; - choices[256 * 0 + 8] = "Sport"; - choices[256 * 0 + 9] = "Night Scene Portrait"; - choices[256 * 0 + 10] = "No Flash"; - choices[256 * 0 + 11] = "Night Scene"; - choices[256 * 0 + 12] = "Surf & Snow"; - choices[256 * 0 + 13] = "Text"; - choices[256 * 0 + 14] = "Sunset"; - choices[256 * 0 + 15] = "Kids"; - choices[256 * 0 + 16] = "Pet"; - choices[256 * 0 + 17] = "Candlelight"; - choices[256 * 0 + 18] = "Museum"; - choices[256 * 0 + 19] = "Food"; - choices[256 * 0 + 20] = "Stage Lighting"; - choices[256 * 0 + 21] = "Night Snap"; - choices[256 * 0 + 23] = "Blue Sky"; - choices[256 * 0 + 24] = "Sunset"; - choices[256 * 0 + 26] = "Night Scene HDR"; - choices[256 * 0 + 27] = "HDR"; - choices[256 * 0 + 28] = "Quick Macro"; - choices[256 * 0 + 29] = "Forest"; - choices[256 * 0 + 30] = "Backlight Silhouette"; - choices[256 * 1 + 4] = "Auto PICT (Standard)"; - choices[256 * 1 + 5] = "Auto PICT (Portrait)"; - choices[256 * 1 + 6] = "Auto PICT (Landscape)"; - choices[256 * 1 + 7] = "Auto PICT (Macro)"; - choices[256 * 1 + 8] = "Auto PICT (Sport)"; - choices[256 * 2 + 0] = "Program (HyP)"; - choices[256 * 2 + 1] = "Hi-speed Program (HyP)"; - choices[256 * 2 + 2] = "DOF Program (HyP)"; - choices[256 * 2 + 3] = "MTF Program (HyP)"; - choices[256 * 2 + 22] = "Shallow DOF (HyP)"; - choices[256 * 3 + 0] = "Green Mode"; - choices[256 * 4 + 0] = "Shutter Speed Priority"; - choices[256 * 5 + 0] = "Aperture Priority"; - choices[256 * 6 + 0] = "Program Tv Shift"; - choices[256 * 7 + 0] = "Program Av Shift"; - choices[256 * 8 + 0] = "Manual"; - choices[256 * 9 + 0] = "Bulb"; - choices[256 * 10 + 0] = "Aperture Priority, Off-Auto-Aperture"; - choices[256 * 11 + 0] = "Manual, Off-Auto-Aperture"; - choices[256 * 12 + 0] = "Bulb, Off-Auto-Aperture"; - choices[256 * 13 + 0] = "Shutter & Aperture Priority AE"; - choices[256 * 15 + 0] = "Sensitivity Priority AE"; - choices[256 * 16 + 0] = "Flash X-Sync Speed AE"; - choices[256 * 18 + 0] = "Auto Program (Normal)"; - choices[256 * 18 + 1] = "Auto Program (Hi-speed)"; - choices[256 * 18 + 2] = "Auto Program (DOF)"; - choices[256 * 18 + 3] = "Auto Program (MTF)"; - choices[256 * 18 + 22] = "Auto Program (Shallow DOF)"; - choices[256 * 20 + 22] = "Blur Control"; - choices[256 * 254 + 0] = "Video"; - choices[256 * 255 + 0] = "Video (Auto Aperture)"; - choices[256 * 255 + 4] = "Video (4)"; - } - std::string toString (const Tag* t) const override - { - int c = 256 * t->toInt (0, BYTE) + t->toInt (1, BYTE); - const ChoicesIterator r = choices.find (c); - - if (r != choices.end()) { - std::ostringstream s; - s << r->second; - - if ( t->toInt (1, BYTE) == 0 ) { - s << "\n1/2 EV steps"; - } else { - s << "\n1/3 EV steps"; - } - - return s.str(); - } else { - char buffer[1024]; - t->toString (buffer); - return std::string (buffer); - } - } -}; -PAPictureModeInterpreter2 paPictureModeInterpreter2; - -class PADriveModeInterpreter : public ChoiceInterpreter<> -{ - std::map choices1; - std::map choices2; - std::map choices3; -public: - PADriveModeInterpreter() - { - choices[0] = "Single-frame"; - choices[1] = "Continuous"; - choices[2] = "Continuous (Lo)"; - choices[3] = "Burst"; - choices[4] = "Continuous (Medium)"; - choices[255] = "Video"; - choices1[0] = "No Timer"; - choices1[1] = "Self-timer (12 s)"; - choices1[2] = "Self-timer (2 s)"; - choices1[15] = "Video"; - choices1[16] = "Mirror Lock-up"; - choices1[255] = "n/a"; - choices2[0] = "Shutter Button"; - choices2[1] = "Remote Control (3 s delay)"; - choices2[2] = "Remote Control"; - choices2[4] = "Remote Continuous Shooting"; - choices3[0] = "Single Exposure"; - choices3[1] = "Multiple Exposure"; - choices3[15] = "Interval Movie"; - choices3[16] = "HDR"; - choices3[32] = "HDR Strong 1"; - choices3[48] = "HDR Strong 2"; - choices3[64] = "HDR Strong 3"; - choices3[224] = "HDR Auto"; - choices3[255] = "Video"; - } - std::string toString (const Tag* t) const override - { - const ChoicesIterator r = choices.find (t->toInt (0, BYTE)); - std::map::const_iterator r1 = choices1.find (t->toInt (1, BYTE)); - std::map::const_iterator r2 = choices2.find (t->toInt (2, BYTE)); - std::map::const_iterator r3 = choices3.find (t->toInt (3, BYTE)); - std::ostringstream s; - s << ((r != choices.end()) ? r->second : ""); - s << ((r1 != choices1.end()) ? r1->second : "") << " "; - s << ((r2 != choices2.end()) ? r2->second : "") << " "; - s << ((r3 != choices3.end()) ? r3->second : "") << " "; - return s.str(); - } -}; -PADriveModeInterpreter paDriveModeInterpreter; - -class PAColorSpaceInterpreter: public ChoiceInterpreter<> -{ -public: - PAColorSpaceInterpreter() - { - choices[0] = "sRGB"; - choices[1] = "Adobe RGB"; - } -}; -PAColorSpaceInterpreter paColorSpaceInterpreter; - -class PALensTypeInterpreter : public IntLensInterpreter< int > -{ -public: - PALensTypeInterpreter () - { - choices.insert (p_t (256 * 0 + 0, "M-42 or No Lens")); - choices.insert (p_t (256 * 1 + 0, "K or M Lens")); - choices.insert (p_t (256 * 2 + 0, "A Series Lens")); - choices.insert (p_t (256 * 3 + 0, "Sigma")); - choices.insert (p_t (256 * 3 + 17, "smc PENTAX-FA SOFT 85mm f/2.8")); - choices.insert (p_t (256 * 3 + 18, "smc PENTAX-F 1.7X AF ADAPTER")); - choices.insert (p_t (256 * 3 + 19, "smc PENTAX-F 24-50mm f/4")); - choices.insert (p_t (256 * 3 + 20, "smc PENTAX-F 35-80mm f/4-5.6")); - choices.insert (p_t (256 * 3 + 21, "smc PENTAX-F 80-200mm f/4.7-5.6")); - choices.insert (p_t (256 * 3 + 22, "smc PENTAX-F FISH-EYE 17-28mm f/3.5-4.5")); - choices.insert (p_t (256 * 3 + 23, "smc PENTAX-F 100-300mm f/4.5-5.6 or Sigma Lens")); - choices.insert (p_t (256 * 3 + 23, "Sigma AF 28-300mm f/3.5-5.6 DL IF")); - choices.insert (p_t (256 * 3 + 23, "Sigma AF 28-300mm f/3.5-6.3 DG IF Macro")); - choices.insert (p_t (256 * 3 + 23, "Tokina 80-200mm f/2.8 ATX-Pro")); - choices.insert (p_t (256 * 3 + 24, "smc PENTAX-F 35-135mm f/3.5-4.5")); - choices.insert (p_t (256 * 3 + 25, "smc PENTAX-F 35-105mm f/4-5.6 or Sigma or Tokina Lens")); - choices.insert (p_t (256 * 3 + 25, "Sigma 55-200mm f/4-5.6 DC")); - choices.insert (p_t (256 * 3 + 25, "Sigma AF 28-300mm f/3.5-5.6 DL IF")); - choices.insert (p_t (256 * 3 + 25, "Sigma AF 28-300mm f/3.5-6.3 DL IF")); - choices.insert (p_t (256 * 3 + 25, "Sigma AF 28-300mm f/3.5-6.3 DG IF Macro")); - choices.insert (p_t (256 * 3 + 25, "Tokina 80-200mm f/2.8 ATX-Pro")); - choices.insert (p_t (256 * 3 + 26, "smc PENTAX-F* 250-600mm f/5.6 ED[IF]")); - choices.insert (p_t (256 * 3 + 27, "smc PENTAX-F 28-80mm f/3.5-4.5 or Tokina Lens")); - choices.insert (p_t (256 * 3 + 27, "Tokina AT-X Pro AF 28-70mm f/2.6-2.8")); - choices.insert (p_t (256 * 3 + 28, "smc PENTAX-F 35-70mm f/3.5-4.5 or Tokina Lens")); - choices.insert (p_t (256 * 3 + 28, "Tokina 19-35mm f/3.5-4.5 AF")); - choices.insert (p_t (256 * 3 + 28, "Tokina AT-X AF 400mm f/5.6")); - choices.insert (p_t (256 * 3 + 29, "PENTAX-F 28-80mm f/3.5-4.5 or Sigma or Tokina Lens")); - choices.insert (p_t (256 * 3 + 29, "Sigma AF 18-125mm f/3.5-5.6 DC")); - choices.insert (p_t (256 * 3 + 29, "Tokina AT-X PRO 28-70mm f/2.6-2.8")); - choices.insert (p_t (256 * 3 + 30, "PENTAX-F 70-200mm f/4-5.6")); - choices.insert (p_t (256 * 3 + 31, "smc PENTAX-F 70-210mm f/4-5.6 or Tokina or Takumar Lens")); - choices.insert (p_t (256 * 3 + 31, "Tokina AF 730 75-300mm f/4.5-5.6")); - choices.insert (p_t (256 * 3 + 31, "Takumar-F 70-210mm f/4-5.6")); - choices.insert (p_t (256 * 3 + 32, "smc PENTAX-F 50mm f/1.4")); - choices.insert (p_t (256 * 3 + 33, "smc PENTAX-F 50mm f/1.7")); - choices.insert (p_t (256 * 3 + 34, "smc PENTAX-F 135mm f/2.8 [IF]")); - choices.insert (p_t (256 * 3 + 35, "smc PENTAX-F 28mm f/2.8")); - choices.insert (p_t (256 * 3 + 36, "Sigma 20mm f/1.8 EX DG Aspherical RF")); - choices.insert (p_t (256 * 3 + 38, "smc PENTAX-F* 300mm f/4.5 ED[IF]")); - choices.insert (p_t (256 * 3 + 39, "smc PENTAX-F* 600mm f/4 ED[IF]")); - choices.insert (p_t (256 * 3 + 40, "smc PENTAX-F Macro 100mm f/2.8")); - choices.insert (p_t (256 * 3 + 41, "smc PENTAX-F Macro 50mm f/2.8 or Sigma Lens")); - choices.insert (p_t (256 * 3 + 41, "Sigma 50mm f/2.8 Macro")); - choices.insert (p_t (256 * 3 + 42, "Sigma 300mm f/2.8 EX DG APO IF")); - choices.insert (p_t (256 * 3 + 44, "Sigma or Tamron Lens (3 44)")); - choices.insert (p_t (256 * 3 + 44, "Sigma AF 10-20mm f/4-5.6 EX DC")); - choices.insert (p_t (256 * 3 + 44, "Sigma 12-24mm f/4.5-5.6 EX DG")); - choices.insert (p_t (256 * 3 + 44, "Sigma 17-70mm f/2.8-4.5 DC Macro")); - choices.insert (p_t (256 * 3 + 44, "Sigma 18-50mm f/3.5-5.6 DC")); - choices.insert (p_t (256 * 3 + 44, "Sigma 17-35mm f/2.8-4 EX DG")); - choices.insert (p_t (256 * 3 + 44, "Tamron 35-90mm f/4 AF")); - choices.insert (p_t (256 * 3 + 44, "Sigma AF 18-35mm f/3.5-4.5 Aspherical")); - choices.insert (p_t (256 * 3 + 46, "Sigma or Samsung Lens (3 46)")); - choices.insert (p_t (256 * 3 + 46, "Sigma APO 70-200mm f/2.8 EX")); - choices.insert (p_t (256 * 3 + 46, "Sigma EX APO 100-300mm f/4 IF")); - choices.insert (p_t (256 * 3 + 46, "Samsung/Schneider D-XENON 50-200mm f/4-5.6 ED")); - choices.insert (p_t (256 * 3 + 50, "smc PENTAX-FA 28-70mm f/4 AL")); - choices.insert (p_t (256 * 3 + 51, "Sigma 28mm f/1.8 EX DG Aspherical Macro")); - choices.insert (p_t (256 * 3 + 52, "smc PENTAX-FA 28-200mm f/3.8-5.6 AL[IF] or Tamron Lens")); - choices.insert (p_t (256 * 3 + 52, "Tamron AF LD 28-200mm f/3.8-5.6 [IF] Aspherical (171D)")); - choices.insert (p_t (256 * 3 + 53, "smc PENTAX-FA 28-80mm f/3.5-5.6 AL")); - choices.insert (p_t (256 * 3 + 247, "smc PENTAX-DA FISH-EYE 10-17mm f/3.5-4.5 ED[IF]")); - choices.insert (p_t (256 * 3 + 248, "smc PENTAX-DA 12-24mm f/4 ED AL[IF]")); - choices.insert (p_t (256 * 3 + 250, "smc PENTAX-DA 50-200mm f/4-5.6 ED")); - choices.insert (p_t (256 * 3 + 251, "smc PENTAX-DA 40mm f/2.8 Limited")); - choices.insert (p_t (256 * 3 + 252, "smc PENTAX-DA 18-55mm f/3.5-5.6 AL")); - choices.insert (p_t (256 * 3 + 253, "smc PENTAX-DA 14mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 3 + 254, "smc PENTAX-DA 16-45mm f/4 ED AL")); - choices.insert (p_t (256 * 3 + 255, "Sigma Lens (3 255)")); - choices.insert (p_t (256 * 3 + 255, "Sigma 18-200mm f/3.5-6.3 DC")); - choices.insert (p_t (256 * 3 + 255, "Sigma DL-II 35-80mm f/4-5.6")); - choices.insert (p_t (256 * 3 + 255, "Sigma DL Zoom 75-300mm f/4-5.6")); - choices.insert (p_t (256 * 3 + 255, "Sigma DF EX Aspherical 28-70mm f/2.8")); - choices.insert (p_t (256 * 3 + 255, "Sigma AF Tele 400mm f/5.6 Multi-coated")); - choices.insert (p_t (256 * 3 + 255, "Sigma 24-60mm f/2.8 EX DG")); - choices.insert (p_t (256 * 3 + 255, "Sigma 70-300mm f/4-5.6 Macro")); - choices.insert (p_t (256 * 3 + 255, "Sigma 55-200mm f/4-5.6 DC")); - choices.insert (p_t (256 * 3 + 255, "Sigma 18-50mm f/2.8 EX DC")); - choices.insert (p_t (256 * 4 + 1, "smc PENTAX-FA SOFT 28mm f/2.8")); - choices.insert (p_t (256 * 4 + 2, "smc PENTAX-FA 80-320mm f/4.5-5.6")); - choices.insert (p_t (256 * 4 + 3, "smc PENTAX-FA 43mm f/1.9 Limited")); - choices.insert (p_t (256 * 4 + 6, "smc PENTAX-FA 35-80mm f/4-5.6")); - choices.insert (p_t (256 * 4 + 9, "Irix 11mm f/4 Firefly")); - choices.insert (p_t (256 * 4 + 10, "Irix 15mm f/2.4")); - choices.insert (p_t (256 * 4 + 12, "smc PENTAX-FA 50mm f/1.4")); - choices.insert (p_t (256 * 4 + 15, "smc PENTAX-FA 28-105mm f/4-5.6 [IF]")); - choices.insert (p_t (256 * 4 + 16, "Tamron AF 80-210mm f/4-5.6 (178D)")); - choices.insert (p_t (256 * 4 + 19, "Tamron SP AF 90mm f/2.8 (172E)")); - choices.insert (p_t (256 * 4 + 20, "smc PENTAX-FA 28-80mm f/3.5-5.6")); - choices.insert (p_t (256 * 4 + 21, "Cosina AF 100-300mm f/5.6-6.7")); - choices.insert (p_t (256 * 4 + 22, "Tokina 28-80mm f/3.5-5.6")); - choices.insert (p_t (256 * 4 + 23, "smc PENTAX-FA 20-35mm f/4 AL")); - choices.insert (p_t (256 * 4 + 24, "smc PENTAX-FA 77mm f/1.8 Limited")); - choices.insert (p_t (256 * 4 + 25, "Tamron SP AF 14mm f/2.8")); - choices.insert (p_t (256 * 4 + 26, "smc PENTAX-FA Macro 100mm f/3.5 or Cosina Lens")); - choices.insert (p_t (256 * 4 + 26, "Cosina 100mm f/3.5 Macro")); - choices.insert (p_t (256 * 4 + 27, "Tamron AF 28-300mm f/3.5-6.3 LD Aspherical[IF] Macro (185D/285D)")); - choices.insert (p_t (256 * 4 + 28, "smc PENTAX-FA 35mm f/2 AL")); - choices.insert (p_t (256 * 4 + 29, "Tamron AF 28-200mm f/3.8-5.6 LD Super II Macro (371D)")); - choices.insert (p_t (256 * 4 + 34, "smc PENTAX-FA 24-90mm f/3.5-4.5 AL[IF]")); - choices.insert (p_t (256 * 4 + 35, "smc PENTAX-FA 100-300mm f/4.7-5.8")); - choices.insert (p_t (256 * 4 + 36, "Tamron AF 70-300mm f/4-5.6 LD Macro 1:2")); - choices.insert (p_t (256 * 4 + 37, "Tamron SP AF 24-135mm f/3.5-5.6 AD AL (190D)")); - choices.insert (p_t (256 * 4 + 38, "smc PENTAX-FA 28-105mm f/3.2-4.5 AL[IF]")); - choices.insert (p_t (256 * 4 + 39, "smc PENTAX-FA 31mm f/1.8 AL Limited")); - choices.insert (p_t (256 * 4 + 41, "Tamron AF 28-200mm Super Zoom f/3.8-5.6 Aspherical XR [IF] Macro (A03)")); - choices.insert (p_t (256 * 4 + 43, "smc PENTAX-FA 28-90mm f/3.5-5.6")); - choices.insert (p_t (256 * 4 + 44, "smc PENTAX-FA J 75-300mm f/4.5-5.8 AL")); - choices.insert (p_t (256 * 4 + 45, "Tamron Lens (4 45)")); - choices.insert (p_t (256 * 4 + 45, "Tamron 28-300mm f/3.5-6.3 Ultra zoom XR")); - choices.insert (p_t (256 * 4 + 45, "Tamron AF 28-300mm f/3.5-6.3 XR Di LD Aspherical [IF] Macro")); - choices.insert (p_t (256 * 4 + 46, "smc PENTAX-FA J 28-80mm f/3.5-5.6 AL")); - choices.insert (p_t (256 * 4 + 47, "smc PENTAX-FA J 18-35mm f/4-5.6 AL")); - choices.insert (p_t (256 * 4 + 49, "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro")); - choices.insert (p_t (256 * 4 + 51, "smc PENTAX-D FA 50mm f/2.8 Macro")); - choices.insert (p_t (256 * 4 + 52, "smc PENTAX-D FA 100mm f/2.8 Macro")); - choices.insert (p_t (256 * 4 + 55, "Samsung/Schneider D-XENOGON 35mm f/2")); - choices.insert (p_t (256 * 4 + 56, "Samsung/Schneider D-XENON 100mm f/2.8 Macro")); - choices.insert (p_t (256 * 4 + 75, "Tamron SP AF 70-200mm f/2.8 Di LD [IF] Macro (A001)")); - choices.insert (p_t (256 * 4 + 214, "smc PENTAX-DA 35mm f/2.4 AL")); - choices.insert (p_t (256 * 4 + 229, "smc PENTAX-DA 18-55mm f/3.5-5.6 AL II")); - choices.insert (p_t (256 * 4 + 230, "Tamron SP AF 17-50mm f/2.8 XR Di II")); - choices.insert (p_t (256 * 4 + 231, "smc PENTAX-DA 18-250mm f/3.5-6.3 ED AL [IF]")); - choices.insert (p_t (256 * 4 + 237, "Samsung/Schneider D-XENOGON 10-17mm f/3.5-4.5")); - choices.insert (p_t (256 * 4 + 239, "Samsung/Schneider D-XENON 12-24mm f/4 ED AL [IF]")); - choices.insert (p_t (256 * 4 + 242, "smc PENTAX-DA* 16-50mm f/2.8 ED AL [IF] SDM (SDM unused)")); - choices.insert (p_t (256 * 4 + 243, "smc PENTAX-DA 70mm f/2.4 Limited")); - choices.insert (p_t (256 * 4 + 244, "smc PENTAX-DA 21mm f/3.2 AL Limited")); - choices.insert (p_t (256 * 4 + 245, "Samsung/Schneider D-XENON 50-200mm f/4-5.6")); - choices.insert (p_t (256 * 4 + 246, "Samsung/Schneider D-XENON 18-55mm f/3.5-5.6")); - choices.insert (p_t (256 * 4 + 247, "smc PENTAX-DA FISH-EYE 10-17mm f/3.5-4.5 ED[IF]")); - choices.insert (p_t (256 * 4 + 248, "smc PENTAX-DA 12-24mm f/4 ED AL [IF]")); - choices.insert (p_t (256 * 4 + 249, "Tamron XR DiII 18-200mm f/3.5-6.3 (A14)")); - choices.insert (p_t (256 * 4 + 250, "smc PENTAX-DA 50-200mm f/4-5.6 ED")); - choices.insert (p_t (256 * 4 + 251, "smc PENTAX-DA 40mm f/2.8 Limited")); - choices.insert (p_t (256 * 4 + 252, "smc PENTAX-DA 18-55mm f/3.5-5.6 AL")); - choices.insert (p_t (256 * 4 + 253, "smc PENTAX-DA 14mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 4 + 254, "smc PENTAX-DA 16-45mm f/4 ED AL")); - choices.insert (p_t (256 * 5 + 1, "smc PENTAX-FA* 24mm f/2 AL[IF]")); - choices.insert (p_t (256 * 5 + 2, "smc PENTAX-FA 28mm f/2.8 AL")); - choices.insert (p_t (256 * 5 + 3, "smc PENTAX-FA 50mm f/1.7")); - choices.insert (p_t (256 * 5 + 4, "smc PENTAX-FA 50mm f/1.4")); - choices.insert (p_t (256 * 5 + 5, "smc PENTAX-FA* 600mm f/4 ED[IF]")); - choices.insert (p_t (256 * 5 + 6, "smc PENTAX-FA* 300mm f/4.5 ED[IF]")); - choices.insert (p_t (256 * 5 + 7, "smc PENTAX-FA 135mm f/2.8 [IF]")); - choices.insert (p_t (256 * 5 + 8, "smc PENTAX-FA Macro 50mm f/2.8")); - choices.insert (p_t (256 * 5 + 9, "smc PENTAX-FA Macro 100mm f/2.8")); - choices.insert (p_t (256 * 5 + 10, "smc PENTAX-FA* 85mm f/1.4 [IF]")); - choices.insert (p_t (256 * 5 + 11, "smc PENTAX-FA* 200mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 5 + 12, "smc PENTAX-FA 28-80mm f/3.5-4.7")); - choices.insert (p_t (256 * 5 + 13, "smc PENTAX-FA 70-200mm f/4-5.6")); - choices.insert (p_t (256 * 5 + 14, "smc PENTAX-FA* 250-600mm f/5.6 ED[IF]")); - choices.insert (p_t (256 * 5 + 15, "smc PENTAX-FA 28-105mm f/4-5.6")); - choices.insert (p_t (256 * 5 + 16, "smc PENTAX-FA 100-300mm f/4.5-5.6")); - choices.insert (p_t (256 * 5 + 98, "smc PENTAX-FA 100-300mm f/4.5-5.6")); - choices.insert (p_t (256 * 6 + 1, "smc PENTAX-FA* 85mm f/1.4 [IF]")); - choices.insert (p_t (256 * 6 + 2, "smc PENTAX-FA* 200mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 6 + 3, "smc PENTAX-FA* 300mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 6 + 4, "smc PENTAX-FA* 28-70mm f/2.8 AL")); - choices.insert (p_t (256 * 6 + 5, "smc PENTAX-FA* 80-200mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 6 + 6, "smc PENTAX-FA* 28-70mm f/2.8 AL")); - choices.insert (p_t (256 * 6 + 7, "smc PENTAX-FA* 80-200mm f/2.8 ED[IF]")); - choices.insert (p_t (256 * 6 + 8, "smc PENTAX-FA 28-70mm f/4AL")); - choices.insert (p_t (256 * 6 + 9, "smc PENTAX-FA 20mm f/2.8")); - choices.insert (p_t (256 * 6 + 10, "smc PENTAX-FA* 400mm f/5.6 ED[IF]")); - choices.insert (p_t (256 * 6 + 13, "smc PENTAX-FA* 400mm f/5.6 ED[IF]")); - choices.insert (p_t (256 * 6 + 14, "smc PENTAX-FA* Macro 200mm f/4 ED[IF]")); - choices.insert (p_t (256 * 7 + 0, "smc PENTAX-DA 21mm f/3.2 AL Limited")); - choices.insert (p_t (256 * 7 + 58, "smc PENTAX-D FA Macro 100mm f/2.8 WR")); - choices.insert (p_t (256 * 7 + 75, "Tamron SP AF 70-200mm f/2.8 Di LD [IF] Macro (A001)")); - choices.insert (p_t (256 * 7 + 201, "smc Pentax-DA L 50-200mm f/4-5.6 ED WR")); - choices.insert (p_t (256 * 7 + 202, "smc PENTAX-DA L 18-55mm f/3.5-5.6 AL WR")); - choices.insert (p_t (256 * 7 + 203, "HD PENTAX-DA 55-300mm f/4-5.8 ED WR")); - choices.insert (p_t (256 * 7 + 204, "HD PENTAX-DA 15mm f/4 ED AL Limited")); - choices.insert (p_t (256 * 7 + 205, "HD PENTAX-DA 35mm f/2.8 Macro Limited")); - choices.insert (p_t (256 * 7 + 206, "HD PENTAX-DA 70mm f/2.4 Limited")); - choices.insert (p_t (256 * 7 + 207, "HD PENTAX-DA 21mm f/3.2 ED AL Limited")); - choices.insert (p_t (256 * 7 + 208, "HD PENTAX-DA 40mm f/2.8 Limited")); - choices.insert (p_t (256 * 7 + 212, "smc PENTAX-DA 50mm f/1.8")); - choices.insert (p_t (256 * 7 + 213, "smc PENTAX-DA 40mm f/2.8 XS")); - choices.insert (p_t (256 * 7 + 214, "smc PENTAX-DA 35mm f/2.4 AL")); - choices.insert (p_t (256 * 7 + 216, "smc PENTAX-DA L 55-300mm f/4-5.8 ED")); - choices.insert (p_t (256 * 7 + 217, "smc PENTAX-DA 50-200mm f/4-5.6 ED WR")); - choices.insert (p_t (256 * 7 + 218, "smc PENTAX-DA 18-55mm f/3.5-5.6 AL WR")); - choices.insert (p_t (256 * 7 + 220, "Tamron SP AF 10-24mm f/3.5-4.5 Di II LD Aspherical [IF]")); - choices.insert (p_t (256 * 7 + 221, "smc PENTAX-DA L 50-200mm f/4-5.6 ED")); - choices.insert (p_t (256 * 7 + 222, "smc PENTAX-DA L 18-55mm f/3.5-5.6")); - choices.insert (p_t (256 * 7 + 223, "Samsung/Schneider D-XENON 18-55mm f/3.5-5.6 II")); - choices.insert (p_t (256 * 7 + 224, "smc PENTAX-DA 15mm f/4 ED AL Limited")); - choices.insert (p_t (256 * 7 + 225, "Samsung/Schneider D-XENON 18-250mm f/3.5-6.3")); - choices.insert (p_t (256 * 7 + 226, "smc PENTAX-DA* 55mm f/1.4 SDM (SDM unused)")); - choices.insert (p_t (256 * 7 + 227, "smc PENTAX-DA* 60-250mm f/4 [IF] SDM (SDM unused)")); - choices.insert (p_t (256 * 7 + 228, "Samsung 16-45mm f/4 ED")); - choices.insert (p_t (256 * 7 + 229, "smc PENTAX-DA 18-55mm f/3.5-5.6 AL II")); - choices.insert (p_t (256 * 7 + 230, "Tamron AF 17-50mm f/2.8 XR Di-II LD (Model A16)")); - choices.insert (p_t (256 * 7 + 231, "smc PENTAX-DA 18-250mm f/3.5-6.3 ED AL [IF]")); - choices.insert (p_t (256 * 7 + 233, "smc PENTAX-DA 35mm f/2.8 Macro Limited")); - choices.insert (p_t (256 * 7 + 234, "smc PENTAX-DA* 300mm f/4 ED [IF] SDM (SDM unused)")); - choices.insert (p_t (256 * 7 + 235, "smc PENTAX-DA* 200mm f/2.8 ED [IF] SDM (SDM unused)")); - choices.insert (p_t (256 * 7 + 236, "smc PENTAX-DA 55-300mm f/4-5.8 ED")); - choices.insert (p_t (256 * 7 + 238, "Tamron AF 18-250mm f/3.5-6.3 Di II LD Aspherical [IF] Macro")); - choices.insert (p_t (256 * 7 + 241, "smc PENTAX-DA* 50-135mm f/2.8 ED [IF] SDM (SDM unused)")); - choices.insert (p_t (256 * 7 + 242, "smc PENTAX-DA* 16-50mm f/2.8 ED AL [IF] SDM (SDM unused)")); - choices.insert (p_t (256 * 7 + 243, "smc PENTAX-DA 70mm f/2.4 Limited")); - choices.insert (p_t (256 * 7 + 244, "smc PENTAX-DA 21mm f/3.2 AL Limited")); - choices.insert (p_t (256 * 8 + 0, "Sigma 50-150mm f/2.8 II APO EX DC HSM")); - choices.insert (p_t (256 * 8 + 3, "Sigma AF 18-125mm f/3.5-5.6 DC")); - choices.insert (p_t (256 * 8 + 4, "Sigma 50mm f/1.4 EX DG HSM")); - choices.insert (p_t (256 * 8 + 7, "Sigma 24-70mm f/2.8 IF EX DG HSM")); - choices.insert (p_t (256 * 8 + 8, "Sigma 18-250mm f/3.5-6.3 DC OS HSM")); - choices.insert (p_t (256 * 8 + 11, "Sigma 10-20mm f/3.5 EX DC HSM")); - choices.insert (p_t (256 * 8 + 12, "Sigma 70-300mm f/4-5.6 DG OS")); - choices.insert (p_t (256 * 8 + 13, "Sigma 120-400mm f/4.5-5.6 APO DG OS HSM")); - choices.insert (p_t (256 * 8 + 14, "Sigma 17-70mm f/2.8-4.0 DC Macro OS HSM")); - choices.insert (p_t (256 * 8 + 15, "Sigma 150-500mm f/5-6.3 APO DG OS HSM")); - choices.insert (p_t (256 * 8 + 16, "Sigma 70-200mm f/2.8 EX DG Macro HSM II")); - choices.insert (p_t (256 * 8 + 17, "Sigma 50-500mm f/4.5-6.3 DG OS HSM")); - choices.insert (p_t (256 * 8 + 18, "Sigma 8-16mm f/4.5-5.6 DC HSM")); - choices.insert (p_t (256 * 8 + 21, "Sigma 17-50mm f/2.8 EX DC OS HSM")); - choices.insert (p_t (256 * 8 + 22, "Sigma 85mm f/1.4 EX DG HSM")); - choices.insert (p_t (256 * 8 + 23, "Sigma 70-200mm f/2.8 APO EX DG OS HSM")); - choices.insert (p_t (256 * 8 + 25, "Sigma 17-50mm f/2.8 EX DC HSM")); - choices.insert (p_t (256 * 8 + 27, "Sigma 18-200mm f/3.5-6.3 II DC HSM")); - choices.insert (p_t (256 * 8 + 28, "Sigma 18-250mm f/3.5-6.3 DC Macro HSM")); - choices.insert (p_t (256 * 8 + 29, "Sigma 35mm f/1.4 DG HSM")); - choices.insert (p_t (256 * 8 + 30, "Sigma 17-70mm f/2.8-4 DC Macro HSM | C")); - choices.insert (p_t (256 * 8 + 31, "Sigma 18-35mm f/1.8 DC HSM")); - choices.insert (p_t (256 * 8 + 32, "Sigma 30mm f/1.4 DC HSM | A")); - choices.insert (p_t (256 * 8 + 33, "Sigma 18-200mm f/3.5-6.3 DC Macro HSM")); - choices.insert (p_t (256 * 8 + 34, "Sigma 18-300mm f/3.5-6.3 DC Macro HSM")); - choices.insert (p_t (256 * 8 + 59, "HD PENTAX-D FA 150-450mm f/4.5-5.6 ED DC AW")); - choices.insert (p_t (256 * 8 + 60, "HD PENTAX-D FA* 70-200mm f/2.8 ED DC AW")); - choices.insert (p_t (256 * 8 + 61, "HD PENTAX-D FA 28-105mm f/3.5-5.6 ED DC WR")); - choices.insert (p_t (256 * 8 + 62, "HD PENTAX-D FA 24-70mm f/2.8 ED SDM WR")); - choices.insert (p_t (256 * 8 + 63, "HD PENTAX-D FA 15-30mm f/2.8 ED SDM WR")); - choices.insert (p_t (256 * 8 + 64, "HD PENTAX-D FA* 50mm f/1.4 SDM AW")); - choices.insert (p_t (256 * 8 + 197, "HD PENTAX-DA 55-300mm f/4.5-6.3 ED PLM WR RE")); - choices.insert (p_t (256 * 8 + 198, "smc PENTAX-DA L 18-50mm f/4-5.6 DC WR RE")); - choices.insert (p_t (256 * 8 + 199, "HD PENTAX-DA 18-50mm f/4-5.6 DC WR RE")); - choices.insert (p_t (256 * 8 + 200, "HD PENTAX-DA 16-85mm f/3.5-5.6 ED DC WR")); - choices.insert (p_t (256 * 8 + 209, "HD PENTAX-DA 20-40mm f/2.8-4 ED Limited DC WR")); - choices.insert (p_t (256 * 8 + 210, "smc PENTAX-DA 18-270mm f/3.5-6.3 ED SDM")); - choices.insert (p_t (256 * 8 + 211, "HD PENTAX-DA 560mm f/5.6 ED AW")); - choices.insert (p_t (256 * 8 + 215, "smc PENTAX-DA 18-135mm f/3.5-5.6 ED AL [IF] DC WR")); - choices.insert (p_t (256 * 8 + 226, "smc PENTAX-DA* 55mm f/1.4 SDM")); - choices.insert (p_t (256 * 8 + 227, "smc PENTAX-DA* 60-250mm f/4 [IF] SDM")); - choices.insert (p_t (256 * 8 + 232, "smc PENTAX-DA 17-70mm f/4 AL [IF] SDM")); - choices.insert (p_t (256 * 8 + 234, "smc PENTAX-DA* 300mm f/4 ED [IF] SDM")); - choices.insert (p_t (256 * 8 + 235, "smc PENTAX-DA* 200mm f/2.8 ED [IF] SDM")); - choices.insert (p_t (256 * 8 + 241, "smc PENTAX-DA* 50-135mm f/2.8 ED [IF] SDM")); - choices.insert (p_t (256 * 8 + 242, "smc PENTAX-DA* 16-50mm f/2.8 ED AL [IF] SDM")); - choices.insert (p_t (256 * 8 + 255, "Sigma Lens (8 255)")); - choices.insert (p_t (256 * 8 + 255, "Sigma 70-200mm f/2.8 EX DG Macro HSM II")); - choices.insert (p_t (256 * 8 + 255, "Sigma 150-500mm f/5-6.3 DG APO [OS] HSM")); - choices.insert (p_t (256 * 8 + 255, "Sigma 50-150mm f/2.8 II APO EX DC HSM")); - choices.insert (p_t (256 * 8 + 255, "Sigma 4.5mm f/2.8 EX DC HSM Circular Fisheye")); - choices.insert (p_t (256 * 8 + 255, "Sigma 50-200mm f/4-5.6 DC OS")); - choices.insert (p_t (256 * 8 + 255, "Sigma 24-70mm f/2.8 EX DG HSM")); - choices.insert (p_t (256 * 9 + 0, "645 Manual Lens")); - choices.insert (p_t (256 * 10 + 0, "645 A Series Lens")); - choices.insert (p_t (256 * 11 + 1, "smc PENTAX-FA 645 75mm f/2.8")); - choices.insert (p_t (256 * 11 + 2, "smc PENTAX-FA 645 45mm f/2.8")); - choices.insert (p_t (256 * 11 + 3, "smc PENTAX-FA* 645 300mm f/4 ED [IF]")); - choices.insert (p_t (256 * 11 + 4, "smc PENTAX-FA 645 45-85mm f/4.5")); - choices.insert (p_t (256 * 11 + 5, "smc PENTAX-FA 645 400mm f/5.6 ED [IF]")); - choices.insert (p_t (256 * 11 + 7, "smc PENTAX-FA 645 Macro 120mm f/4")); - choices.insert (p_t (256 * 11 + 8, "smc PENTAX-FA 645 80-160mm f/4.5")); - choices.insert (p_t (256 * 11 + 9, "smc PENTAX-FA 645 200mm f/4 [IF]")); - choices.insert (p_t (256 * 11 + 10, "smc PENTAX-FA 645 150mm f/2.8 [IF]")); - choices.insert (p_t (256 * 11 + 11, "smc PENTAX-FA 645 35mm f/3.5 AL [IF]")); - choices.insert (p_t (256 * 11 + 12, "smc PENTAX-FA 645 300mm f/5.6 ED [IF]")); - choices.insert (p_t (256 * 11 + 14, "smc PENTAX-FA 645 55-110mm f/5.6")); - choices.insert (p_t (256 * 11 + 16, "smc PENTAX-FA 645 33-55mm f/4.5 AL")); - choices.insert (p_t (256 * 11 + 17, "smc PENTAX-FA 645 150-300mm f/5.6 ED [IF]")); - choices.insert (p_t (256 * 11 + 21, "HD PENTAX-D FA 645 35mm f/3.5 AL [IF]")); - choices.insert (p_t (256 * 13 + 18, "smc PENTAX-D FA 645 55mm f/2.8 AL [IF] SDM AW")); - choices.insert (p_t (256 * 13 + 19, "smc PENTAX-D FA 645 25mm f/4 AL [IF] SDM AW")); - choices.insert (p_t (256 * 13 + 20, "HD PENTAX-D FA 645 90mm f/2.8 ED AW SR")); - choices.insert (p_t (256 * 13 + 253, "HD PENTAX-DA 645 28-45mm f/4.5 ED AW SR")); - choices.insert (p_t (256 * 13 + 254, "smc PENTAX-DA 645 25mm f/4 AL [IF] SDM AW")); - choices.insert (p_t (256 * 21 + 0, "Pentax Q Manual Lens")); - choices.insert (p_t (256 * 21 + 1, "01 Standard Prime 8.5mm f/1.9")); - choices.insert (p_t (256 * 21 + 2, "02 Standard Zoom 5-15mm f/2.8-4.5")); - choices.insert (p_t (256 * 21 + 6, "06 Telephoto Zoom 15-45mm f/2.8")); - choices.insert (p_t (256 * 21 + 7, "07 Mount Shield 11.5mm f/9")); - choices.insert (p_t (256 * 21 + 8, "08 Wide Zoom 3.8-5.9mm f/3.7-4")); - choices.insert (p_t (256 * 21 + 233, "Adapter Q for K-mount Lens")); - choices.insert (p_t (256 * 22 + 3, "03 Fish-eye 3.2mm f/5.6")); - choices.insert (p_t (256 * 22 + 4, "04 Toy Lens Wide 6.3mm f/7.1")); - choices.insert (p_t (256 * 22 + 5, "05 Toy Lens Telephoto 18mm f/8")); - } - std::string toString (const Tag* t) const override - { - double *liArray = nullptr; - double maxApertureAtFocal = 0.; - double focalLength = 0.; - int lensID = 256 * t->toInt (0, BYTE) + t->toInt (1, BYTE); - TagDirectory *root = t->getParent()->getRoot(); - - if (root) { - - Tag *t1; - t1 = root->findTag ("FocalLength"); // Should get tag 0x920A (rational64u) from the standard Exif tag list - - if ( t1) { - focalLength = t1->toDouble(); // Focal Length - } - - t1 = root->findTag ("MaxAperture"); - - if (t1) { - double maxAperture = t1->toDouble(); // MaxApertureValue at focal Length - - if (maxAperture != 0.) { - maxApertureAtFocal = maxAperture; - } else { - t1 = root->findTag ("NominalMaxAperture"); - - if (t1) { - maxApertureAtFocal = t1->toDouble(); - } - } - } - - t1 = root->getTagP ("LensInfo"); - - if (t1) { - liArray = t1->toDoubleArray(); - } - - // Focal length below 10mm are set to 0 by the camera in the standard Exif tag, so we'll look into the makernotes - // This value will have decimals, which reflects more precision... or imprecision, due to the packed form of this value, who knows? - if (focalLength == 0.) { - rtexif::TagDirectory* mnote = root->findTag ("MakerNote")->getDirectory(); - rtexif::Tag* flt = mnote->getTagP ("LensInfo/FocalLength"); - - if (flt) { - focalLength = flt->toDouble (); - } else if ((flt = mnote->getTagP ("FocalLength"))) { - focalLength = flt->toDouble(); - } - } - } - - std::string retval = guess ( lensID, focalLength, maxApertureAtFocal, liArray); - - if (liArray) { - delete [] liArray; - } - - return retval; - } -}; -PALensTypeInterpreter paLensTypeInterpreter; - -class PASRResultInterpreter: public Interpreter -{ -public: - PASRResultInterpreter() { } - std::string toString (const Tag* t) const override - { - std::ostringstream str; - int b = t->toInt (0, BYTE); - - if (!b) { - str << "Not stabilized"; - } else if (b & 1) { - str << "Stabilized"; - } else if (b & 64) { - str << "Not Ready"; - } - - return str.str(); - } -}; -PASRResultInterpreter paSRResultInterpreter; - -class PAHighISONoiseInterpreter: public ChoiceInterpreter<> -{ -public: - // HighISONoiseReduction - PAHighISONoiseInterpreter() - { - choices[0] = "Off"; - choices[1] = "Weakest"; - choices[2] = "Weak"; - choices[3] = "Strong"; - choices[4] = "Medium"; - choices[255] = "Auto"; - } -}; -PAHighISONoiseInterpreter paHighISONoiseInterpreter; - -class PAMonochromeFilterEffectInterpreter: public ChoiceInterpreter<> -{ -public: - PAMonochromeFilterEffectInterpreter() - { - choices[1] = "Green"; - choices[2] = "Yellow"; - choices[3] = "Orange"; - choices[4] = "Red"; - choices[5] = "Magenta"; - choices[6] = "Blue"; - choices[7] = "Cyan"; - choices[8] = "Infrared"; - choices[65535] = "None"; - } -}; -PAMonochromeFilterEffectInterpreter paMonochromeFilterEffectInterpreter; - -class PAMonochromeToningInterpreter: public ChoiceInterpreter<> -{ -public: - PAMonochromeToningInterpreter() - { - choices[0] = "-4"; - choices[1] = "-3"; - choices[2] = "-2"; - choices[3] = "-1"; - choices[4] = "0"; - choices[5] = "1"; - choices[6] = "2"; - choices[7] = "3"; - choices[8] = "4"; - choices[65535] = "None"; - } -}; -PAMonochromeToningInterpreter paMonochromeToningInterpreter; - -class PAShadowCorrectionInterpreter: public ChoiceInterpreter<> -{ -public: - PAShadowCorrectionInterpreter() - { - choices[ 0 ] = "Off"; - choices[ 1 ] = "On"; - choices[ 2 ] = "Auto 2"; - choices[ 1 << 8 | 1 ] = "Weak"; - choices[ 1 << 8 | 2 ] = "Normal"; - choices[ 1 << 8 | 3 ] = "Strong"; - choices[ 2 << 8 | 4 ] = "Auto"; - } - - std::string toString (const Tag* t) const override - { - int idx = 0; - - if (t->getCount() == 1) { - idx = t->toInt (0, BYTE); - } else if (t->getCount() == 2) { - idx = t->toInt (0, BYTE) << 8 | t->toInt (1, BYTE); - } - - const ChoicesIterator r = choices.find (idx); - std::ostringstream s; - s << ((r != choices.end()) ? r->second : "n/a"); - return s.str(); - } -}; -PAShadowCorrectionInterpreter paShadowCorrectionInterpreter; - -class PAISOAutoParametersInterpreter: public ChoiceInterpreter<> -{ -public: - PAISOAutoParametersInterpreter() - { - choices[1] = "Slow"; - choices[2] = "Standard"; - choices[3] = "Fast"; - } - std::string toString (const Tag* t) const override - { - const ChoicesIterator r = choices.find (t->toInt (0, BYTE)); - std::ostringstream s; - s << ((r != choices.end()) ? r->second : "n/a"); - return s.str(); - } -}; -PAISOAutoParametersInterpreter paISOAutoParametersInterpreter; - -class PABleachBypassToningInterpreter: public ChoiceInterpreter<> -{ -public: - PABleachBypassToningInterpreter() - { - choices[1] = "Green"; - choices[2] = "Yellow"; - choices[3] = "Orange"; - choices[4] = "Red"; - choices[5] = "Magenta"; - choices[6] = "Purple"; - choices[7] = "Blue"; - choices[8] = "Cyan"; - choices[65535] = "Off"; - } -}; -PABleachBypassToningInterpreter paBleachBypassToningInterpreter; - -class PABlurControlInterpreter: public ChoiceInterpreter<> -{ -public: - PABlurControlInterpreter() - { - choices[0] = "Off"; - choices[1] = "Low"; - choices[2] = "Medium"; - choices[3] = "High"; - } - std::string toString (const Tag* t) const override - { - const ChoicesIterator r = choices.find (t->toInt (0, BYTE)); - std::ostringstream s; - s << ((r != choices.end()) ? r->second : "n/a"); - return s.str(); - } -}; -PABlurControlInterpreter paBlurControlInterpreter; - -class PAHDRInterpreter: public ChoiceInterpreter<> -{ - std::map choices1; - std::map choices2; -public: - PAHDRInterpreter() - { - choices[0] = "Off"; - choices[1] = "HDR Auto"; - choices[2] = "HDR 1"; - choices[3] = "HDR 2"; - choices[4] = "HDR 3"; - choices[5] = "Advanced"; - - choices1[0] = "Auto-align Off"; - choices1[1] = "Auto-align On"; - - choices2[0] = "n/a"; - choices2[4] = "1 EV"; - choices2[8] = "2 EV"; - choices2[12] = "3 EV"; - } - std::string toString (const Tag* t) const override - { - const ChoicesIterator r = choices.find (t->toInt (0, BYTE)); - std::map::const_iterator r1 = choices1.find (t->toInt (1, BYTE)); - std::map::const_iterator r2 = choices2.find (t->toInt (2, BYTE)); - std::ostringstream s; - s << ((r != choices.end() ) ? r->second : "") << std::endl; - s << ((r1 != choices1.end()) ? r1->second : "") << std::endl; - s << ((r2 != choices2.end()) ? r2->second : ""); - return s.str(); - } -}; -PAHDRInterpreter paHDRInterpreter; - -class PACrossProcessInterpreter: public ChoiceInterpreter<> -{ -public: - PACrossProcessInterpreter() - { - choices[ 0] = "Off"; - choices[ 1] = "Randow"; - choices[ 2] = "Preset 1"; - choices[ 3] = "Preset 2"; - choices[ 4] = "Preset 3"; - choices[33] = "Favorite 1"; - choices[34] = "Favorite 2"; - choices[35] = "Favorite 3"; - } -}; -PACrossProcessInterpreter paCrossProcessInterpreter; - -class PAPowerSourceInterpreter: public ChoiceInterpreter<> -{ -public: - PAPowerSourceInterpreter() - { - choices[2] = "Body Battery"; - choices[3] = "Grip Battery "; - choices[4] = "External Power Supply"; - } -}; -PAPowerSourceInterpreter paPowerSourceInterpreter; - -class PALensModelQInterpreter: public Interpreter -{ -public: - PALensModelQInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[31]; - buffer[0] = 0; // - return buffer; // TODO: how to get the string content!? - -// // normal path below (copy the content of the string), but has to be bug fixed -// memcpy (buffer, t->getValue(), 30); -// buffer[30] = 0; -// return buffer; - } -}; -PALensModelQInterpreter paLensModelQInterpreter; - -class PALensInfoQInterpreter: public Interpreter -{ -public: - PALensInfoQInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[21]; - buffer[0] = 0; - return buffer; // TODO: how to get the string content!? - -// // normal path below (copy the content of the string), but has to be bug fixed -// memcpy (buffer, t->getValue(), 20); -// buffer[20] = 0; -// return buffer; - } -}; -PALensInfoQInterpreter paLensInfoQInterpreter; - -class PAFlashExposureCompInterpreter: public Interpreter -{ -public: - PAFlashExposureCompInterpreter() {} - std::string toString (const Tag* t) const override - { - int a; - - if (t->getCount() == 1) { - a = t->toInt (0, SLONG) / 256; // int32u - } else { - a = t->toInt (0, SBYTE) / 6; // int8u[2] - } - - char buffer[32]; - sprintf (buffer, "%d", a ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a; - - if (t->getCount() == 1) { - a = t->toInt (0, SLONG) / 256; // int32u - } else { - a = t->toInt (0, SBYTE) / 6; // int8u[2] - } - - return double (a); - } -}; -PAFlashExposureCompInterpreter paFlashExposureCompInterpreter; - -class PAFocalLengthInterpreter: public Interpreter -{ -public: - PAFocalLengthInterpreter() {} - std::string toString (const Tag* t) const override - { - double a = double (t->toInt (0, LONG)); - - if (a > 1.) { - char buffer[32]; - sprintf (buffer, "%.2f", a / 100. ); - return buffer; - } else { - return "n/a"; - } - } - double toDouble (const Tag* t, int ofs) override - { - double a = double (t->toInt (0, LONG)); - - if (a > 1.) { - return a / 100.; - } else { - return 0.; - } - } -}; -PAFocalLengthInterpreter paFocalLengthInterpreter; - -class PALensDataFocalLengthInterpreter: public Interpreter -{ -public: - PALensDataFocalLengthInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, BYTE); - float b = float (10 * int (a >> 2)) * pow (4.f, float (int (a & 0x03) - 2)); - - if (b > 1.f) { - char buffer[32]; - sprintf (buffer, "%.2f", b ); - return buffer; - } else { - return "n/a"; - } - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (ofs, BYTE); - float b = float (10 * int (a >> 2)) * pow (4.f, float (int (a & 0x03) - 2)); - - if (b > 1.f) { - return b; - } else { - return 0.; - } - } -}; -PALensDataFocalLengthInterpreter paLensDataFocalLengthInterpreter; - -class PAISOfInterpreter: public Interpreter -{ -public: - PAISOfInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, BYTE); - char buffer[32]; - double v = 100.*exp (double (a - 32) * log (2.) / 8.); - sprintf (buffer, "%.1f", v ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, BYTE); - return 100.*exp (double (a - 32) * log (2.) / 8.); - } -}; -PAISOfInterpreter paISOfInterpreter; - -class PAMaxApertureInterpreter: public Interpreter -{ -public: - PAMaxApertureInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, BYTE); - a &= 0x7F; - - if (a > 1) { - char buffer[32]; - double v = pow (2.0, (a - 1) / 32.0); - - if ( v < 0. || v > 1000. ) { - return "undef"; - } - - sprintf (buffer, "%.1f", v ); - return buffer; - } else { - return "n/a"; - } - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, BYTE); - a &= 0x7F; - - if (a > 1) { - return pow (2.0, double (a - 1) / 32.0); - } else { - return 0.; - } - } -}; -PAMaxApertureInterpreter paMaxApertureInterpreter; - -class PAAEXvInterpreter: public Interpreter -{ -public: - PAAEXvInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, BYTE); - char buffer[32]; - double v = double (a - 64) / 8.; - sprintf (buffer, "%.1f", v ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, BYTE); - return double (a - 64) / 8.; - } -}; -PAAEXvInterpreter paAEXvInterpreter; - -class PAAEBXvInterpreter: public Interpreter -{ -public: - PAAEBXvInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, SBYTE); - char buffer[32]; - double v = double (a) / 8.; - sprintf (buffer, "%.1f", v ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, SBYTE); - return double (a) / 8.; - } -}; -PAAEBXvInterpreter paAEBXvInterpreter; - -class PAApertureInterpreter: public Interpreter -{ -public: - PAApertureInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, BYTE); - char buffer[32]; - double v = exp ((double (a) - 68.) * log (2.) / 16.); - sprintf (buffer, "%.1f", v ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, BYTE); - return exp ((double (a) - 68.) * log (2.) / 16.); - } -}; -PAApertureInterpreter paApertureInterpreter; - -class PAExposureTimeInterpreter: public Interpreter -{ -public: - PAExposureTimeInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->toInt (0, BYTE); - char buffer[32]; - double v = 24.*exp (- (double (a) - 32.) * log (2.) / 8.); - sprintf (buffer, "%.6f", v ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, BYTE); - return 24.*exp (- (double (a) - 32.) * log (2.) / 8.); - } -}; -PAExposureTimeInterpreter paExposureTimeInterpreter; - -class PANominalMinApertureInterpreter: public Interpreter -{ -public: - PANominalMinApertureInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - int a = t->toInt (0, BYTE); - int mina = a & 0x0F; - sprintf (buffer, "%.1f", double (int (pow (2.0, double (mina + 10) / 4.0) + 0.2))); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = t->toInt (0, BYTE) & 0x0F; - return double (int (pow (2.0, double (a + 10) / 4.0) + 0.2)); - } -}; -PANominalMinApertureInterpreter paNominalMinApertureInterpreter; - -class PANominalMaxApertureInterpreter: public Interpreter -{ -public: - PANominalMaxApertureInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - int a = t->toInt (0, BYTE); - int maxa = (a & 0xF0) >> 4; - sprintf (buffer, "%.1f", double (int (pow (2.0, double (maxa) / 4.0) + 0.2)) ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - int a = ( t->toInt (0, BYTE) & 0xF0) >> 4; - return double (int (pow (2.0, double (a) / 4.0) + 0.2)); - } -}; -PANominalMaxApertureInterpreter paNominalMaxApertureInterpreter; - -class PAFlashStatusInterpreter: public ChoiceInterpreter<> -{ -public: - PAFlashStatusInterpreter() - { - choices[0] = "Off"; - choices[1] = "Off (1)"; - choices[2] = "External, Did not fire"; - choices[6] = "External, Fired"; - choices[8] = "Internal, Did not fire (0x08)"; - choices[9] = "Internal, Did not fire"; - choices[13] = "Internal, Fired"; - } -}; -PAFlashStatusInterpreter paFlashStatusInterpreter; - -class PAInternalFlashModeInterpreter: public ChoiceInterpreter<> -{ -public: - PAInternalFlashModeInterpreter() - { - choices[0] = "n/a - Off-Auto-Aperture"; - choices[134] = "Fired, Wireless (Control)"; - choices[149] = "Fired, Wireless (Master)"; - choices[192] = "Fired"; - choices[193] = "Fired, Red-eye reduction"; - choices[194] = "Fired, Auto"; - choices[195] = "Fired, Auto, Red-eye reduction"; - choices[198] = "Fired, Wireless (Control), Fired normally not as control"; - choices[200] = "Fired, Slow-sync"; - choices[201] = "Fired, Slow-sync, Red-eye reduction"; - choices[202] = "Fired, Trailing-curtain Sync"; - choices[240] = "Did not fire, Normal"; - choices[241] = "Did not fire, Red-eye reduction"; - choices[242] = "Did not fire, Auto"; - choices[243] = "Did not fire, Auto, Red-eye reduction"; - choices[244] = "Did not fire, (Unknown 0xf4)"; - choices[245] = "Did not fire, Wireless (Master)"; - choices[246] = "Did not fire, Wireless (Control)"; - choices[248] = "Did not fire, Slow-sync"; - choices[249] = "Did not fire, Slow-sync, Red-eye reduction"; - choices[250] = "Did not fire, Trailing-curtain Sync"; - } -}; -PAInternalFlashModeInterpreter paInternalFlashModeInterpreter; - -class PAExternalFlashModeInterpreter: public ChoiceInterpreter<> -{ -public: - PAExternalFlashModeInterpreter() - { - choices[0] = "n/a - Off-Auto-Aperture"; - choices[63] = "Off"; - choices[64] = "On, Auto"; - choices[191] = "On, Flash Problem"; - choices[192] = "On, Manual"; - choices[196] = "On, P-TTL Auto"; - choices[197] = "On, Contrast-control Sync"; - choices[198] = "On, High-speed Sync"; - choices[204] = "On, Wireless"; - choices[205] = "On, Wireless, High-speed Sync"; - choices[240] = "Not Connected"; - } -}; -PAExternalFlashModeInterpreter paExternalFlashModeInterpreter; - -class PAExternalFlashExposureCompInterpreter: public ChoiceInterpreter<> -{ -public: - PAExternalFlashExposureCompInterpreter() - { - choices[0] = "n/a"; - choices[144] = "n/a (Manual Mode)"; - choices[164] = "-3.0"; - choices[167] = "-2.5"; - choices[168] = "-2.0"; - choices[171] = "-1.5"; - choices[172] = "-1.0"; - choices[175] = "-0.5"; - choices[176] = "0.0"; - choices[179] = "0.5"; - choices[180] = "1.0"; - } -}; -PAExternalFlashExposureCompInterpreter paExternalFlashExposureCompInterpreter; - -class PAExternalFlashBounceInterpreter: public ChoiceInterpreter<> -{ -public: - PAExternalFlashBounceInterpreter() - { - choices[0] = "n/a"; - choices[16] = "Direct"; - choices[48] = "Bonce"; - } -}; -PAExternalFlashBounceInterpreter paExternalFlashBounceInterpreter; - -class PAExternalFlashGNInterpreter: public Interpreter -{ -public: - PAExternalFlashGNInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - int b = t->toInt (0, BYTE) & 0x1F; - sprintf (buffer, "%.0f", pow (2., b / 16. + 4) ); - return buffer; - } -}; -PAExternalFlashGNInterpreter paExternalFlashGNInterpreter; - -class PAEVStepsInterpreter: public Interpreter -{ -public: - PAEVStepsInterpreter() {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - - if ( t->toInt (0, BYTE) & 0x20 ) { - str << "1/3 EV steps"; - } else { - str << "1/2 EV steps"; - } - - return str.str(); - } -}; -PAEVStepsInterpreter paEVStepsInterpreter; - -class PAEDialinInterpreter: public Interpreter -{ -public: - PAEDialinInterpreter() {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - - if ( t->toInt (0, BYTE) & 0x40 ) { - str << "P Shift"; - } else { - str << "Tv or Av"; - } - - return str.str(); - } -}; -PAEDialinInterpreter paEDialinInterpreter; - -class PAApertureRingUseInterpreter: public Interpreter -{ -public: - PAApertureRingUseInterpreter() {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - - if ( t->toInt (0, BYTE) & 0x80 ) { - str << "Permitted"; - } else { - str << "Prohibited"; - } - - return str.str(); - } -}; -PAApertureRingUseInterpreter paApertureRingUseInterpreter; - -class PAFlashOptionInterpreter: public ChoiceInterpreter<> -{ -public: - PAFlashOptionInterpreter() - { - choices[0] = "Normal"; - choices[1] = "Red-eye reduction"; - choices[2] = "Auto"; - choices[3] = "Auto, Red-eye reduction"; - choices[5] = "Wireless (Master)"; - choices[6] = "Wireless (Control)"; - choices[8] = "Slow-sync"; - choices[9] = "Slow-sync, Red-eye reduction"; - choices[10] = "Trailing-curtain Sync"; - } - std::string toString (const Tag* t) const override - { - const ChoicesIterator r = choices.find (t->toInt (0, BYTE) >> 4); - - if (r != choices.end()) { - return r->second; - } else { - char buffer[1024]; - t->toString (buffer); - return std::string (buffer); - } - } -}; -PAFlashOptionInterpreter paFlashOptionInterpreter; - -class PAMeteringMode2Interpreter: public Interpreter -{ -public: - PAMeteringMode2Interpreter() {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - int v = (t->toInt (0, BYTE) & 0xF); - - if (!v) { - str << "Multi-segment"; - } else if (v & 1) { - str << "Center-weighted average"; - } else if (v & 2) { - str << "Spot"; - } - - return str.str(); - } -}; -PAMeteringMode2Interpreter paMeteringMode2Interpreter; - -class PAExposureBracketStepSizeInterpreter: public ChoiceInterpreter<> -{ -public: - PAExposureBracketStepSizeInterpreter() - { - choices[3] = "0.3"; - choices[4] = "0.5"; - choices[5] = "0.7"; - choices[8] = "1.0"; - choices[11] = "1.3"; - choices[12] = "1.5"; - choices[13] = "1.7"; - choices[16] = "2.0"; - } -}; -PAExposureBracketStepSizeInterpreter paExposureBracketStepSizeInterpreter; - -class PAPictureMode2Interpreter: public ChoiceInterpreter<> -{ -public: - PAPictureMode2Interpreter() - { - choices[0] = "Scene Mode"; - choices[1] = "Auto PICT"; - choices[2] = "Program AE"; - choices[3] = "Green Mode"; - choices[4] = "Shutter Speed Priority"; - choices[5] = "Aperture Priority"; - choices[6] = "Program Tv Shift"; - choices[7] = "Program Av Shift"; - choices[8] = "Manual"; - choices[9] = "Bulb"; - choices[10] = "Aperture Priority, Off-Auto-Aperture"; - choices[11] = "Manual, Off-Auto-Aperture"; - choices[12] = "Bulb, Off-Auto-Aperture"; - choices[13] = "Shutter & Aperture Priority AE"; - choices[15] = "Sensitivity Priority AE"; - choices[16] = "Flash X-Sync Speed AE"; - } -}; -PAPictureMode2Interpreter paPictureMode2Interpreter; - -class PAProgramLineInterpreter: public Interpreter -{ -public: - PAProgramLineInterpreter() {} - std::string toString (const Tag* t) const override - { - std::ostringstream str; - int c = t->toInt (0, BYTE); - - switch (c & 0xf) { - case 0: - str << "Manual"; - break; - - case 1: - str << "AF-S"; - break; - - case 2: - str << "AF-C"; - break; - - case 3: - str << "AF-A"; - break; - } - - if ( (c & 0xF0) == 0) { - str << ", Point Selection Auto"; - } else if ( c & 0x20 ) { - str << ", Fixed Center Point Selected"; - } else if ( c & 0x10 ) { - str << ", Point Selected"; - } - - return str.str(); - } -}; -PAProgramLineInterpreter paProgramLineInterpreter; - -class PAAFModeInterpreter: public Interpreter -{ -public: - PAAFModeInterpreter() {} - std::string toString (const Tag* t) const override - { - switch (t->toInt (0, BYTE) & 0x3) { - case 0: - return "Normal"; - - case 1: - return "Hi Speed"; - - case 2: - return "Depth"; - - case 3: - return "MTF"; - } - - return"Normal"; - } - -}; -PAAFModeInterpreter paAFModeInterpreter; - -class PAAFPointSelectedInterpreter: public Interpreter -{ -public: - PAAFPointSelectedInterpreter() {} - std::string toString (const Tag* t) const override - { - int c = t->toInt (0, SHORT); - - if ( !c ) { - return "Auto"; - } else { - const char *ps[] = {"Upper-left", "Top", "Upper-right", "Left", "Mid-left", "Center", "Mid-right", "Right", "Lower-left", "Bottom", "Lower-right"}; - - for ( int iBit = 0; iBit < 11; iBit++) - if ( c & (1 << iBit) ) { - return ps[iBit]; - } - - return "n/a"; - } - } -}; -PAAFPointSelectedInterpreter paAFPointSelectedInterpreter; - -class PADriveMode2Interpreter: public Interpreter -{ -public: - PADriveMode2Interpreter() {} - std::string toString (const Tag* t) const override - { - int c = t->toInt (0, BYTE); - - if ( !c ) { - return "Single-frame"; - } else if ( c & 0x01) { - return "Continuous"; - } else if ( c & 0x02) { - return "Continuous (Lo)"; - } else if ( c & 0x04) { - return "Self-timer (12 s)"; - } else if ( c & 0x08) { - return "Self-timer (2 s)"; - } else if ( c & 0x10 ) { - return "Remote Control (3 s delay)"; - } else if ( c & 0x20) { - return "Remote Control"; - } else if ( c & 0x40) { - return "Exposure Bracket"; - } else if ( c & 0x80) { - return "Multiple Exposure"; - } else { - return "Unknown"; - } - } -}; -PADriveMode2Interpreter paDriveMode2Interpreter; - -const TagAttrib pentaxAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "PentaxVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "PentaxModelType", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0002, AUTO, "PreviewImageSize", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0003, AUTO, "PreviewImageLength", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0004, AUTO, "PreviewImageStart", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0005, AUTO, "PentaxModelID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "Date", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "Time", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0008, AUTO, "Quality", &paQualityInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0009, AUTO, "PentaxImageSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000b, AUTO, "PictureMode", &paPictureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000c, AUTO, "FlashMode", &paFlashModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000d, AUTO, "FocusMode", &paFocusModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000e, AUTO, "AFPointSelected", &paAFPointInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000f, AUTO, "AFPointsInFocus", &paAFFocusInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0010, AUTO, "FocusPosition", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0012, AUTO, "ExposureTime", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0013, AUTO, "FNumber", &paFNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0014, AUTO, "ISO", &paISOInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0015, AUTO, "LightReading", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0016, AUTO, "ExposureCompensation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0017, AUTO, "MeteringMode", &paMeteringModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0018, AUTO, "AutoBracketing", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0019, AUTO, "WhiteBalance", &paWhiteBalanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001a, AUTO, "WhiteBalanceMode", &paWhiteBalanceModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001b, AUTO, "BlueBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001c, AUTO, "RedBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001d, AUTO, "FocalLength", &paFocalLengthInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001e, AUTO, "DigitalZoom", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001f, AUTO, "Saturation", &paSaturationInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0020, AUTO, "Contrast", &paContrastInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0021, AUTO, "Sharpness", &paSharpnessInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0022, AUTO, "WorldTimeLocation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0023, AUTO, "HometownCity", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x0024, AUTO, "DestinationCity", &stdInterpreter}, - {0, AC_NEW, 0, nullptr, 0x0025, AUTO, "HometownDST", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0026, AUTO, "DestinationDST", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0027, AUTO, "DSPFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0028, AUTO, "CPUFirmwareVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0029, AUTO, "FrameNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x002d, AUTO, "EffectiveLV", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0032, AUTO, "ImageProcessing", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0033, AUTO, "PictureMode", &paPictureModeInterpreter2}, - {0, AC_WRITE, 0, nullptr, 0x0034, AUTO, "DriveMode", &paDriveModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0037, AUTO, "ColorSpace", &paColorSpaceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0038, AUTO, "ImageAreaOffset", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0039, AUTO, "RawImageSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003c, AUTO, "AFPointsInFocus", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003e, AUTO, "PreviewImageBorders", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x003f, AUTO, "LensType", &paLensTypeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0040, AUTO, "SensitivityAdjust", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0041, AUTO, "ImageProcessingCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0047, AUTO, "CameraTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0048, AUTO, "AELock", &paOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0049, AUTO, "NoiseReduction", &paOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x004d, AUTO, "FlashExposureComp", &paFlashExposureCompInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x004f, AUTO, "ImageTone", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0050, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxSRInfoAttribs, 0x005c, AUTO, "ShakeReductionInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x005d, AUTO, "ShutterCount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0069, AUTO, "DynamicRangeExpansion", &paOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0071, AUTO, "HighISONoiseReduction", &paHighISONoiseInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0072, AUTO, "AFAdjustment", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0073, AUTO, "MonochromeFilterEffect", &paMonochromeFilterEffectInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0074, AUTO, "MonochromeToning", &paMonochromeToningInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0076, AUTO, "FaceDetect", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0077, AUTO, "FaceDetectFrameSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0079, AUTO, "ShadowCorrection", &paShadowCorrectionInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x007a, AUTO, "ISOAutoParameters", &paISOAutoParametersInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x007b, AUTO, "CrossProcess", &paCrossProcessInterpreter}, - {0, AC_WRITE, 0, pentaxLensCorrAttribs, 0x007d, AUTO, "LensCorr", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x007f, AUTO, "BleachBypassToning", &paBleachBypassToningInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0082, AUTO, "BlurControl", &paBlurControlInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0085, AUTO, "HDR", &paHDRInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0088, AUTO, "NeutralDensityFilter", &paOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x008b, AUTO, "ISO", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0200, AUTO, "BlackPoint", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0201, AUTO, "WhitePoint", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0203, AUTO, "ColorMatrixA", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0204, AUTO, "ColorMatrixB", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxCameraSettingsAttribs, 0x0205, AUTO, "CameraSettings", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxAEInfoAttribs, 0x0206, AUTO, "AEInfo", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxLensDataAttribs, 0x0207, AUTO, "LensInfo", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxFlashInfoAttribs, 0x0208, AUTO, "FlashInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0209, AUTO, "AEMeteringSegments", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020a, AUTO, "FlashADump", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020b, AUTO, "FlashBDump", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020d, AUTO, "WB_RGGBLevelsDaylight", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020e, AUTO, "WB_RGGBLevelsShade", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x020f, AUTO, "WB_RGGBLevelsCloudy", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0210, AUTO, "WB_RGGBLevelsTungsten", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0211, AUTO, "WB_RGGBLevelsFluorescentD", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0212, AUTO, "WB_RGGBLevelsFluorescentN", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0213, AUTO, "WB_RGGBLevelsFluorescentW", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0214, AUTO, "WB_RGGBLevelsFlash", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxCameraInfoAttribs, 0x0215, AUTO, "CameraInfo", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxBatteryInfoAttribs, 0x0216, AUTO, "BatteryInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x021f, AUTO, "AFInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0222, AUTO, "ColorInfo", &stdInterpreter}, - {0, AC_WRITE, 0, pentaxLensInfoQAttribs, 0x0239, AUTO, "LensInfoQ", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03fe, AUTO, "DataDump", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x03ff, AUTO, "UnknownInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0402, AUTO, "ToneCurve", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0403, AUTO, "ToneCurves", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0e00, AUTO, "PrintIM", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxSRInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "SRResult", &paSRResultInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ShakeReduction", &paShakeReductionInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "SRHalfPressTime", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "SRFocalLength", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxSRInfo2Attribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "SRResult", &paSRResultInterpreter}, // assuming it's the same interpreter, but that's not sure - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ShakeReduction", &paShakeReduction2Interpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxLensDataAttribs[] = { - {0, AC_WRITE, 0, nullptr, 9, AUTO, "FocalLength", &paLensDataFocalLengthInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "NominalMaxAperture", &paNominalMaxApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "NominalMinAperture", &paNominalMinApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 14, AUTO, "MaxAperture", &paMaxApertureInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxLensInfoQAttribs[] = { - {0, AC_WRITE, 0, nullptr, 12, AUTO, "LensModel", &paLensModelQInterpreter}, - {0, AC_WRITE, 0, nullptr, 42, AUTO, "LensInfo", &paLensInfoQInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxLensCorrAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "DistortionCorrection", &paOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ChromaticAberrationCorrection", &paOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "VignettingCorrection", &paOnOffInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxCameraSettingsAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "PictureMode2", &paPictureMode2Interpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ProgramLine", &paProgramLineInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "EVSteps", &paEVStepsInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "E-DialinProgram", &paEDialinInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ApertureRing", &paApertureRingUseInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "FlashOptions", &paFlashOptionInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "MeteringMode2", &paMeteringMode2Interpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "AFMode", &paAFModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "AFPointSelected2", &paAFPointSelectedInterpreter}, - {0, AC_WRITE, 0, nullptr, 7, AUTO, "DriveMode2", &paDriveMode2Interpreter}, - {0, AC_WRITE, 0, nullptr, 8, AUTO, "ExposureBracketStepSize", &paExposureBracketStepSizeInterpreter}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "BracketShotNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "WhiteBalanceSet", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxAEInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "AEExposureTime", &paExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "AEAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "AE_ISO", &paISOfInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "AEXv", &paAEXvInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, SBYTE, "AEBXv", &paAEBXvInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "AEMinExposureTime", &paExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 6, AUTO, "AEProgramMode", &paAEProgramModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "AEMaxAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "AEMaxAperture2", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 11, AUTO, "AEMinAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 12, AUTO, "AEMeteringMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 14, SBYTE, "FlashExposureCompSet", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxAEInfo2Attribs[] = { - {0, AC_WRITE, 0, nullptr, 2, AUTO, "AEExposureTime", &paExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "AEAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "AE_ISO", &paISOfInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "AEXv", &paAEXvInterpreter}, - {0, AC_WRITE, 0, nullptr, 6, SBYTE, "AEBXv", &paAEBXvInterpreter}, - {0, AC_WRITE, 0, nullptr, 8, SBYTE, "AEError", &stdInterpreter}, -//{0, AC_WRITE, 0, 0, 11, AUTO, "AEApertureSteps", &}, - {0, AC_WRITE, 0, nullptr, 15, AUTO, "SceneMode", &paSceneModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 16, AUTO, "AEMaxAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "AEMaxAperture2", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 18, AUTO, "AEMinAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 19, AUTO, "AEMinExposureTime", &paExposureTimeInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxAEInfo3Attribs[] = { - {0, AC_WRITE, 0, nullptr, 16, AUTO, "AEExposureTime", &paExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "AEAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 18, AUTO, "AE_ISO", &paISOfInterpreter}, - {0, AC_WRITE, 0, nullptr, 28, AUTO, "AEMaxAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 29, AUTO, "AEMaxAperture2", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 30, AUTO, "AEMinAperture", &paApertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 31, AUTO, "AEMinExposureTime", &paExposureTimeInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxFlashInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "FlashStatus", &paFlashStatusInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "InternalFlashMode", &paInternalFlashModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "ExternalFlashMode", &paExternalFlashModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "InternalFlashStrength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 24, AUTO, "ExternalFlashGuideNumber", &paExternalFlashGNInterpreter}, - {0, AC_WRITE, 0, nullptr, 25, AUTO, "ExternalFlashExposureComp", &paExternalFlashExposureCompInterpreter}, - {0, AC_WRITE, 0, nullptr, 26, AUTO, "ExternalFlashBounce", &paExternalFlashBounceInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxBatteryInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "PowerSource", &paPowerSourceInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "BatteryStates", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "BatteryADBodyNoLoad", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "BatteryADBodyLoad", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "BatteryADGripNoLoad", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "BatteryADGripLoad", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib pentaxCameraInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "PentaxModelID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ManufactureDate", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "ProductionCode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "InternalSerialNumber", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -} -#endif - - - - diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc deleted file mode 100644 index 571fd4e6b..000000000 --- a/rtexif/rtexif.cc +++ /dev/null @@ -1,3488 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Some parts of the source code (e.g. ciff support) are taken from dcraw - * that is copyrighted by Dave Coffin - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "rtexif.h" - -#include "../rtengine/procparams.h" - -#include "../rtgui/cacheimagedata.h" -#include "../rtgui/version.h" -#include "../rtgui/ppversion.h" - -// see end of ExifManager::parse(bool, bool) -#define PRINT_METADATA_TREE 0 - -using namespace std; - -namespace rtexif -{ - -Interpreter stdInterpreter; - -//--------------- class TagDirectory ------------------------------------------ -// this class is a collection (an array) of tags -//----------------------------------------------------------------------------- - -TagDirectory::TagDirectory () - : attribs (ifdAttribs), order (HOSTORDER), parent (nullptr) {} - -TagDirectory::TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border) - : attribs (ta), order (border), parent (p) {} - -TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border, bool skipIgnored) - : attribs (ta), order (border), parent (p) -{ - - int numOfTags = get2 (f, order); - - if (numOfTags <= 0 || numOfTags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit - return; - } - - bool thumbdescr = false; - - for (int i = 0; i < numOfTags; i++) { - - Tag* newTag = new Tag (this, f, base); - - // filter out tags with unknown type - if ((int)newTag->getType() == 0) { - delete newTag; - continue; - } - - if (skipIgnored) { - int id = newTag->getID(); - - // detect and possibly ignore tags of directories belonging to the embedded thumbnail image - if (attribs == ifdAttribs && id == TIFFTAG_SUBFILETYPE && newTag->toInt() != 0) { - thumbdescr = true; - } - - const TagAttrib* attrib = getAttrib (id); - - if (!attrib || attrib->ignore == 1 || (thumbdescr && attrib->ignore == 2)) { - delete newTag; - } else { - addTag (newTag); - } - } else { - addTag (newTag); - } - } -} - -TagDirectory::~TagDirectory () -{ - - for (size_t i = 0; i < tags.size(); i++) { - delete tags[i]; - } -} - -class CompareTags -{ -public: - int operator() (Tag* const& a, Tag* const& b) const - { - return a->getID() < b->getID(); - } -}; - -void TagDirectory::sort () -{ - - std::sort (tags.begin(), tags.end(), CompareTags()); - - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->isDirectory()) - for (int j = 0; tags[i]->getDirectory (j); j++) { - tags[i]->getDirectory (j)->sort (); - } -} -TagDirectory* TagDirectory::getRoot() -{ - if (parent) { - return parent->getRoot(); - } else { - return this; - } -} - -const TagAttrib* TagDirectory::getAttrib (int id) -{ - - if (attribs) - for (int i = 0; attribs[i].ignore != -1; i++) - if (attribs[i].ID == id) { - return &attribs[i]; - } - - return nullptr; -} - -const TagAttrib* TagDirectory::getAttrib (const char* name) -{ - - if (attribs) - for (int i = 0; attribs[i].ignore != -1; i++) - if (!strcmp (attribs[i].name, name)) { - return &attribs[i]; - } - - return nullptr; -} - -const TagAttrib* TagDirectory::getAttribP (const char* name) -{ - - if (attribs) - for (int i = 0; attribs[i].ignore != -1; i++) { - // Yeah, self made comparison! - const char *n = name; - const char *a = attribs[i].name; - - while (*n && *a && *n == *a) { - n++; - a++; - }; - - if (!*a && (!*n || *n == '/')) { - // we reached the end of the subpart of name and the end of attribs->name, so they match - if (*n == '/') { - Tag* tag = getTag (attribs[i].ID); - TagDirectory *tagDir; - - if (attribs[i].subdirAttribs && tag && (tagDir = tag->getDirectory())) { - return tagDir->getAttribP (n + 1); - } else { - return nullptr; - } - } else { - return &attribs[i]; - } - } - } - - return nullptr; -} - -void TagDirectory::printAll (unsigned int level) const -{ - - // set the spacer prefix string - char prefixStr[level * 4 + 1]; - unsigned int i; - - for (i = 0; i < level * 4; i++) { - prefixStr[i] = ' '; - } - - prefixStr[i] = '\0'; - - // recursively iterate over the tag list - for (size_t i = 0; i < tags.size(); i++) { - std::string name = tags[i]->nameToString (); - - TagDirectory* currTagDir; - if (tags[i]->isDirectory()) { - for (int j = 0; (currTagDir = tags[i]->getDirectory (j)) != nullptr; j++) { - printf ("%s+-- DIRECTORY %s[%d]:\n", prefixStr, name.c_str(), j); - currTagDir->printAll (level + 1); - } - } else { - printf ("%s- %s\n", prefixStr, name.c_str()); - } - } -} - -/** @brief Dump the TagDirectory and its sub-directories to the file 'fname' - * - * This method has been created to dump the metadata for the Custom Profile Builders. - * It contains an [RT General] section to communicate some parameters, then the TagDirectory follows. - * - * The key is composed as follow: "010F_Make", i.e. "tag number or ID _ tag name" - * Entries like: - * - * 927C_MakerNotesSony=$subdir - * - * indicates that this tag refer to a sub-directory. RT's Keywords begins with $, where & is the first char of the value. - * $subdir is the only keyword so far. - * - * You'll have then to check for the [EXIF/927C_MakerNotesSony] section, given that the root section - * is named [EXIF]. - * - * WARNING: Some string will be sanitized, i.e. the new line char will be replaced by "\n". You'll - * have to check for this escape string if you want a correct display of the value, but your KeyFile module - * will most likely handle that automatically for you. - * - * @param commFNname Absolute path of the temporary communication file's name - * @param commFNname Absolute path of the image's file name - * @param commFNname Absolute path of the output profiles's file name - * @param defaultPParams absolute or relative path (to the application's folder) of the default ProcParams to use - * @param cfs pointer to a CacheImageData object that will contain common values - * @param flagMode will tell whether the Custom Profile Builder is called for on flagging event or for real development - * @param keyfile The KeyFile object to dump to. Has to be NULL (default value) on first call! - * @param tagDirName Name of the current TagDirectory (full path, i.e. "EXIF/MakerNotes/LensInfo"). Can be empty on first call, "EXIF" will then be used - * - * @return True if everything went fine, false otherwise - */ -bool TagDirectory::CPBDump (const Glib::ustring &commFName, const Glib::ustring &imageFName, const Glib::ustring &profileFName, const Glib::ustring &defaultPParams, - const CacheImageData* cfs, const bool flagMode, Glib::KeyFile *keyFile, Glib::ustring tagDirName) const -{ - const auto kf = keyFile ? keyFile : new Glib::KeyFile; - - if (!kf) { - return false; - } - - if (!keyFile || tagDirName.empty()) { - tagDirName = "EXIF"; - } - - std::vector tagDirList; - std::vector tagDirPaths; - - FILE *f = nullptr; - - if (!keyFile) { - // open the file in write mode - f = g_fopen (commFName.c_str (), "wt"); - - if (f == nullptr) { - printf ("TagDirectory::keyFileDump(\"%s\") >>> Error: unable to open file with write access!\n", commFName.c_str()); - delete kf; - return false; - } - - try { - - kf->set_string ("RT General", "CachePath", options.cacheBaseDir); - kf->set_string ("RT General", "AppVersion", RTVERSION); - kf->set_integer ("RT General", "ProcParamsVersion", PPVERSION); - kf->set_string ("RT General", "ImageFileName", imageFName); - kf->set_string ("RT General", "OutputProfileFileName", profileFName); - kf->set_string ("RT General", "DefaultProcParams", defaultPParams); - kf->set_boolean ("RT General", "FlaggingMode", flagMode); - - kf->set_integer ("Common Data", "FrameCount", cfs->frameCount); - kf->set_integer ("Common Data", "SampleFormat", cfs->sampleFormat); - kf->set_boolean ("Common Data", "IsHDR", cfs->isHDR); - kf->set_boolean ("Common Data", "IsPixelShift", cfs->isPixelShift); - kf->set_double ("Common Data", "FNumber", cfs->fnumber); - kf->set_double ("Common Data", "Shutter", cfs->shutter); - kf->set_double ("Common Data", "FocalLength", cfs->focalLen); - kf->set_integer ("Common Data", "ISO", cfs->iso); - kf->set_string ("Common Data", "Lens", cfs->lens); - kf->set_string ("Common Data", "Make", cfs->camMake); - kf->set_string ("Common Data", "Model", cfs->camModel); - - } catch (Glib::KeyFileError&) {} - } - - // recursively iterate over the tag list - for (size_t i = 0; i < tags.size(); i++) { - std::string tagName = tags[i]->nameToString (); - - if (tags[i]->isDirectory()) - for (int j = 0; tags[i]->getDirectory (j); j++) { - // Accumulating the TagDirectories to dump later - tagDirPaths.push_back ( Glib::ustring ( tagDirName + "/" + getDumpKey (tags[i]->getID(), tagName) ) ); - tagDirList.push_back (tags[i]->getDirectory (j)); - - try { - kf->set_string (tagDirName, getDumpKey (tags[i]->getID(), tagName), "$subdir"); - } catch (Glib::KeyFileError&) {} - } else { - try { - kf->set_string (tagDirName, getDumpKey (tags[i]->getID(), tagName), tags[i]->valueToString()); - } catch (Glib::KeyFileError&) {} - } - } - - // dumping the sub-directories - for (size_t i = 0; i < tagDirList.size(); i++) { - tagDirList.at (i)->CPBDump (commFName, imageFName, profileFName, defaultPParams, cfs, flagMode, kf, tagDirPaths.at (i)); - } - - if (!keyFile) { - try { - fprintf (f, "%s", kf->to_data().c_str()); - } catch (Glib::KeyFileError&) {} - - fclose (f); - delete kf; - } - - return true; -} - -Glib::ustring TagDirectory::getDumpKey (int tagID, const Glib::ustring &tagName) -{ - Glib::ustring key; - - if (options.CPBKeys == CPBKT_TID || options.CPBKeys == CPBKT_TID_NAME) { - key = Glib::ustring (Glib::ustring::format (std::fixed, std::hex, std::setfill (L'0'), std::setw (4), tagID)); - } - - if (options.CPBKeys == CPBKT_TID_NAME) { - key += Glib::ustring ("_"); - } - - if (options.CPBKeys == CPBKT_TID_NAME || options.CPBKeys == CPBKT_NAME) { - key += Glib::ustring (tagName); - } - - return key; -} -void TagDirectory::addTag (Tag* &tag) -{ - - // look up if it already exists: - if (getTag (tag->getID())) { - delete tag; - tag = nullptr; - } else { - tags.push_back (tag); - } -} - -void TagDirectory::addTagFront (Tag* &tag) -{ - - // look up if it already exists: - if (getTag (tag->getID())) { - delete tag; - tag = nullptr; - } else { - tags.insert (tags.begin(), tag); - } -} - -void TagDirectory::replaceTag (Tag* tag) -{ - - // look up if it already exists: - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->getID() == tag->getID()) { - delete tags[i]; - tags[i] = tag; - return; - } - - tags.push_back (tag); -} - -Tag* TagDirectory::getTag (int ID) const -{ - - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->getID() == ID) { - return tags[i]; - } - - return nullptr; -} - -Tag* TagDirectory::getTag (const char* name) const -{ - - if (attribs) { - for (int i = 0; attribs[i].ignore != -1; i++) - if (!strcmp (attribs[i].name, name)) { - return getTag (attribs[i].ID); - } - } - - return nullptr; -} - -Tag* TagDirectory::getTagP (const char* name) const -{ - - if (attribs) - for (int i = 0; attribs[i].ignore != -1; i++) { - // Yeah, self made comparison! - const char *n = name; - const char *a = attribs[i].name; - - while (*n && *a && *n == *a) { - n++; - a++; - }; - - if (!*a && (!*n || *n == '/')) { - // we reached the end of the subpart of name and the end of attribs->name, so they match - if (*n == '/') { - Tag* tag = getTag (attribs[i].ID); - TagDirectory *tagDir; - - if (attribs[i].subdirAttribs && tag && (tagDir = tag->getDirectory())) { - return tagDir->getTagP (n + 1); - } else { - return nullptr; - } - } else { - return getTag (attribs[i].ID); - } - } - } - - return nullptr; -} - -Tag* TagDirectory::findTag (const char* name, bool lookUpward) const -{ - Tag* t = getTag(name); - if (t) { - return t; - } - - Tag* foundTag = nullptr; - int tagDistance = 10000; - - for (auto tag : tags) { - if (tag->isDirectory()) { - TagDirectory *dir; - int i = 0; - // Find the shortest path to that tag - while ((dir = tag->getDirectory(i)) != nullptr) { - TagDirectory *dir = tag->getDirectory(); - Tag* t = dir->findTag (name); - - if (t) { - int currTagDistance = t->getDistanceFrom(this); - if (currTagDistance < tagDistance) { - tagDistance = currTagDistance; - foundTag = t; - } - } - ++i; - } - } - } - - if (foundTag) { - return foundTag; - } - - if (lookUpward && parent) { - Tag* t = parent->findTagUpward(name); - - if (t) { - return t; - } - } - - return nullptr; -} - -std::vector TagDirectory::findTags (int ID) -{ - - std::vector tagList; - - //assuming that an entry can only exist once - Tag* t = getTag(ID); - if (t) { - tagList.push_back(t); - } - - for (auto tag : tags) { - if (tag->isDirectory()) { - TagDirectory *dir; - int i = 0; - while ((dir = tag->getDirectory(i)) != nullptr) { - std::vector subTagList = dir->findTags (ID); - - if (!subTagList.empty()) { - // concatenating the 2 vectors - // not really optimal in a memory efficiency pov - for (auto tag2 : subTagList) { - tagList.push_back(tag2); - } - } - ++i; - } - } - } - - return tagList; -} - -std::vector TagDirectory::findTags (const char* name) -{ - - std::vector tagList; - - //assuming that an entry can only exist once - Tag* t = getTag(name); - if (t) { - tagList.push_back(t); - } - - for (auto tag : tags) { - if (tag->isDirectory()) { - TagDirectory *dir; - int i = 0; - while ((dir = tag->getDirectory(i)) != nullptr) { - std::vector subTagList = dir->findTags (name); - - if (!subTagList.empty()) { - // concatenating the 2 vectors - // not really optimal in a memory efficiency pov, but adding 10 items should be a maximum - for (auto tag2 : subTagList) { - tagList.push_back(tag2); - } - } - ++i; - } - } - } - - return tagList; -} - - -Tag* TagDirectory::findTagUpward (const char* name) const -{ - Tag* t = findTag(name); - if (t) { - return t; - } - - if (parent) { - Tag* t = parent->findTagUpward(name); - - if (t) { - return t; - } - } - - return nullptr; -} - - -// Searches a simple value, as either attribute or element -// only for simple values, not for entries with special chars or free text -bool TagDirectory::getXMPTagValue (const char* name, char* value) const -{ - *value = 0; - - if (!getTag ("ApplicationNotes")) { - return false; - } - - char *sXMP = (char*)getTag ("ApplicationNotes")->getValue(); - - // Check for full word - char *pos = sXMP; - - bool found = false; - - do { - pos = strstr (pos, name); - - if (pos) { - char nextChar = * (pos + strlen (name)); - - if (nextChar == ' ' || nextChar == '>' || nextChar == '=') { - found = true; - } else { - pos += strlen (name); - } - } - } while (pos && !found); - - if (!found) { - return false; - } - - char *posTag = strchr (pos, '>'); - char *posAttr = strchr (pos, '"'); - - if (!posTag && !posAttr) { - return false; - } - - if (posTag && (!posAttr || posTag < posAttr)) { - // Tag - pos = strchr (posTag + 1, '<'); - strncpy (value, posTag + 1, pos - posTag - 1); - value[pos - posTag - 1] = 0; - return true; - } else if (posAttr && (!posTag || posAttr < posTag)) { - // Attribute - pos = strchr (posAttr + 1, '"'); - strncpy (value, posAttr + 1, pos - posAttr - 1); - value[pos - posAttr - 1] = 0; - return true; - } else { - return false; - } -} - -void TagDirectory::keepTag (int ID) -{ - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->getID() == ID) { - tags[i]->setKeep (true); - } -} - -int TagDirectory::calculateSize () -{ - - int size = 2; // space to store the number of tags - - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->getKeep()) { - size += 12 + tags[i]->calculateSize (); - } - - size += 4; // next ifd pointer - return size; -} - -TagDirectory* TagDirectory::clone (TagDirectory* parent) -{ - - TagDirectory* td = new TagDirectory (parent, attribs, order); - - for (size_t i = 0; i < tags.size(); i++) { - td->tags.push_back (tags[i]->clone (td)); - } - - return td; -} - -int TagDirectory::write (int start, unsigned char* buffer) -{ - - int size = calculateSize (); - int tagnum = 0; - int nondirspace = 0; - - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->getKeep()) { - tagnum++; - - if (!tags[i]->isDirectory()) { - nondirspace += tags[i]->calculateSize(); - } - } - - int nextValOffs = start + 2 + tagnum * 12 + 4; - int nextDirOffs = nextValOffs + nondirspace; - int pos = start; - sset2 (tagnum, buffer + start, order); - pos += 2; - int maxPos = start + size; - - for (size_t i = 0; i < tags.size(); i++) { - if (tags[i]->getKeep()) { - if (!tags[i]->isDirectory()) { - nextValOffs = tags[i]->write (pos, nextValOffs, buffer); // pos: where to put the tag, dataoffset: the place where the value can be put. return: next data offset - } else { - nextDirOffs = tags[i]->write (pos, nextDirOffs, buffer); // pos: where to put the tag, dataoffset: the place where the value can be put. return: next data offset - } - - pos += 12; - } - } - - sset4 (0, buffer + pos, order); - return maxPos; -} - -void TagDirectory::applyChange (const std::string &name, const Glib::ustring &value) -{ - - std::string::size_type dp = name.find_first_of ('.'); - std::string fseg = name.substr (0, dp); - - // this is a final segment: apply change - if (dp == std::string::npos) { - - Tag* t = nullptr; - - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->nameToString() == fseg) { - t = tags[i]; - break; - } - - if (value == "#keep" && t) { - t->setKeep (true); - } else if (value == "#delete" && t) { - t->setKeep (false); - } else if (t && !t->isDirectory()) { - if (name == "UserComment") { - // UserComment can be Unicode - t->userCommentFromString (value); - } else { - t->valueFromString (value); - } - } else { - const TagAttrib* attrib = nullptr; - - for (int i = 0; attribs[i].ignore != -1; i++) { - if (!strcmp (attribs[i].name, fseg.c_str())) { - attrib = &attribs[i]; - break; - } - } - - if (attrib) { - Tag* nt = new Tag (this, attrib); - if (name == "UserComment") { - // UserComment can be Unicode - nt->initUserComment (value); - } else { - nt->initString (value.c_str()); - } - addTag (nt); - } - } - } - // this is a subdirectory - else { - // try to find it - std::string::size_type dp1 = fseg.find_first_of ('['); - std::string basename = fseg.substr (0, dp1); - Tag* t = nullptr; - int dirnum = -1; - - for (size_t i = 0; i < tags.size(); i++) - if (tags[i]->isDirectory()) { - for (int j = 0; tags[i]->getDirectory (j); j++) { - if (tags[i]->nameToString (j) == fseg) { - t = tags[i]; - dirnum = j; - break; - } - } - - if (!t && tags[i]->nameToString() == basename) { // found it, but that directory index does not exist - t = tags[i]; - dirnum = -1; - } - } - - if (!t && value != "#keep" && value != "#delete") { - const TagAttrib* attrib = nullptr; - - for (int i = 0; attribs[i].ignore != -1; i++) - if (!strcmp (attribs[i].name, fseg.c_str())) { - attrib = &attribs[i]; - break; - } - - if (attrib && attrib->subdirAttribs) { - t = new Tag (this, attrib); - t->initSubDir (); - addTag (t); - } - - dirnum = 0; - } - - if (t && dirnum >= 0) { - t->getDirectory (dirnum)->applyChange (name.substr (dp + 1, std::string::npos), value); - } - } -} - -TagDirectoryTable::TagDirectoryTable () - : values (nullptr), zeroOffset (0), valuesSize (0), defaultType (INVALID) -{ -} - -TagDirectoryTable::TagDirectoryTable (TagDirectory* p, unsigned char *v, int memsize, int offs, TagType type, const TagAttrib* ta, ByteOrder border) - : TagDirectory (p, ta, border), zeroOffset (offs), valuesSize (memsize), defaultType ( type ) -{ - values = new unsigned char[valuesSize]; - memcpy (values, v, valuesSize); - - // Security ; will avoid to read above the buffer limit if the RT's tagDirectoryTable is longer that what's in the file - int count = valuesSize / getTypeSize (type); - - for (const TagAttrib* tattr = ta; tattr->ignore != -1 && tattr->ID < count; ++tattr) { - Tag* newTag = new Tag (this, tattr, (values + zeroOffset + tattr->ID * getTypeSize (type)), tattr->type == AUTO ? type : tattr->type); - tags.push_back (newTag); // Here we can insert more tag in the same offset because of bitfield meaning - } -} - -TagDirectoryTable::TagDirectoryTable (TagDirectory* p, FILE* f, int memsize, int offs, TagType type, const TagAttrib* ta, ByteOrder border) - : TagDirectory (p, ta, border), zeroOffset (offs), valuesSize (memsize), defaultType ( type ) -{ - values = new unsigned char[valuesSize]; - if (fread (values, 1, valuesSize, f) == static_cast(valuesSize)) { - - // Security ; will avoid to read above the buffer limit if the RT's tagDirectoryTable is longer that what's in the file - int count = valuesSize / getTypeSize (type); - - for (const TagAttrib* tattr = ta; tattr->ignore != -1 && tattr->ID < count; ++tattr) { - Tag* newTag = new Tag (this, tattr, (values + zeroOffset + tattr->ID * getTypeSize (type)), tattr->type == AUTO ? type : tattr->type); - tags.push_back (newTag); // Here we can insert more tag in the same offset because of bitfield meaning - } - } -} -TagDirectory* TagDirectoryTable::clone (TagDirectory* parent) -{ - - TagDirectory* td = new TagDirectoryTable (parent, values, valuesSize, zeroOffset, defaultType, attribs, order); - return td; -} - -TagDirectoryTable::~TagDirectoryTable() -{ - if (values) { - delete [] values; - } -} -int TagDirectoryTable::calculateSize () -{ - return valuesSize; -} - -int TagDirectoryTable::write (int start, unsigned char* buffer) -{ - if ( values && valuesSize) { - memcpy (buffer + start, values, valuesSize); - return start + valuesSize; - } else { - return start; - } -} - -//--------------- class Tag --------------------------------------------------- -// this class represents a tag stored in the directory -//----------------------------------------------------------------------------- - -Tag::Tag (TagDirectory* p, FILE* f, int base) - : type (INVALID), count (0), value (nullptr), allocOwnMemory (true), attrib (nullptr), parent (p), directory (nullptr) -{ - - ByteOrder order = getOrder(); - - tag = get2 (f, order); - type = (TagType)get2 (f, order); - count = get4 (f, order); - - if (!count) { - count = 1; - } - - makerNoteKind = NOMK; - keep = false; - - // filter out invalid tags - // note the large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, - // (only a small part of it will actually be parsed though) - if ((int)type < 1 || (int)type > 14 || count > 10 * 1024 * 1024) { - type = INVALID; - valuesize = 0; - return; - } - - // store next Tag's position in file - int save = ftell (f) + 4; - - // load value field (possibly seek before) - valuesize = count * getTypeSize (type); - - if (valuesize > 4) { - fseek (f, get4 (f, getOrder()) + base, SEEK_SET); - } - - attrib = parent->getAttrib (tag); - - if (attrib && (attrib->action == AC_WRITE || attrib->action == AC_NEW)) { - keep = true; - } - - if ( tag == 0xc634 ) { // DNGPrivateData - int currPos = ftell (f); - const int buffersize = 32; - char buffer[buffersize], *p = buffer; - - while ( fread (p, 1, 1, f ) && *p != 0 && p - buffer < buffersize - 1 ) { - p++; - } - - *p = 0; - - if ( !strncmp (buffer, "Adobe", 5) ) { - fread (buffer, 1, 14, f ); - - if ( !strncmp ( buffer, "MakN", 4) ) { - ByteOrder bom = ((buffer[8] == 'M' && buffer[9] == 'M') ? MOTOROLA : INTEL) ; - Tag* tmake = parent->getRoot()->findTag ("Make"); - std::string make ( tmake ? tmake->valueToString() : ""); - int save = ftell (f); - int originalOffset = sget4 ( (unsigned char*)&buffer[10], ( make.find ("SONY") != std::string::npos ) || ( make.find ("Canon") != std::string::npos ) || ( make.find ("OLYMPUS") != std::string::npos ) ? MOTOROLA : bom ); - - if ( !parseMakerNote (f, save - originalOffset, bom )) { - type = INVALID; - } - } - } else if ( !strncmp (buffer, "PENTAX", 6) ) { - makerNoteKind = HEADERIFD; - fread (buffer, 1, 2, f); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, currPos, pentaxAttribs, strncmp (buffer, "MM", 2) ? INTEL : MOTOROLA); - directory[1] = nullptr; - } else - /* SONY uses this tag to write hidden info and pointer to private encrypted tags - { - unsigned offset =sget4((unsigned char*)buffer, order); - fseek(f,offset,SEEK_SET); - makerNoteKind = TABLESUBDIR; - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, sonyDNGMakerNote, order); - directory[1] = NULL; - fseek (f, save, SEEK_SET); - return; - }*/ - { - type = INVALID; - } - } - - if (tag == 0x002e) { // location of the embedded preview image in raw files of Panasonic cameras - ExifManager eManager(f, nullptr, true); - const auto fpos = ftell(f); - if (fpos >= 0) { - eManager.parseJPEG(fpos); // try to parse the exif data from the preview image - - if (eManager.roots.size()) { - const TagDirectory* const previewdir = eManager.roots.at(0); - if (previewdir->getTag ("Exif")) { - if (previewdir->getTag ("Make")) { - if (previewdir->getTag ("Make")->valueToString() == "Panasonic") { // "make" is not yet available here, so get it from the preview tags to assure we're doing the right thing - Tag* t = new Tag (parent->getRoot(), lookupAttrib (ifdAttribs, "Exif")); // replace raw exif with preview exif assuming there are the same - t->initSubDir (previewdir->getTag ("Exif")->getDirectory()); - parent->getRoot()->addTag (t); - } - } - } - } - } - } - - // if this tag is the makernote, it needs special treatment (brand specific parsing) - if (tag == 0x927C && attrib && !strcmp (attrib->name, "MakerNote") ) { - if ( !parseMakerNote (f, base, order )) { - type = INVALID; - fseek (f, save, SEEK_SET); - return; - } - } else if (attrib && attrib->subdirAttribs) { - // Some subdirs are specific of maker and model - char make[128], model[128]; - make[0] = 0; - model[0] = 0; - Tag* tmake = parent->getRoot()->getTag ("Make"); - - if (tmake) { - tmake->toString (make); - } - - Tag* tmodel = parent->getRoot()->getTag ("Model"); - - if (tmodel) { - tmodel->toString (model); - } - - if (!strncmp (make, "SONY", 4)) { - switch ( tag ) { - case 0x0010: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - - if (count == 15360) { - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, sonyCameraInfoAttribs, order); - } else { - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, sonyCameraInfo2Attribs, order); - } - - break; - - case 0x0114: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - - if (count == 280 || count == 364) { - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SHORT, sonyCameraSettingsAttribs, MOTOROLA); - } else if (count == 332) { - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SHORT, sonyCameraSettingsAttribs2, MOTOROLA); - } else if (count == 1536 || count == 2048) { - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, sonyCameraSettingsAttribs3, INTEL); - } else { - // Unknown CameraSettings - delete [] directory; - directory = nullptr; - type = INVALID; - } - - makerNoteKind = directory ? TABLESUBDIR : NOMK; - break; - - case 0x9405: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SHORT, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - - default: - goto defsubdirs; - } - } else if ((!strncmp (make, "PENTAX", 6)) || (!strncmp (make, "RICOH", 5) && !strncmp (model, "PENTAX", 6))) { // Either the former Pentax brand or the RICOH brand + PENTAX model" - switch ( tag ) { - case 0x007d: - case 0x0205: - case 0x0208: - case 0x0216: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - - case 0x0215: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, LONG, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - - case 0x005c: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - - if (count == 4) { // SRInfo - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxSRInfoAttribs, order); - } else if (count == 2) { // SRInfo2 - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxSRInfo2Attribs, order); - } else { - // Unknown SRInfo - delete [] directory; - directory = nullptr; - type = INVALID; - } - - makerNoteKind = directory ? TABLESUBDIR : NOMK; - break; - - case 0x0206: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - - if (count == 21) { // AEInfo2 - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxAEInfo2Attribs, order); - } else if (count == 48) { // AEInfo3 - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxAEInfo3Attribs, order); - } else if (count <= 25) { // AEInfo - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, pentaxAEInfoAttribs, order); - } else { - // Unknown AEInfo - delete [] directory; - directory = nullptr; - type = INVALID; - } - - makerNoteKind = directory ? TABLESUBDIR : NOMK; - break; - - case 0x0207: { - // There are 2 format pentaxLensDataAttribs - int offsetFirst = 4; // LensInfo2 - - if ( strstr (model, "*ist") || strstr (model, "GX-1") || strstr (model, "K200D") || (strstr (model, "K100D") && !strstr (model, "K100D Super")) || strstr (model, "K110D") || strstr (model, "645Z")) { - offsetFirst = 3; // LensInfo - } else if ( strstr (model, "645D") ) { - offsetFirst = 13; // LensInfo3 - } else if ( strstr (model, "K-01") || strstr (model, "K-30") || strstr (model, "K-50")) { - offsetFirst = 15; // LensInfo5 - } else if ( strstr (model, "K-5") || strstr (model, "K-r") ) { - offsetFirst = 12; // LensInfo4 - } else if (!strncmp (make, "RICOH", 5)) { // all PENTAX camera model produced under the RICOH era uses LensInfo5, for now... - offsetFirst = 15; // LensInfo5 too - } - - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, offsetFirst, BYTE, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - } - break; - - case 0x0239: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - - default: - goto defsubdirs; - } - } else if (!strncmp (make, "Canon", 5)) { - switch ( tag ) { - case 0x0001: - case 0x0002: - case 0x0004: - case 0x0005: - case 0x0093: - case 0x0098: - case 0x00a0: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, SSHORT, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - - case 0x009a: - case 0x4013: - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, LONG, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - - default: - goto defsubdirs; - } - } else if (!strncmp (make, "NIKON", 5)) { - switch (tag) { - case 0x0025: { - directory = new TagDirectory*[2]; - directory[1] = nullptr; - directory[0] = new TagDirectoryTable (parent, f, valuesize, 0, BYTE, attrib->subdirAttribs, order); - makerNoteKind = TABLESUBDIR; - break; - } - - default: - goto defsubdirs; - } - } else if (type == UNDEFINED) { - count = 1; - type = LONG; - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, attrib->subdirAttribs, order); - directory[1] = nullptr; - } else { - goto defsubdirs; - } - } else { - // read value - value = new unsigned char [valuesize + 1]; - auto readSize = fread (value, 1, valuesize, f); - value[readSize] = '\0'; - } - - // seek back to the saved position - fseek (f, save, SEEK_SET); - return; - -defsubdirs: - // read value - value = new unsigned char [valuesize]; - if (fread (value, 1, valuesize, f) != static_cast(valuesize)) { - type = INVALID; - } else { - // count the number of valid subdirs - int sdcount = count; - - if (sdcount > 0) { - if (parent->getAttribTable() == olympusAttribs) { - sdcount = 1; - } - - // allocate space - directory = new TagDirectory*[sdcount + 1]; - - // load directories - for (size_t j = 0, i = 0; j < count; j++, i++) { - int newpos = base + toInt (j * 4, LONG); - fseek (f, newpos, SEEK_SET); - directory[i] = new TagDirectory (parent, f, base, attrib->subdirAttribs, order); - } - - // set the terminating NULL - directory[sdcount] = nullptr; - } else { - type = INVALID; - } - } - // seek back to the saved position - fseek (f, save, SEEK_SET); - return; - -} - -bool Tag::parseMakerNote (FILE* f, int base, ByteOrder bom ) -{ - value = nullptr; - Tag* tmake = parent->getRoot()->findTag ("Make"); - std::string make ( tmake ? tmake->valueToString() : ""); - - Tag* tmodel = parent->getRoot()->findTag ("Model"); - std::string model ( tmodel ? tmodel->valueToString() : ""); - - if ( make.find ( "NIKON" ) != std::string::npos ) { - if ( model.find ("NIKON E700") != std::string::npos || - model.find ("NIKON E800") != std::string::npos || - model.find ("NIKON E900") != std::string::npos || - model.find ("NIKON E900S") != std::string::npos || - model.find ("NIKON E910") != std::string::npos || - model.find ("NIKON E950") != std::string::npos ) { - makerNoteKind = HEADERIFD; - valuesize = 8; - value = new unsigned char[8]; - fread (value, 1, 8, f); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, nikon2Attribs, bom); - directory[1] = nullptr; - } else if ( model.find ("NIKON E990") != std::string::npos || - (model.find ("NIKON D1") != std::string::npos && model.size() > 8 && model.at (8) != '0')) { - makerNoteKind = IFD; - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, nikon3Attribs, bom); - directory[1] = nullptr; - } else { - // needs refinement! (embedded tiff header parsing) - makerNoteKind = NIKON3; - valuesize = 18; - value = new unsigned char[18]; - int basepos = ftell (f); - fread (value, 1, 18, f); - directory = new TagDirectory*[2]; - // byte order for makernotes can be different from exif byte order. We have to get it from makernotes header - ByteOrder MakerNoteOrder; - - if (value[10] == 'M' && value[11] == 'M') { - MakerNoteOrder = rtexif::MOTOROLA; - } else { - MakerNoteOrder = rtexif::INTEL; - } - - directory[0] = new TagDirectory (parent, f, basepos + 10, nikon3Attribs, MakerNoteOrder); - directory[1] = nullptr; - } - } else if ( make.find ( "Canon" ) != std::string::npos ) { - makerNoteKind = IFD; - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, canonAttribs, bom); - directory[1] = nullptr; - } else if ( make.find ( "PENTAX" ) != std::string::npos ) { - makerNoteKind = HEADERIFD; - valuesize = 6; - value = new unsigned char[6]; - fread (value, 1, 6, f); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, pentaxAttribs, bom); - directory[1] = nullptr; - } else if ( (make.find ( "RICOH" ) != std::string::npos ) && (model.find ("PENTAX") != std::string::npos) ) { - makerNoteKind = HEADERIFD; - valuesize = 10; - value = new unsigned char[10]; - fread (value, 1, 10, f); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, ftell (f) - 10, pentaxAttribs, bom); - directory[1] = nullptr; - } else if ( make.find ( "FUJIFILM" ) != std::string::npos ) { - makerNoteKind = FUJI; - valuesize = 12; - value = new unsigned char[12]; - fread (value, 1, 12, f); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, ftell (f) - 12, fujiAttribs, INTEL); - directory[1] = nullptr; - } else if ( make.find ( "KONICA MINOLTA" ) != std::string::npos || make.find ( "Minolta" ) != std::string::npos ) { - makerNoteKind = IFD; - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, minoltaAttribs, bom); - directory[1] = nullptr; - } else if ( make.find ( "SONY" ) != std::string::npos ) { - valuesize = 12; - value = new unsigned char[12]; - fread (value, 1, 12, f); - - if (!strncmp ((char*)value, "SONY DSC", 8)) { - makerNoteKind = HEADERIFD; - } else { - makerNoteKind = IFD; - fseek (f, -12, SEEK_CUR); - } - - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, sonyAttribs, bom ); - directory[1] = nullptr; - } else if ( make.find ( "OLYMPUS" ) != std::string::npos ) { - makerNoteKind = HEADERIFD; - valuesize = 8; - value = new unsigned char[12]; - fread (value, 1, 8, f); - directory = new TagDirectory*[2]; - directory[1] = nullptr; - - if (!strncmp ((char*)value, "OLYMPUS", 7)) { - makerNoteKind = OLYMPUS2; - fread (value + 8, 1, 4, f); - valuesize = 12; - directory[0] = new TagDirectory (parent, f, ftell (f) - 12, olympusAttribs, value[8] == 'I' ? INTEL : MOTOROLA); - } else { - directory[0] = new TagDirectory (parent, f, base, olympusAttribs, bom); - } - } else if ( make.find ( "Panasonic" ) != std::string::npos) { - makerNoteKind = HEADERIFD; - valuesize = 12; - value = new unsigned char[12]; - fread (value, 1, 12, f); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, f, base, panasonicAttribs, bom); - directory[1] = nullptr; - } else { - return false; - } - - return true; -} - -Tag* Tag::clone (TagDirectory* parent) -{ - - Tag* t = new Tag (parent, attrib); - - t->tag = tag; - t->type = type; - t->count = count; - t->keep = keep; - t->valuesize = valuesize; - - if (value) { - t->value = new unsigned char [valuesize]; - memcpy (t->value, value, valuesize); - } else { - value = nullptr; - } - - t->makerNoteKind = makerNoteKind; - - if (directory) { - int ds = 0; - - for (; directory[ds]; ds++); - - t->directory = new TagDirectory*[ds + 1]; - - for (int i = 0; i < ds; i++) { - t->directory[i] = directory[i]->clone (parent); - } - - t->directory[ds] = nullptr; - } else { - t->directory = nullptr; - } - - return t; -} - -Tag::~Tag () -{ - - // delete value - if (value && allocOwnMemory) { - delete [] value; - } - - // if there are directories behind the tag, delete them - if (directory) { - int i = 0; - - while (directory[i]) { - delete directory[i++]; - } - - delete [] directory; - } -} - -int Tag::getDistanceFrom(const TagDirectory *root) -{ - int i = 0; - TagDirectory *currTagDir = parent; - while (currTagDir != nullptr && currTagDir != root) { - ++i; - if (parent->getParent() == currTagDir) { - break; - } - currTagDir = parent->getParent(); - } - return i; -} - -void Tag::setInt (int v, int ofs, TagType astype) -{ - - if (astype == SHORT) { - sset2 (v, value + ofs, getOrder()); - } else if (astype == RATIONAL) { - sset4 (v, value + ofs, getOrder()); - sset4 (1, value + ofs + 4, getOrder()); - } else { - sset4 (v, value + ofs, getOrder()); - } -} - -void Tag::fromInt (int v) -{ - - if (type == SHORT) { - sset2 (v, value, getOrder()); - } else { - sset4 (v, value, getOrder()); - } -} - -void Tag::fromString (const char* v, int size) -{ - - if ( value && allocOwnMemory) { - delete [] value; - } - - if (size < 0) { - valuesize = strlen (v) + 1; - } else { - valuesize = size; - } - - count = valuesize; - - if ( allocOwnMemory ) { - value = new unsigned char [valuesize]; - } - - if(value) { - memcpy ((char*)value, v, valuesize); - } -} - -int Tag::toInt (int ofs, TagType astype) const -{ - if (attrib) { - return attrib->interpreter->toInt (this, ofs, astype); - } - - int a; - - if (astype == INVALID) { - astype = type; - } - - switch (astype) { - //case SBYTE: return (signed char)(value[ofs]); - case SBYTE: - return int ((reinterpret_cast (value))[ofs]); - - case BYTE: - return value[ofs]; - - case ASCII: - return 0; - - case SSHORT: - return (int)int2_to_signed (sget2 (value + ofs, getOrder())); - - case SHORT: - return (int)sget2 (value + ofs, getOrder()); - - case SLONG: - case LONG: - return (int)sget4 (value + ofs, getOrder()); - - case SRATIONAL: - case RATIONAL: - a = (int)sget4 (value + ofs + 4, getOrder()); - return a == 0 ? 0 : (int)sget4 (value + ofs, getOrder()) / a; - - case FLOAT: - return (int)toDouble (ofs); - - case UNDEFINED: - return 0; - - default: - return 0; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) - } - - return 0; -} - -double Tag::toDouble (int ofs) const -{ - if (attrib) { - return attrib->interpreter->toDouble (this, ofs); - } - - union IntFloat { - uint32_t i; - float f; - } conv; - - double ud, dd; - - switch (type) { - case SBYTE: - return (double) (int ((reinterpret_cast (value))[ofs])); - - case BYTE: - return (double) ((int)value[ofs]); - - case ASCII: - return 0.0; - - case SSHORT: - return (double)int2_to_signed (sget2 (value + ofs, getOrder())); - - case SHORT: - return (double) ((int)sget2 (value + ofs, getOrder())); - - case SLONG: - case LONG: - return (double) ((int)sget4 (value + ofs, getOrder())); - - case SRATIONAL: - case RATIONAL: - ud = (int)sget4 (value + ofs, getOrder()); - dd = (int)sget4 (value + ofs + 4, getOrder()); - return dd == 0. ? 0. : (double)ud / (double)dd; - - case FLOAT: - conv.i = sget4 (value + ofs, getOrder()); - return conv.f; // IEEE FLOATs are already C format, they just need a recast - - case UNDEFINED: - return 0.; - - default: - return 0.; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) - } - -} - -/** - * @brief Create an array of the elements - */ -double* Tag::toDoubleArray (int ofs) const -{ - double *values = new double[count]; - - for (unsigned int i = 0; i < count; ++i) { - values[i] = toDouble (ofs + i * getTypeSize (type)); - } - - return values; -} - -void Tag::toRational (int& num, int& denom, int ofs) const -{ - - switch (type) { - case BYTE: - num = (int)value[ofs]; - denom = 1; - break; - - case ASCII: - num = 0; - denom = 0; - break; - - case SSHORT: - case SHORT: - num = (int)sget2 (value + ofs, getOrder()); - denom = 1; - break; - - case SLONG: - case LONG: - num = (int)sget4 (value + ofs, getOrder()); - denom = 1; - break; - - case SRATIONAL: - case RATIONAL: - num = (int)sget4 (value + ofs, getOrder()); - denom = (int)sget4 (value + ofs + 4, getOrder()); - break; - - case FLOAT: - num = 0; - denom = 0; - break; - - case UNDEFINED: - num = 0; - denom = 0; - break; - - default: - num = 0; - denom = 0; - break; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) - } -} - -void Tag::toString (char* buffer, int ofs) const -{ - - if (type == UNDEFINED && !directory) { - bool isstring = true; - unsigned int i = 0; - - for (i = 0; i + ofs < count && i < 64 && value[i + ofs]; i++) - if (value[i + ofs] < 32 || value[i + ofs] > 126) { - isstring = false; - } - - if (isstring) { - int j = 0; - - for (i = 0; i + ofs < count && i < 64 && value[i + ofs]; i++) { - if (value[i + ofs] == '<' || value[i + ofs] == '>') { - buffer[j++] = '\\'; - } - - buffer[j++] = value[i + ofs]; - } - - buffer[j++] = 0; - return; - } - } else if (type == ASCII) { - sprintf (buffer, "%.64s", value + ofs); - return; - } - - size_t maxcount = rtengine::min(count, 10); - - strcpy (buffer, ""); - - for (ssize_t i = 0; i < rtengine::min(maxcount, valuesize - ofs); i++) { - if (i > 0) { - strcat (buffer, ", "); - } - - char* b = buffer + strlen (buffer); - - switch (type) { - case UNDEFINED: - case BYTE: - sprintf (b, "%d", value[i + ofs]); - break; - - case SSHORT: - sprintf (b, "%d", toInt (2 * i + ofs)); - break; - - case SHORT: - sprintf (b, "%u", toInt (2 * i + ofs)); - break; - - case SLONG: - sprintf (b, "%d", toInt (4 * i + ofs)); - break; - - case LONG: - sprintf (b, "%u", toInt (4 * i + ofs)); - break; - - case SRATIONAL: - case RATIONAL: - sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder())); - break; - - case FLOAT: - sprintf (b, "%g", toDouble (8 * i + ofs)); - break; - - default: - break; - } - } - - if (count > maxcount) { - strcat (buffer, "..."); - } -} - -std::string Tag::nameToString (int i) -{ - - char buffer[1025]; - - if (attrib) { - strncpy (buffer, attrib->name, 1024); - } else { - sprintf (buffer, "0x%x", tag); - } - - if (i > 0) { - sprintf (buffer + strlen (buffer) - 1, "[%d]", i); - } - - return buffer; -} - -std::string Tag::valueToString () const -{ - - if (attrib && attrib->interpreter) { - return attrib->interpreter->toString (this); - } else { - char buffer[1024]; - toString (buffer); - return buffer; - } -} - -void Tag::valueFromString (const std::string& value) -{ - - if (attrib && attrib->interpreter) { - attrib->interpreter->fromString (this, value); - } -} - -void Tag::userCommentFromString (const Glib::ustring& text) -{ - - if (!allocOwnMemory) { - return; - } - if (value) { - delete [] value; - value = nullptr; - } - initUserComment(text); -} - -int Tag::calculateSize () -{ - int size = 0; - - if (directory) { - int j; - - for (j = 0; directory[j]; j++) { - size += directory[j]->calculateSize (); - } - - if (j > 1) { - size += 4 * j; - } - if (makerNoteKind != NOMK) { - count = directory[0]->calculateSize () / getTypeSize (type); - } - } else if (valuesize > 4) { - size += valuesize + (valuesize % 2); // we align tags to even byte positions - } - - - if (makerNoteKind == NIKON3 || makerNoteKind == OLYMPUS2 || makerNoteKind == FUJI || makerNoteKind == HEADERIFD) { - size += valuesize; - } - - return size; -} - -int Tag::write (int offs, int dataOffs, unsigned char* buffer) -{ - - if ((int)type == 0 || offs > 65500) { - return dataOffs; - } - - sset2 (tag, buffer + offs, parent->getOrder()); - offs += 2; - unsigned short typ = type; - sset2 (typ, buffer + offs, parent->getOrder()); - offs += 2; - sset4 (count, buffer + offs, parent->getOrder()); - offs += 4; - - if (!directory) { - if (valuesize > 4) { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - memcpy (buffer + dataOffs, value, valuesize); - - if (valuesize % 2) { - buffer[dataOffs + valuesize] = 0; // zero padding required by the exif standard - } - - return dataOffs + valuesize + (valuesize % 2); - } else { - memcpy (buffer + offs, value, valuesize); - return dataOffs; - } - } else { - if (makerNoteKind == NIKON3) { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - memcpy (buffer + dataOffs, value, 18); - dataOffs += 10; - dataOffs += directory[0]->write (8, buffer + dataOffs); - return dataOffs; - } else if (makerNoteKind == OLYMPUS2 || makerNoteKind == FUJI) { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - memcpy (buffer + dataOffs, value, valuesize); - dataOffs += valuesize + directory[0]->write (valuesize, buffer + dataOffs); - return dataOffs; - } else if (makerNoteKind == HEADERIFD) { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - memcpy (buffer + dataOffs, value, valuesize); - dataOffs += valuesize; - dataOffs += directory[0]->write (dataOffs, buffer); - return dataOffs; - } else if ( makerNoteKind == TABLESUBDIR) { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - dataOffs = directory[0]->write (dataOffs, buffer); - return dataOffs; - } else if (!directory[1]) { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - return directory[0]->write (dataOffs, buffer); - } else { - sset4 (dataOffs, buffer + offs, parent->getOrder()); - int linkOffs = dataOffs; - - for (int i = 0; directory[i]; i++) { - dataOffs += 4; - } - - for (int i = 0; directory[i]; i++) { - sset4 (dataOffs, buffer + linkOffs, parent->getOrder()); - linkOffs += 4; - dataOffs = directory[i]->write (dataOffs, buffer); - } - - return dataOffs; - } - } -} - -Tag::Tag (TagDirectory* p, const TagAttrib* attr) - : tag (attr ? attr->ID : -1), type (INVALID), count (0), value (nullptr), valuesize (0), keep (true), allocOwnMemory (true), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK) -{ -} - -Tag::Tag (TagDirectory* p, const TagAttrib* attr, int data, TagType t) - : tag (attr ? attr->ID : -1), type (t), count (1), value (nullptr), valuesize (0), keep (true), allocOwnMemory (true), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK) -{ - - initInt (data, t); -} - -Tag::Tag (TagDirectory* p, const TagAttrib* attr, unsigned char *data, TagType t) - : tag (attr ? attr->ID : -1), type (t), count (1), value (nullptr), valuesize (0), keep (true), allocOwnMemory (false), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK) -{ - - initType (data, t); -} - -Tag::Tag (TagDirectory* p, const TagAttrib* attr, const char* text) - : tag (attr ? attr->ID : -1), type (ASCII), count (1), value (nullptr), valuesize (0), keep (true), allocOwnMemory (true), attrib (attr), parent (p), directory (nullptr), makerNoteKind (NOMK) -{ - - initString (text); -} - -void Tag::initType (unsigned char *data, TagType type) -{ - valuesize = getTypeSize (type); - - if ( allocOwnMemory ) { - value = new unsigned char[valuesize]; - memcpy ((char*)value, data, valuesize); - } else { - value = data; - } -} - -void Tag::initInt (int data, TagType t, int cnt) -{ - - type = t; - - if (t == LONG) { - valuesize = 4; - } else if (t == SHORT) { - valuesize = 2; - } else if (t == BYTE) { - valuesize = 1; - } else if (t == RATIONAL) { - valuesize = 8; - } - - count = cnt; - valuesize *= count; - value = new unsigned char[valuesize]; - setInt (data, 0, t); -} - -void Tag::swapByteOrder2(unsigned char *buffer, int count) -{ - unsigned char* ptr = buffer; - for (int i = 0; i < count; i+=2) { - unsigned char c = ptr[0]; - ptr[0] = ptr[1]; - ptr[1] = c; - ptr += 2; - } -} -void Tag::initUserComment (const Glib::ustring &text) -{ - const bool useBOM = false; // set it to true if you want to output BOM in UCS-2/UTF-8 UserComments ; this could be turned to an options entry - type = UNDEFINED; - if (text.is_ascii()) { - valuesize = count = 8 + strlen (text.c_str()); - value = new unsigned char[valuesize]; - memcpy(value, "ASCII\0\0\0", 8); - memcpy(value + 8, text.c_str(), valuesize - 8); - } else { - glong wcStrSize = 0; - gunichar2 *commentStr = g_utf8_to_utf16 (text.c_str(), -1, nullptr, &wcStrSize, nullptr); - valuesize = count = wcStrSize * 2 + 8 + (useBOM ? 2 : 0); - value = new unsigned char[valuesize]; - memcpy(value, "UNICODE\0", 8); - - if (useBOM) { - if (getOrder() == INTEL) { //Little Endian - value[8] = 0xFF; - value[9] = 0xFE; - } else { - value[8] = 0xFE; - value[9] = 0xFF; - } - } - - // Swapping byte order to match the Exif's byte order - if (getOrder() != HOSTORDER) { - swapByteOrder2((unsigned char*)commentStr, wcStrSize * 2); - } - - memcpy(value + 8 + (useBOM ? 2 : 0), (char*)commentStr, wcStrSize * 2); - g_free(commentStr); - } -} - -void Tag::initString (const char* text) -{ - - type = ASCII; - count = strlen (text) + 1; - valuesize = count; - value = new unsigned char[valuesize]; - strcpy ((char*)value, text); -} - -void Tag::initSubDir () -{ - type = LONG; - valuesize = 4; - count = 1; - value = new unsigned char[4]; - setInt (0); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, attrib ? attrib->subdirAttribs : nullptr, parent->getOrder()); - directory[1] = nullptr; -} - -void Tag::initSubDir (TagDirectory* dir) -{ - type = LONG; - valuesize = 4; - count = 1; - value = new unsigned char[4]; - setInt (0); - directory = new TagDirectory*[2]; - directory[0] = dir; - directory[1] = nullptr; -} - -void Tag::initMakerNote (MNKind mnk, const TagAttrib* ta) -{ - type = UNDEFINED; - valuesize = 4; - count = 1; - value = new unsigned char[4]; - setInt (0); - directory = new TagDirectory*[2]; - directory[0] = new TagDirectory (parent, ta, parent->getOrder()); - directory[1] = nullptr; - makerNoteKind = mnk; -} - -void Tag::initUndefArray (const char* data, int len) -{ - type = UNDEFINED; - count = valuesize = len; - value = new unsigned char[valuesize]; - memcpy (value, data, len); -} - -void Tag::initLongArray (const char* data, int len) -{ - type = LONG; - count = (len + 3) / 4; - valuesize = count * 4; - value = new unsigned char[valuesize]; - memcpy (value, data, len); -} - -void Tag::initRational (int num, int den) -{ - count = 1; - valuesize = 8; - value = new unsigned char[8]; - type = RATIONAL; - setInt (num, 0); - setInt (den, 4); -} - -//--------------- class IFDParser --------------------------------------------- -// static functions to read tag directories from different kinds of files -//----------------------------------------------------------------------------- - - -const TagAttrib* lookupAttrib (const TagAttrib* dir, const char* field) -{ - - for (int i = 0; dir[i].ignore != -1; i++) - if (!strcmp (dir[i].name, field)) { - return &dir[i]; - } - - return nullptr; -} - -void ExifManager::setIFDOffset(unsigned int offset) -{ - IFDOffset = offset; -} - -void ExifManager::parseCIFF () -{ - - TagDirectory* root = new TagDirectory (nullptr, ifdAttribs, INTEL); - Tag* exif = new Tag (root, lookupAttrib (ifdAttribs, "Exif")); - exif->initSubDir (); - root->addTag (exif); - if (exif) { - Tag* mn = new Tag (exif->getDirectory(), lookupAttrib (exifAttribs, "MakerNote")); - mn->initMakerNote (IFD, canonAttribs); - exif->getDirectory()->addTag (mn); - } - parseCIFF (rml->ciffLength, root); - root->sort (); - parse(true); -} - -Tag* ExifManager::saveCIFFMNTag (TagDirectory* root, int len, const char* name) -{ - int s = ftell (f); - if(s >= 0) { - char* data = new char [len]; - fread (data, len, 1, f); - TagDirectory* mn = root->getTag ("Exif")->getDirectory()->getTag ("MakerNote")->getDirectory(); - Tag* cs = new Tag (mn, lookupAttrib (canonAttribs, name)); - cs->initUndefArray (data, len); - mn->addTag (cs); - fseek (f, s, SEEK_SET); - delete [] data; - return cs; - } else { - return nullptr; - } -} - -void ExifManager::parseCIFF (int length, TagDirectory* root) -{ - - if (!f) { - #ifndef NDEBUG - std::cerr << "ERROR : no file opened !" << std::endl; - #endif - return; - } - - char buffer[1024]; - Tag* t; - - if (fseek(f, rml->ciffBase + length - 4, SEEK_SET)) { - return; - } - - int dirStart = get4 (f, INTEL) + rml->ciffBase; - if (fseek(f, dirStart, SEEK_SET)) { - return; - } - - int numOfTags = get2 (f, INTEL); - - if (numOfTags > 100) { - return; - } - - float exptime, shutter, aperture, fnumber, ev; - exptime = fnumber = shutter = aperture = ev = -1000.f; - int focal_len, iso; - focal_len = iso = -1; - - TagDirectory* exif = root->getTag ("Exif")->getDirectory(); - - time_t timestamp = time (nullptr); - - for (int i = 0; i < numOfTags; i++) { - - int type = get2 (f, INTEL); - int len = get4 (f, INTEL); - int nextPos = ftell (f) + 4; - - // seek to the location of the value - fseek (f, rml->ciffBase + get4 (f, INTEL), SEEK_SET); - - if ((((type >> 8) + 8) | 8) == 0x38) { - ExifManager( - f, - std::unique_ptr( - new rtengine::RawMetaDataLocation( - ftell(f), - len - ) - ), - true - ).parseCIFF(len, root); // Parse a sub-table - } - - if (type == 0x0810) { - fread (buffer, 64, 1, f); - t = new Tag (root, lookupAttrib (ifdAttribs, "Artist")); - t->initString (buffer); - root->addTag (t); - } - - if (type == 0x080a) { - fread (buffer, 64, 1, f); - t = new Tag (root, lookupAttrib (ifdAttribs, "Make")); - t->initString (buffer); - root->addTag (t); - if (!fseek (f, strlen (buffer) - 63, SEEK_CUR)) { - if (fread (buffer, 64, 1, f) == 1) { - t = new Tag (root, lookupAttrib (ifdAttribs, "Model")); - t->initString (buffer); - root->addTag (t); - } - } - } - - if (type == 0x1818) { - ev = int_to_float (get4 (f, INTEL)); - shutter = int_to_float (get4 (f, INTEL)); - exptime = pow (2, -shutter); - aperture = int_to_float (get4 (f, INTEL)); - fnumber = pow (2, aperture / 2); - - } - - ExifManager exifManager(f, nullptr, true); - if (type == 0x102d) { - Tag* t = exifManager.saveCIFFMNTag (root, len, "CanonCameraSettings"); - int mm = t->toInt (34, SHORT); - Tag* nt = new Tag (exif, lookupAttrib (exifAttribs, "MeteringMode")); - - switch (mm) { - case 0: - nt->initInt (5, SHORT); - break; - - case 1: - nt->initInt (3, SHORT); - break; - - case 2: - nt->initInt (1, SHORT); - break; - - case 3: - nt->initInt (5, SHORT); - break; - - case 4: - nt->initInt (6, SHORT); - break; - - case 5: - nt->initInt (2, SHORT); - break; - } - - exif->addTag (nt); - nt = new Tag (exif, lookupAttrib (exifAttribs, "MaxApertureValue")); - nt->initRational (t->toInt (52, SHORT), 32); - exif->addTag (nt); - int em = t->toInt (40, SHORT); - nt = new Tag (exif, lookupAttrib (exifAttribs, "ExposureProgram")); - - switch (em) { - case 0: - nt->initInt (2, SHORT); - break; - - case 1: - nt->initInt (2, SHORT); - break; - - case 2: - nt->initInt (4, SHORT); - break; - - case 3: - nt->initInt (3, SHORT); - break; - - case 4: - nt->initInt (1, SHORT); - break; - - default: - nt->initInt (0, SHORT); - break; - } - - exif->addTag (nt); - nt = new Tag (exif, lookupAttrib (exifAttribs, "Flash")); - - if (t->toInt (8, SHORT) == 0) { - nt->initInt (0, SHORT); - } else { - nt->initInt (1, SHORT); - } - - exif->addTag (nt); - nt = new Tag (exif, lookupAttrib (exifAttribs, "MaxApertureValue")); - nt->initRational (t->toInt (52, SHORT), 32); - exif->addTag (nt); - } - - if (type == 0x1029) { - exifManager.saveCIFFMNTag (root, len, "CanonFocalLength"); - } - - if (type == 0x1031) { - exifManager.saveCIFFMNTag (root, len, "SensorInfo"); - } - - if (type == 0x1033) { - exifManager.saveCIFFMNTag (root, len, "CustomFunctions"); - } - - if (type == 0x1038) { - exifManager.saveCIFFMNTag (root, len, "CanonAFInfo"); - } - - if (type == 0x1093) { - exifManager.saveCIFFMNTag (root, len, "CanonFileInfo"); - } - - if (type == 0x10a9) { - exifManager.saveCIFFMNTag (root, len, "ColorBalance"); - } - - if (type == 0x102a) { - exifManager.saveCIFFMNTag (root, len, "CanonShotInfo"); - - iso = pow (2, (get4 (f, INTEL), get2 (f, INTEL)) / 32.0 - 4) * 50; - aperture = (get2 (f, INTEL), (short)get2 (f, INTEL)) / 32.0f; - fnumber = pow (2, aperture / 2); - shutter = ((short)get2 (f, INTEL)) / 32.0f; - ev = ((short)get2 (f, INTEL)) / 32.0f; - fseek (f, 34, SEEK_CUR); - - if (shutter > 1e6) { - shutter = get2 (f, INTEL) / 10.0f; - } - - exptime = pow (2, -shutter); - } - - if (type == 0x5029) { - focal_len = len >> 16; - - if ((len & 0xffff) == 2) { - focal_len /= 32; - } - } - -// if (type == 0x5813) flash_used = int_to_float(len); - if (type == 0x580e) { - timestamp = len; - } - - if (type == 0x180e) { - timestamp = get4 (f, INTEL); - } - - if ((type | 0x4000) == 0x580e) { - timestamp = mktime (gmtime (×tamp)); - } - - fseek (f, nextPos, SEEK_SET); - } - - if (shutter > -999) { - t = new Tag (exif, lookupAttrib (exifAttribs, "ShutterSpeedValue")); - t->initRational ((int) (shutter * 10000), 10000); - exif->addTag (t); - } - - if (exptime > -999) { - t = new Tag (exif, lookupAttrib (exifAttribs, "ExposureTime")); - t->initRational ((int) (exptime * 10000), 10000); - exif->addTag (t); - } - - if (aperture > -999) { - t = new Tag (exif, lookupAttrib (exifAttribs, "ApertureValue")); - t->initRational ((int) (aperture * 10), 10); - exif->addTag (t); - } - - if (fnumber > -999) { - t = new Tag (exif, lookupAttrib (exifAttribs, "FNumber")); - t->initRational ((int) (fnumber * 10), 10); - exif->addTag (t); - } - - if (ev > -999) { - t = new Tag (exif, lookupAttrib (exifAttribs, "ExposureBiasValue")); - t->initRational ((int) (ev * 1000), 1000); - exif->addTag (t); - } - - if (iso > 0) { - t = new Tag (exif, lookupAttrib (exifAttribs, "ISOSpeedRatings")); - t->initInt (iso, LONG); - exif->addTag (t); - } - - if (focal_len > 0) { - t = new Tag (exif, lookupAttrib (exifAttribs, "FocalLength")); - t->initRational (focal_len * 32, 32); - exif->addTag (t); - } - - if (timestamp != time (nullptr)) { - struct tm* tim = localtime (×tamp); - strftime (buffer, 20, "%Y:%m:%d %H:%M:%S", tim); - t = new Tag (exif, lookupAttrib (exifAttribs, "DateTimeOriginal")); - t->initString (buffer); - exif->addTag (t); - t = new Tag (exif, lookupAttrib (exifAttribs, "DateTimeDigitized")); - t->initString (buffer); - exif->addTag (t); - t = new Tag (root, lookupAttrib (ifdAttribs, "DateTime")); - t->initString (buffer); - root->addTag (t); - } - - roots.push_back(root); - -} - -static void -parse_leafdata (TagDirectory* root, ByteOrder order) -{ - - Tag *leafdata = root->getTag ("LeafData"); - - if (!leafdata) { - return; - } - - unsigned char *value = leafdata->getValue(); - int valuesize = leafdata->getValueSize(); - - // parse LeafData tag, a tag specific to Leaf digital backs, and has a custom - // format with 52 byte tag headers starting with "PKTS" - const char *PKTS_tag = (order == MOTOROLA) ? "PKTS" : "STKP"; - char *hdr; - int pos = 0; - - // There are lots of sub-tags in here, but for now we only care about those directly - // useful to RT, which is ISO and rotation. Shutter speed and aperture is not - // available here. - int iso_speed = 0; - int rotation_angle = 0; - int found_count = 0; - - while (pos + (int)sizeof (hdr) <= valuesize && found_count < 2) { - hdr = (char *)&value[pos]; - - if (strncmp (hdr, PKTS_tag, 4) != 0) { - // in a few cases the header can be offset a few bytes, don't know why - // it does not seem to be some sort of alignment, it appears random, - // this check takes care of it, restart if we find an offset match. - int offset = 1; - - for (; offset <= 3; offset++) { - if (strncmp (&hdr[offset], PKTS_tag, 4) == 0) { - pos += offset; - break; - } - } - - if (offset <= 3) { - continue; - } - - break; - } - - int size = sget4 ((unsigned char *)&hdr[48], order); - - if (pos + size > valuesize) { - break; - } - - pos += 52; - char *val = (char *)&value[pos]; - - if (strncmp (&hdr[8], "CameraObj_ISO_speed", 19) == 0) { - iso_speed = 25 * (1 << std::max((atoi (val) - 1), 0)); - found_count++; - } else if (strncmp (&hdr[8], "ImgProf_rotation_angle", 22) == 0) { - rotation_angle = atoi (val); - found_count++; - } else { - // check if this is a sub-directory, include test for that strange offset of next header - if (size >= 8 && - (strncmp (val, PKTS_tag, 4) == 0 || - strncmp (&val[1], PKTS_tag, 4) == 0 || - strncmp (&val[2], PKTS_tag, 4) == 0 || - strncmp (&val[3], PKTS_tag, 4) == 0)) { - // start of next hdr, this is a sub-directory, we skip those for now. - size = 0; - } - } - - pos += size; - } - - // create standard tags from the custom Leaf tags - Tag* exif = root->getTag ("Exif"); - - if (!exif) { - exif = new Tag (root, root->getAttrib ("Exif")); - exif->initSubDir(); - root->addTagFront (exif); - } - - if (exif && !exif->getDirectory()->getTag ("ISOSpeedRatings")) { - Tag *t = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings")); - t->initInt (iso_speed, LONG); - exif->getDirectory()->addTagFront (t); - } - - if (!root->getTag ("Orientation")) { - int orientation; - - switch (rotation_angle) { - case 0: - orientation = 1; - break; - - case 90: - orientation = 6; - break; - - case 180: - orientation = 3; - break; - - case 270: - orientation = 8; - break; - - default: - orientation = 1; - break; - } - - Tag *t = new Tag (root, root->getAttrib ("Orientation")); - t->initInt (orientation, SHORT); - root->addTagFront (t); - } - - // now look in ApplicationNotes tag for additional information - Tag *appnotes = root->getTag ("ApplicationNotes"); - - if (!appnotes) { - return; - } - - char *xmp = (char *)appnotes->getValue(); - char *end, *p; - - // Quick-and-dirty value extractor, no real xml parsing. - // We could make it more generic, but we just get most important - // values we know use to be in there. - if ((p = strstr (xmp, "xmlns:tiff")) != nullptr && - (end = strstr (p, "")) != nullptr) { - *end = '\0'; - - while ((p = strstr (p, "')) == nullptr) { - break; - } - - *tagend = '\0'; - char *val = &tagend[1]; - - if ((p = strstr (val, "getAttrib (tag) && !root->getTag (tag)) { - Tag *t = new Tag (root, root->getAttrib (tag)); - - if (strcmp (tag, "Make") == 0 || - strcmp (tag, "Model") == 0) { - if (strcmp (tag, "Model") == 0) { - // Leaf adds back serial number and camera model to the 'Model' - // tag, we strip that away here so the back can be recognized - // and matched against DCP profile - char *p1 = strchr (val, '('); - - if (p1 != nullptr) { - *p1 = '\0'; - } - - // Model name also contains a leading "Leaf " which we already - // have in the Make name, remove that. - if (strstr (val, "Leaf ") == val) { - t->initString (&val[5]); - } else { - t->initString (val); - } - - if (p1 != nullptr) { - *p1 = '('; - } - } else { - t->initString (val); - } - - root->addTagFront (t); - } else { - delete t; - } - } - - *p = '<'; - *tagend = '>'; - } - - *end = '<'; - } - - if ((p = strstr (xmp, "xmlns:exif")) != nullptr && - (end = strstr (p, "")) != nullptr) { - *end = '\0'; - - while ((p = strstr (p, "')) == nullptr) { - break; - } - - *tagend = '\0'; - char *val = &tagend[1]; - - if ((p = strstr (val, "getDirectory()->getAttrib (tag) && !exif->getDirectory()->getTag (tag)) { - Tag *t = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib (tag)); - int num, denom; - struct tm tm; - - if (strcmp (tag, "ApertureValue") == 0 && sscanf (val, "%d/%d", &num, &denom) == 2) { - t->initRational (num, denom); - exif->getDirectory()->addTagFront (t); - // we also make an "FNumber" tag since many tools don't interpret ApertureValue - // according to Exif standard - t = new Tag (exif->getDirectory(), lookupAttrib (exifAttribs, "FNumber")); - double f = pow (sqrt (2.0), ((double)num / denom)); - - if (f > 10.0) { - t->initRational ((int)floor (f), 1); - } else { - t->initRational ((int)floor (f * 10.0), 10); - } - - exif->getDirectory()->addTagFront (t); - } else if (strcmp (tag, "ShutterSpeedValue") == 0 && sscanf (val, "%d/%d", &num, &denom) == 2) { - t->initRational (num, denom); - exif->getDirectory()->addTagFront (t); - // we also make an "ExposureTime" tag since many tools don't interpret ShutterSpeedValue - // according to Exif standard - t = new Tag (exif->getDirectory(), lookupAttrib (exifAttribs, "ExposureTime")); - double f = 1.0 / pow (2.0, ((double)num / denom)); - - if (f > 10.0) { - t->initRational ((int)floor (f), 1); - } else if (f > 1.0) { - t->initRational ((int)floor (f * 10.0), 10); - } else if (f == 1.0) { - t->initRational (1, 1); - } else { - f = 1.0 / f; - static const double etimes[] = { - 10000, 8000, 6400, 6000, 5000, - 4000, 3200, 3000, 2500, - 2000, 1600, 1500, 1250, - 1000, 800, 750, 640, - 500, 400, 350, 320, - 250, 200, 180, 160, - 125, 100, 90, 80, - 60, 50, 45, 40, - 30, 25, 22, 20, - 15, 13, 11, 10, - 8, 6, 5, - 4, 3, 2.5, - 2, 1.6, 1.5, 1.3, - 1, -1 - }; - double diff = etimes[0]; - int idx = -1; - - for (int i = 1; etimes[i] > 0; i++) { - if (abs (etimes[i] - f) < diff) { - idx = i; - diff = abs (etimes[i] - f); - } - } - - if (idx != -1 && f < etimes[0]) { - f = etimes[idx]; - } - - if (f < 2) { - t->initRational (10, (int) (10 * f)); - } else { - t->initRational (1, (int)f); - } - } - - exif->getDirectory()->addTagFront (t); - } else if (strcmp (tag, "FocalLength") == 0 && sscanf (val, "%d/%d", &num, &denom) == 2) { - t->initRational (num, denom); - exif->getDirectory()->addTagFront (t); - } else if (strcmp (tag, "ISOSpeedRatings") == 0) { - char *p1 = val; - - while (*p1 != '\0' && !isdigit (*p1)) { - p1++; - } - - if (*p1 != '\0') { - t->initInt (atoi (p1), LONG); - exif->getDirectory()->addTagFront (t); - } else { - delete t; - } - } else if (strcmp (tag, "DateTimeOriginal") == 0 && - sscanf (val, "%d-%d-%dT%d:%d:%dZ", - &tm.tm_year, &tm.tm_mon, - &tm.tm_mday, &tm.tm_hour, - &tm.tm_min, &tm.tm_sec) == 6) { - char tstr[64]; - sprintf (tstr, "%04d:%02d:%02d %02d:%02d:%02d", tm.tm_year, tm.tm_mon, - tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - t->initString (tstr); - exif->getDirectory()->addTagFront (t); - } else { - delete t; - } - } - - *p = '<'; - *tagend = '>'; - } - - *end = '<'; - } -} - -void ExifManager::parseRaw (bool skipIgnored) { - parse(true, skipIgnored); -} - -void ExifManager::parseStd (bool skipIgnored) { - parse(false, skipIgnored); -} - -void ExifManager::parse (bool isRaw, bool skipIgnored) -{ - int ifdOffset = IFDOffset; - - if (!f) { - #ifndef NDEBUG - std::cerr << "ERROR : no file opened !" << std::endl; - #endif - return; - } - setlocale (LC_NUMERIC, "C"); // to set decimal point in sscanf - - if (order == ByteOrder::UNKNOWN) { - // read tiff header - fseek (f, rml->exifBase, SEEK_SET); - unsigned short bo; - fread (&bo, 1, 2, f); - order = (ByteOrder) ((int)bo); - get2 (f, order); - if (!ifdOffset) { - ifdOffset = get4 (f, order); - } - } - - do { - // seek to IFD - fseek (f, rml->exifBase + ifdOffset, SEEK_SET); - - // first read the IFD directory - TagDirectory* root = new TagDirectory (nullptr, f, rml->exifBase, ifdAttribs, order, skipIgnored); - - // fix ISO issue with nikon and panasonic cameras - Tag* make = root->getTag ("Make"); - Tag* exif = root->getTag ("Exif"); - - if (exif && !exif->getDirectory()->getTag ("ISOSpeedRatings")) { - if (make && !strncmp ((char*)make->getValue(), "NIKON", 5)) { - Tag* mn = exif->getDirectory()->getTag ("MakerNote"); - - if (mn) { - Tag* iso = mn->getDirectory()->getTag ("ISOSpeed"); - - if (iso) { - std::string isov = iso->valueToString (); - Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings")); - niso->initInt (atoi (isov.c_str()), SHORT); - exif->getDirectory()->addTagFront (niso); - } - } - } else if (make && (!strncmp ((char*)make->getValue(), "Panasonic", 9) || !strncmp ((char*)make->getValue(), "LEICA", 5))) { - Tag* iso = root->getTag ("PanaISO"); - - if (iso) { - std::string isov = iso->valueToString (); - Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings")); - niso->initInt (atoi (isov.c_str()), SHORT); - exif->getDirectory()->addTagFront (niso); - } - } - } - - if (make && !strncmp ((char*)make->getValue(), "Kodak", 5)) { - if (!exif) { - // old Kodak cameras may have exif tags in IFD0, reparse and create an exif subdir - fseek (f, rml->exifBase + ifdOffset, SEEK_SET); - TagDirectory* exifdir = new TagDirectory (nullptr, f, rml->exifBase, exifAttribs, order, true); - - exif = new Tag (root, root->getAttrib ("Exif")); - exif->initSubDir (exifdir); - root->addTagFront (exif); - - if (exif && !exif->getDirectory()->getTag ("ISOSpeedRatings") && exif->getDirectory()->getTag ("ExposureIndex")) { - Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings")); - niso->initInt (exif->getDirectory()->getTag ("ExposureIndex")->toInt(), SHORT); - exif->getDirectory()->addTagFront (niso); - } - } - - Tag *kodakIFD = root->getTag ("KodakIFD"); - - if (kodakIFD && kodakIFD->getDirectory()->getTag ("TextualInfo")) { - parseKodakIfdTextualInfo (kodakIFD->getDirectory()->getTag ("TextualInfo"), exif); - } - } - - parse_leafdata (root, order); - - if (make && !strncmp ((char*)make->getValue(), "Hasselblad", 10)) { - /* - Figuring out the Hasselblad model is a mess. Hasselblad raw data comes in four slightly - different containers, 3FR (directly from CF card), FFF (same as 3FR but filtered through - Phocus, calibration data applied and a bit different tags), Adobe-generated DNGs and - Phocus-generated DNGs. - - FFF usually has a sane model name in Model (and is used as reference for what we shall - call the different Hasselblad models), but 3FR only says like "Hasselblad H3D" for - all H3D models, or "Flash Sync" if the back has been used on a mechanical camera body. - V-mount backs may have the model name of the V body instead of the back model. Etc... - as said it's a mess. - - This code is supposed to handle all raw containers and end up with the same model - regardless of container. - - We don't differ between single shot and multi-shot models, and probably there's no use - of doing so. You need Hasselblad's own software to shoot multi-shot and can only do that - tethered. In single-shot mode they should be exactly the same as the single-shot models. - */ - Tag *subd = root->getTag (0x14a); - Tag *iw = (subd) ? subd->getDirectory()->getTag ("ImageWidth") : nullptr; - int sensorWidth = (iw) ? iw->toInt() : 0; - Tag* tmodel = root->getTag ("Model"); - const char *model = (tmodel) ? (const char *)tmodel->getValue() : ""; - - if (strstr (model, "Hasselblad ") == model) { - model += 11; - } else { - // if HxD is used in flash sync mode for example, we need to fetch model from this tag - Tag* tmodel3 = root->getTag ("UniqueCameraModel"); - const char *model3 = (tmodel3) ? (const char *)tmodel3->getValue() : ""; - - if (strstr (model3, "Hasselblad ") == model3) { - model = model3 + 11; - } - } - - // FIXME: due to lack of test files this Hasselblad model identification is not 100% complete - // This needs checking out: CFV-39/CFV-50 3FR, H3DII vs H3D, old CF/CFH models - - if (!strcmp (model, "H3D")) { - // We can't differ between H3D and H3DII for the 22, 31 and 39 models. There's was no H3D-50 so we know that is a - // H3DII-50. At the time of writing I have no test files for the H3D vs H3DII models, so there still may be a chance - // to differ between them. AFAIK Adobe's DNG converter don't differ between them, and actually call the H3DII-50 - // H3D-50 although Hasselblad never released such a model. - switch (sensorWidth) { - case 4096: - tmodel->initString ("H3D-22"); - break; - - case 6542: - tmodel->initString ("H3D-31"); - break; - - case 7262: - tmodel->initString ("H3D-39"); - break; - - case 8282: - tmodel->initString ("H3DII-50"); - break; - } - } else if (!strcmp (model, "H4D")) { - switch (sensorWidth) { - case 6542: - tmodel->initString ("H4D-31"); - break; - - case 7410: - tmodel->initString ("H4D-40"); - break; - - case 8282: - tmodel->initString ("H4D-50"); - break; - - case 9044: - tmodel->initString ("H4D-60"); - break; - } - } else if (!strcmp (model, "H5D")) { - switch (sensorWidth) { - case 7410: - tmodel->initString ("H5D-40"); - break; - - case 8282: - tmodel->initString ("H5D-50"); - break; - - case 8374: - tmodel->initString ("H5D-50c"); - break; - - case 9044: - tmodel->initString ("H5D-60"); - break; - } - } else if (!strcmp (model, "CFV")) { - switch (sensorWidth) { - case 7262: - tmodel->initString ("CFV-39"); - break; - - case 8282: - tmodel->initString ("CFV-50"); - break; - - case 8374: - tmodel->initString ("CFV-50c"); - break; - } - } - - // and a few special cases - Tag* tmodel3 = root->getTag ("UniqueCameraModel"); - const char *model3 = (tmodel3) ? (const char *)tmodel3->getValue() : ""; - - if (strstr (model3, "Hasselblad ") == model3) { - model3 = model3 + 11; - } - - if (!strcmp (model3, "ixpressCF132")) { - tmodel->initString ("CF-22"); - } else if (!strcmp (model3, "Hasselblad96")) { - tmodel->initString ("CFV"); // popularly called CFV-16, but the official name is CFV - } else if (!strcmp (model3, "Hasselblad234")) { - tmodel->initString ("CFV-39"); - } else if (sensorWidth == 4090) { - tmodel->initString ("V96C"); - } - - // and yet some, this is for Adobe-generated DNG files - Tag* tmodel4 = root->getTag ("LocalizedCameraModel"); - - if (tmodel4) { - const char *model4 = (const char *)tmodel4->getValue(); - - if (strstr (model4, "Hasselblad ") == model4) { - model4 = model4 + 11; - } - - if (!strcmp (model4, "ixpressCF132-22")) { - tmodel->initString ("CF-22"); - } else if (!strcmp (model4, "Hasselblad96-16")) { - tmodel->initString ("CFV"); - } else if (!strcmp (model4, "Hasselblad234-39")) { - tmodel->initString ("CFV-39"); - } else if (!strcmp (model4, "H3D-50")) { - // Adobe names H3DII-50 incorrectly as H3D-50 - tmodel->initString ("H3DII-50"); - } else if (strstr (model4, "H3D-") == model4 || strstr (model4, "H4D-") == model4 || strstr (model4, "H5D-") == model4) { - tmodel->initString (model4); - } - } - } - - if (!root->getTag ("Orientation")) { - if (make && !strncmp ((char*)make->getValue(), "Phase One", 9)) { - int orientation = 0; - Tag *iw = root->getTag ("ImageWidth"); - - if (iw) { - // from dcraw, derive orientation from image width - orientation = "0653"[iw->toInt() & 3] - '0'; - } - - Tag *t = new Tag (root, root->getAttrib ("Orientation")); - t->initInt (orientation, SHORT); - root->addTagFront (t); - } - } - - // --- detecting image root IFD based on SubFileType, or if not provided, on PhotometricInterpretation - - bool frameRootDetected = false; - - if(!frameRootDetected) { - std::vector risTagList = root->findTags("RawImageSegmentation"); - if (!risTagList.empty()) { - for (auto ris : risTagList) { - frames.push_back(ris->getParent()); - frameRootDetected = true; - - #if PRINT_METADATA_TREE - printf("\n--------------- FRAME (RAWIMAGESEGMENTATION) ---------------\n\n"); - ris->getParent()->printAll (); - #endif - } - } - } - - if(!frameRootDetected) { - std::vector sftTagList = root->findTags(TIFFTAG_SUBFILETYPE); - if (!sftTagList.empty()) { - for (auto sft : sftTagList) { - int sftVal = sft->toInt(); - if (sftVal == 0 || (!isRaw && sftVal == 2)) { - frames.push_back(sft->getParent()); - frameRootDetected = true; - -#if PRINT_METADATA_TREE - printf("\n--------------- FRAME (SUBFILETYPE) ---------------\n\n"); - sft->getParent()->printAll (); -#endif - } - } - } - } - - if(!frameRootDetected) { - std::vector sftTagList = root->findTags(TIFFTAG_OSUBFILETYPE); - if (!sftTagList.empty()) { - for (auto sft : sftTagList) { - int sftVal = sft->toInt(); - if (sftVal == OFILETYPE_IMAGE) { - frames.push_back(sft->getParent()); - frameRootDetected = true; - -#if PRINT_METADATA_TREE - printf("\n--------------- FRAME (OSUBFILETYPE) ---------------\n\n"); - sft->getParent()->printAll (); -#endif - } - } - } - } - - if(!frameRootDetected) { - std::vector piTagList = root->findTags("PhotometricInterpretation"); - if (!piTagList.empty()) { - for (auto pi : piTagList) { - int piVal = pi->toInt(); - if (piVal == (isRaw ? 32803 : 2)) { - frames.push_back(pi->getParent()); - //frameRootDetected = true; not used afterward - -#if PRINT_METADATA_TREE - printf("\n--------------- FRAME (PHOTOMETRIC) ---------------\n\n"); - pi->getParent()->printAll (); -#endif - } - } - } - } - - // --- getting next sibling root - - ifdOffset = get4 (f, order); - - roots.push_back(root); - -#if PRINT_METADATA_TREE - printf("\n~~~~~~~~~ ROOT ~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); - root->printAll (); -#endif - - } while (ifdOffset > 0 && !onlyFirst); - - // Security check : if there's at least one root, there must be at least one image. - // If the following occurs, then image detection above has failed or it's an unsupported file type. - // Yet the result of this should be valid. - if (!roots.empty() && frames.empty()) { - frames.push_back(roots.at(0)); - } -} - -void ExifManager::parseJPEG (int offset) -{ - if (!f) { - #ifndef NDEBUG - std::cerr << "ERROR : no file opened !" << std::endl; - #endif - return; - } - - if(!fseek (f, offset, SEEK_SET)) { - unsigned char c; - if(fread (&c, 1, 1, f) == 1) { - constexpr unsigned char markerl = 0xff; - const char exifid[] = "Exif\0\0"; - char idbuff[8]; - int tiffbase = -1; - - while (fread (&c, 1, 1, f)) { - if (c != markerl) { - continue; - } - - if (fread (&c, 1, 1, f) && c == 0xe1) { // APP1 marker found - if (fread (idbuff, 1, 8, f) < 8) { - return; - } - - if (!memcmp (idbuff + 2, exifid, 6)) { // Exif info found - tiffbase = ftell (f); - - // We need a RawMetaDataLocation to put the 'tiffbase' value - const bool rmlCreated = !rml; - if (rmlCreated) { - rml.reset(new rtengine::RawMetaDataLocation(0)); - } - rml->exifBase = tiffbase; - parse (false); - if (rmlCreated) { - rml.reset(); - } - return; - } - } - } - } - } -} - -void ExifManager::parseTIFF (bool skipIgnored) -{ - if (!rml) { - rml.reset(new rtengine::RawMetaDataLocation(0)); - parse(false, skipIgnored); - rml.reset(); - } else { - parse (false,skipIgnored); - } -} - -std::vector ExifManager::getDefaultTIFFTags (TagDirectory* forthis) -{ - - std::vector defTags; - - defTags.reserve (12); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "ImageWidth"), 0, LONG)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "ImageHeight"), 0, LONG)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "XResolution"), 300, RATIONAL)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "YResolution"), 300, RATIONAL)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "ResolutionUnit"), 2, SHORT)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "Software"), "RawTherapee " RTVERSION)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "Orientation"), 1, SHORT)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "SamplesPerPixel"), 3, SHORT)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "BitsPerSample"), 8, SHORT)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "PlanarConfiguration"), 1, SHORT)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "PhotometricInterpretation"), 2, SHORT)); - defTags.push_back (new Tag (forthis, lookupAttrib (ifdAttribs, "Compression"), 1, SHORT)); - - return defTags; -} - - - -int ExifManager::createJPEGMarker (const TagDirectory* root, const rtengine::procparams::ExifPairs& changeList, int W, int H, unsigned char* buffer) -{ - - // write tiff header - int offs = 6; - memcpy (buffer, "Exif\0\0", 6); - ByteOrder order = INTEL; - - if (root) { - order = root->getOrder (); - } - - sset2 ((unsigned short)order, buffer + offs, order); - offs += 2; - sset2 (42, buffer + offs, order); - offs += 2; - sset4 (8, buffer + offs, order); - - TagDirectory* cl; - - if (root) { - cl = (const_cast (root))->clone (nullptr); - } else { - cl = new TagDirectory (nullptr, ifdAttribs, INTEL); - } - - for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) { - cl->applyChange (i->first, i->second); - } - - const std::vector defTags = getDefaultTIFFTags (cl); - - defTags[0]->setInt (W, 0, LONG); - defTags[1]->setInt (H, 0, LONG); - defTags[8]->setInt (8, 0, SHORT); - - for (int i = defTags.size() - 1; i >= 0; i--) { - Tag* defTag = defTags[i]; - cl->replaceTag (defTag->clone (cl)); - delete defTag; - } - - cl->sort (); - int size = cl->write (8, buffer + 6); - - delete cl; - - return size + 6; -} - -int ExifManager::createPNGMarker(const TagDirectory* root, const rtengine::procparams::ExifPairs &changeList, int W, int H, int bps, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize) -{ -// write tiff header - int offs = 0; - ByteOrder order = HOSTORDER; - - if (root) { - order = root->getOrder (); - } - - TagDirectory* cl; - - if (root) { - cl = (const_cast (root))->clone (nullptr); - // remove some unknown top level tags which produce warnings when opening a tiff - Tag *removeTag = cl->getTag (0x9003); - - if (removeTag) { - removeTag->setKeep (false); - } - - removeTag = cl->getTag (0x9211); - - if (removeTag) { - removeTag->setKeep (false); - } - } else { - cl = new TagDirectory (nullptr, ifdAttribs, HOSTORDER); - } - - if (iptcdata) { - Tag* iptc = new Tag (cl, lookupAttrib (ifdAttribs, "IPTCData")); - iptc->initLongArray (iptcdata, iptclen); - cl->replaceTag (iptc); - } - -// apply list of changes - for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) { - cl->applyChange (i->first, i->second); - } - - // append default properties - const std::vector defTags = getDefaultTIFFTags (cl); - - defTags[0]->setInt (W, 0, LONG); - defTags[1]->setInt (H, 0, LONG); - defTags[8]->initInt (0, SHORT, 3); - - for (int i = 0; i < 3; i++) { - defTags[8]->setInt (bps, i * 2, SHORT); - } - - for (int i = defTags.size() - 1; i >= 0; i--) { - Tag* defTag = defTags[i]; - cl->replaceTag (defTag->clone (cl)); - delete defTag; - } - - cl->sort (); - bufferSize = cl->calculateSize() + 8; - buffer = new unsigned char[bufferSize]; // this has to be deleted in caller - sset2 ((unsigned short)order, buffer + offs, order); - offs += 2; - sset2 (42, buffer + offs, order); - offs += 2; - sset4 (8, buffer + offs, order); - - int endOffs = cl->write (8, buffer); - -// cl->printAll(); - delete cl; - - return endOffs; -} - - -//----------------------------------------------------------------------------- -// global functions to read byteorder dependent data -//----------------------------------------------------------------------------- -unsigned short sget2 (unsigned char *s, rtexif::ByteOrder order) -{ - - if (order == rtexif::INTEL) { - return s[0] | s[1] << 8; - } else { - return s[0] << 8 | s[1]; - } -} - -int sget4 (unsigned char *s, rtexif::ByteOrder order) -{ - - if (order == rtexif::INTEL) { - return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; - } else { - return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; - } -} - -inline unsigned short get2 (FILE* f, rtexif::ByteOrder order) -{ - - unsigned char str[2] = { 0xff, 0xff }; - fread (str, 1, 2, f); - return rtexif::sget2 (str, order); -} - -int get4 (FILE* f, rtexif::ByteOrder order) -{ - - unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff }; - fread (str, 1, 4, f); - return rtexif::sget4 (str, order); -} - -void sset2 (unsigned short v, unsigned char *s, rtexif::ByteOrder order) -{ - - if (order == rtexif::INTEL) { - s[0] = v & 0xff; - v >>= 8; - s[1] = v; - } else { - s[1] = v & 0xff; - v >>= 8; - s[0] = v; - } -} - -void sset4 (int v, unsigned char *s, rtexif::ByteOrder order) -{ - - if (order == rtexif::INTEL) { - s[0] = v & 0xff; - v >>= 8; - s[1] = v & 0xff; - v >>= 8; - s[2] = v & 0xff; - v >>= 8; - s[3] = v; - } else { - s[3] = v & 0xff; - v >>= 8; - s[2] = v & 0xff; - v >>= 8; - s[1] = v & 0xff; - v >>= 8; - s[0] = v; - } -} - -float int_to_float (int i) -{ - union { - int i; - float f; - } u; - u.i = i; - return u.f; -} - -short int int2_to_signed (short unsigned int i) -{ - union { - short unsigned int i; - short int s; - } u; - u.i = i; - return u.s; -} - -/* Function to parse and extract focal length and aperture information from description - * @fullname must conform to the following formats - * mm f/ - * -mm f/ - * -mm f/- - * NB: no space between separator '-'; no space between focal length and 'mm' - */ -bool extractLensInfo (const std::string &fullname, double &minFocal, double &maxFocal, double &maxApertureAtMinFocal, double &maxApertureAtMaxFocal) -{ - minFocal = 0.0; - maxFocal = 0.0; - maxApertureAtMinFocal = 0.0; - maxApertureAtMaxFocal = 0.0; - char buffer[1025]; - strncpy (buffer, fullname.c_str(), 1024); - char *pF = strstr (buffer, "f/" ); - - if ( pF ) { - sscanf (pF + 2, "%lf-%lf", &maxApertureAtMinFocal, &maxApertureAtMaxFocal); - - if (maxApertureAtMinFocal > 0. && maxApertureAtMaxFocal == 0.) { - maxApertureAtMaxFocal = maxApertureAtMinFocal; - } - - char *pMM = pF - 3; - - while ( pMM[0] != 'm' && pMM[1] != 'm' && pMM > buffer) { - pMM--; - } - - if ( pMM[0] == 'm' && pMM[1] == 'm' ) { - char *sp = pMM; - - while ( *sp != ' ' && sp > buffer ) { - sp--; - } - - sscanf (sp + 1, "%lf-%lf", &minFocal, &maxFocal); - - if (maxFocal == 0.) { - maxFocal = minFocal; - } - - return true; - } - } - - return false; -} - -} diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h deleted file mode 100644 index 43b296746..000000000 --- a/rtexif/rtexif.h +++ /dev/null @@ -1,690 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _MEXIF3_ -#define _MEXIF3_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../rtengine/noncopyable.h" -#include "../rtengine/rawmetadatalocation.h" - -namespace rtengine -{ - -namespace procparams -{ - class ExifPairs; -} - -} - -class CacheImageData; - -namespace rtexif -{ - -enum TagType {INVALID = 0, BYTE = 1, ASCII = 2, SHORT = 3, LONG = 4, RATIONAL = 5, SBYTE = 6, UNDEFINED = 7, SSHORT = 8, SLONG = 9, SRATIONAL = 10, FLOAT = 11, DOUBLE = 12, OLYUNDEF = 13, AUTO = 98, SUBDIR = 99}; -enum ActionCode { - AC_DONTWRITE, // don't write it to the output - AC_WRITE, // write it to the output - AC_SYSTEM, // changed by RT (not editable/deletable) - don't write, don't show - AC_NEW, // new addition - write, don't show - - AC_INVALID = 100, // invalid state -}; -enum ByteOrder {UNKNOWN = 0, INTEL = 0x4949, MOTOROLA = 0x4D4D}; -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ -const ByteOrder HOSTORDER = INTEL; -#else -const enum ByteOrder HOSTORDER = MOTOROLA; -#endif -enum MNKind {NOMK, IFD, HEADERIFD, NIKON3, OLYMPUS2, FUJI, TABLESUBDIR}; - -bool extractLensInfo (const std::string &fullname, double &minFocal, double &maxFocal, double &maxApertureAtMinFocal, double &maxApertureAtMaxFocal); - -unsigned short sget2 (unsigned char *s, ByteOrder order); -int sget4 (unsigned char *s, ByteOrder order); -unsigned short get2 (FILE* f, ByteOrder order); -int get4 (FILE* f, ByteOrder order); -void sset2 (unsigned short v, unsigned char *s, ByteOrder order); -void sset4 (int v, unsigned char *s, ByteOrder order); -float int_to_float (int i); -short int int2_to_signed (short unsigned int i); - -struct TIFFHeader { - - unsigned short byteOrder; - unsigned short fixed; - unsigned int ifdOffset; -}; - -class Tag; -class Interpreter; - -/// Structure of information describing an Exif tag -struct TagAttrib { - int ignore; // =0: never ignore, =1: always ignore, =2: ignore if the subdir type is reduced image, =-1: end of table - ActionCode action; - int editable; - const TagAttrib* subdirAttribs; // !NULL if this tag points to a subdir - /** Numeric identifier of tag (or index inside DirectoryTable) - To avoid rewriting all the tables, and to address the problem of TagDirectoryTable with heterogeneous tag's type, - this parameter is now an unsigned int, where the leftmost 2 bytes represent the tag's type, which by default will be aqual - to 0 (INVALID). Only non null tag type will be used. See nikon attrib for an example - */ - unsigned short ID; - TagType type; - const char* name; - Interpreter* interpreter; // Call back hook -}; - -const TagAttrib* lookupAttrib (const TagAttrib* dir, const char* field); - -/// A directory of tags -class TagDirectory -{ - -protected: - std::vector tags; // tags in the directory - const TagAttrib* attribs; // descriptor table to decode the tags - ByteOrder order; // byte order - TagDirectory* parent; // parent directory (NULL if root) - static Glib::ustring getDumpKey (int tagID, const Glib::ustring &tagName); - -public: - TagDirectory (); - TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border, bool skipIgnored = true); - TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border); - virtual ~TagDirectory (); - - inline ByteOrder getOrder () const - { - return order; - } - TagDirectory* getParent () - { - return parent; - } - TagDirectory* getRoot (); - inline int getCount () const - { - return tags.size (); - } - const TagAttrib* getAttrib (int id); - // Find a Tag by scanning the whole tag tree and stopping at the first occurrence - const TagAttrib* getAttrib (const char* name); - // Try to get the Tag at a given location. 'name' is a path relative to this directory (e.g. "LensInfo/FocalLength") - const TagAttrib* getAttribP (const char* name); - const TagAttrib* getAttribTable() - { - return attribs; - } - // Find a Tag by scanning the whole tag tree and stopping at the first occurrence - Tag* getTag (const char* name) const; - // Try to get the Tag at a given location. 'name' is a path relative to this directory (e.g. "LensInfo/FocalLength") - Tag* getTagP (const char* name) const; - Tag* getTag (int ID) const; - - // Try to get the Tag in the current directory and in subdirectories - // if lookUpward = true, it will scan the parents TagDirectory up to the root one, - // but w/o looking into their subdirs - virtual Tag* findTag (const char* name, bool lookUpward = false) const; - // Find a all Tags with the given name by scanning the whole tag tree - std::vector findTags (const char* name); - // Find a all Tags with the given ID by scanning the whole tag tree - std::vector findTags (int ID); - // Try to get the Tag in the current directory and in parent directories - // (won't look into subdirs) - virtual Tag* findTagUpward (const char* name) const; - bool getXMPTagValue (const char* name, char* value) const; - - void keepTag (int ID); - void addTag (Tag* &a); - void addTagFront (Tag* &a); - void replaceTag (Tag* a); - inline Tag* getTagByIndex (int ix) - { - return tags[ix]; - } - inline void setOrder (ByteOrder bo) - { - order = bo; - } - - virtual int calculateSize (); - virtual int write (int start, unsigned char* buffer); - virtual TagDirectory* clone (TagDirectory* parent); - void applyChange (const std::string &field, const Glib::ustring &value); - - virtual void printAll (unsigned int level = 0) const; // reentrant debug function, keep level=0 on first call ! - virtual bool CPBDump (const Glib::ustring &commFName, const Glib::ustring &imageFName, const Glib::ustring &profileFName, const Glib::ustring &defaultPParams, - const CacheImageData* cfs, const bool flagMode, Glib::KeyFile *keyFile = nullptr, Glib::ustring tagDirName = "") const; - virtual void sort (); -}; - -// a table of tags: id are offset from beginning and not identifiers -class TagDirectoryTable: public TagDirectory -{ -protected: - unsigned char *values; // Tags values are saved internally here - long zeroOffset; // Offset 0 (index 0) could be at an offset from values - long valuesSize; // Size of allocated memory - TagType defaultType; // Default type of all tags in this directory -public: - TagDirectoryTable(); - TagDirectoryTable (TagDirectory* p, unsigned char *v, int memsize, int offs, TagType type, const TagAttrib* ta, ByteOrder border); - TagDirectoryTable (TagDirectory* p, FILE* f, int memsize, int offset, TagType type, const TagAttrib* ta, ByteOrder border); - ~TagDirectoryTable() override; - int calculateSize () override; - int write (int start, unsigned char* buffer) override; - TagDirectory* clone (TagDirectory* parent) override; -}; - -// a class representing a single tag -class Tag : - public rtengine::NonCopyable -{ - -protected: - unsigned short tag; - TagType type; - unsigned int count; - unsigned char* value; - int valuesize; - bool keep; - bool allocOwnMemory; - - const TagAttrib* attrib; - TagDirectory* parent; - TagDirectory** directory; - MNKind makerNoteKind; - bool parseMakerNote (FILE* f, int base, ByteOrder bom ); - -public: - Tag (TagDirectory* parent, FILE* f, int base); // parse next tag from the file - Tag (TagDirectory* parent, const TagAttrib* attr); - Tag (TagDirectory* parent, const TagAttrib* attr, unsigned char *data, TagType t); - Tag (TagDirectory* parent, const TagAttrib* attr, int data, TagType t); // create a new tag from array (used - Tag (TagDirectory* parent, const TagAttrib* attr, const char* data); // create a new tag from array (used - - ~Tag (); - void initType (unsigned char *data, TagType type); - void initInt (int data, TagType t, int count = 1); - void initUserComment (const Glib::ustring &text); - void initString (const char* text); - void initSubDir (); - void initSubDir (TagDirectory* dir); - void initMakerNote (MNKind mnk, const TagAttrib* ta); - void initUndefArray (const char* data, int len); - void initLongArray (const char* data, int len); - void initRational (int num, int den); - - static void swapByteOrder2 (unsigned char *buffer, int count); - - // get basic tag properties - int getID () const - { - return tag; - } - int getCount () const - { - return count; - } - TagType getType () const - { - return (attrib && attrib->type > INVALID && attrib->type < AUTO) ? attrib->type : type; - } - unsigned char* getValue () const - { - return value; - } - signed char* getSignedValue () const - { - return reinterpret_cast (value); - } - const TagAttrib* getAttrib () const - { - return attrib; - } - inline ByteOrder getOrder () const - { - return parent ? parent->getOrder() : HOSTORDER; - } - inline TagDirectory* getParent () const - { - return parent; - } - int getValueSize () const - { - return valuesize; - } - bool getOwnMemory () const - { - return allocOwnMemory; - } - - // read/write value - int toInt (int ofs = 0, TagType astype = INVALID) const; - void fromInt (int v); - double toDouble (int ofs = 0) const; - double* toDoubleArray (int ofs = 0) const; - void toRational (int& num, int& denom, int ofs = 0) const; - void toString (char* buffer, int ofs = 0) const; - void fromString (const char* v, int size = -1); - void setInt (int v, int ofs = 0, TagType astype = LONG); - int getDistanceFrom (const TagDirectory *root); - - // additional getter/setter for more comfortable use - std::string valueToString () const; - std::string nameToString (int i = 0); - void valueFromString (const std::string& value); - void userCommentFromString (const Glib::ustring& text); - - // functions for writing - int calculateSize (); - int write (int offs, int dataOffs, unsigned char* buffer); - Tag* clone (TagDirectory* parent); - - // to control if the tag shall be written - bool getKeep () - { - return keep; - } - void setKeep (bool k) - { - keep = k; - } - - // get subdirectory (there can be several, the last is NULL) - bool isDirectory () - { - return directory != nullptr; - } - TagDirectory* getDirectory (int i = 0) - { - return (directory) ? directory[i] : nullptr; - } - - MNKind getMakerNoteFormat () - { - return makerNoteKind; - } -}; - -class ExifManager -{ - - Tag* saveCIFFMNTag (TagDirectory* root, int len, const char* name); - void parseCIFF (int length, TagDirectory* root); - void parse (bool isRaw, bool skipIgnored = true); - -public: - FILE* f; - std::unique_ptr rml; - ByteOrder order; - bool onlyFirst; // Only first IFD - unsigned int IFDOffset; - std::vector roots; - std::vector frames; - - ExifManager (FILE* fHandle, std::unique_ptr _rml, bool onlyFirstIFD) - : f(fHandle), rml(std::move(_rml)), order(UNKNOWN), onlyFirst(onlyFirstIFD), - IFDOffset(0) {} - - void setIFDOffset(unsigned int offset); - - - void parseRaw (bool skipIgnored = true); - void parseStd (bool skipIgnored = true); - void parseJPEG (int offset = 0); // offset: to extract exif data from a embedded preview/thumbnail - void parseTIFF (bool skipIgnored = true); - void parseCIFF (); - - /// @brief Get default tag for TIFF - /// @param forthis The byte order will be taken from the given directory. - /// @return The ownership of the return tags is passed to the caller. - static std::vector getDefaultTIFFTags (TagDirectory* forthis); - static int createJPEGMarker (const TagDirectory* root, const rtengine::procparams::ExifPairs& changeList, int W, int H, unsigned char* buffer); - static int createTIFFHeader (const TagDirectory* root, const rtengine::procparams::ExifPairs& changeList, int W, int H, int bps, const char* profiledata, int profilelen, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize); - static int createPNGMarker(const TagDirectory *root, const rtengine::procparams::ExifPairs &changeList, int W, int H, int bps, const char *iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize); -}; - -class Interpreter -{ -public: - Interpreter () {} - virtual ~Interpreter() {}; - virtual std::string toString (const Tag* t) const - { - char buffer[1024]; - t->toString (buffer); - std::string s (buffer); - std::string::size_type p1 = s.find_first_not_of (' '); - - if ( p1 == std::string::npos ) { - return s; - } else { - return s.substr (p1, s.find_last_not_of (' ') - p1 + 1); - } - } - virtual void fromString (Tag* t, const std::string& value) - { - if (t->getType() == SHORT || t->getType() == LONG) { - t->fromInt (atoi (value.c_str())); - } else { - t->fromString (value.c_str()); - } - } - // Get the value as a double - virtual double toDouble (const Tag* t, int ofs = 0) - { - double ud, dd; - - switch (t->getType()) { - case SBYTE: - return double (int (t->getSignedValue()[ofs])); - - case BYTE: - return (double) ((int)t->getValue()[ofs]); - - case ASCII: - return 0.0; - - case SSHORT: - return (double)int2_to_signed (sget2 (t->getValue() + ofs, t->getOrder())); - - case SHORT: - return (double) ((int)sget2 (t->getValue() + ofs, t->getOrder())); - - case SLONG: - case LONG: - return (double) ((int)sget4 (t->getValue() + ofs, t->getOrder())); - - case SRATIONAL: - case RATIONAL: - ud = (int)sget4 (t->getValue() + ofs, t->getOrder()); - dd = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); - return dd == 0. ? 0. : (double)ud / (double)dd; - - case FLOAT: - return double (sget4 (t->getValue() + ofs, t->getOrder())); - - case UNDEFINED: - return 0.; - - default: - return 0.; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) - } - } - // Get the value as an int - virtual int toInt (const Tag* t, int ofs = 0, TagType astype = INVALID) - { - int a; - - if (astype == INVALID || astype == AUTO) { - astype = t->getType(); - } - - switch (astype) { - case SBYTE: - return int (t->getSignedValue()[ofs]); - - case BYTE: - return t->getValue()[ofs]; - - case ASCII: - return 0; - - case SSHORT: - return (int)int2_to_signed (sget2 (t->getValue() + ofs, t->getOrder())); - - case SHORT: - return (int)sget2 (t->getValue() + ofs, t->getOrder()); - - case SLONG: - case LONG: - return (int)sget4 (t->getValue() + ofs, t->getOrder()); - - case SRATIONAL: - case RATIONAL: - a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); - return a == 0 ? 0 : (int)sget4 (t->getValue() + ofs, t->getOrder()) / a; - - case FLOAT: - return (int)toDouble (t, ofs); - - case UNDEFINED: - return 0; - - default: - return 0; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) - } - - return 0; - } -}; - -extern Interpreter stdInterpreter; - -template -class ChoiceInterpreter : public Interpreter -{ -protected: - using Choices = std::map; - using ChoicesIterator = typename Choices::const_iterator; - Choices choices; -public: - ChoiceInterpreter () {}; - std::string toString (const Tag* t) const override - { - const typename std::map::const_iterator r = choices.find(t->toInt()); - - if (r != choices.end()) { - return r->second; - } else { - char buffer[1024]; - t->toString(buffer); - return buffer; - } - } -}; - -template< class T > -class IntLensInterpreter : public Interpreter -{ -protected: - typedef std::multimap< T, std::string> container_t; - typedef typename std::multimap< T, std::string>::const_iterator it_t; - typedef std::pair< T, std::string> p_t; - container_t choices; - - virtual std::string guess (const T lensID, double focalLength, double maxApertureAtFocal, double *lensInfoArray) const - { - it_t r; - size_t nFound = choices.count ( lensID ); - - switch ( nFound ) { - case 0: { // lens Unknown - std::ostringstream s; - s << lensID; - return s.str(); - } - - case 1: // lens found - r = choices.find ( lensID ); - return r->second; - - default: - // More than one hit: we must guess - break; - } - - std::string bestMatch ("Unknown"); - double a1, a2, f1, f2; - - /* FIRST TRY - * - * Get the lens info (min/man focal, min/max aperture) and compare them to the possible choice - */ - if (lensInfoArray) { - for ( r = choices.lower_bound ( lensID ); r != choices.upper_bound (lensID); ++r ) { - if ( !extractLensInfo ( r->second, f1, f2, a1, a2) ) { - continue; - } - - if (f1 == lensInfoArray[0] && f2 == lensInfoArray[1] && a1 == lensInfoArray[2] && a2 == lensInfoArray[3]) - // can't match better! we take this entry as being the one - { - return r->second; - } - } - - // No lens found, we update the "unknown" string with the lens info values - if (lensInfoArray[0] == lensInfoArray[1]) { - bestMatch += Glib::ustring::compose (" (%1mm", int (lensInfoArray[0])); - } else { - bestMatch += Glib::ustring::compose (" (%1-%2mm", int (lensInfoArray[0]), int (lensInfoArray[1])); - } - - if (lensInfoArray[2] == lensInfoArray[3]) { - bestMatch += Glib::ustring::compose (" f/%1)", Glib::ustring::format (std::fixed, std::setprecision (1), lensInfoArray[2])); - } else - bestMatch += Glib::ustring::compose (" f/%1-%2)", - Glib::ustring::format (std::fixed, std::setprecision (1), lensInfoArray[2]), - Glib::ustring::format (std::fixed, std::setprecision (1), lensInfoArray[3])); - } - - /* SECOND TRY - * - * Choose the best match: thanks to exiftool by Phil Harvey - * first throws for "out of focal range" and lower or upper aperture of the lens compared to MaxApertureAtFocal - * if the lens is not constant aperture, calculate aprox. aperture of the lens at focalLength - * and compare with actual aperture. - */ - std::ostringstream candidates; - double deltaMin = 1000.; - - for ( r = choices.lower_bound ( lensID ); r != choices.upper_bound (lensID); ++r ) { - double dif; - - if ( !extractLensInfo ( r->second, f1, f2, a1, a2) ) { - continue; - } - - if ( f1 == 0. || a1 == 0.) { - continue; - } - - if ( focalLength < f1 - .5 || focalLength > f2 + 0.5 ) { - continue; - } - - if ( maxApertureAtFocal > 0.1) { - double lensAperture; - - if ( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 + 0.15) { - continue; - } - - if ( a1 == a2 || f1 == f2) { - lensAperture = a1; - } else { - lensAperture = exp ( log (a1) + (log (a2) - log (a1)) / (log (f2) - log (f1)) * (log (focalLength) - log (f1)) ); - } - - dif = std::abs (lensAperture - maxApertureAtFocal); - } else { - dif = 0; - } - - if ( dif < deltaMin ) { - deltaMin = dif; - bestMatch = r->second; - } - - if ( dif < 0.15) { - if ( candidates.tellp() ) { - candidates << "\n or " << r->second; - } else { - candidates << r->second; - } - } - } - - if ( !candidates.tellp() ) { - return bestMatch; - } else { - return candidates.str(); - } - } -}; - -inline static int getTypeSize ( TagType type ) -{ - return ("11124811248484"[type < 14 ? type : 0] - '0'); -} - -extern const TagAttrib exifAttribs[]; -extern const TagAttrib gpsAttribs[]; -extern const TagAttrib iopAttribs[]; -extern const TagAttrib ifdAttribs[]; -extern const TagAttrib nikon2Attribs[]; -extern const TagAttrib nikon3Attribs[]; -extern const TagAttrib canonAttribs[]; -extern const TagAttrib pentaxAttribs[]; -extern const TagAttrib pentaxLensDataAttribs[]; -extern const TagAttrib pentaxLensInfoQAttribs[]; -extern const TagAttrib pentaxLensCorrAttribs[]; -extern const TagAttrib pentaxAEInfoAttribs[]; -extern const TagAttrib pentaxAEInfo2Attribs[]; -extern const TagAttrib pentaxAEInfo3Attribs[]; -extern const TagAttrib pentaxCameraSettingsAttribs[]; -extern const TagAttrib pentaxFlashInfoAttribs[]; -extern const TagAttrib pentaxSRInfoAttribs[]; -extern const TagAttrib pentaxSRInfo2Attribs[]; -extern const TagAttrib pentaxBatteryInfoAttribs[]; -extern const TagAttrib pentaxCameraInfoAttribs[]; -extern const TagAttrib fujiAttribs[]; -extern const TagAttrib minoltaAttribs[]; -extern const TagAttrib sonyAttribs[]; -extern const TagAttrib sonyTag9405Attribs[]; -extern const TagAttrib sonyCameraInfoAttribs[]; -extern const TagAttrib sonyCameraInfo2Attribs[]; -extern const TagAttrib sonyCameraSettingsAttribs[]; -extern const TagAttrib sonyCameraSettingsAttribs2[]; -extern const TagAttrib sonyCameraSettingsAttribs3[]; -//extern const TagAttrib sonyDNGMakerNote[]; -extern const TagAttrib olympusAttribs[]; -extern const TagAttrib kodakIfdAttribs[]; -void parseKodakIfdTextualInfo (Tag *textualInfo, Tag* exif); -extern const TagAttrib panasonicAttribs[]; -extern const TagAttrib panasonicRawAttribs[]; -} -#endif diff --git a/rtexif/sonyminoltaattribs.cc b/rtexif/sonyminoltaattribs.cc deleted file mode 100644 index 0c6e433ff..000000000 --- a/rtexif/sonyminoltaattribs.cc +++ /dev/null @@ -1,2640 +0,0 @@ -/* - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _SONYMINOLTAATTRIBS_ -#define _SONYMINOLTAATTRIBS_ - -#include - -#include "rtexif.h" - -namespace rtexif -{ - -class SANoYesInterpreter : public ChoiceInterpreter<> -{ -public: - SANoYesInterpreter () - { - choices[1] = "No"; - choices[16] = "Yes"; - } -}; -SANoYesInterpreter saNoYesInterpreter; - -class SAOnOffInterpreter : public ChoiceInterpreter<> -{ -public: - SAOnOffInterpreter () - { - choices[0] = "Off"; - choices[1] = "On"; - choices[5] = "On"; - } -}; -SAOnOffInterpreter saOnOffInterpreter; - -class SAOnOffInterpreter2 : public ChoiceInterpreter<> -{ -public: - SAOnOffInterpreter2 () - { - choices[1] = "Off"; - choices[16] = "On"; - } -}; -SAOnOffInterpreter2 saOnOffInterpreter2; - -class SAOnOffInterpreter3 : public ChoiceInterpreter<> -{ -public: - SAOnOffInterpreter3 () - { - choices[1] = "Off"; - choices[16] = "On (Auto)"; - choices[17] = "On (Manual)"; - } -}; -SAOnOffInterpreter3 saOnOffInterpreter3; - -class SAOnOffInterpreter4 : public ChoiceInterpreter<> -{ -public: - SAOnOffInterpreter4 () - { - choices[0] = "n/a"; - choices[1] = "Off"; - choices[16] = "On"; - choices[255] = "None"; - } -}; -SAOnOffInterpreter4 saOnOffInterpreter4; - -class SAOnOffInterpreter5 : public ChoiceInterpreter<> -{ -public: - SAOnOffInterpreter5 () - { - choices[1] = "On"; - choices[2] = "Off"; - } -}; -SAOnOffInterpreter5 saOnOffInterpreter5; - -class SAHighISONoiseReduction : public ChoiceInterpreter<> -{ -public: - SAHighISONoiseReduction () - { - choices[0] = "Off"; - choices[1] = "Low"; - choices[2] = "Normal"; - choices[3] = "High"; - choices[256] = "Auto"; - choices[65535] = "n/a"; - } -}; -SAHighISONoiseReduction saHighISONoiseReduction; - -class SAHighISONoiseReduction2 : public ChoiceInterpreter<> -{ -public: - SAHighISONoiseReduction2 () - { - choices[0] = "Normal"; - choices[1] = "High"; - choices[2] = "Low"; - choices[3] = "Off"; - choices[65535] = "n/a"; - } -}; -SAHighISONoiseReduction2 saHighISONoiseReduction2; - -class SAHighISONoiseReduction3 : public ChoiceInterpreter<> -{ -public: - SAHighISONoiseReduction3 () - { - choices[0] = "Normal"; - choices[1] = "Low"; - choices[2] = "High"; - choices[3] = "Off"; - } -}; -SAHighISONoiseReduction3 saHighISONoiseReduction3; - -class SAHighISONoiseReduction4 : public ChoiceInterpreter<> -{ -public: - SAHighISONoiseReduction4 () - { - choices[0] = "Off"; - choices[1] = "Low"; - choices[2] = "Normal"; - choices[3] = "High"; - } -}; -SAHighISONoiseReduction4 saHighISONoiseReduction4; - -class SAHighISONoiseReduction5 : public ChoiceInterpreter<> -{ -public: - SAHighISONoiseReduction5 () - { - choices[16] = "Low"; - choices[19] = "Auto"; - } -}; -SAHighISONoiseReduction5 saHighISONoiseReduction5; - -class SASmileShutterMode : public ChoiceInterpreter<> -{ -public: - SASmileShutterMode () - { - choices[17] = "Slight smile"; - choices[18] = "Normal smile"; - choices[19] = "Big smile"; - } -}; -SASmileShutterMode saSmileShutterMode; - -class SAHDRLevel : public ChoiceInterpreter<> -{ -public: - SAHDRLevel () - { - choices[33] = "1 EV"; - choices[34] = "1.5 EV"; - choices[35] = "2 EV"; - choices[36] = "2.5 EV"; - choices[37] = "3 EV"; - choices[38] = "3.5 EV"; - choices[39] = "4 EV"; - choices[40] = "5 EV"; - choices[41] = "6 EV"; - } -}; -SAHDRLevel saHDRLevel; - -class SAViewingMode : public ChoiceInterpreter<> -{ -public: - SAViewingMode () - { - choices[0] = "n/a"; - choices[16] = "ViewFinder"; - choices[33] = "Focus Check Live View"; - choices[34] = "Quick AF Live View"; - } -}; -SAViewingMode saViewingMode; - -class SAFlashAction : public ChoiceInterpreter<> -{ -public: - SAFlashAction () - { - choices[1] = "Did not fire"; - choices[2] = "Fired"; - } -}; -SAFlashAction saFlashAction; - -class SALiveViewFocusMode : public ChoiceInterpreter<> -{ -public: - SALiveViewFocusMode () - { - choices[0] = "n/a"; - choices[1] = "AF"; - choices[16] = "Manual"; - } -}; -SALiveViewFocusMode saLiveViewFocusMode; - -class SALensMount : public ChoiceInterpreter<> -{ -public: - SALensMount () - { - choices[1] = "Unknown"; - choices[16] = "A-Mount"; - choices[17] = "E-Mount"; - } -}; -SALensMount saLensMount; - -class SASweepPanoramaSize : public ChoiceInterpreter<> -{ -public: - SASweepPanoramaSize () - { - choices[1] = "Standard"; - choices[2] = "Wide"; - } -}; -SASweepPanoramaSize saSweepPanoramaSize; - -class SASweepPanoramaDirection : public ChoiceInterpreter<> -{ -public: - SASweepPanoramaDirection () - { - choices[1] = "Right"; - choices[2] = "Left"; - choices[3] = "Up"; - choices[4] = "Down"; - } -}; -SASweepPanoramaDirection saSweepPanoramaDirection; - -class SALiveViewAFSetting : public ChoiceInterpreter<> -{ -public: - SALiveViewAFSetting () - { - choices[0] = "n/a"; - choices[1] = "Phase-detect AF"; - choices[2] = "Contrast AF"; - } -}; -SALiveViewAFSetting saLiveViewAFSetting; - -class SAPanoramaSize3D : public ChoiceInterpreter<> -{ -public: - SAPanoramaSize3D () - { - choices[0] = "n/a"; - choices[1] = "Standard"; - choices[2] = "Wide"; - choices[3] = "16:9"; - } -}; -SAPanoramaSize3D saPanoramaSize3D; - -class SALiveViewMetering : public ChoiceInterpreter<> -{ -public: - SALiveViewMetering () - { - choices[0] = "n/a"; - choices[16] = "40 segment"; - choices[32] = "1200-zone Evaluative"; - } -}; -SALiveViewMetering saLiveViewMetering; - -class SAWhiteBalanceInterpreter: public ChoiceInterpreter<> -{ -public: - SAWhiteBalanceInterpreter() - { - choices[ 0x0] = "Auto"; - choices[ 0x1] = "Color Temperature/Color Filter"; - choices[0x10] = "Daylight"; - choices[0x20] = "Cloudy"; - choices[0x30] = "Shade"; - choices[0x40] = "Tungsten"; - choices[0x50] = "Flash"; - choices[0x60] = "Fluorescent"; - choices[0x70] = "Custom"; - choices[0x80] = "Underwater"; - } -}; -SAWhiteBalanceInterpreter saWhiteBalanceInterpreter; - -class SAWhiteBalanceSettingInterpreter: public ChoiceInterpreter<> -{ -public: - SAWhiteBalanceSettingInterpreter() - { - choices[0x10] = "Auto (-3)"; - choices[0x11] = "Auto (-2)"; - choices[0x12] = "Auto (-1)"; - choices[0x13] = "Auto (0)"; - choices[0x14] = "Auto (+1)"; - choices[0x15] = "Auto (+2)"; - choices[0x16] = "Auto (+3)"; - choices[0x20] = "Daylight (-3)"; - choices[0x21] = "Daylight (-2)"; - choices[0x22] = "Daylight (-1)"; - choices[0x23] = "Daylight (0)"; - choices[0x24] = "Daylight (+1)"; - choices[0x25] = "Daylight (+2)"; - choices[0x26] = "Daylight (+3)"; - choices[0x30] = "Shade (-3)"; - choices[0x31] = "Shade (-2)"; - choices[0x32] = "Shade (-1)"; - choices[0x33] = "Shade (0)"; - choices[0x34] = "Shade (+1)"; - choices[0x35] = "Shade (+2)"; - choices[0x36] = "Shade (+3)"; - choices[0x40] = "Cloudy (-3)"; - choices[0x41] = "Cloudy (-2)"; - choices[0x42] = "Cloudy (-1)"; - choices[0x43] = "Cloudy (0)"; - choices[0x44] = "Cloudy (+1)"; - choices[0x45] = "Cloudy (+2)"; - choices[0x46] = "Cloudy (+3)"; - choices[0x50] = "Tungsten (-3)"; - choices[0x51] = "Tungsten (-2)"; - choices[0x52] = "Tungsten (-1)"; - choices[0x53] = "Tungsten (0)"; - choices[0x54] = "Tungsten (+1)"; - choices[0x55] = "Tungsten (+2)"; - choices[0x56] = "Tungsten (+3)"; - choices[0x60] = "Fluorescent (-3)"; - choices[0x61] = "Fluorescent (-2)"; - choices[0x62] = "Fluorescent (-1)"; - choices[0x63] = "Fluorescent (0)"; - choices[0x64] = "Fluorescent (+1)"; - choices[0x65] = "Fluorescent (+2)"; - choices[0x66] = "Fluorescent (+3)"; - choices[0x70] = "Flash (-3)"; - choices[0x71] = "Flash (-2)"; - choices[0x72] = "Flash (-1)"; - choices[0x73] = "Flash (0)"; - choices[0x74] = "Flash (+1)"; - choices[0x75] = "Flash (+2)"; - choices[0x76] = "Flash (+3)"; - choices[0xa3] = "Custom"; - choices[0xf3] = "Color Temperature/Color Filter"; - } -}; -SAWhiteBalanceSettingInterpreter saWhiteBalanceSettingInterpreter; - -class SASceneModeInterpreter : public ChoiceInterpreter<> -{ -public: - SASceneModeInterpreter () - { - choices[0] = "Standard"; - choices[1] = "Portrait"; - choices[2] = "Text"; - choices[3] = "Night Scene"; - choices[4] = "Sunset"; - choices[5] = "Sports"; - choices[6] = "Landscape"; - choices[7] = "Night Portrait"; - choices[8] = "Macro"; - choices[9] = "Super Macro"; - choices[16] = "Auto"; - choices[17] = "Night View/Portrait"; - choices[18] = "Sweep Panorama"; - choices[19] = "Handheld Night Shot"; - choices[20] = "Anti Motion Blur"; - choices[21] = "Cont. Priority AE"; - choices[22] = "Auto+"; - choices[23] = "3D Sweep Panorama"; - choices[24] = "Superior Auto"; - choices[25] = "High Sensitivity"; - choices[26] = "Fireworks"; - choices[27] = "Food"; - choices[28] = "Pet"; - choices[33] = "HDR"; - choices[65535] = "n/a"; - } -}; -SASceneModeInterpreter saSceneModeInterpreter; - -class SAZoneMatchingInterpreter : public ChoiceInterpreter<> -{ -public: - SAZoneMatchingInterpreter () - { - choices[0] = "ISO Setting Used"; - choices[1] = "High Key"; - choices[2] = "Low Key"; - } -}; -SAZoneMatchingInterpreter saZoneMatchingInterpreter; - -class SADynamicRangeOptimizerInterpreter : public ChoiceInterpreter<> -{ -public: - SADynamicRangeOptimizerInterpreter () - { - choices[0] = "Off"; - choices[1] = "Standard"; - choices[2] = "Advanced"; - choices[3] = "Auto"; - choices[8] = "Advanced Lv1"; - choices[9] = "Advanced Lv2"; - choices[10] = "Advanced Lv3"; - choices[11] = "Advanced Lv4"; - choices[12] = "Advanced Lv5"; - choices[16] = "Lv1"; - choices[17] = "Lv2"; - choices[18] = "Lv3"; - choices[19] = "Lv4"; - choices[20] = "Lv5"; - } -}; -SADynamicRangeOptimizerInterpreter saDynamicRangeOptimizerInterpreter; - -class SAColorModeInterpreter : public ChoiceInterpreter<> -{ -public: - SAColorModeInterpreter () - { - choices[0] = "Standard"; - choices[1] = "Vivid"; - choices[2] = "Portrait"; - choices[3] = "Landscape"; - choices[4] = "Sunset"; - choices[5] = "Night View/Portrait"; - choices[6] = "B&W"; - choices[7] = "Adobe RGB"; - choices[12] = "Neutral"; - choices[13] = "Clear"; - choices[14] = "Deep"; - choices[15] = "Light"; - choices[16] = "Autumn Leaves"; - choices[17] = "Sepia"; - choices[100] = "Neutral"; - choices[101] = "Clear"; - choices[102] = "Deep"; - choices[103] = "Light"; - choices[104] = "Night View"; - choices[105] = "Autumn Leaves"; - } -}; -SAColorModeInterpreter saColorModeInterpreter; - -class SAExposureModeInterpreter : public ChoiceInterpreter<> -{ -public: - SAExposureModeInterpreter () - { - choices[0] = "Program AE"; - choices[1] = "Portrait"; - choices[2] = "Beach"; - choices[3] = "Sports"; - choices[4] = "Snow"; - choices[5] = "Landscape"; - choices[6] = "Auto"; - choices[7] = "Aperture-priority AE"; - choices[8] = "Shutter speed priority AE"; - choices[9] = "Night Scene / Twilight"; - choices[10] = "Hi-Speed Shutter"; - choices[11] = "Twilight Portrait"; - choices[12] = "Soft Snap/Portrait"; - choices[13] = "Fireworks"; - choices[14] = "Smile Shutter"; - choices[15] = "Manual"; - choices[18] = "High Sensitivity"; - choices[19] = "Macro"; - choices[20] = "Advanced Sports Shooting"; - choices[29] = "Underwater"; - choices[33] = "Food"; - choices[34] = "Sweep Panorama"; - choices[35] = "Handheld Night Shot"; - choices[36] = "Anti Motion Blur"; - choices[37] = "Pet"; - choices[38] = "Backlight Correction HDR"; - choices[39] = "Superior Auto"; - choices[40] = "Background Defocus"; - choices[41] = "Soft Skin"; - choices[42] = "3D Image"; - choices[65535] = "n/a"; - } -}; -SAExposureModeInterpreter saExposureModeInterpreter; - -class SAQualityInterpreter : public ChoiceInterpreter<> -{ -public: - SAQualityInterpreter () - { - choices[0] = "Normal"; - choices[1] = "Fine"; - } -}; -SAQualityInterpreter saQualityInterpreter; - -class SAAntiBlurInterpreter : public ChoiceInterpreter<> -{ -public: - SAAntiBlurInterpreter () - { - choices[0] = "Off"; - choices[1] = "On (Continuous)"; - choices[2] = "On (Shooting)"; - choices[65535] = "n/a"; - } -}; -SAAntiBlurInterpreter saAntiBlurInterpreter; - -class SALensIDInterpreter : public IntLensInterpreter -{ -public: - SALensIDInterpreter () - { - choices = { - {0, "Minolta AF 28-85mm f/3.5-4.5 New"}, - {1, "Minolta AF 80-200mm f/2.8 HS-APO G"}, - {2, "Minolta AF 28-70mm f/2.8 G"}, - {3, "Minolta AF 28-80mm f/4-5.6"}, - {4, "Minolta AF 85mm f/1.4G"}, - {5, "Minolta AF 35-70mm f/3.5-4.5 [II]"}, - {6, "Minolta AF 24-85mm f/3.5-4.5 [New]"}, - {7, "Minolta AF 100-300mm f/4.5-5.6 APO [New] or 100-400mm or Sigma Lens"}, - {7, "Minolta AF 100-400mm f/4.5-6.7 APO"}, - {7, "Sigma AF 100-300mm f/4 EX DG IF"}, - {8, "Minolta AF 70-210mm f/4.5-5.6 [II]"}, - {9, "Minolta AF 50mm f/3.5 Macro"}, - {10, "Minolta AF 28-105mm f/3.5-4.5 [New]"}, - {11, "Minolta AF 300mm f/4 HS-APO G"}, - {12, "Minolta AF 100mm f/2.8 Soft Focus"}, - {13, "Minolta AF 75-300mm f/4.5-5.6 (New or II)"}, - {14, "Minolta AF 100-400mm f/4.5-6.7 APO"}, - {15, "Minolta AF 400mm f/4.5 HS-APO G"}, - {16, "Minolta AF 17-35mm f/3.5 G"}, - {17, "Minolta AF 20-35mm f/3.5-4.5"}, - {18, "Minolta AF 28-80mm f/3.5-5.6 II"}, - {19, "Minolta AF 35mm f/1.4 G"}, - {20, "Minolta/Sony 135mm f/2.8 [T4.5] STF"}, - {22, "Minolta AF 35-80mm f/4-5.6 II"}, - {23, "Minolta AF 200mm f/4 Macro APO G"}, - {24, "Minolta/Sony AF 24-105mm f/3.5-4.5 (D) or Sigma or Tamron Lens"}, - {24, "Sigma 18-50mm f/2.8"}, - {24, "Sigma 17-70mm f/2.8-4.5 (D)"}, - {24, "Sigma 20-40mm f/2.8 EX DG Aspherical IF"}, - {24, "Sigma 18-200mm f/3.5-6.3 DC"}, - {24, "Sigma DC 18-125mm f/4-5,6 D"}, - {24, "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro"}, - {25, "Minolta AF 100-300mm f/4.5-5.6 APO (D) or Sigma Lens"}, - {25, "Sigma 100-300mm f/4 EX (APO (D) or D IF)"}, - {25, "Sigma 70mm f/2.8 EX DG Macro"}, - {25, "Sigma 20mm f/1.8 EX DG Aspherical RF"}, - {25, "Sigma 30mm f/1.4 EX DC"}, - {25, "Sigma 24mm f/1.8 EX DG ASP Macro"}, - {27, "Minolta AF 85mm f/1.4 G (D)"}, - {28, "Minolta/Sony AF 100mm f/2.8 Macro (D) or Tamron Lens"}, - {28, "Tamron SP AF 90mm f/2.8 Di Macro"}, - {28, "Tamron SP AF 180mm f/3.5 Di LD [IF] Macro"}, - {29, "Minolta/Sony AF 75-300mm f/4.5-5.6 (D)"}, - {30, "Minolta AF 28-80mm f/3.5-5.6 (D) or Sigma Lens"}, - {30, "Sigma AF 10-20mm f/4-5.6 EX DC"}, - {30, "Sigma AF 12-24mm f/4.5-5.6 EX DG"}, - {30, "Sigma 28-70mm EX DG f/2.8"}, - {30, "Sigma 55-200mm f/4-5.6 DC"}, - {31, "Minolta/Sony AF 50mm f/2.8 Macro (D) or f/3.5"}, - {31, "Minolta/Sony AF 50mm f/3.5 Macro"}, - {32, "Minolta/Sony AF 300mm f/2.8 G or 1.5x Teleconverter"}, - {33, "Minolta/Sony AF 70-200mm f/2.8 G"}, - {35, "Minolta AF 85mm f/1.4 G (D) Limited"}, - {36, "Minolta AF 28-100mm f/3.5-5.6 (D)"}, - {38, "Minolta AF 17-35mm f/2.8-4 (D)"}, - {39, "Minolta AF 28-75mm f/2.8 (D)"}, - {40, "Minolta/Sony AF DT 18-70mm f/3.5-5.6 (D)"}, - {41, "Minolta/Sony AF DT 11-18mm f/4.5-5.6 (D) or Tamron Lens"}, - {41, "Tamron SP AF 11-18mm f/4.5-5.6 Di II LD Aspherical IF"}, - {42, "Minolta/Sony AF DT 18-200mm f/3.5-6.3 (D)"}, - {43, "Sony 35mm f/1.4 G (SAL35F14G)"}, - {44, "Sony 50mm f/1.4 (SAL50F14)"}, - {45, "Carl Zeiss Planar T* 85mm f/1.4 ZA (SAL85F14Z)"}, - {46, "Carl Zeiss Vario-Sonnar T* DT 16-80mm f/3.5-4.5 ZA (SAL1680Z)"}, - {47, "Carl Zeiss Sonnar T* 135mm f/1.8 ZA (SAL135F18Z)"}, - {48, "Carl Zeiss Vario-Sonnar T* 24-70mm f/2.8 ZA SSM (SAL2470Z) or ZA SSM II"}, - {48, "Carl Zeiss Vario-Sonnar T* 24-70mm f/2.8 ZA SSM II (SAL2470Z2)"}, - {49, "Sony DT 55-200mm f/4-5.6 (SAL55200)"}, - {50, "Sony DT 18-250mm f/3.5-6.3 (SAL18250)"}, - {51, "Sony DT 16-105mm f/3.5-5.6 (SAL16105)"}, - {52, "Sony 70-300mm f/4.5-5.6 G SSM (SAL70300G) or G SSM II or Tamron Lens"}, - {52, "Sony 70-300mm f/4.5-5.6 G SSM II (SAL70300G2)"}, - {52, "Tamron SP 70-300mm f/4-5.6 Di USD"}, - {53, "Sony 70-400mm f/4-5.6 G SSM (SAL70400G)"}, - {54, "Carl Zeiss Vario-Sonnar T* 16-35mm f/2.8 ZA SSM (SAL1635Z) or ZA SSM II"}, - {54, "Carl Zeiss Vario-Sonnar T* 16-35mm f/2.8 ZA SSM II (SAL1635Z2)"}, - {55, "Sony DT 18-55mm f/3.5-5.6 SAM (SAL1855) or SAM II"}, - {55, "Sony DT 18-55mm f/3.5-5.6 SAM II (SAL18552)"}, - {56, "Sony DT 55-200mm f/4-5.6 SAM (SAL55200-2)"}, - {57, "Sony DT 50mm f/1.8 SAM (SAL50F18) or Tamron Lens or Commlite CM-EF-NEX adapter"}, - {57, "Tamron SP AF 60mm f/2 Di II LD [IF] Macro 1:1"}, - {57, "Tamron 18-270mm f/3.5-6.3 Di II PZD"}, - {58, "Sony DT 30mm f/2.8 Macro SAM (SAL30M28)"}, - {59, "Sony 28-75mm f/2.8 SAM (SAL2875)"}, - {60, "Carl Zeiss Distagon T* 24mm f/2 ZA SSM (SAL24F20Z)"}, - {61, "Sony 85mm f/2.8 SAM (SAL85F28)"}, - {62, "Sony DT 35mm f/1.8 SAM (SAL35F18)"}, - {63, "Sony DT 16-50mm f/2.8 SSM (SAL1650)"}, - {64, "Sony 500mm f/4 G SSM (SAL500F40G)"}, - {65, "Sony DT 18-135mm f/3.5-5.6 SAM (SAL18135)"}, - {66, "Sony 300mm f/2.8 G SSM II (SAL300F28G2)"}, - {67, "Sony 70-200mm f/2.8 G SSM II (SAL70200G2)"}, - {68, "Sony DT 55-300mm f/4.5-5.6 SAM (SAL55300)"}, - {69, "Sony 70-400mm f/4-5.6 G SSM II (SAL70400G2)"}, - {70, "Carl Zeiss Planar T* 50mm f/1.4 ZA SSM (SAL50F14Z)"}, - {128, "Tamron or Sigma Lens (128)"}, - {128, "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical [IF] Macro"}, - {128, "Tamron AF 28-300mm f/3.5-6.3 XR Di LD Aspherical [IF] Macro"}, - {128, "Tamron 80-300mm f/3.5-6.3"}, - {128, "Tamron AF 28-200mm f/3.8-5.6 XR Di Aspherical [IF] Macro"}, - {128, "Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical IF"}, - {128, "Sigma AF 50-150mm f/2.8 EX DC APO HSM II"}, - {128, "Sigma 10-20mm f/3.5 EX DC HSM"}, - {128, "Sigma 70-200mm f/2.8 II EX DG APO MACRO HSM"}, - {128, "Sigma 10mm f/2.8 EX DC HSM Fisheye"}, - {128, "Sigma 50mm f/1.4 EX DG HSM"}, - {128, "Sigma 85mm f/1.4 EX DG HSM"}, - {128, "Sigma 24-70mm f/2.8 IF EX DG HSM"}, - {128, "Sigma 18-250mm f/3.5-6.3 DC OS HSM"}, - {128, "Sigma 17-50mm f/2.8 EX DC HSM"}, - {128, "Sigma 17-70mm f/2.8-4 DC Macro HSM"}, - {128, "Sigma 150mm f/2.8 EX DG OS HSM APO Macro"}, - {128, "Sigma 150-500mm f/5-6.3 APO DG OS HSM"}, - {128, "Tamron AF 28-105mm f/4-5.6 [IF]"}, - {128, "Sigma 35mm f/1.4 DG HSM"}, - {128, "Sigma 18-35mm f/1.8 DC HSM"}, - {128, "Sigma 50-500mm f/4.5-6.3 APO DG OS HSM"}, - {128, "Sigma 24-105mm f/4 DG HSM | A"}, - {128, "Sigma 30mm f/1.4"}, - {128, "Sigma 35mm f/1.4 DG HSM | A"}, - {128, "Sigma 105mm f/2.8 EX DG OS HSM Macro"}, - {128, "Sigma 180mm f/2.8 EX DG OS HSM APO Macro"}, - {128, "Sigma 18-300mm f/3.5-6.3 DC Macro HSM | C"}, - {128, "Sigma 18-50mm f/2.8-4.5 DC HSM"}, - {129, "Tamron Lens (129)"}, - {129, "Tamron 200-400mm f/5.6 LD"}, - {129, "Tamron 70-300mm f/4-5.6 LD"}, - {131, "Tamron 20-40mm f/2.7-3.5 SP Aspherical IF"}, - {135, "Vivitar 28-210mm f/3.5-5.6"}, - {136, "Tokina EMZ M100 AF 100mm f/3.5"}, - {137, "Cosina 70-210mm f/2.8-4 AF"}, - {138, "Soligor 19-35mm f/3.5-4.5"}, - {139, "Tokina AF 28-300mm f/4-6.3"}, - {142, "Voigtlander 70-300mm f/4.5-5.6"}, - {146, "Voigtlander Macro APO-Lanthar 125mm f/2.5 SL"}, - {194, "Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical [IF]"}, - {202, "Tamron SP AF 70-200mm f/2.8 Di LD [IF] Macro"}, - {203, "Tamron SP 70-200mm f/2.8 Di USD"}, - {204, "Tamron SP 24-70mm f/2.8 Di USD"}, - {212, "Tamron 28-300mm f/3.5-6.3 Di PZD"}, - {213, "Tamron 16-300mm f/3.5-6.3 Di II PZD Macro"}, - {214, "Tamron SP 150-600mm f/5-6.3 Di USD"}, - {215, "Tamron SP 15-30mm f/2.8 Di USD"}, - {216, "Tamron SP 45mm f/1.8 Di USD"}, - {217, "Tamron SP 35mm f/1.8 Di USD"}, - {218, "Tamron SP 90mm f/2.8 Di Macro 1:1 USD (F017)"}, - {220, "Tamron SP 150-600mm f/5-6.3 Di USD G2"}, - {224, "Tamron SP 90mm f/2.8 Di Macro 1:1 USD (F004)"}, - {255, "Tamron Lens (255)"}, - {255, "Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical"}, - {255, "Tamron AF 18-250mm f/3.5-6.3 XR Di II LD"}, - {255, "Tamron AF 55-200mm f/4-5.6 Di II LD Macro"}, - {255, "Tamron AF 70-300mm f/4-5.6 Di LD Macro 1:2"}, - {255, "Tamron SP AF 200-500mm f/5.0-6.3 Di LD IF"}, - {255, "Tamron SP AF 10-24mm f/3.5-4.5 Di II LD Aspherical IF"}, - {255, "Tamron SP AF 70-200mm f/2.8 Di LD IF Macro"}, - {255, "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical IF"}, - {255, "Tamron AF 90-300mm f/4.5-5.6 Telemacro"}, - {1868, "Sigma MC-11 SA-E Mount Converter with not-supported Sigma lens"}, - {2550, "Minolta AF 50mm f/1.7"}, - {2551, "Minolta AF 35-70mm f/4 or Other Lens"}, - {2551, "Sigma UC AF 28-70mm f/3.5-4.5"}, - {2551, "Sigma AF 28-70mm f/2.8"}, - {2551, "Sigma M-AF 70-200mm f/2.8 EX Aspherical"}, - {2551, "Quantaray M-AF 35-80mm f/4-5.6"}, - {2551, "Tokina 28-70mm f/2.8-4.5 AF"}, - {2552, "Minolta AF 28-85mm f/3.5-4.5 or Other Lens"}, - {2552, "Tokina 19-35mm f/3.5-4.5"}, - {2552, "Tokina 28-70mm f/2.8 AT-X"}, - {2552, "Tokina 80-400mm f/4.5-5.6 AT-X AF II 840"}, - {2552, "Tokina AF PRO 28-80mm f/2.8 AT-X 280"}, - {2552, "Tokina AT-X PRO [II] AF 28-70mm f/2.6-2.8 270"}, - {2552, "Tamron AF 19-35mm f/3.5-4.5"}, - {2552, "Angenieux AF 28-70mm f/2.6"}, - {2552, "Tokina AT-X 17 AF 17mm f/3.5"}, - {2552, "Tokina 20-35mm f/3.5-4.5 II AF"}, - {2553, "Minolta AF 28-135mm f/4-4.5 or Sigma Lens"}, - {2553, "Sigma ZOOM-alpha 35-135mm f/3.5-4.5"}, - {2553, "Sigma 28-105mm f/2.8-4 Aspherical"}, - {2553, "Sigma 28-105mm f/4-5.6 UC"}, - {2554, "Minolta AF 35-105mm f/3.5-4.5"}, - {2555, "Minolta AF 70-210mm f/4 Macro or Sigma Lens"}, - {2555, "Sigma 70-210mm f/4-5.6 APO"}, - {2555, "Sigma M-AF 70-200mm f/2.8 EX APO"}, - {2555, "Sigma 75-200mm f/2.8-3.5"}, - {2556, "Minolta AF 135mm f/2.8"}, - {2557, "Minolta/Sony AF 28mm f/2.8"}, - {2558, "Minolta AF 24-50mm f/4"}, - {2560, "Minolta AF 100-200mm f/4.5"}, - {2561, "Minolta AF 75-300mm f/4.5-5.6 or Sigma Lens"}, - {2561, "Sigma 70-300mm f/4-5.6 DL Macro"}, - {2561, "Sigma 300mm f/4 APO Macro"}, - {2561, "Sigma AF 500mm f/4.5 APO"}, - {2561, "Sigma AF 170-500mm f/5-6.3 APO Aspherical"}, - {2561, "Tokina AT-X AF 300mm f/4"}, - {2561, "Tokina AT-X AF 400mm f/5.6 SD"}, - {2561, "Tokina AF 730 II 75-300mm f/4.5-5.6"}, - {2561, "Sigma 800mm f/5.6 APO"}, - {2561, "Sigma AF 400mm f/5.6 APO Macro"}, - {2561, "Sigma 1000mm f/8 APO"}, - {2562, "Minolta AF 50mm f/1.4 [New]"}, - {2563, "Minolta AF 300mm f/2.8 APO or Sigma Lens"}, - {2563, "Sigma AF 50-500mm f/4-6.3 EX DG APO"}, - {2563, "Sigma AF 170-500mm f/5-6.3 APO Aspherical"}, - {2563, "Sigma AF 500mm f/4.5 EX DG APO"}, - {2563, "Sigma 400mm f/5.6 APO"}, - {2564, "Minolta AF 50mm f/2.8 Macro or Sigma Lens"}, - {2564, "Sigma 50mm f/2.8 EX Macro"}, - {2565, "Minolta AF 600mm f/4 APO"}, - {2566, "Minolta AF 24mm f/2.8 or Sigma Lens"}, - {2566, "Sigma 17-35mm f/2.8-4 EX Aspherical"}, - {2572, "Minolta/Sony AF 500mm f/8 Reflex"}, - {2578, "Minolta/Sony AF 16mm f/2.8 Fisheye or Sigma Lens"}, - {2578, "Sigma 8mm f/4 EX [DG] Fisheye"}, - {2578, "Sigma 14mm f/3.5"}, - {2578, "Sigma 15mm f/2.8 Fisheye"}, - {2579, "Minolta/Sony AF 20mm f/2.8 or Tokina Lens"}, - {2579, "Tokina AT-X Pro DX 11-16mm f/2.8"}, - {2581, "Minolta AF 100mm f/2.8 Macro [New] or Sigma or Tamron Lens"}, - {2581, "Sigma AF 90mm f/2.8 Macro"}, - {2581, "Sigma AF 105mm f/2.8 EX [DG] Macro"}, - {2581, "Sigma 180mm f/5.6 Macro"}, - {2581, "Sigma 180mm f/3.5 EX DG Macro"}, - {2581, "Tamron 90mm f/2.8 Macro"}, - {2585, "Minolta AF 35-105mm f/3.5-4.5 New or Tamron Lens"}, - {2585, "Beroflex 35-135mm f/3.5-4.5"}, - {2585, "Tamron 24-135mm f/3.5-5.6"}, - {2588, "Minolta AF 70-210mm f/3.5-4.5"}, - {2589, "Minolta AF 80-200mm f/2.8 APO or Tokina Lens"}, - {2589, "Tokina 80-200mm f/2.8"}, - {2590, "Minolta AF 200mm f/2.8 G APO + Minolta AF 1.4x APO or Other Lens + 1.4x"}, - {2590, "Minolta AF 600mm f/4 HS-APO G + Minolta AF 1.4x APO"}, - {2591, "Minolta AF 35mm f/1.4"}, - {2592, "Minolta AF 85mm f/1.4 G (D)"}, - {2593, "Minolta AF 200mm f/2.8 APO"}, - {2594, "Minolta AF 3x-1x f/1.7-2.8 Macro"}, - {2596, "Minolta AF 28mm f/2"}, - {2597, "Minolta AF 35mm f/2 [New]"}, - {2598, "Minolta AF 100mm f/2"}, - {2601, "Minolta AF 200mm f/2.8 G APO + Minolta AF 2x APO or Other Lens + 2x"}, - {2601, "Minolta AF 600mm f/4 HS-APO G + Minolta AF 2x APO"}, - {2604, "Minolta AF 80-200mm f/4.5-5.6"}, - {2605, "Minolta AF 35-80mm f/4-5.6"}, - {2606, "Minolta AF 100-300mm f/4.5-5.6"}, - {2607, "Minolta AF 35-80mm f/4-5.6"}, - {2608, "Minolta AF 300mm f/2.8 HS-APO G"}, - {2609, "Minolta AF 600mm f/4 HS-APO G"}, - {2612, "Minolta AF 200mm f/2.8 HS-APO G"}, - {2613, "Minolta AF 50mm f/1.7 New"}, - {2615, "Minolta AF 28-105mm f/3.5-4.5 xi"}, - {2616, "Minolta AF 35-200mm f/4.5-5.6 xi"}, - {2618, "Minolta AF 28-80mm f/4-5.6 xi"}, - {2619, "Minolta AF 80-200mm f/4.5-5.6 xi"}, - {2620, "Minolta AF 28-70mm f/2.8 G"}, - {2621, "Minolta AF 100-300mm f/4.5-5.6 xi"}, - {2624, "Minolta AF 35-80mm f/4-5.6 Power Zoom"}, - {2628, "Minolta AF 80-200mm f/2.8 HS-APO G"}, - {2629, "Minolta AF 85mm f/1.4 New"}, - {2631, "Minolta/Sony AF 100-300mm f/4.5-5.6 APO"}, - {2632, "Minolta AF 24-50mm f/4 New"}, - {2638, "Minolta AF 50mm f/2.8 Macro New"}, - {2639, "Minolta AF 100mm f/2.8 Macro"}, - {2641, "Minolta/Sony AF 20mm f/2.8 New"}, - {2642, "Minolta AF 24mm f/2.8 New"}, - {2644, "Minolta AF 100-400mm f/4.5-6.7 APO"}, - {2662, "Minolta AF 50mm f/1.4 New"}, - {2667, "Minolta AF 35mm f/2 New"}, - {2668, "Minolta AF 28mm f/2 New"}, - {2672, "Minolta AF 24-105mm f/3.5-4.5 (D)"}, - {3046, "Metabones Canon EF Speed Booster"}, - {4567, "Tokina 70-210mm f/4-5.6"}, - {4570, "Tamron AF 35-135mm f/3.5-4.5"}, - {4571, "Vivitar 70-210mm f/4.5-5.6"}, - {4574, "2x Teleconverter or Tamron or Tokina Lens"}, - {4574, "Tamron SP AF 90mm f/2.5"}, - {4574, "Tokina RF 500mm f/8.0 x2"}, - {4574, "Tokina 300mm f/2.8 x2"}, - {4575, "1.4x Teleconverter"}, - {4585, "Tamron SP AF 300mm f/2.8 LD IF"}, - {4586, "Tamron SP AF 35-105mm f/2.8 LD Aspherical IF"}, - {4587, "Tamron AF 70-210mm f/2.8 SP LD"}, - {4812, "Metabones Canon EF Speed Booster Ultra"}, - {6118, "Canon EF Adapter"}, - {6528, "Sigma 16mm f/2.8 Filtermatic Fisheye"}, - {6553, "E-Mount, T-Mount, Other Lens or no lens"}, - {6553, "Sony E 16mm f/2.8"}, - {6553, "Sony E 18-55mm f/3.5-5.6 OSS"}, - {6553, "Sony E 55-210mm f/4.5-6.3 OSS"}, - {6553, "Sony E 18-200mm f/3.5-6.3 OSS"}, - {6553, "Sony E 30mm f/3.5 Macro"}, - {6553, "Sony E 24mm f/1.8 ZA"}, - {6553, "Sony E 50mm f/1.8 OSS"}, - {6553, "Sony E 16-70mm f/4 ZA OSS"}, - {6553, "Sony E 10-18mm f/4 OSS"}, - {6553, "Sony E PZ 16-50mm f/3.5-5.6 OSS"}, - {6553, "Sony FE 35mm f/2.8 ZA"}, - {6553, "Sony FE 24-70mm f/4 ZA OSS"}, - {6553, "Sony FE 85mm f/1.8"}, - {6553, "Sony E 18-200mm f/3.5-6.3 OSS LE"}, - {6553, "Sony E 20mm f/2.8"}, - {6553, "Sony E 35mm f/1.8 OSS"}, - {6553, "Sony E PZ 18-105mm f/4 G OSS"}, - {6553, "Sony FE 12-24mm f/4 G"}, - {6553, "Sony FE 90mm f/2.8 Macro G OSS"}, - {6553, "Sony E 18-50mm f/4-5.6"}, - {6553, "Sony FE 24mm f/1.4 GM"}, - {6553, "Sony FE 24-105mm f/4 G OSS"}, - {6553, "Sony E PZ 18-200mm f/3.5-6.3 OSS"}, - {6553, "Sony FE 55mm f/1.8 ZA"}, - {6553, "Sony FE 70-200mm f/4 G OSS"}, - {6553, "Sony FE 16-35mm f/4 ZA OSS"}, - {6553, "Sony FE 50mm f/2.8 Macro"}, - {6553, "Sony FE 28-70mm f/3.5-5.6 OSS"}, - {6553, "Sony FE 35mm f/1.4 ZA"}, - {6553, "Sony FE 24-240mm f/3.5-6.3 OSS"}, - {6553, "Sony FE 28mm f/2"}, - {6553, "Sony FE PZ 28-135mm f/4 G OSS"}, - {6553, "Sony FE 100mm f/2.8 STF GM OSS"}, - {6553, "Sony E PZ 18-110mm f/4 G OSS"}, - {6553, "Sony FE 24-70mm f/2.8 GM"}, - {6553, "Sony FE 50mm f/1.4 ZA"}, - {6553, "Sony FE 85mm f/1.4 GM"}, - {6553, "Sony FE 50mm f/1.8"}, - {6553, "Sony FE 21mm f/2.8 (SEL28F20 + SEL075UWC)"}, - {6553, "Sony FE 16mm f/3.5 Fisheye (SEL28F20 + SEL057FEC)"}, - {6553, "Sony FE 70-300mm f/4.5-5.6 G OSS"}, - {6553, "Sony FE 100-400mm f/4.5-5.6 GM OSS"}, - {6553, "Sony FE 70-200mm f/2.8 GM OSS"}, - {6553, "Sony FE 16-35mm f/2.8 GM"}, - {6553, "Sony FE 400mm f/2.8 GM OSS"}, - {6553, "Sony E 18-135mm f/3.5-5.6 OSS"}, - {6553, "Sony FE 70-200mm f/2.8 GM OSS + 1.4X Teleconverter"}, - {6553, "Sony FE 70-200mm f/2.8 GM OSS + 2X Teleconverter"}, - {6553, "Sony FE 100-400mm f/4.5-5.6 GM OSS + 1.4X Teleconverter"}, - {6553, "Sony FE 100-400mm f/4.5-5.6 GM OSS + 2X Teleconverter"}, - {6553, "Sony FE 400mm f/2.8 GM OSS + 1.4X Teleconverter"}, - {6553, "Sony FE 400mm f/2.8 GM OSS + 2X Teleconverter"}, - {6553, "Samyang AF 50mm f/1.4 FE"}, - {6553, "Samyang AF 14mm f/2.8 FE"}, - {6553, "Samyang AF 24mm f/2.8"}, - {6553, "Samyang AF 35mm f/2.8 FE"}, - {6553, "Samyang AF 35mm f/1.4"}, - {6553, "Sigma 19mm f/2.8 [EX] DN"}, - {6553, "Sigma 30mm f/2.8 [EX] DN"}, - {6553, "Sigma 60mm f/2.8 DN"}, - {6553, "Sigma 30mm f/1.4 DC DN | C"}, - {6553, "Sigma 85mm f/1.4 DG HSM | A"}, - {6553, "Sigma 16mm f/1.4 DC DN | C"}, - {6553, "Sigma 105mm f/1.4 DG HSM | A"}, - {6553, "Sigma 56mm f/1.4 DC DN | C"}, - {6553, "Sigma 70-200mm f/2.8 DG OS HSM | S"}, - {6553, "Sigma 70mm f/2.8 DG MACRO | A"}, - {6553, "Tamron 18-200mm f/3.5-6.3 Di III VC"}, - {6553, "Tamron 28-75mm f/2.8 Di III RXD"}, - {6553, "Tokina Firin 20mm f/2 FE MF"}, - {6553, "Voigtlander SUPER WIDE-HELIAR 15mm f/4.5 III"}, - {6553, "Voigtlander HELIAR-HYPER WIDE 10mm f/5.6"}, - {6553, "Voigtlander ULTRA WIDE-HELIAR 12mm f/5.6 III"}, - {6553, "Voigtlander MACRO APO-LANTHAR 65mm f/2 Aspherical"}, - {6553, "Voigtlander NOKTON 40mm f/1.2 Aspherical"}, - {6553, "Voigtlander NOKTON classic 35mm f/1.4"}, - {6553, "Voigtlander MACRO APO-LANTHAR 110mm f/2.5"}, - {6553, "Voigtlander COLOR-SKOPAR 21mm f/3.5 Aspherical"}, - {6553, "Zeiss Touit 12mm f/2.8"}, - {6553, "Zeiss Touit 32mm f/1.8"}, - {6553, "Zeiss Touit 50mm f/2.8 Macro"}, - {6553, "Zeiss Batis 25mm f/2"}, - {6553, "Zeiss Batis 85mm f/1.8"}, - {6553, "Zeiss Batis 18mm f/2.8"}, - {6553, "Zeiss Batis 135mm f/2.8"}, - {6553, "Zeiss Batis 40mm f/2 CF"}, - {6553, "Zeiss Loxia 50mm f/2"}, - {6553, "Zeiss Loxia 35mm f/2"}, - {6553, "Zeiss Loxia 21mm f/2.8"}, - {6553, "Zeiss Loxia 85mm f/2.4"}, - {6553, "Zeiss Loxia 25mm f/2.4"}, - {6553, "Arax MC 35mm f/2.8 Tilt+Shift"}, - {6553, "Arax MC 80mm f/2.8 Tilt+Shift"}, - {6553, "Zenitar MF 16mm f/2.8 Fisheye M42"}, - {6553, "Samyang 500mm Mirror f/8.0"}, - {6553, "Pentacon Auto 135mm f/2.8"}, - {6553, "Pentacon Auto 29mm f/2.8"}, - {6553, "Helios 44-2 58mm f/2.0"}, - {18688, "Sigma MC-11 SA-E Mount Converter with not-supported Sigma lens"}, - {25501, "Minolta AF 50mm f/1.7"}, - {25511, "Minolta AF 35-70mm f/4 or Other Lens"}, - {25511, "Sigma UC AF 28-70mm f/3.5-4.5"}, - {25511, "Sigma AF 28-70mm f/2.8"}, - {25511, "Sigma M-AF 70-200mm f/2.8 EX Aspherical"}, - {25511, "Quantaray M-AF 35-80mm f/4-5.6"}, - {25511, "Tokina 28-70mm f/2.8-4.5 AF"}, - {25521, "Minolta AF 28-85mm f/3.5-4.5 or Other Lens"}, - {25521, "Tokina 19-35mm f/3.5-4.5"}, - {25521, "Tokina 28-70mm f/2.8 AT-X"}, - {25521, "Tokina 80-400mm f/4.5-5.6 AT-X AF II 840"}, - {25521, "Tokina AF PRO 28-80mm f/2.8 AT-X 280"}, - {25521, "Tokina AT-X PRO [II] AF 28-70mm f/2.6-2.8 270"}, - {25521, "Tamron AF 19-35mm f/3.5-4.5"}, - {25521, "Angenieux AF 28-70mm f/2.6"}, - {25521, "Tokina AT-X 17 AF 17mm f/3.5"}, - {25521, "Tokina 20-35mm f/3.5-4.5 II AF"}, - {25531, "Minolta AF 28-135mm f/4-4.5 or Sigma Lens"}, - {25531, "Sigma ZOOM-alpha 35-135mm f/3.5-4.5"}, - {25531, "Sigma 28-105mm f/2.8-4 Aspherical"}, - {25531, "Sigma 28-105mm f/4-5.6 UC"}, - {25541, "Minolta AF 35-105mm f/3.5-4.5"}, - {25551, "Minolta AF 70-210mm f/4 Macro or Sigma Lens"}, - {25551, "Sigma 70-210mm f/4-5.6 APO"}, - {25551, "Sigma M-AF 70-200mm f/2.8 EX APO"}, - {25551, "Sigma 75-200mm f/2.8-3.5"}, - {25561, "Minolta AF 135mm f/2.8"}, - {25571, "Minolta/Sony AF 28mm f/2.8"}, - {25581, "Minolta AF 24-50mm f/4"}, - {25601, "Minolta AF 100-200mm f/4.5"}, - {25611, "Minolta AF 75-300mm f/4.5-5.6 or Sigma Lens"}, - {25611, "Sigma 70-300mm f/4-5.6 DL Macro"}, - {25611, "Sigma 300mm f/4 APO Macro"}, - {25611, "Sigma AF 500mm f/4.5 APO"}, - {25611, "Sigma AF 170-500mm f/5-6.3 APO Aspherical"}, - {25611, "Tokina AT-X AF 300mm f/4"}, - {25611, "Tokina AT-X AF 400mm f/5.6 SD"}, - {25611, "Tokina AF 730 II 75-300mm f/4.5-5.6"}, - {25611, "Sigma 800mm f/5.6 APO"}, - {25611, "Sigma AF 400mm f/5.6 APO Macro"}, - {25611, "Sigma 1000mm f/8 APO"}, - {25621, "Minolta AF 50mm f/1.4 [New]"}, - {25631, "Minolta AF 300mm f/2.8 APO or Sigma Lens"}, - {25631, "Sigma AF 50-500mm f/4-6.3 EX DG APO"}, - {25631, "Sigma AF 170-500mm f/5-6.3 APO Aspherical"}, - {25631, "Sigma AF 500mm f/4.5 EX DG APO"}, - {25631, "Sigma 400mm f/5.6 APO"}, - {25641, "Minolta AF 50mm f/2.8 Macro or Sigma Lens"}, - {25641, "Sigma 50mm f/2.8 EX Macro"}, - {25651, "Minolta AF 600mm f/4 APO"}, - {25661, "Minolta AF 24mm f/2.8 or Sigma Lens"}, - {25661, "Sigma 17-35mm f/2.8-4 EX Aspherical"}, - {25721, "Minolta/Sony AF 500mm f/8 Reflex"}, - {25781, "Minolta/Sony AF 16mm f/2.8 Fisheye or Sigma Lens"}, - {25781, "Sigma 8mm f/4 EX [DG] Fisheye"}, - {25781, "Sigma 14mm f/3.5"}, - {25781, "Sigma 15mm f/2.8 Fisheye"}, - {25791, "Minolta/Sony AF 20mm f/2.8 or Tokina Lens"}, - {25791, "Tokina AT-X Pro DX 11-16mm f/2.8"}, - {25811, "Minolta AF 100mm f/2.8 Macro [New] or Sigma or Tamron Lens"}, - {25811, "Sigma AF 90mm f/2.8 Macro"}, - {25811, "Sigma AF 105mm f/2.8 EX [DG] Macro"}, - {25811, "Sigma 180mm f/5.6 Macro"}, - {25811, "Sigma 180mm f/3.5 EX DG Macro"}, - {25811, "Tamron 90mm f/2.8 Macro"}, - {25851, "Beroflex 35-135mm f/3.5-4.5"}, - {25858, "Minolta AF 35-105mm f/3.5-4.5 New or Tamron Lens"}, - {25858, "Tamron 24-135mm f/3.5-5.6"}, - {25881, "Minolta AF 70-210mm f/3.5-4.5"}, - {25891, "Minolta AF 80-200mm f/2.8 APO or Tokina Lens"}, - {25891, "Tokina 80-200mm f/2.8"}, - {25901, "Minolta AF 200mm f/2.8 G APO + Minolta AF 1.4x APO or Other Lens + 1.4x"}, - {25901, "Minolta AF 600mm f/4 HS-APO G + Minolta AF 1.4x APO"}, - {25911, "Minolta AF 35mm f/1.4"}, - {25921, "Minolta AF 85mm f/1.4 G (D)"}, - {25931, "Minolta AF 200mm f/2.8 APO"}, - {25941, "Minolta AF 3x-1x f/1.7-2.8 Macro"}, - {25961, "Minolta AF 28mm f/2"}, - {25971, "Minolta AF 35mm f/2 [New]"}, - {25981, "Minolta AF 100mm f/2"}, - {26011, "Minolta AF 200mm f/2.8 G APO + Minolta AF 2x APO or Other Lens + 2x"}, - {26011, "Minolta AF 600mm f/4 HS-APO G + Minolta AF 2x APO"}, - {26041, "Minolta AF 80-200mm f/4.5-5.6"}, - {26051, "Minolta AF 35-80mm f/4-5.6"}, - {26061, "Minolta AF 100-300mm f/4.5-5.6"}, - {26071, "Minolta AF 35-80mm f/4-5.6"}, - {26081, "Minolta AF 300mm f/2.8 HS-APO G"}, - {26091, "Minolta AF 600mm f/4 HS-APO G"}, - {26121, "Minolta AF 200mm f/2.8 HS-APO G"}, - {26131, "Minolta AF 50mm f/1.7 New"}, - {26151, "Minolta AF 28-105mm f/3.5-4.5 xi"}, - {26161, "Minolta AF 35-200mm f/4.5-5.6 xi"}, - {26181, "Minolta AF 28-80mm f/4-5.6 xi"}, - {26191, "Minolta AF 80-200mm f/4.5-5.6 xi"}, - {26201, "Minolta AF 28-70mm f/2.8 G"}, - {26211, "Minolta AF 100-300mm f/4.5-5.6 xi"}, - {26241, "Minolta AF 35-80mm f/4-5.6 Power Zoom"}, - {26281, "Minolta AF 80-200mm f/2.8 HS-APO G"}, - {26291, "Minolta AF 85mm f/1.4 New"}, - {26311, "Minolta/Sony AF 100-300mm f/4.5-5.6 APO"}, - {26321, "Minolta AF 24-50mm f/4 New"}, - {26381, "Minolta AF 50mm f/2.8 Macro New"}, - {26391, "Minolta AF 100mm f/2.8 Macro"}, - {26411, "Minolta/Sony AF 20mm f/2.8 New"}, - {26421, "Minolta AF 24mm f/2.8 New"}, - {26441, "Minolta AF 100-400mm f/4.5-6.7 APO"}, - {26621, "Minolta AF 50mm f/1.4 New"}, - {26671, "Minolta AF 35mm f/2 New"}, - {26681, "Minolta AF 28mm f/2 New"}, - {26721, "Minolta AF 24-105mm f/3.5-4.5 (D)"}, - {30464, "Metabones Canon EF Speed Booster"}, - {45671, "Tokina 70-210mm f/4-5.6"}, - {45701, "Tamron AF 35-135mm f/3.5-4.5"}, - {45711, "Vivitar 70-210mm f/4.5-5.6"}, - {45741, "2x Teleconverter or Tamron or Tokina Lens"}, - {45741, "Tamron SP AF 90mm f/2.5"}, - {45741, "Tokina RF 500mm f/8.0 x2"}, - {45741, "Tokina 300mm f/2.8 x2"}, - {45751, "1.4x Teleconverter"}, - {45851, "Tamron SP AF 300mm f/2.8 LD IF"}, - {45861, "Tamron SP AF 35-105mm f/2.8 LD Aspherical IF"}, - {45871, "Tamron AF 70-210mm f/2.8 SP LD"}, - {48128, "Metabones Canon EF Speed Booster Ultra"}, - {61184, "Canon EF Adapter"}, - {65280, "Sigma 16mm f/2.8 Filtermatic Fisheye"}, - {65535, "E-Mount, T-Mount, Other Lens or no lens"}, - {65535, "Sony E 16mm f/2.8"}, - {65535, "Sony E 18-55mm f/3.5-5.6 OSS"}, - {65535, "Sony E 55-210mm f/4.5-6.3 OSS"}, - {65535, "Sony E 18-200mm f/3.5-6.3 OSS"}, - {65535, "Sony E 30mm f/3.5 Macro"}, - {65535, "Sony E 24mm f/1.8 ZA"}, - {65535, "Sony E 50mm f/1.8 OSS"}, - {65535, "Sony E 16-70mm f/4 ZA OSS"}, - {65535, "Sony E 10-18mm f/4 OSS"}, - {65535, "Sony E PZ 16-50mm f/3.5-5.6 OSS"}, - {65535, "Sony FE 35mm f/2.8 ZA"}, - {65535, "Sony FE 24-70mm f/4 ZA OSS"}, - {65535, "Sony FE 85mm f/1.8"}, - {65535, "Sony E 18-200mm f/3.5-6.3 OSS LE"}, - {65535, "Sony E 20mm f/2.8"}, - {65535, "Sony E 35mm f/1.8 OSS"}, - {65535, "Sony E PZ 18-105mm f/4 G OSS"}, - {65535, "Sony FE 12-24mm f/4 G"}, - {65535, "Sony FE 90mm f/2.8 Macro G OSS"}, - {65535, "Sony E 18-50mm f/4-5.6"}, - {65535, "Sony FE 24mm f/1.4 GM"}, - {65535, "Sony FE 24-105mm f/4 G OSS"}, - {65535, "Sony E PZ 18-200mm f/3.5-6.3 OSS"}, - {65535, "Sony FE 55mm f/1.8 ZA"}, - {65535, "Sony FE 70-200mm f/4 G OSS"}, - {65535, "Sony FE 16-35mm f/4 ZA OSS"}, - {65535, "Sony FE 50mm f/2.8 Macro"}, - {65535, "Sony FE 28-70mm f/3.5-5.6 OSS"}, - {65535, "Sony FE 35mm f/1.4 ZA"}, - {65535, "Sony FE 24-240mm f/3.5-6.3 OSS"}, - {65535, "Sony FE 28mm f/2"}, - {65535, "Sony FE PZ 28-135mm f/4 G OSS"}, - {65535, "Sony FE 100mm f/2.8 STF GM OSS"}, - {65535, "Sony E PZ 18-110mm f/4 G OSS"}, - {65535, "Sony FE 24-70mm f/2.8 GM"}, - {65535, "Sony FE 50mm f/1.4 ZA"}, - {65535, "Sony FE 85mm f/1.4 GM"}, - {65535, "Sony FE 50mm f/1.8"}, - {65535, "Sony FE 21mm f/2.8 (SEL28F20 + SEL075UWC)"}, - {65535, "Sony FE 16mm f/3.5 Fisheye (SEL28F20 + SEL057FEC)"}, - {65535, "Sony FE 70-300mm f/4.5-5.6 G OSS"}, - {65535, "Sony FE 100-400mm f/4.5-5.6 GM OSS"}, - {65535, "Sony FE 70-200mm f/2.8 GM OSS"}, - {65535, "Sony FE 16-35mm f/2.8 GM"}, - {65535, "Sony FE 400mm f/2.8 GM OSS"}, - {65535, "Sony E 18-135mm f/3.5-5.6 OSS"}, - {65535, "Sony FE 70-200mm f/2.8 GM OSS + 1.4X Teleconverter"}, - {65535, "Sony FE 70-200mm f/2.8 GM OSS + 2X Teleconverter"}, - {65535, "Sony FE 100-400mm f/4.5-5.6 GM OSS + 1.4X Teleconverter"}, - {65535, "Sony FE 100-400mm f/4.5-5.6 GM OSS + 2X Teleconverter"}, - {65535, "Sony FE 400mm f/2.8 GM OSS + 1.4X Teleconverter"}, - {65535, "Sony FE 400mm f/2.8 GM OSS + 2X Teleconverter"}, - {65535, "Samyang AF 50mm f/1.4 FE"}, - {65535, "Samyang AF 14mm f/2.8 FE"}, - {65535, "Samyang AF 24mm f/2.8"}, - {65535, "Samyang AF 35mm f/2.8 FE"}, - {65535, "Samyang AF 35mm f/1.4"}, - {65535, "Sigma 19mm f/2.8 [EX] DN"}, - {65535, "Sigma 30mm f/2.8 [EX] DN"}, - {65535, "Sigma 60mm f/2.8 DN"}, - {65535, "Sigma 30mm f/1.4 DC DN | C"}, - {65535, "Sigma 85mm f/1.4 DG HSM | A"}, - {65535, "Sigma 16mm f/1.4 DC DN | C"}, - {65535, "Sigma 105mm f/1.4 DG HSM | A"}, - {65535, "Sigma 56mm f/1.4 DC DN | C"}, - {65535, "Sigma 70-200mm f/2.8 DG OS HSM | S"}, - {65535, "Sigma 70mm f/2.8 DG MACRO | A"}, - {65535, "Tamron 18-200mm f/3.5-6.3 Di III VC"}, - {65535, "Tamron 28-75mm f/2.8 Di III RXD"}, - {65535, "Tokina Firin 20mm f/2 FE MF"}, - {65535, "Voigtlander SUPER WIDE-HELIAR 15mm f/4.5 III"}, - {65535, "Voigtlander HELIAR-HYPER WIDE 10mm f/5.6"}, - {65535, "Voigtlander ULTRA WIDE-HELIAR 12mm f/5.6 III"}, - {65535, "Voigtlander MACRO APO-LANTHAR 65mm f/2 Aspherical"}, - {65535, "Voigtlander NOKTON 40mm f/1.2 Aspherical"}, - {65535, "Voigtlander NOKTON classic 35mm f/1.4"}, - {65535, "Voigtlander MACRO APO-LANTHAR 110mm f/2.5"}, - {65535, "Voigtlander COLOR-SKOPAR 21mm f/3.5 Aspherical"}, - {65535, "Zeiss Touit 12mm f/2.8"}, - {65535, "Zeiss Touit 32mm f/1.8"}, - {65535, "Zeiss Touit 50mm f/2.8 Macro"}, - {65535, "Zeiss Batis 25mm f/2"}, - {65535, "Zeiss Batis 85mm f/1.8"}, - {65535, "Zeiss Batis 18mm f/2.8"}, - {65535, "Zeiss Batis 135mm f/2.8"}, - {65535, "Zeiss Batis 40mm f/2 CF"}, - {65535, "Zeiss Loxia 50mm f/2"}, - {65535, "Zeiss Loxia 35mm f/2"}, - {65535, "Zeiss Loxia 21mm f/2.8"}, - {65535, "Zeiss Loxia 85mm f/2.4"}, - {65535, "Zeiss Loxia 25mm f/2.4"}, - {65535, "Arax MC 35mm f/2.8 Tilt+Shift"}, - {65535, "Arax MC 80mm f/2.8 Tilt+Shift"}, - {65535, "Zenitar MF 16mm f/2.8 Fisheye M42"}, - {65535, "Samyang 500mm Mirror f/8.0"}, - {65535, "Pentacon Auto 135mm f/2.8"}, - {65535, "Pentacon Auto 29mm f/2.8"}, - {65535, "Helios 44-2 58mm f/2.0"}, - }; - } - - std::string toString (const Tag* t) const override - { - int lensID = t->toInt(); - Tag *lensInfoTag = t->getParent()->getRoot()->findTag ("LensInfo"); - Tag *apertureTag = t->getParent()->getRoot()->findTag ("MaxApertureValue"); - Tag *focalLengthTag = t->getParent()->getRoot()->findTag ("FocalLength"); - double maxApertureAtFocal = 0.; - double focalLength = 0.; - - if ( apertureTag ) { - maxApertureAtFocal = pow (2.0, apertureTag->toDouble() / 2.0); - } - - if ( focalLengthTag ) { - focalLength = focalLengthTag->toDouble(); - } - - double *liArray = nullptr; - - if (lensInfoTag) { - liArray = lensInfoTag->toDoubleArray(); - } - - std::string retval = guess ( lensID, focalLength, maxApertureAtFocal, liArray); - - if (liArray) { - delete [] liArray; - } - - return retval; - } -}; -SALensIDInterpreter saLensIDInterpreter; - -class SALensID2Interpreter : public IntLensInterpreter< int > -{ -public: - SALensID2Interpreter () - { - choices.insert (p_t (0, "Unknown E-mount lens or other lens")); - choices.insert (p_t (1, "Sony LA-EA1 or Sigma MC-11 Adapter")); - choices.insert (p_t (2, "Sony LA-EA2 Adapter")); - choices.insert (p_t (3, "Sony LA-EA3 Adapter")); - choices.insert (p_t (6, "Sony LA-EA4 Adapter")); - choices.insert (p_t (44, "Metabones Canon EF Smart Adapter")); - choices.insert (p_t (78, "Metabones Canon EF Smart Adapter Mark III or Other Adapter")); - choices.insert (p_t (234, "Metabones Canon EF Smart Adapter Mark IV")); - choices.insert (p_t (239, "Metabones Canon EF Speed Booster")); - choices.insert (p_t (32784, "Sony E 16mm f/2.8")); - choices.insert (p_t (32785, "Sony E 18-55mm f/3.5-5.6 OSS")); - choices.insert (p_t (32786, "Sony E 55-210mm f/4.5-6.3 OSS")); - choices.insert (p_t (32787, "Sony E 18-200mm f/3.5-6.3 OSS")); - choices.insert (p_t (32788, "Sony E 30mm f/3.5 Macro")); - choices.insert (p_t (32789, "Sony E 24mm f/1.8 ZA or Samyang AF 50mm f/1.4 FE")); - choices.insert (p_t (32789, "Samyang AF 50mm f/1.4 FE")); - choices.insert (p_t (32790, "Sony E 50mm f/1.8 OSS or Samyang AF 14mm f/2.8 FE")); - choices.insert (p_t (32790, "Samyang AF 14mm f/2.8 FE")); - choices.insert (p_t (32791, "Sony E 16-70mm f/4 ZA OSS")); - choices.insert (p_t (32792, "Sony E 10-18mm f/4 OSS")); - choices.insert (p_t (32793, "Sony E PZ 16-50mm f/3.5-5.6 OSS")); - choices.insert (p_t (32794, "Sony FE 35mm f/2.8 ZA or Samyang AF 24mm f/2.8 FE")); - choices.insert (p_t (32794, "Samyang AF 24mm f/2.8 FE")); - choices.insert (p_t (32795, "Sony FE 24-70mm f/4 ZA OSS")); - choices.insert (p_t (32796, "Sony FE 85mm f/1.8")); - choices.insert (p_t (32797, "Sony E 18-200mm f/3.5-6.3 OSS LE")); - choices.insert (p_t (32798, "Sony E 20mm f/2.8")); - choices.insert (p_t (32799, "Sony E 35mm f/1.8 OSS")); - choices.insert (p_t (32800, "Sony E PZ 18-105mm f/4 G OSS")); - choices.insert (p_t (32801, "Sony FE 12-24mm f/4 G")); - choices.insert (p_t (32802, "Sony FE 90mm f/2.8 Macro G OSS")); - choices.insert (p_t (32803, "Sony E 18-50mm f/4-5.6")); - choices.insert (p_t (32804, "Sony FE 24mm f/1.4 GM")); - choices.insert (p_t (32805, "Sony FE 24-105mm f/4 G OSS")); - choices.insert (p_t (32807, "Sony E PZ 18-200mm f/3.5-6.3 OSS")); - choices.insert (p_t (32808, "Sony FE 55mm f/1.8 ZA")); - choices.insert (p_t (32810, "Sony FE 70-200mm f/4 G OSS")); - choices.insert (p_t (32811, "Sony FE 16-35mm f/4 ZA OSS")); - choices.insert (p_t (32812, "Sony FE 50mm f/2.8 Macro")); - choices.insert (p_t (32813, "Sony FE 28-70mm f/3.5-5.6 OSS")); - choices.insert (p_t (32814, "Sony FE 35mm f/1.4 ZA")); - choices.insert (p_t (32815, "Sony FE 24-240mm f/3.5-6.3 OSS")); - choices.insert (p_t (32816, "Sony FE 28mm f/2")); - choices.insert (p_t (32817, "Sony FE PZ 28-135mm f/4 G OSS")); - choices.insert (p_t (32819, "Sony FE 100mm f/2.8 STF GM OSS")); - choices.insert (p_t (32820, "Sony E PZ 18-110mm f/4 G OSS")); - choices.insert (p_t (32821, "Sony FE 24-70mm f/2.8 GM")); - choices.insert (p_t (32822, "Sony FE 50mm f/1.4 ZA")); - choices.insert (p_t (32823, "Sony FE 85mm f/1.4 GM")); - choices.insert (p_t (32824, "Sony FE 50mm f/1.8")); - choices.insert (p_t (32826, "Sony FE 21mm f/2.8 (SEL28F20 + SEL075UWC)")); - choices.insert (p_t (32827, "Sony FE 16mm f/3.5 Fisheye (SEL28F20 + SEL057FEC)")); - choices.insert (p_t (32828, "Sony FE 70-300mm f/4.5-5.6 G OSS")); - choices.insert (p_t (32829, "Sony FE 100-400mm f/4.5-5.6 GM OSS")); - choices.insert (p_t (32830, "Sony FE 70-200mm f/2.8 GM OSS")); - choices.insert (p_t (32831, "Sony FE 16-35mm f/2.8 GM")); - choices.insert (p_t (32848, "Sony FE 400mm f/2.8 GM OSS")); - choices.insert (p_t (32849, "Sony E 18-135mm f/3.5-5.6 OSS")); - choices.insert (p_t (33072, "Sony FE 70-200mm f/2.8 GM OSS + 1.4X Teleconverter")); - choices.insert (p_t (33073, "Sony FE 70-200mm f/2.8 GM OSS + 2X Teleconverter")); - choices.insert (p_t (33076, "Sony FE 100mm f/2.8 STF GM OSS (macro mode)")); - choices.insert (p_t (33077, "Sony FE 100-400mm f/4.5-5.6 GM OSS + 1.4X Teleconverter")); - choices.insert (p_t (33078, "Sony FE 100-400mm f/4.5-5.6 GM OSS + 2X Teleconverter")); - choices.insert (p_t (33079, "Sony FE 400mm f/2.8 GM OSS + 1.4X Teleconverter")); - choices.insert (p_t (33080, "Sony FE 400mm f/2.8 GM OSS + 2X Teleconverter")); - choices.insert (p_t (49201, "Zeiss Touit 12mm f/2.8")); - choices.insert (p_t (49202, "Zeiss Touit 32mm f/1.8")); - choices.insert (p_t (49203, "Zeiss Touit 50mm f/2.8 Macro")); - choices.insert (p_t (49216, "Zeiss Batis 25mm f/2")); - choices.insert (p_t (49217, "Zeiss Batis 85mm f/1.8")); - choices.insert (p_t (49218, "Zeiss Batis 18mm f/2.8")); - choices.insert (p_t (49219, "Zeiss Batis 135mm f/2.8")); - choices.insert (p_t (49220, "Zeiss Batis 40mm f/2 CF")); - choices.insert (p_t (49232, "Zeiss Loxia 50mm f/2")); - choices.insert (p_t (49233, "Zeiss Loxia 35mm f/2")); - choices.insert (p_t (49234, "Zeiss Loxia 21mm f/2.8")); - choices.insert (p_t (49235, "Zeiss Loxia 85mm f/2.4")); - choices.insert (p_t (49236, "Zeiss Loxia 25mm f/2.4")); - choices.insert (p_t (49457, "Tamron 28-75mm f/2.8 Di III RXD")); - choices.insert (p_t (50480, "Sigma 30mm f/1.4 DC DN | C")); - choices.insert (p_t (50481, "Sigma 50mm f/1.4 DG HSM | A")); - choices.insert (p_t (50482, "Sigma 18-300mm f/3.5-6.3 DC MACRO OS HSM | C + MC-11")); - choices.insert (p_t (50483, "Sigma 18-35mm f/1.8 DC HSM | A + MC-11")); - choices.insert (p_t (50484, "Sigma 24-35mm f/2 DG HSM | A + MC-11")); - choices.insert (p_t (50486, "Sigma 150-600mm f/5-6.3 DG OS HSM | C + MC-11")); - choices.insert (p_t (50487, "Sigma 20mm f/1.4 DG HSM | A + MC-11")); - choices.insert (p_t (50488, "Sigma 35mm f/1.4 DG HSM | A")); - choices.insert (p_t (50489, "Sigma 150-600mm f/5-6.3 DG OS HSM | S + MC-11")); - choices.insert (p_t (50490, "Sigma 120-300mm f/2.8 DG OS HSM | S + MC-11")); - choices.insert (p_t (50492, "Sigma 24-105mm f/4 DG OS HSM | A + MC-11")); - choices.insert (p_t (50493, "Sigma 17-70mm f/2.8-4 DC MACRO OS HSM | C + MC-11")); - choices.insert (p_t (50495, "Sigma 50-100mm f/1.8 DC HSM | A + MC-11")); - choices.insert (p_t (50499, "Sigma 85mm f/1.4 DG HSM | A")); - choices.insert (p_t (50501, "Sigma 100-400mm f/5-6.3 DG OS HSM | C + MC-11")); - choices.insert (p_t (50503, "Sigma 16mm f/1.4 DC DN | C")); - choices.insert (p_t (50507, "Sigma 105mm f/1.4 DG HSM | A")); - choices.insert (p_t (50508, "Sigma 56mm f/1.4 DC DN | C")); - choices.insert (p_t (50512, "Sigma 70-200mm f/2.8 DG OS HSM | S")); - choices.insert (p_t (50513, "Sigma 70mm f/2.8 DG MACRO | A")); - choices.insert (p_t (50992, "Voigtlander SUPER WIDE-HELIAR 15mm f/4.5 III")); - choices.insert (p_t (50993, "Voigtlander HELIAR-HYPER WIDE 10mm f/5.6")); - choices.insert (p_t (50994, "Voigtlander ULTRA WIDE-HELIAR 12mm f/5.6 III")); - choices.insert (p_t (50995, "Voigtlander MACRO APO-LANTHAR 65mm f/2 Aspherical")); - choices.insert (p_t (50996, "Voigtlander NOKTON 40mm f/1.2 Aspherical")); - choices.insert (p_t (50997, "Voigtlander NOKTON classic 35mm f/1.4")); - choices.insert (p_t (50998, "Voigtlander MACRO APO-LANTHAR 110mm f/2.5")); - choices.insert (p_t (50999, "Voigtlander COLOR-SKOPAR 21mm f/3.5 Aspherical")); - choices.insert (p_t (51505, "Samyang AF 14mm f/2.8 FE or Samyang AF 35mm f/2.8 FE")); - choices.insert (p_t (51505, "Samyang AF 35mm f/2.8 FE")); - choices.insert (p_t (51507, "Samyang AF 35mm f/1.4")); - } - - std::string toString (const Tag* t) const override - { - int lensID = t->toInt(); - Tag *lensInfoTag = t->getParent()->getRoot()->findTag ("LensInfo"); - Tag *apertureTag = t->getParent()->getRoot()->findTag ("MaxApertureValue"); - Tag *focalLengthTag = t->getParent()->getRoot()->findTag ("FocalLength"); - double maxApertureAtFocal = 0.; - double focalLength = 0.; - - if ( apertureTag ) { - maxApertureAtFocal = pow (2.0, apertureTag->toDouble() / 2.0); - } - - if ( focalLengthTag ) { - focalLength = focalLengthTag->toDouble(); - } - - double *liArray = nullptr; - - if (lensInfoTag) { - liArray = lensInfoTag->toDoubleArray(); - } - - std::string retval = guess ( lensID, focalLength, maxApertureAtFocal, liArray); - - if (liArray) { - delete [] liArray; - } - - return retval; - } -}; -SALensID2Interpreter saLensID2Interpreter; - -class MATeleconverterInterpreter : public ChoiceInterpreter<> -{ -public: - MATeleconverterInterpreter () - { - choices[0x0] = "None"; - choices[0x4] = "Minolta/Sony AF 1.4x APO (D) (0x04)"; - choices[0x5] = "Minolta/Sony AF 2x APO (D) (0x05)"; - choices[0x48] = "Minolta/Sony AF 2x APO (D)"; - choices[0x50] = "Minolta AF 2x APO II"; - choices[0x60] = "Minolta AF 2x APO"; - choices[0x88] = "Minolta/Sony AF 1.4x APO (D)"; - choices[0x90] = "Minolta AF 1.4x APO II"; - choices[0xa0] = "Minolta AF 1.4x APO"; - } -}; -MATeleconverterInterpreter maTeleconverterInterpreter; - -class MAQualityInterpreter : public ChoiceInterpreter<> -{ -public: - MAQualityInterpreter () - { - choices[0] = "RAW"; - choices[1] = "Super Fine"; - choices[2] = "Fine"; - choices[3] = "Standard"; - choices[4] = "Economy"; - choices[5] = "Extra Fine"; - choices[6] = "RAW + JPEG"; - choices[7] = "Compressed RAW"; - choices[8] = "Compressed RAW + JPEG"; - } -}; -MAQualityInterpreter maQualityInterpreter; - -class MAImageSizeInterpreter : public ChoiceInterpreter<> -{ -public: - MAImageSizeInterpreter () - { - choices[1] = "1600x1200"; - choices[2] = "1280x960"; - choices[3] = "640x480"; - choices[5] = "2560x1920"; - choices[6] = "2272x1704"; - choices[7] = "2048x1536"; - } -}; -MAImageSizeInterpreter maImageSizeInterpreter; - -class SAQualityInterpreter2 : public ChoiceInterpreter<> -{ -public: - SAQualityInterpreter2 () - { - choices[0] = "Raw"; - choices[2] = "cRAW"; - choices[16] = "Extra fine"; - choices[32] = "Fine"; - choices[34] = "RAW + JPEG"; - choices[35] = "cRAW + JPEG"; - choices[48] = "Standard"; - } -}; -SAQualityInterpreter2 saQualityInterpreter2; - -class SAQualityInterpreter3 : public ChoiceInterpreter<> -{ -public: - SAQualityInterpreter3 () - { - choices[2] = "RAW"; - choices[4] = "RAW + JPEG"; - choices[6] = "Fine"; - choices[7] = "Standard"; - } -}; -SAQualityInterpreter3 saQualityInterpreter3; - -class SADriveMode : public ChoiceInterpreter<> -{ -public: - SADriveMode () - { - choices[1] = "Single Frame"; - choices[2] = "Continuous High"; - choices[4] = "Self-timer 10 sec"; - choices[5] = "Self-timer 2 sec, Mirror Lock-up"; - choices[6] = "Single-frame Bracketing"; - choices[7] = "Continuous Bracketing"; - choices[10] = "Remote Commander"; - choices[11] = "Mirror Lock-up"; - choices[18] = "Continuous Low"; - choices[24] = "White Balance Bracketing Low"; - choices[25] = "D-Range Optimizer Bracketing Low"; - choices[40] = "White Balance Bracketing High"; - choices[41] = "D-Range Optimizer Bracketing High"; - } -}; -SADriveMode saDriveMode; - -class SADriveMode2 : public ChoiceInterpreter<> -{ -public: - SADriveMode2 () - { - choices[1] = "Single Frame"; - choices[2] = "Continuous High"; - choices[4] = "Self-timer 10 sec"; - choices[5] = "Self-timer 2 sec, Mirror Lock-up"; - choices[7] = "Continuous Bracketing"; - choices[10] = "Remote Commander"; - choices[11] = "Continuous Self-timer"; - } -}; -SADriveMode2 saDriveMode2; - -class SADriveMode3 : public ChoiceInterpreter<> -{ -public: - SADriveMode3 () - { - choices[16] = "Single Frame"; - choices[33] = "Continuous High"; - choices[34] = "Continuous Low"; - choices[48] = "Speed Priority Continuous"; - choices[81] = "Self-timer 10 sec"; - choices[82] = "Self-timer 2 sec, Mirror Lock-up"; - choices[113] = "Continuous Bracketing 0.3 EV"; - choices[117] = "Continuous Bracketing 0.7 EV"; - choices[145] = "White Balance Bracketing Low"; - choices[146] = "White Balance Bracketing High"; - choices[192] = "Remote Commander"; - choices[209] = "Continuous - HDR"; - choices[210] = "Continuous - Multi Frame NR"; - choices[211] = "Continuous - Handheld Night Shot"; - choices[212] = "Continuous - Anti Motion Blur"; - choices[213] = "Continuous - Sweep Panorama"; - choices[214] = "Continuous - 3D Sweep Panorama"; - } -}; -SADriveMode3 saDriveMode3; - -class SAFocusMode: public ChoiceInterpreter<> -{ -public: - SAFocusMode () - { - choices[0] = "Manual"; - choices[1] = "AF-S"; - choices[2] = "AF-C"; - choices[3] = "AF-A"; - choices[4] = "Permanent-AF"; - choices[65535] = "n/a"; - } -}; -SAFocusMode saFocusMode; - -class SAFocusMode2: public ChoiceInterpreter<> -{ -public: - SAFocusMode2 () - { - choices[0] = "Manual"; - choices[1] = "AF-S"; - choices[2] = "AF-C"; - choices[3] = "AF-A"; - choices[65535] = "n/a"; - } -}; -SAFocusMode2 saFocusMode2; - -class SAFocusModeSetting3: public ChoiceInterpreter<> -{ -public: - SAFocusModeSetting3 () - { - choices[17] = "AF-S"; - choices[18] = "AF-C"; - choices[19] = "AF-A"; - choices[32] = "Manual"; - choices[48] = "DMF"; - choices[65535] = "n/a"; - } -}; -SAFocusModeSetting3 saFocusModeSetting3; - -class SAAFMode: public ChoiceInterpreter<> -{ -public: - SAAFMode() - { - choices[0] = "Default"; - choices[1] = "Multi AF"; - choices[2] = "Center AF"; - choices[3] = "Spot AF"; - choices[4] = "Flexible Spot AF"; - choices[6] = "Touch AF"; - choices[14] = "Tracking"; - choices[15] = "Face Tracking"; - choices[65535] = "n/a"; - } -}; -SAAFMode saAFMode; - -class SAAFAreaMode: public ChoiceInterpreter<> -{ -public: - SAAFAreaMode () - { - choices[0] = "Wide"; - choices[1] = "Local"; - choices[2] = "Spot"; - } -}; -SAAFAreaMode saAFAreaMode; - -class SAAFAreaMode2: public ChoiceInterpreter<> -{ -public: - SAAFAreaMode2 () - { - choices[1] = "Wide"; - choices[2] = "Spot"; - choices[3] = "Local"; - choices[4] = "Flexible"; - } -}; -SAAFAreaMode2 saAFAreaMode2; - -class SAAFPointSelected: public ChoiceInterpreter<> -{ -public: - SAAFPointSelected () - { - choices[1] = "Center"; - choices[2] = "Top"; - choices[3] = "Top-Right"; - choices[4] = "Right"; - choices[5] = "Bottom-Right"; - choices[6] = "Bottom"; - choices[7] = "Bottom-Left"; - choices[8] = "Left"; - choices[9] = "Top-Left"; - choices[10] = "Far Right"; - choices[11] = "Far Left"; - } -}; -SAAFPointSelected saAFPointSelected; - -class SACameraInfoAFPointSelected: public ChoiceInterpreter<> -{ -public: - SACameraInfoAFPointSelected () - { - choices[0] = "Auto"; - choices[1] = "Center"; - choices[2] = "Top"; - choices[3] = "Upper-Right"; - choices[4] = "Right"; - choices[5] = "Lower-Right"; - choices[6] = "Bottom"; - choices[7] = "Lower-Left"; - choices[8] = "Left"; - choices[9] = "Upper-Left"; - choices[10] = "Far Right"; - choices[11] = "Far Left"; - choices[12] = "Upper-middle"; - choices[13] = "Near Right"; - choices[14] = "Lower-middle"; - choices[15] = "Near Left"; - } -}; -SACameraInfoAFPointSelected saCameraInfoAFPointSelected; - -class SACameraInfoAFPoint: public ChoiceInterpreter<> -{ -public: - SACameraInfoAFPoint () - { - choices[0] = "Upper-Left"; - choices[1] = "Left"; - choices[2] = "Lower-Left"; - choices[3] = "Far Left"; - choices[4] = "Top (horizontal)"; - choices[5] = "Near Right"; - choices[6] = "Center (horizontal)"; - choices[7] = "Near Left"; - choices[8] = "Bottom (horizontal)"; - choices[9] = "Top (vertical)"; - choices[10] = "Center (vertical)"; - choices[11] = "Bottom (vertical)"; - choices[12] = "Far Right"; - choices[13] = "Upper-Right"; - choices[14] = "Right"; - choices[15] = "Lower-Right"; - choices[16] = "Upper-middle"; - choices[17] = "Lower-middle"; - choices[255] = "(none)"; - } -}; -SACameraInfoAFPoint saCameraInfoAFPoint; - -class SAAFPointSelected2: public ChoiceInterpreter<> -{ -public: - SAAFPointSelected2 () - { - choices[1] = "Center"; - choices[2] = "Top"; - choices[3] = "Top-Right"; - choices[4] = "Right"; - choices[5] = "Bottom-Right"; - choices[6] = "Bottom"; - choices[7] = "Bottom-Left"; - choices[8] = "Left"; - choices[9] = "Top-Left"; - } -}; -SAAFPointSelected2 saAFPointSelected2; - -class SAMeteringMode0_3: public ChoiceInterpreter<> -{ -public: - SAMeteringMode0_3 () - { - choices[0] = "Multi-segment"; - choices[2] = "Center-weighted Average"; - choices[3] = "Spot"; - } -}; -SAMeteringMode0_3 saMeteringMode0_3; - -class SAMeteringMode1_3: public ChoiceInterpreter<> -{ -public: - SAMeteringMode1_3 () - { - choices[1] = "Multi-segment"; - choices[2] = "Center-weighted Average"; - choices[3] = "Spot"; - } -}; -SAMeteringMode1_3 saMeteringMode1_3; - -class SAMeteringMode1_4: public ChoiceInterpreter<> -{ -public: - SAMeteringMode1_4 () - { - choices[1] = "Multi-segment"; - choices[2] = "Center-weighted Average"; - choices[4] = "Spot"; - } -}; -SAMeteringMode1_4 saMeteringMode1_4; - -class SADynamicRangeOptimizerMode: public ChoiceInterpreter<> -{ -public: - SADynamicRangeOptimizerMode () - { - choices[0] = "Off"; - choices[1] = "Standard"; - choices[2] = "Advanced Auto"; - choices[3] = "Advanced Level"; - choices[4097] = "Auto"; - } -}; -SADynamicRangeOptimizerMode saDynamicRangeOptimizerMode; - -class SADynamicRangeOptimizerSetting: public ChoiceInterpreter<> -{ -public: - SADynamicRangeOptimizerSetting () - { - choices[1] = "Off"; - choices[2] = "On (Auto)"; - choices[3] = "On (Manual)"; - } -}; -SADynamicRangeOptimizerSetting saDynamicRangeOptimizerSetting; - -class SACreativeStyle: public ChoiceInterpreter<> -{ -public: - SACreativeStyle () - { - choices[1] = "Standard"; - choices[2] = "Vivid"; - choices[3] = "Portrait"; - choices[4] = "Landscape"; - choices[5] = "Sunset"; - choices[6] = "Night View/Portrait"; - choices[8] = "B&W"; - choices[9] = "Adobe RGB"; - choices[11] = "Neutral"; - choices[12] = "Clear"; - choices[13] = "Deep"; - choices[14] = "Light"; - choices[15] = "Autumn Leaves"; - choices[16] = "Sepia"; - } -}; -SACreativeStyle saCreativeStyle; - -class SACreativeStyle2: public ChoiceInterpreter<> -{ -public: - SACreativeStyle2 () - { - choices[1] = "Standard"; - choices[2] = "Vivid"; - choices[3] = "Portrait"; - choices[4] = "Landscape"; - choices[5] = "Sunset"; - choices[6] = "Night View/Portrait"; - choices[8] = "B&W"; - } -}; -SACreativeStyle2 saCreativeStyle2; - -class SACreativeStyleSetting: public ChoiceInterpreter<> -{ -public: - SACreativeStyleSetting () - { - choices[16] = "Standard"; - choices[32] = "Vivid"; - choices[64] = "Portrait"; - choices[80] = "Landscape"; - choices[96] = "B&W"; - choices[160] = "Sunset"; - } -}; -SACreativeStyleSetting saCreativeStyleSetting; - -class SAFlashControl: public ChoiceInterpreter<> -{ -public: - SAFlashControl () - { - choices[1] = "ADI Flash"; - choices[2] = "Pre-flash TTL"; - } -}; -SAFlashControl saFlashControl; - -class SAFlashMode: public ChoiceInterpreter<> -{ -public: - SAFlashMode () - { - choices[0] = "ADI"; - choices[1] = "TTL"; - } -}; -SAFlashMode saFlashMode; - -class SAFlashMode2: public ChoiceInterpreter<> -{ -public: - SAFlashMode2 () - { - choices[1] = "Flash Off"; - choices[16] = "Autoflash"; - choices[17] = "Fill-flash"; - choices[18] = "Slow Sync"; - choices[19] = "Rear Sync"; - choices[20] = "Wireless"; - } -}; -SAFlashMode2 saFlashMode2; - -class SAExposureProgram: public ChoiceInterpreter<> -{ -public: - SAExposureProgram () - { - choices[0] = "Auto"; - choices[1] = "Manual"; - choices[2] = "Program AE"; - choices[3] = "Aperture-priority AE"; - choices[4] = "Shutter speed priority AE"; - choices[8] = "Program Shift A"; - choices[9] = "Program Shift S"; - choices[16] = "Portrait"; - choices[17] = "Sports"; - choices[18] = "Sunset"; - choices[19] = "Night Portrait"; - choices[20] = "Landscape"; - choices[21] = "Macro"; - choices[35] = "Auto No Flash"; - } -}; -SAExposureProgram saExposureProgram; - -class SAExposureProgram2: public ChoiceInterpreter<> -{ -public: - SAExposureProgram2 () - { - choices[1] = "Program AE"; - choices[2] = "Aperture-priority AE"; - choices[3] = "Shutter speed priority AE"; - choices[4] = "Manual"; - choices[5] = "Cont. Priority AE"; - choices[16] = "Auto"; - choices[17] = "Auto (no flash)"; - choices[18] = "Auto+"; - choices[49] = "Portrait"; - choices[50] = "Landscape"; - choices[51] = "Macro"; - choices[52] = "Sports"; - choices[53] = "Sunset"; - choices[54] = "Night view"; - choices[55] = "Night view/portrait"; - choices[56] = "Handheld Night Shot"; - choices[57] = "3D Sweep Panorama"; - choices[64] = "Auto 2"; - choices[65] = "Auto 2 (no flash)"; - choices[80] = "Sweep Panorama"; - choices[96] = "Anti Motion Blur"; - choices[128] = "Toy Camera"; - choices[129] = "Pop Color"; - choices[130] = "Posterization"; - choices[131] = "Posterization B/W"; - choices[132] = "Retro Photo"; - choices[133] = "High-key"; - choices[134] = "Partial Color Red"; - choices[135] = "Partial Color Green"; - choices[136] = "Partial Color Blue"; - choices[137] = "Partial Color Yellow"; - choices[138] = "High Contrast Monochrome"; - } -}; -SAExposureProgram2 saExposureProgram2; - -class SARotation: public ChoiceInterpreter<> -{ -public: - SARotation () - { - choices[0] = "Horizontal"; - choices[1] = "Rotate 90 CW"; - choices[2] = "Rotate 270 CW"; - choices[3] = "None"; - } -}; -SARotation saRotation; - -class SASonyImageSize: public ChoiceInterpreter<> -{ -public: - SASonyImageSize () - { - choices[1] = "Large"; - choices[2] = "Medium"; - choices[3] = "Small"; - } -}; -SASonyImageSize saSonyImageSize; - -class SASonyImageSize3: public ChoiceInterpreter<> -{ -public: - SASonyImageSize3 () - { - choices[21] = "Large (3:2)"; - choices[22] = "Medium (3:2)"; - choices[23] = "Small (3:2)"; - choices[25] = "Large (16:9)"; - choices[26] = "Medium (16:9) "; - choices[27] = "Small (16:9)"; - } -}; -SASonyImageSize3 saSonyImageSize3; - -class SAAspectRatio: public ChoiceInterpreter<> -{ -public: - SAAspectRatio () - { - choices[1] = "3:2"; - choices[2] = "16:9"; - } -}; -SAAspectRatio saAspectRatio; - -class SAAspectRatio2: public ChoiceInterpreter<> -{ -public: - SAAspectRatio2 () - { - choices[4] = "3:2"; - choices[8] = "16:9"; - } -}; -SAAspectRatio2 saAspectRatio2; - -class SAExposureLevelIncrements: public ChoiceInterpreter<> -{ -public: - SAExposureLevelIncrements () - { - choices[33] = "1/3 EV"; - choices[50] = "1/2 EV"; - } -}; -SAExposureLevelIncrements saExposureLevelIncrements; - -class SAAFIlluminator: public ChoiceInterpreter<> -{ -public: - SAAFIlluminator () - { - choices[0] = "Off"; - choices[1] = "Auto"; - choices[65535] = "n/a"; - } -}; -SAAFIlluminator saAFIlluminator; - -class SAColorSpace1_2: public ChoiceInterpreter<> -{ -public: - SAColorSpace1_2 () - { - choices[1] = "sRGB"; - choices[2] = "AdobeRGB"; - } -}; -SAColorSpace1_2 saColorSpace1_2; - -class SAColorSpace0_5: public ChoiceInterpreter<> -{ -public: - SAColorSpace0_5 () - { - choices[0] = "sRGB"; - choices[1] = "AdobeRGB"; - choices[5] = "AdobeRGB"; - } -}; -SAColorSpace0_5 saColorSpace0_5; - -class SAColorSpace5_6: public ChoiceInterpreter<> -{ -public: - SAColorSpace5_6 () - { - choices[5] = "AdobeRGB"; - choices[6] = "sRGB"; - } -}; -SAColorSpace5_6 saColorSpace5_6; - -class SAReleaseModeInterpreter: public ChoiceInterpreter<> -{ -public: - SAReleaseModeInterpreter () - { - choices[0] = "Normal"; - choices[2] = "Continuous"; - choices[5] = "Exposure Bracketing"; - choices[6] = "White Balance Bracketing"; - choices[8] = "DRO Bracketing"; - choices[65535] = "n/a"; - } -}; -SAReleaseModeInterpreter saReleaseModeInterpreter; - -class SAImageStyleInterpreter: public ChoiceInterpreter<> -{ -public: - SAImageStyleInterpreter () - { - choices[1] = "Standard"; - choices[2] = "Vivid"; - choices[3] = "Portrait"; - choices[4] = "Landscape"; - choices[5] = "Sunset"; - choices[7] = "Night View/Portrait"; - choices[8] = "B&W"; - choices[9] = "Adobe RGB"; - choices[11] = "Neutral"; - choices[129] = "StyleBox1"; - choices[130] = "StyleBox2"; - choices[131] = "StyleBox3"; - choices[132] = "StyleBox4"; - choices[133] = "StyleBox5"; - choices[134] = "StyleBox6"; - } -}; -SAImageStyleInterpreter saImageStyleInterpreter; - -class SAPictureEffectInterpreter: public ChoiceInterpreter<> -{ -public: - SAPictureEffectInterpreter() - { - choices[0] = "Off"; - choices[1] = "Toy Camera"; - choices[2] = "Pop Color"; - choices[3] = "Posterization"; - choices[4] = "Posterization B/W"; - choices[5] = "Retro Photo"; - choices[6] = "Soft High Key"; - choices[7] = "Partial Color (red)"; - choices[8] = "Partial Color (green)"; - choices[9] = "Partial Color (blue)"; - choices[10] = "Partial Color (yellow)"; - choices[13] = "High Contrast Monochrome"; - choices[16] = "Toy Camera (normal)"; - choices[17] = "Toy Camera (cool)"; - choices[18] = "Toy Camera (warm)"; - choices[19] = "Toy Camera (green)"; - choices[20] = "Toy Camera (magenta)"; - choices[32] = "Soft Focus (low)"; - choices[33] = "Soft Focus"; - choices[34] = "Soft Focus (high)"; - choices[48] = "Miniature (auto)"; - choices[49] = "Miniature (top)"; - choices[50] = "Miniature (middle horizontal)"; - choices[51] = "Miniature (bottom)"; - choices[52] = "Miniature (left)"; - choices[53] = "Miniature (middle vertical)"; - choices[54] = "Miniature (right)"; - choices[64] = "HDR Painting (low)"; - choices[65] = "HDR Painting"; - choices[66] = "HDR Painting (high)"; - choices[80] = "Rich-tone Monochrome"; - choices[97] = "Water Color"; - choices[98] = "Water Color 2"; - choices[112] = "Illustration (low)"; - choices[113] = "Illustration"; - choices[114] = "Illustration (high)"; - } -}; -SAPictureEffectInterpreter saPictureEffectInterpreter; - -class SACameraInfoFocusStatusInterpreter : public ChoiceInterpreter<> -{ -public: - SACameraInfoFocusStatusInterpreter() - { - choices[0] = "Manual - Not confirmed (0)"; - choices[4] = "Manual - Not confirmed (4)"; - choices[16] = "AF-C - Confirmed"; - choices[24] = "AF-C - Not Confirmed"; - choices[64] = "AF-S - Confirmed"; - } -}; -SACameraInfoFocusStatusInterpreter saCameraInfoFocusStatusInterpreter; - -class SAExposureTimeInterpreter : public Interpreter -{ -public: - SAExposureTimeInterpreter () {} - std::string toString (const Tag* t) const override - { - double a = t->toDouble(); - - if (a > 0) { - char buffer[32]; - sprintf (buffer, "%.4f", a); - return buffer; - } else { - return "n/a"; - } - } - double toDouble (const Tag* t, int ofs) override - { - // Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT - TagType astype = t->getType(); - int a = 0; - - if (astype == BYTE) { - a = t->getValue()[ofs]; - } else if (astype == SHORT) { - a = (int)sget2 (t->getValue() + ofs, t->getOrder()); - } - - // Decode the value - if (a > 0) { - return pow (2., 6. - (double (a) / 8.)); - } else { - return 0.; - } - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - // Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT - int a = 0; - - if (astype == INVALID || astype == AUTO) { - astype = t->getType(); - } - - if (astype == BYTE) { - a = t->getValue()[ofs]; - } else if (astype == SHORT) { - a = (int)sget2 (t->getValue() + ofs, t->getOrder()); - } - - // Decode the value - if (a) { - return int (powf (2.f, 6.f - (float (a) / 8.f)) + 0.5f); - } else { - return 0; - } - } -}; -SAExposureTimeInterpreter saExposureTimeInterpreter; - -class SAFNumberInterpreter : public Interpreter -{ -public: - SAFNumberInterpreter () {} - std::string toString (const Tag* t) const override - { - double a = double (t->toDouble()); - - if (a) { - char buffer[32]; - sprintf (buffer, "%.1f", a / 100. ); - return buffer; - } else { - return "n/a"; - } - } - double toDouble (const Tag* t, int ofs) override - { - // Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT - TagType astype = t->getType(); - int a = 0; - - if (astype == BYTE) { - a = t->getValue()[ofs]; - } else if (astype == SHORT) { - a = (int)sget2 (t->getValue() + ofs, t->getOrder()); - } - - // Decode the value - if (a > 0) { - return pow (2., (double (a) / 8. - 1.) / 2.); - } else { - return 0.; - } - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - // Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT - int a = 0; - - if (astype == INVALID || astype == AUTO) { - astype = t->getType(); - } - - if (astype == BYTE) { - a = t->getValue()[ofs]; - } else if (astype == SHORT) { - a = (int)sget2 (t->getValue() + ofs, t->getOrder()); - } - - // Decode the value - if (a) { - return int (powf (2.f, (float (a) / 8.f - 1.f) / 2.f) + 0.5f); - } else { - return 0; - } - } -}; -SAFNumberInterpreter saFNumberInterpreter; - -class SAISOSettingInterpreter : public Interpreter -{ -public: - SAISOSettingInterpreter () {} - std::string toString (const Tag* t) const override - { - int a = t->toInt(); - - if (a) { - char buffer[32]; - sprintf (buffer, "%d", a ); - return buffer; - } else { - return "Auto"; - } - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - // Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT - int a = 0; - - if (astype == INVALID || astype == AUTO) { - astype = t->getType(); - } - - if (astype == BYTE) { - a = t->getValue()[ofs]; - } else if (astype == SHORT) { - a = (int)sget2 (t->getValue() + ofs, t->getOrder()); - } - - // Decode the value - if (a && a != 254) { // 254 = 'Auto' for CameraSettings3, but we might say the same for CameraSettings & CameraSettings2 (?) - return int (expf ((double (a) / 8.f - 6.f) * logf (2.f)) * 100.f + 0.5f); - } else { - return 0; - } - } -}; -SAISOSettingInterpreter saISOSettingInterpreter; - -class SAExposureCompSetInterpreter : public Interpreter -{ -public: - SAExposureCompSetInterpreter () {} - std::string toString (const Tag* t) const override - { - double a = t->toDouble(); - char buffer[32]; - sprintf (buffer, "%.2f", a ); - return buffer; - } - double toDouble (const Tag* t, int ofs) override - { - // Get the value - int a = t->getValue()[ofs]; - // Decode the value - return (double (a) - 128.) / 24.; - } -}; -SAExposureCompSetInterpreter saExposureCompSetInterpreter; - -class SAAFMicroAdjValueInterpreter : public Interpreter -{ -public: - SAAFMicroAdjValueInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%d", t->getValue()[0] - 20); - return buffer; - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - return t->getValue()[0] - 20; - } -}; -SAAFMicroAdjValueInterpreter saAFMicroAdjValueInterpreter; - -class SAAFMicroAdjModeInterpreter : public Interpreter -{ -public: - SAAFMicroAdjModeInterpreter() {} - std::string toString (const Tag* t) const override - { - int a = t->getValue()[0] & 0x80; - - if (a == 0x80) { - return "On"; - } - - return "Off"; - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - return (t->getValue()[0] & 0x80) == 0x80 ? 1 : 0; - } -}; - -SAAFMicroAdjModeInterpreter saAFMicroAdjModeInterpreter; - -class SAAFMicroAdjRegisteredLensesInterpreter : public Interpreter -{ -public: - SAAFMicroAdjRegisteredLensesInterpreter() {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%d", t->getValue()[0] & 0x7f); - return buffer; - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - return t->getValue()[0] & 0x7f; - } -}; -SAAFMicroAdjRegisteredLensesInterpreter saAFMicroAdjRegisteredLensesInterpreter; - -class SAFocusStatusInterpreter : public Interpreter -{ -public: - SAFocusStatusInterpreter () {} - std::string toString (const Tag* t) const override - { - std::string retval; - int a = t->toInt(); - - if (a == 0) { - retval = "Not confirmed"; - } else if (a == 4) { - retval = "Not confirmed, Tracking"; - } else { - if (a & 1) { - retval = "Confirmed"; - } - - if (a & 2) { - if (!retval.empty()) { - retval += ", "; - } - - retval += "Failed"; - } - - if (a & 4) - if (!retval.empty()) { - retval += ", "; - } - - retval += "Tracking"; - } - - return retval; - } -}; -SAFocusStatusInterpreter saFocusStatusInterpreter; - -class SAColorTemperatureSettingInterpreter : public Interpreter -{ -public: - SAColorTemperatureSettingInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - sprintf (buffer, "%d", t->toInt()); - return buffer; - } - int toInt (const Tag* t, int ofs, TagType astype) override - { - int a = 0; - - if (astype == INVALID || astype == AUTO) { - astype = t->getType(); - } - - if (astype == BYTE) { - a = t->getValue()[ofs]; - } else if (astype == SHORT) { - a = (int)sget2 (t->getValue() + ofs, t->getOrder()); - } - - return a * 100; - } -}; -SAColorTemperatureSettingInterpreter saColorTemperatureSettingInterpreter; - -const TagAttrib minoltaAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "MakerNoteVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "MinoltaCameraSettingsOld", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "MinoltaCameraSettings", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0004, AUTO, "MinoltaCameraSettings7D", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0018, AUTO, "ImageStabilization", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0040, AUTO, "CompressedImageSize", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0081, AUTO, "PreviewImage", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0088, AUTO, "PreviewImageStart", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0089, AUTO, "PreviewImageLength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0100, AUTO, "SceneMode", &saSceneModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0101, AUTO, "ColorMode", &saColorModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0102, AUTO, "MinoltaQuality", &maQualityInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0103, AUTO, "MinoltaImageSize", &maImageSizeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0105, AUTO, "Teleconverter", &maTeleconverterInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0107, AUTO, "ImageStabilization", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010a, AUTO, "ZoneMatching", &saZoneMatchingInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010b, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010c, AUTO, "LensID", &saLensIDInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0113, AUTO, "ImageStabilization", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0114, AUTO, "MinoltaCameraSettings", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0e00, AUTO, "PrintIM", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0f00, AUTO, "MinoltaCameraSettings2", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyAttribs[] = { - {0, AC_WRITE, 0, sonyCameraInfoAttribs, 0x0010, AUTO, "CameraInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0102, AUTO, "Quality", &maQualityInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0104, AUTO, "FlashExposureComp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0106, AUTO, "TeleConverter", &maTeleconverterInterpreter}, - {0, AC_WRITE, 0, sonyCameraSettingsAttribs, 0x0114, AUTO, "SonyCameraSettings", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0115, AUTO, "WhiteBalance", &saWhiteBalanceInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x0e00, AUTO, "PrintIM", &stdInterpreter}, - {1, AC_WRITE, 0, nullptr, 0x2001, AUTO, "PreviewImage", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x2009, AUTO, "HighISONoiseReduction", &saHighISONoiseReduction}, - {0, AC_WRITE, 0, nullptr, 0x200a, AUTO, "AutoHDR", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x200b, AUTO, "MultiFrameNoiseReduction", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x200e, AUTO, "PictureEffect", &saPictureEffectInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x2011, AUTO, "VignettingCorrection", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x2012, AUTO, "LateralChromaticAberration", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x2013, AUTO, "DistortionCorrection", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb020, AUTO, "ColorReproduction", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb021, AUTO, "ColorTemperature", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb022, AUTO, "ColorCompensationFilter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb023, AUTO, "SceneMode", &saSceneModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb024, AUTO, "ZoneMatching", &saZoneMatchingInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb025, AUTO, "DynamicRangeOptimizer", &saDynamicRangeOptimizerInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb026, AUTO, "ImageStabilization", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb027, AUTO, "LensID", &saLensIDInterpreter}, - {0, AC_WRITE, 0, minoltaAttribs, 0xb028, AUTO, "MinoltaMakerNote", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb029, AUTO, "ColorMode", &saColorModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb040, AUTO, "Macro", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb041, AUTO, "ExposureMode", &saExposureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb042, AUTO, "FocusMode", &saFocusMode}, - {0, AC_WRITE, 0, nullptr, 0xb043, AUTO, "AFMode", &saAFMode}, - {0, AC_WRITE, 0, nullptr, 0xb044, AUTO, "AFIlluminator", &saAFIlluminator}, - {0, AC_WRITE, 0, nullptr, 0xb047, AUTO, "Quality", &saQualityInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb048, AUTO, "FlashLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb049, AUTO, "ReleaseMode", &saReleaseModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb04a, AUTO, "SequenceNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb04b, AUTO, "AntiBlur", &saAntiBlurInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb04e, AUTO, "LongExposureNoiseReduction", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb04f, AUTO, "DynamicRangeOptimizer", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xb050, AUTO, "HighISONoiseReduction2", &saHighISONoiseReduction2}, - {0, AC_WRITE, 0, nullptr, 0xb052, AUTO, "IntelligentAuto", &stdInterpreter}, - {0, AC_WRITE, 0, sonyTag9405Attribs, 0x9405, AUTO, "Tag9405", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyTag9405Attribs[] = { - {0, AC_WRITE, 0, nullptr, 0x005d, AUTO, "LensFormat", &stdInterpreter}, // 9405b start here - {0, AC_WRITE, 0, nullptr, 0x005e, AUTO, "LensMount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0060, SHORT, "LensType2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0062, SHORT, "LensType", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0603, AUTO, "LensFormat", &stdInterpreter}, // 9405a start here - {0, AC_WRITE, 0, nullptr, 0x0604, AUTO, "LensMount", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0605, SHORT, "LensType2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0608, SHORT, "LensType", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyCameraInfoAttribs[] = { - {0, AC_WRITE, 0, nullptr, 14, SHORT, "FocalLength", &saExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 16, SHORT, "FocalLengthTeleZoom", &saExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 25, AUTO, "FocusStatus", &saCameraInfoFocusStatusInterpreter}, - {0, AC_WRITE, 0, nullptr, 28, AUTO, "AFPointSelected", &saCameraInfoAFPointSelected}, - {0, AC_WRITE, 0, nullptr, 29, AUTO, "FocusMode", &saFocusMode2}, - {0, AC_WRITE, 0, nullptr, 32, AUTO, "AFPoint", &saCameraInfoAFPoint}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyCameraInfo2Attribs[] = { - {0, AC_WRITE, 0, nullptr, 304, AUTO, "AFMicroAdjValue", &saAFMicroAdjValueInterpreter}, - {0, AC_WRITE, 0, nullptr, 305, AUTO, "AFMicroAdjMode", &saAFMicroAdjModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 305, AUTO, "AFMicroAdjRegisteredLenses", &saAFMicroAdjRegisteredLensesInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyCameraSettingsAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "ExposureTime", &saExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "FNumber", &saFNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 4, AUTO, "DriveMode", &saDriveMode}, - {0, AC_WRITE, 0, nullptr, 6, AUTO, "WhiteBalanceFineTune", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 16, AUTO, "FocusModeSetting", &saFocusMode}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "AFAreaMode", &saAFAreaMode}, - {0, AC_WRITE, 0, nullptr, 18, AUTO, "AFPointSelected", &saAFPointSelected}, - {0, AC_WRITE, 0, nullptr, 21, AUTO, "MeteringMode", &saMeteringMode1_4}, - {0, AC_WRITE, 0, nullptr, 22, AUTO, "ISOSetting", &saISOSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 24, AUTO, "DynamicRangeOptimizerMode", &saDynamicRangeOptimizerMode}, - {0, AC_WRITE, 0, nullptr, 25, AUTO, "DynamicRangeOptimizerLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 26, AUTO, "CreativeStyle", &saCreativeStyle}, - {0, AC_WRITE, 0, nullptr, 28, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 29, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 30, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 31, AUTO, "ZoneMatchingValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 34, AUTO, "Brightness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 35, AUTO, "FlashMode", &saFlashMode}, - {0, AC_WRITE, 0, nullptr, 40, AUTO, "PrioritySetupShutterRelease", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 41, AUTO, "AFIlluminator", &saAFIlluminator}, - {0, AC_WRITE, 0, nullptr, 42, AUTO, "AFWithShutter", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 43, AUTO, "LongExposureNoiseReduction", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 44, AUTO, "HighISONoiseReduction", &saHighISONoiseReduction3}, - {0, AC_WRITE, 0, nullptr, 45, AUTO, "ImageStyle", &saImageStyleInterpreter}, - {0, AC_WRITE, 0, nullptr, 60, AUTO, "ExposureProgram", &saExposureProgram}, - {0, AC_WRITE, 0, nullptr, 61, AUTO, "ImageStabilization", &saOnOffInterpreter}, - {0, AC_WRITE, 0, nullptr, 63, AUTO, "Rotation", &saRotation}, - {0, AC_WRITE, 0, nullptr, 77, AUTO, "FocusMode", &saFocusMode}, - {0, AC_WRITE, 0, nullptr, 83, AUTO, "FocusStatus", &saFocusStatusInterpreter}, - {0, AC_WRITE, 0, nullptr, 84, AUTO, "SonyImageSize", &saSonyImageSize}, - {0, AC_WRITE, 0, nullptr, 85, AUTO, "AspectRatio", &saAspectRatio}, - {0, AC_WRITE, 0, nullptr, 86, AUTO, "Quality", &saQualityInterpreter2}, - {0, AC_WRITE, 0, nullptr, 88, AUTO, "ExposureLevelIncrements", &saExposureLevelIncrements}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyCameraSettingsAttribs2[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "ExposureTime", &saExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "FNumber", &saFNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 11, AUTO, "ColorTemperatureSetting", &saColorTemperatureSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 15, AUTO, "FocusMode", &saFocusMode2}, - {0, AC_WRITE, 0, nullptr, 16, AUTO, "AFAreaMode", &saAFAreaMode}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "AFPointSelected", &saAFPointSelected2}, - {0, AC_WRITE, 0, nullptr, 19, AUTO, "MeteringMode", &saMeteringMode1_4}, - {0, AC_WRITE, 0, nullptr, 20, AUTO, "ISOSetting", &saISOSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 22, AUTO, "DynamicRangeOptimizerMode", &saDynamicRangeOptimizerMode}, - {0, AC_WRITE, 0, nullptr, 23, AUTO, "DynamicRangeOptimizerLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 24, AUTO, "CreativeStyle", &saCreativeStyle2}, - {0, AC_WRITE, 0, nullptr, 25, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 26, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 27, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 35, AUTO, "FlashMode", &saFlashMode}, - {0, AC_WRITE, 0, nullptr, 38, AUTO, "HighISONoiseReduction", &saHighISONoiseReduction4}, - {0, AC_WRITE, 0, nullptr, 60, AUTO, "ExposureProgram", &saExposureProgram}, - {0, AC_WRITE, 0, nullptr, 63, AUTO, "Rotation", &saRotation}, - {0, AC_WRITE, 0, nullptr, 83, AUTO, "FocusStatus", &saFocusStatusInterpreter}, - {0, AC_WRITE, 0, nullptr, 84, AUTO, "SonyImageSize", &saSonyImageSize}, - {0, AC_WRITE, 0, nullptr, 85, AUTO, "AspectRatio", &saAspectRatio}, - {0, AC_WRITE, 0, nullptr, 86, AUTO, "Quality", &saQualityInterpreter2}, - {0, AC_WRITE, 0, nullptr, 88, AUTO, "ExposureLevelIncrements", &saExposureLevelIncrements}, - {0, AC_WRITE, 0, nullptr, 126, AUTO, "DriveMode", &saDriveMode2}, - {0, AC_WRITE, 0, nullptr, 131, AUTO, "ColorSpace", &saColorSpace5_6}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -const TagAttrib sonyCameraSettingsAttribs3[] = { - {0, AC_WRITE, 0, nullptr, 0, AUTO, "ShutterSpeedSetting", &saExposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 1, AUTO, "ApertureSetting", &saFNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 2, AUTO, "ISOSetting", &saISOSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "ExposureCompensationSet", &saExposureCompSetInterpreter}, - {0, AC_WRITE, 0, nullptr, 3, AUTO, "DriveModeSetting", &saDriveMode3}, - {0, AC_WRITE, 0, nullptr, 5, AUTO, "ExposureProgram", &saExposureProgram2}, - {0, AC_WRITE, 0, nullptr, 6, AUTO, "FocusModeSetting", &saFocusModeSetting3}, - {0, AC_WRITE, 0, nullptr, 7, AUTO, "MeteringMode", &saMeteringMode1_3}, - {0, AC_WRITE, 0, nullptr, 9, AUTO, "SonyImageSize", &saSonyImageSize3}, - {0, AC_WRITE, 0, nullptr, 10, AUTO, "AspectRatio", &saAspectRatio2}, - {0, AC_WRITE, 0, nullptr, 11, AUTO, "Quality", &saQualityInterpreter3}, - {0, AC_WRITE, 0, nullptr, 12, AUTO, "DynamicRangeOptimizerSetting", &saDynamicRangeOptimizerSetting}, - {0, AC_WRITE, 0, nullptr, 14, AUTO, "ColorSpace", &saColorSpace1_2}, - {0, AC_WRITE, 0, nullptr, 15, AUTO, "CreativeStyleSetting", &saCreativeStyleSetting}, - {0, AC_WRITE, 0, nullptr, 16, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 17, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 18, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 22, AUTO, "WhiteBalance", &saWhiteBalanceSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 23, AUTO, "ColorTemperatureSetting", &saColorTemperatureSettingInterpreter}, - {0, AC_WRITE, 0, nullptr, 23, AUTO, "ColorCompensationFilterSet", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 32, AUTO, "FlashMode", &saFlashMode2}, - {0, AC_WRITE, 0, nullptr, 33, AUTO, "FlashControl", &saFlashControl}, - {0, AC_WRITE, 0, nullptr, 35, AUTO, "FlashExposureCompSet", &saExposureCompSetInterpreter}, - {0, AC_WRITE, 0, nullptr, 36, AUTO, "AFAreaMode", &saAFAreaMode2}, - {0, AC_WRITE, 0, nullptr, 37, AUTO, "LongExposureNoiseReduction", &saOnOffInterpreter2}, - {0, AC_WRITE, 0, nullptr, 38, AUTO, "HighISONoiseReduction", &saHighISONoiseReduction5}, - {0, AC_WRITE, 0, nullptr, 39, AUTO, "SmileShutterMode", &saSmileShutterMode}, - {0, AC_WRITE, 0, nullptr, 40, AUTO, "RedEyeReduction", &saOnOffInterpreter2}, - {0, AC_WRITE, 0, nullptr, 45, AUTO, "HDRSetting", &saOnOffInterpreter3}, - {0, AC_WRITE, 0, nullptr, 46, AUTO, "HDRLevel", &saHDRLevel}, - {0, AC_WRITE, 0, nullptr, 47, AUTO, "ViewingMode", &saViewingMode}, - {0, AC_WRITE, 0, nullptr, 48, AUTO, "FaceDetection", &saOnOffInterpreter2}, - {0, AC_WRITE, 0, nullptr, 49, AUTO, "SmileShutter", &saOnOffInterpreter2}, - {0, AC_WRITE, 0, nullptr, 50, AUTO, "SweepPanoramaSize", &saSweepPanoramaSize}, - {0, AC_WRITE, 0, nullptr, 51, AUTO, "SweepPanoramaDirection", &saSweepPanoramaDirection}, - {0, AC_WRITE, 0, nullptr, 52, AUTO, "DriveMode", &saDriveMode3}, - {0, AC_WRITE, 0, nullptr, 53, AUTO, "MultiFrameNoiseReduction", &saOnOffInterpreter4}, - {0, AC_WRITE, 0, nullptr, 54, AUTO, "LiveViewAFSetting", &saLiveViewAFSetting}, - {0, AC_WRITE, 0, nullptr, 56, AUTO, "PanoramaSize3D", &saPanoramaSize3D}, - {0, AC_WRITE, 0, nullptr, 131, AUTO, "AFButtonPressed", &saNoYesInterpreter}, - {0, AC_WRITE, 0, nullptr, 132, AUTO, "LiveViewMetering", &saLiveViewMetering}, - {0, AC_WRITE, 0, nullptr, 133, AUTO, "ViewingMode2", &saViewingMode}, - {0, AC_WRITE, 0, nullptr, 134, AUTO, "AELock", &saOnOffInterpreter5}, - {0, AC_WRITE, 0, nullptr, 135, AUTO, "FlashAction", &saFlashAction}, - {0, AC_WRITE, 0, nullptr, 139, AUTO, "LiveViewFocusMode", &saLiveViewFocusMode}, - {0, AC_WRITE, 0, nullptr, 153, AUTO, "LensMount", &saLensMount}, - {0, AC_WRITE, 0, nullptr, 643, AUTO, "AFButtonPressed", &saNoYesInterpreter}, - {0, AC_WRITE, 0, nullptr, 644, AUTO, "LiveViewMetering", &saLiveViewMetering}, - {0, AC_WRITE, 0, nullptr, 645, AUTO, "ViewingMode2", &saViewingMode}, - {0, AC_WRITE, 0, nullptr, 646, AUTO, "AELock", &saOnOffInterpreter5}, - {0, AC_WRITE, 0, nullptr, 647, AUTO, "FlashAction", &saFlashAction}, - {0, AC_WRITE, 0, nullptr, 651, AUTO, "LiveViewFocusMode", &saLiveViewFocusMode}, - {0, AC_WRITE, 0, nullptr, 1015, SHORT, "LensType2", &saLensID2Interpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; - -/*const TagAttrib sonyDNGMakerNote[]={ - {0, AC_WRITE, 0, 0, 0x7200, AUTO, "SonyOffset", &stdInterpreter}, - {0, AC_WRITE, 0, 0, 0x7201, AUTO, "SonyLength", &stdInterpreter}, - {0, AC_WRITE, 0, 0, 0x7221, AUTO, "SonyKey", &stdInterpreter}, - {-1, AC_DONTWRITE, 0, 0, 0, AUTO, "", NULL}};*/ - -} -#endif - - diff --git a/rtexif/stdattribs.cc b/rtexif/stdattribs.cc deleted file mode 100644 index ec5534381..000000000 --- a/rtexif/stdattribs.cc +++ /dev/null @@ -1,931 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2010 Oliver Duis - * - * RawTherapee 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. - * - * RawTherapee 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 RawTherapee. If not, see . - */ -#ifndef _STDATTRIBS_ -#define _STDATTRIBS_ - -#include -#include - -#include "rtexif.h" - -namespace rtexif -{ - -class ColorSpaceInterpreter : public ChoiceInterpreter<> -{ - -public: - ColorSpaceInterpreter () - { - choices[1] = "sRGB"; - choices[2] = "Adobe RGB"; - choices[0xffff] = "Uncalibrated"; - } -}; -ColorSpaceInterpreter colorSpaceInterpreter; - -class PreviewColorSpaceInterpreter : public ChoiceInterpreter<> -{ - -public: - PreviewColorSpaceInterpreter () - { - choices[0] = "Unknown"; - choices[1] = "Gray Gamma 2.2"; - choices[2] = "sRGB"; - choices[3] = "Adobe RGB"; - choices[4] = "ProPhoto RGB"; - } -}; -PreviewColorSpaceInterpreter previewColorSpaceInterpreter; - -class LinearSRGBInterpreter : public ChoiceInterpreter<> -{ - -public: - LinearSRGBInterpreter () - { - choices[0] = "Linear"; - choices[1] = "sRGB"; - } -}; -LinearSRGBInterpreter linearSRGBInterpreter; - -class DefaultBlackRenderInterpreter : public ChoiceInterpreter<> -{ - -public: - DefaultBlackRenderInterpreter () - { - choices[0] = "Auto"; - choices[1] = "None"; - } -}; -DefaultBlackRenderInterpreter defaultBlackRenderInterpreter; - -class ExposureProgramInterpreter : public ChoiceInterpreter<> -{ - -public: - ExposureProgramInterpreter () - { - choices[0] = "Not defined"; - choices[1] = "Manual"; - choices[2] = "Normal program"; - choices[3] = "Aperture priority"; - choices[4] = "Shutter priority"; - choices[5] = "Creative program"; - choices[6] = "Action program"; - choices[7] = "Portrait mode"; - choices[8] = "Landscape mode"; - } -}; -ExposureProgramInterpreter exposureProgramInterpreter; - -class MeteringModeInterpreter : public ChoiceInterpreter<> -{ - -public: - MeteringModeInterpreter () - { - choices[0] = "Unknown"; - choices[1] = "Average"; - choices[2] = "Center weighted"; - choices[3] = "Spot"; - choices[4] = "Multispot"; - choices[5] = "Pattern"; - choices[6] = "Partial"; - choices[255] = "Other"; - } -}; -MeteringModeInterpreter meteringModeInterpreter; - -class ExposureModeInterpreter : public ChoiceInterpreter<> -{ - -public: - ExposureModeInterpreter () - { - choices[0] = "Auto exposure"; - choices[1] = "Manual exposure"; - choices[2] = "Auto bracket"; - } -}; -ExposureModeInterpreter exposureModeInterpreter; - -class WhiteBalanceInterpreter : public ChoiceInterpreter<> -{ - -public: - WhiteBalanceInterpreter () - { - choices[0] = "Auto white balance"; - choices[1] = "Manual white balance"; - } -}; -WhiteBalanceInterpreter whiteBalanceInterpreter; - -class SceneCaptureInterpreter : public ChoiceInterpreter<> -{ - -public: - SceneCaptureInterpreter () - { - choices[0] = "Standard"; - choices[1] = "Landscape"; - choices[2] = "Portrait"; - choices[3] = "Night scene"; - } -}; -SceneCaptureInterpreter sceneCaptureInterpreter; - -class GainControlInterpreter : public ChoiceInterpreter<> -{ - -public: - GainControlInterpreter () - { - choices[0] = "None"; - choices[1] = "Low gain up"; - choices[2] = "High gain up"; - choices[3] = "Low gain down"; - choices[4] = "High gain down"; - } -}; -GainControlInterpreter gainControlInterpreter; - -class ContrastInterpreter : public ChoiceInterpreter<> -{ - -public: - ContrastInterpreter () - { - choices[0] = "Normal"; - choices[1] = "Soft"; - choices[2] = "Hard"; - } -}; -ContrastInterpreter contrastInterpreter; - -class SharpnessInterpreter : public ChoiceInterpreter<> -{ - -public: - SharpnessInterpreter () - { - choices[0] = "Normal"; - choices[1] = "Soft"; - choices[2] = "Hard"; - } -}; -SharpnessInterpreter sharpnessInterpreter; - -class SaturationInterpreter : public ChoiceInterpreter<> -{ - -public: - SaturationInterpreter () - { - choices[0] = "Normal"; - choices[1] = "Low saturation"; - choices[2] = "High saturation"; - } -}; -SaturationInterpreter saturationInterpreter; - -class FlashInterpreter : public ChoiceInterpreter<> -{ - -public: - FlashInterpreter () - { - choices[0x0000] = "Flash did not fire"; - choices[0x0001] = "Flash fired"; - choices[0x0005] = "Strobe return light not detected"; - choices[0x0007] = "Strobe return light detected"; - choices[0x0009] = "Flash fired, compulsory flash mode"; - choices[0x000D] = "Flash fired, compulsory flash mode, return light not detected"; - choices[0x000F] = "Flash fired, compulsory flash mode, return light detected"; - choices[0x0010] = "Flash did not fire, compulsory flash mode"; - choices[0x0018] = "Flash did not fire, auto mode"; - choices[0x0019] = "Flash fired, auto mode"; - choices[0x001D] = "Flash fired, auto mode, return light not detected"; - choices[0x001F] = "Flash fired, auto mode, return light detected"; - choices[0x0020] = "No flash function"; - choices[0x0041] = "Flash fired, red-eye reduction mode"; - choices[0x0045] = "Flash fired, red-eye reduction mode, return light not detected"; - choices[0x0047] = "Flash fired, red-eye reduction mode, return light detected"; - choices[0x0049] = "Flash fired, compulsory flash mode, red-eye reduction mode"; - choices[0x004D] = "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected"; - choices[0x004F] = "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected"; - choices[0x0059] = "Flash fired, auto mode, red-eye reduction mode"; - choices[0x005D] = "Flash fired, auto mode, return light not detected, red-eye reduction mode"; - choices[0x005F] = "Flash fired, auto mode, return light detected, red-eye reduction mode"; - } -}; -FlashInterpreter flashInterpreter; - -class LightSourceInterpreter : public ChoiceInterpreter<> -{ - -public: - LightSourceInterpreter () - { - choices[0] = "Unknown"; - choices[1] = "Daylight"; - choices[2] = "Fluorescent"; - choices[3] = "Tungsten"; - choices[4] = "Flash"; - choices[9] = "Fine weather"; - choices[10] = "Cloudy weather"; - choices[11] = "Shade"; - choices[12] = "Daylight fluorescent"; - choices[13] = "Day white fluorescent"; - choices[14] = "Cool white fluorescent"; - choices[15] = "White fluorescent"; - choices[17] = "Standard light A"; - choices[18] = "Standard light B"; - choices[19] = "Standard light C"; - choices[20] = "D55"; - choices[21] = "D65"; - choices[22] = "D75"; - choices[23] = "D50"; - choices[24] = "ISO studio tungsten"; - choices[255] = "Other light source"; - } -}; -LightSourceInterpreter lightSourceInterpreter; - -class CompressionInterpreter : public ChoiceInterpreter<> -{ - -public: - CompressionInterpreter () - { - choices[1] = "Uncompressed"; - choices[6] = "JPEG Compression"; - } -}; -CompressionInterpreter compressionInterpreter; - -class PhotometricInterpreter : public ChoiceInterpreter<> -{ - -public: - PhotometricInterpreter () - { - choices[2] = "RGB"; - choices[6] = "YCbCr"; - } -}; -PhotometricInterpreter photometricInterpreter; - -class ProfileEmbedPolicyInterpreter : public ChoiceInterpreter<> -{ - -public: - ProfileEmbedPolicyInterpreter () - { - choices[0] = "Allow Copying"; - choices[1] = "Embed if Used"; - choices[2] = "Never Embed"; - choices[3] = "No Restrictions"; - } -}; -ProfileEmbedPolicyInterpreter profileEmbedPolicyInterpreter; - -class PlanarConfigInterpreter : public ChoiceInterpreter<> -{ - -public: - PlanarConfigInterpreter () - { - choices[1] = "Chunky format"; - choices[2] = "Planar format"; - } -}; -PlanarConfigInterpreter planarConfigInterpreter; - -class FNumberInterpreter : public Interpreter -{ -public: - FNumberInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double v = t->toDouble(); - - if ( v < 0. || v > 1000. ) { - return "undef"; - } - - sprintf (buffer, "%0.1f", v); - return buffer; - } -}; -FNumberInterpreter fNumberInterpreter; - -class ApertureInterpreter : public Interpreter -{ -public: - ApertureInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double v = pow (2.0, t->toDouble() / 2.0); - - if ( v < 0. || v > 1000. ) { - return "undef"; - } - - sprintf (buffer, "%.1f", v ); - return buffer; - } -}; -ApertureInterpreter apertureInterpreter; - -class ExposureBiasInterpreter : public Interpreter -{ -public: - ExposureBiasInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double v = t->toDouble(); - - if ( v < -1000. || v > 1000. ) { - return "undef"; - } - - sprintf (buffer, "%+0.2f", v ); - return buffer; - } -}; -ExposureBiasInterpreter exposureBiasInterpreter; - -class ShutterSpeedInterpreter : public Interpreter -{ -public: - ShutterSpeedInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double d = pow (2.0, -t->toDouble()); - - if (d > 0.0 && d <= 0.5) { - sprintf (buffer, "1/%.0f", 1.0 / d); - } else { - sprintf (buffer, "%.1f", d); - } - - return buffer; - } -}; -ShutterSpeedInterpreter shutterSpeedInterpreter; - -class ExposureTimeInterpreter : public Interpreter -{ -public: - ExposureTimeInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double d = t->toDouble(); - - if (d > 0.0 && d <= 0.5) { - sprintf (buffer, "1/%.0f", 1.0 / d); - } else { - sprintf (buffer, "%.1f", d); - } - - return buffer; - } -}; -ExposureTimeInterpreter exposureTimeInterpreter; - -class FocalLengthInterpreter : public Interpreter -{ -public: - FocalLengthInterpreter () {} - std::string toString (const Tag* t) const override - { - char buffer[32]; - double v = t->toDouble(); - - if ( v > 1000000. || v < 0 ) { - return "undef"; - } - - sprintf (buffer, "%.1f", v ); - return buffer; - } -}; -FocalLengthInterpreter focalLengthInterpreter; - -class UserCommentInterpreter : public Interpreter -{ -public: - UserCommentInterpreter () {} - std::string toString (const Tag* t) const override - { - int count = t->getCount(); - - if (count <= 8) { - return std::string(); - } - - count = std::min (count, 65535); // limit to 65535 chars to avoid crashes in case of corrupted metadata - unsigned char *buffer = new unsigned char[count - 6]; // include 2 ending null chars for UCS-2 string (possibly) - unsigned char *value = t->getValue(); - - if (!memcmp(value, "ASCII\0\0\0", 8)) { - memcpy(buffer, value + 8, count - 8); - buffer[count - 8] = '\0'; - } else if (!memcmp(value, "UNICODE\0", 8)) { - memcpy(buffer, value + 8, count - 8); - buffer[count - 7] = buffer[count - 8] = '\0'; - Glib::ustring tmp1((char*)buffer); - - - bool hasBOM = false; - enum ByteOrder bo = UNKNOWN; - if (count % 2 || (count >= 11 && (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF))) { - // odd string length can only be UTF-8, don't change anything - std::string retVal ((char*)buffer + 3); - delete [] buffer; - return retVal; - } else if (count >= 10) { - if (buffer[0] == 0xFF && buffer[1] == 0xFE) { - bo = INTEL; // little endian - hasBOM = true; - } else if (buffer[0] == 0xFE && buffer[1] == 0xFF) { - bo = MOTOROLA; // big endian - hasBOM = true; - } - } - if (bo == UNKNOWN) { - // auto-detecting byte order; we still don't know if it's UCS-2 or UTF-8 - int a = 0, b = 0, c = 0, d = 0; - for (int j = 8; j < count; j++) { - unsigned char cc = value[j]; - if (!(j%2)) { - // counting zeros for first byte - if (!cc) { - ++a; - } - } else { - // counting zeros for second byte - if (!cc) { - ++b; - } - } - if (!(cc & 0x80) || ((cc & 0xC0) == 0xC0) || ((cc & 0xC0) == 0x80)) { - ++c; - } - if ((cc & 0xC0) == 0x80) { - ++d; - } - } - if (c == (count - 8) && d) { - // this is an UTF-8 string - std::string retVal ((char*)buffer); - delete [] buffer; - return retVal; - } - if ((a || b) && a != b) { - bo = a > b ? MOTOROLA : INTEL; - } - } - if (bo == UNKNOWN) { - // assuming platform's byte order -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - bo = INTEL; -#else - bo = MOTOROLA; -#endif - } - - // now swapping if necessary - if (!hasBOM && bo != HOSTORDER) { - if (t->getOrder() != HOSTORDER) { - Tag::swapByteOrder2(buffer, count - 8); - } - } - - glong written; - char* utf8Str = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, &written, nullptr); - delete [] buffer; - buffer = new unsigned char[written + 1]; - memcpy(buffer, utf8Str, written); - buffer[written] = 0; - g_free(utf8Str); - } else if (!memcmp(value, "\0\0\0\0\0\0\0\0", 8)) { - // local charset string, whatever it is - memcpy(buffer, value + 8, count - 8); - buffer[count - 7] = buffer[count - 8] = '\0'; - - gsize written = 0; - char *utf8Str = g_locale_to_utf8((char*)buffer, count - 8, nullptr, &written, nullptr); - if (utf8Str && written) { - delete [] buffer; - size_t length = strlen(utf8Str); - buffer = new unsigned char[length + 1]; - strcpy((char*)buffer, utf8Str); - } else { - buffer[0] = 0; - } - if (utf8Str) { - g_free(utf8Str); - } - } else { - // JIS: unsupported - buffer[0] = 0; - } - - std::string retVal ((char*)buffer); - delete [] buffer; - return retVal; - } - void fromString (Tag* t, const std::string& value) override - { - Glib::ustring tmpStr(value); - t->userCommentFromString (tmpStr); - } -}; -UserCommentInterpreter userCommentInterpreter; - -class CFAInterpreter : public Interpreter -{ -public: - CFAInterpreter() {} - std::string toString (const Tag* t) const override - { - char colors[] = "RGB"; - char buffer[1024]; - - for ( int i = 0; i < t->getCount(); i++) { - unsigned char c = t->toInt (i, BYTE); - buffer[i] = c < 3 ? colors[c] : ' '; - } - - buffer[t->getCount()] = 0; - return buffer; - } -}; -CFAInterpreter cfaInterpreter; - -class OrientationInterpreter : public ChoiceInterpreter<> -{ -public: - OrientationInterpreter () - { - choices[1] = "Horizontal (normal)"; - choices[2] = "Mirror horizontal "; - choices[3] = "Rotate 180"; - choices[4] = "Mirror vertical"; - choices[5] = "Mirror horizontal and rotate 270 CW"; - choices[6] = "Rotate 90 CW"; - choices[7] = "Mirror horizontal and rotate 90 CW"; - choices[8] = "Rotate 270 CW"; - // '9' is an "unofficial" value for Orientation but used by some older cameras that lacks orientation sensor, such as Kodak DCS - choices[9] = "Unknown"; - } -}; -OrientationInterpreter orientationInterpreter; - -class UnitsInterpreter : public ChoiceInterpreter<> -{ -public: - UnitsInterpreter() - { - choices[0] = "Unknown"; - choices[1] = "inches"; - choices[2] = "cm"; - } -}; -UnitsInterpreter unitsInterpreter; - -class UTF8BinInterpreter : public Interpreter -{ -public: - UTF8BinInterpreter () {} -}; -UTF8BinInterpreter utf8BinInterpreter; - -class RawImageSegmentationInterpreter : public Interpreter -{ -public: - std::string toString (const Tag* t) const override - { - int segmentNumber = t->toInt(0, SHORT); - int segmentWidth = t->toInt(2, SHORT); - int lastSegmentWidth = t->toInt(4, SHORT); - - char buffer[32]; - sprintf (buffer, "%d %d %d", segmentNumber, segmentWidth, lastSegmentWidth); - return buffer; - } -}; -RawImageSegmentationInterpreter rawImageSegmentationInterpreter; - -const TagAttrib exifAttribs[] = { - {0, AC_SYSTEM, 0, nullptr, 0x0100, AUTO, "ImageWidth", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0101, AUTO, "ImageHeight", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0102, AUTO, "BitsPerSample", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0103, AUTO, "Compression", &compressionInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0153, AUTO, "SampleFormat", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x828d, AUTO, "CFAPatternDim", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x828e, AUTO, "CFAPattern", &cfaInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x829A, AUTO, "ExposureTime", &exposureTimeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x829D, AUTO, "FNumber", &fNumberInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8822, AUTO, "ExposureProgram", &exposureProgramInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8824, AUTO, "SpectralSensitivity", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8827, AUTO, "ISOSpeedRatings", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8828, AUTO, "OECF", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x8832, AUTO, "RecommendedExposureIndex", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9000, AUTO, "ExifVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9003, AUTO, "DateTimeOriginal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9004, AUTO, "DateTimeDigitized", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x9101, AUTO, "ComponentsConfiguration", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x9102, AUTO, "CompressedBitsPerPixel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9201, AUTO, "ShutterSpeedValue", &shutterSpeedInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9202, AUTO, "ApertureValue", &apertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9203, AUTO, "BrightnessValue", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9204, AUTO, "ExposureBiasValue", &exposureBiasInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9205, AUTO, "MaxApertureValue", &apertureInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9206, AUTO, "SubjectDistance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9207, AUTO, "MeteringMode", &meteringModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9208, AUTO, "LightSource", &lightSourceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9209, AUTO, "Flash", &flashInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x920A, AUTO, "FocalLength", &focalLengthInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9214, AUTO, "SubjectArea", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9215, AUTO, "ExposureIndex", &stdInterpreter}, // Note: exists as 0xA215 too, it should be that way - {0, AC_DONTWRITE, 0, nullptr, 0x9216, AUTO, "TIFFEPSStandardID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9217, AUTO, "SensingMethod", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x927C, AUTO, "MakerNote", &stdInterpreter}, - {0, AC_WRITE, 1, nullptr, 0x9286, AUTO, "UserComment", &userCommentInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9290, AUTO, "SubSecTime", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9291, AUTO, "SubSecTimeOriginal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9292, AUTO, "SubSecTimeDigitized", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0xA000, AUTO, "FlashpixVersion", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xA001, AUTO, "ColorSpace", &colorSpaceInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0xA002, AUTO, "PixelXDimension", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0xA003, AUTO, "PixelYDimension", &stdInterpreter}, - {1, AC_DONTWRITE, 0, nullptr, 0xA004, AUTO, "RelatedSoundFile", &stdInterpreter}, - {0, AC_SYSTEM, 0, iopAttribs, 0xA005, AUTO, "Interoperability", &stdInterpreter}, // do not enable, as it causes trouble with FUJI files - {0, AC_WRITE, 0, nullptr, 0xA20B, AUTO, "FlashEnergy", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA20C, AUTO, "SpatialFrequencyResponse", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA20E, AUTO, "FocalPlaneXResolution", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA20F, AUTO, "FocalPlaneYResolution", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA210, AUTO, "FocalPlaneResolutionUnit", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA214, AUTO, "SubjectLocation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA215, AUTO, "ExposureIndex", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA217, AUTO, "SensingMethod", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA300, AUTO, "FileSource", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA301, AUTO, "SceneType", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xA302, AUTO, "CFAPattern", &cfaInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA401, AUTO, "CustomRendered", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA402, AUTO, "ExposureMode", &exposureModeInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA403, AUTO, "WhiteBalance", &whiteBalanceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA404, AUTO, "DigitalZoomRatio", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA405, AUTO, "FocalLengthIn35mmFilm", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA406, AUTO, "SceneCaptureType", &sceneCaptureInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA407, AUTO, "GainControl", &gainControlInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA408, AUTO, "Contrast", &contrastInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA409, AUTO, "Saturation", &saturationInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA40A, AUTO, "Sharpness", &sharpnessInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA40B, AUTO, "DeviceSettingDescription", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA40C, AUTO, "SubjectDistanceRange", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA420, AUTO, "ImageUniqueID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA431, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA432, AUTO, "LensInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA433, AUTO, "LensMake", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA434, AUTO, "LensModel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA435, AUTO, "LensSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xA500, AUTO, "Gamma", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC618, AUTO, "LinearizationTable", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC619, AUTO, "BlackLevelRepeatDim", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC61A, AUTO, "BlackLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC61B, AUTO, "BlackLevelDeltaH", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC61C, AUTO, "BlackLevelDeltaV", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC61D, AUTO, "WhiteLevel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC61E, AUTO, "DefaultScale", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC61F, AUTO, "DefaultCropOrigin", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC620, AUTO, "DefaultCropSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC621, AUTO, "ColorMatrix1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC622, AUTO, "ColorMatrix2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC623, AUTO, "CameraCalibration1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC624, AUTO, "CameraCalibration2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC625, AUTO, "ReductionMatrix1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC626, AUTO, "ReductionMatrix2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC627, AUTO, "AnalogBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC628, AUTO, "AsShotNeutral", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC629, AUTO, "AsShotWhiteXY", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC62A, AUTO, "BaselineExposure", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC62B, AUTO, "BaselineNoise", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC62C, AUTO, "BaselineSharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC62D, AUTO, "BayerGreenSplit", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC62E, AUTO, "LinearResponseLimit", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC62F, AUTO, "CameraSerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC630, AUTO, "DNGLensInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC631, AUTO, "ChromaBlurRadius", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC632, AUTO, "AntiAliasStrength", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC633, AUTO, "ShadowScale", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC65A, AUTO, "CalibrationIlluminant1", &lightSourceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC65B, AUTO, "CalibrationIlluminant2", &lightSourceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC65C, AUTO, "BestQualityScale", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC65D, AUTO, "RawDataUniqueID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC68B, AUTO, "OriginalRawFileName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC68D, AUTO, "ActiveArea", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC68E, AUTO, "MaskedAreas", &stdInterpreter}, -// {0, AC_WRITE, 0, nullptr, 0xC68F, AUTO, "AsShotICCProfile", & ???}, - {0, AC_WRITE, 0, nullptr, 0xC690, AUTO, "AsShotPreProfileMatrix", &stdInterpreter}, -// {0, AC_WRITE, 0, nullptr, 0xC691, AUTO, "CurrentICCProfile", & ???}, - {0, AC_WRITE, 0, nullptr, 0xC692, AUTO, "CurrentPreProfileMatrix", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6BF, AUTO, "ColorimetricReference", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F3, AUTO, "CameraCalibrationSig", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F4, AUTO, "ProfileCalibrationSig", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F5, AUTO, "ProfileIFD", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F6, AUTO, "AsShotProfileName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F7, AUTO, "NoiseReductionApplied", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F8, AUTO, "ProfileName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6F9, AUTO, "ProfileHueSatMapDims", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6FA, AUTO, "ProfileHueSatMapData1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6FB, AUTO, "ProfileHueSatMapData2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6FC, AUTO, "ProfileToneCurve", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6FD, AUTO, "ProfileEmbedPolicy", &profileEmbedPolicyInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC6FE, AUTO, "ProfileCopyright", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC714, AUTO, "ForwardMatrix1", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC715, AUTO, "ForwardMatrix2", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC716, AUTO, "PreviewApplicationName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC717, AUTO, "PreviewApplicationVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC718, AUTO, "PreviewSettingsName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC719, AUTO, "PreviewSettingsDigest", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC71A, AUTO, "PreviewColorSpace", &previewColorSpaceInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC71B, AUTO, "PreviewDateTime", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC71C, AUTO, "RawImageDigest", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC71D, AUTO, "OriginalRawFileDigest", &stdInterpreter}, -// {0, AC_WRITE, 0, nullptr, 0xC71E, AUTO, "SubTileBlockSize", & ???}, -// {0, AC_WRITE, 0, nullptr, 0xC71F, AUTO, "RowInterleaveFactor", & ???}, - {0, AC_WRITE, 0, nullptr, 0xC725, AUTO, "ProfileLookTableDims", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC726, AUTO, "ProfileLookTableData", &stdInterpreter}, -// {0, AC_WRITE, 0, nullptr, 0xC740, AUTO, "OpcodeList1", & ???}, -// {0, AC_WRITE, 0, nullptr, 0xC741, AUTO, "OpcodeList2", & ???}, -// {0, AC_WRITE, 0, nullptr, 0xC74E, AUTO, "OpcodeList3", & ???}, - {0, AC_WRITE, 0, nullptr, 0xC761, AUTO, "NoiseProfile", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC763, AUTO, "TimeCodes", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC764, AUTO, "FrameRate", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC772, AUTO, "TStop", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC789, AUTO, "ReelName", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC791, AUTO, "OriginalDefaultFinalSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC792, AUTO, "OriginalBestQualitySize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC793, AUTO, "OriginalDefaultCropSize", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A1, AUTO, "CameraLabel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A3, AUTO, "ProfileHueSatMapEncoding", &linearSRGBInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A4, AUTO, "ProfileLookTableEncoding", &linearSRGBInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A5, AUTO, "BaselineExposureOffset", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A6, AUTO, "DefaultBlackRender", &defaultBlackRenderInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A7, AUTO, "NewRawImageDigest", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7A8, AUTO, "RawToPreviewGain", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC7B5, AUTO, "DefaultUserCrop", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFDE9, AUTO, "SerialNumber", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFDEA, AUTO, "Lens", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE4C, AUTO, "RawFile", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE4D, AUTO, "Converter", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE4E, AUTO, "WhiteBalance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE51, AUTO, "Exposure", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE52, AUTO, "Shadows", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE53, AUTO, "Brightness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE54, AUTO, "Contrast", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE55, AUTO, "Saturation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE56, AUTO, "Sharpness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE57, AUTO, "Smoothness", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xFE58, AUTO, "MoireFilter", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr } -}; - - -const TagAttrib gpsAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0000, AUTO, "GPSVersionID", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "GPSLatitudeRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0002, AUTO, "GPSLatitude", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0003, AUTO, "GPSLongitudeRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0004, AUTO, "GPSLongitude", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0005, AUTO, "GPSAltitudeRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0006, AUTO, "GPSAltitude", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0007, AUTO, "GPSTimeStamp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0008, AUTO, "GPSSatelites", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0009, AUTO, "GPSStatus", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000a, AUTO, "GPSMeasureMode", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000b, AUTO, "GPSDOP", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000c, AUTO, "GPSSpeedRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000d, AUTO, "GPSSpeed", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000e, AUTO, "GPSTrackRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x000f, AUTO, "GPSTrack", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0010, AUTO, "GPSImgDirectionRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0011, AUTO, "GPSImgDirection", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0012, AUTO, "GPSMapDatum", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0013, AUTO, "GPSDestLatitudeRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0014, AUTO, "GPSDestLatitude", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0015, AUTO, "GPSDestLongitudeRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0016, AUTO, "GPSDestLongitude", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0017, AUTO, "GPSDestBearingRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0018, AUTO, "GPSDestBearing", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0019, AUTO, "GPSDestDistanceRef", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001a, AUTO, "GPSDestDistance", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001b, AUTO, "GPSProcessingMethod", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001c, AUTO, "GPSAreaInformation", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001d, AUTO, "GPSDateStamp", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x001e, AUTO, "GPSDifferential", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr } -}; - -const TagAttrib iopAttribs[] = { - {0, AC_WRITE, 0, nullptr, 0x0001, AUTO, "InteroperabilityIndex", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0002, AUTO, "InteroperabilityVersion", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr } -}; - -const TagAttrib ifdAttribs[] = { - {0, AC_SYSTEM, 0, nullptr, 0x0017, AUTO, "PanaISO", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x00fe, AUTO, "NewSubFileType", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0100, AUTO, "ImageWidth", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0101, AUTO, "ImageHeight", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0102, AUTO, "BitsPerSample", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0103, AUTO, "Compression", &compressionInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0106, AUTO, "PhotometricInterpretation", &photometricInterpreter}, - {0, AC_WRITE, 1, nullptr, 0x010E, AUTO, "ImageDescription", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x010F, AUTO, "Make", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0110, AUTO, "Model", &stdInterpreter}, - {1, AC_DONTWRITE, 0, nullptr, 0x0111, AUTO, "StripOffsets", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0112, AUTO, "Orientation", &orientationInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0115, AUTO, "SamplesPerPixel", &stdInterpreter}, - {1, AC_DONTWRITE, 0, nullptr, 0x0116, AUTO, "RowsPerStrip", &stdInterpreter}, - {1, AC_DONTWRITE, 0, nullptr, 0x0117, AUTO, "StripByteCounts", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x011A, AUTO, "XResolution", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x011B, AUTO, "YResolution", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x011C, AUTO, "PlanarConfiguration", &planarConfigInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0128, AUTO, "ResolutionUnit", &unitsInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x012D, AUTO, "TransferFunction", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0131, AUTO, "Software", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x0132, AUTO, "DateTime", &stdInterpreter}, - {0, AC_WRITE, 1, nullptr, 0x013B, AUTO, "Artist", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x013E, AUTO, "WhitePoint", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x013F, AUTO, "PriomaryChromaticities", &stdInterpreter}, - {0, AC_WRITE, 0, ifdAttribs, 0x014A, AUTO, "SubIFD", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0153, AUTO, "SampleFormat", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0201, AUTO, "JPEGInterchangeFormat", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0202, AUTO, "JPEGInterchangeFormatLength", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0211, AUTO, "YCbCrCoefficients", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0212, AUTO, "YCbCrSubSampling", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0213, AUTO, "YCbCrPositioning", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x0214, AUTO, "ReferenceBlackWhite", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x02bc, AUTO, "ApplicationNotes", &utf8BinInterpreter}, // XMP - {0, AC_WRITE, 0, nullptr, 0x4746, AUTO, "Rating", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x4749, AUTO, "RatingPercent", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x828d, AUTO, "CFAPatternDim", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x828e, AUTO, "CFAPattern", &cfaInterpreter}, - {0, AC_WRITE, 0, kodakIfdAttribs, 0x8290, AUTO, "KodakIFD", &stdInterpreter}, - {0, AC_WRITE, 1, nullptr, 0x8298, AUTO, "Copyright", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x83BB, AUTO, "IPTCData", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0x8606, AUTO, "LeafData", &stdInterpreter}, // is actually a subdir, but a proprietary format - {0, AC_WRITE, 0, exifAttribs, 0x8769, AUTO, "Exif", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0x8773, AUTO, "ICCProfile", &stdInterpreter}, - {0, AC_WRITE, 0, gpsAttribs, 0x8825, AUTO, "GPSInfo", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9003, AUTO, "DateTimeOriginal", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9004, AUTO, "DateTimeDigitized", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0x9211, AUTO, "ImageNumber", &stdInterpreter}, - {0, AC_WRITE, 0, iopAttribs, 0xA005, AUTO, "Interoperability", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xC4A5, AUTO, "PrintIMInformation", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xC612, AUTO, "DNGVersion", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xC613, AUTO, "DNGBackwardVersion", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC614, AUTO, "UniqueCameraModel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xC615, AUTO, "LocalizedCameraModel", &stdInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xc62f, AUTO, "CameraSerialNumber", &stdInterpreter}, - {0, AC_SYSTEM, 0, nullptr, 0xc630, AUTO, "DNGLensInfo", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xC634, AUTO, "MakerNote", &stdInterpreter}, //DNGPrivateData - {0, AC_SYSTEM, 0, nullptr, 0xC640, AUTO, "RawImageSegmentation", &rawImageSegmentationInterpreter}, - {0, AC_WRITE, 0, nullptr, 0xc65d, AUTO, "RawDataUniqueID", &stdInterpreter}, - {0, AC_DONTWRITE, 0, nullptr, 0xc761, AUTO, "NoiseProfile", &stdInterpreter}, - { -1, AC_DONTWRITE, 0, nullptr, 0, AUTO, "", nullptr} -}; -} - -#endif diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 3af955be8..ab58a73f9 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -186,7 +186,7 @@ if(WIN32) ${LENSFUN_INCLUDE_DIRS} ${RSVG_INCLUDE_DIRS} ) - link_directories(. "${PROJECT_SOURCE_DIR}/rtexif" + link_directories(. ${EXTRA_LIBDIR} ${GIOMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc index 35aeb6c91..032a3a4f0 100644 --- a/rtgui/cacheimagedata.cc +++ b/rtgui/cacheimagedata.cc @@ -303,7 +303,3 @@ int CacheImageData::save (const Glib::ustring& fname) } } -rtengine::procparams::IPTCPairs CacheImageData::getIPTCData(unsigned int frame) const -{ - return {}; -} diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index d3aea803b..397bc1c48 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -87,30 +87,26 @@ public: // FramesMetaData interface //------------------------------------------------------------------------- - unsigned int getRootCount () const override { return -1; } + /* unsigned int getRootCount () const override { return -1; } */ unsigned int getFrameCount () const override { return frameCount; } - bool hasExif (unsigned int frame = 0) const override { return false; } - rtexif::TagDirectory* getRootExifData (unsigned int root = 0) const override { return nullptr; } - rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const override { return nullptr; } - rtexif::TagDirectory* getBestExifData (rtengine::ImageSource *imgSource, rtengine::procparams::RAWParams *rawParams) const override { return nullptr; } - bool hasIPTC (unsigned int frame = 0) const override { return false; } - rtengine::procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const override; - tm getDateTime (unsigned int frame = 0) const override { return tm{}; } - time_t getDateTimeAsTS(unsigned int frame = 0) const override { return time_t(-1); } - int getISOSpeed (unsigned int frame = 0) const override { return iso; } - double getFNumber (unsigned int frame = 0) const override { return fnumber; } - double getFocalLen (unsigned int frame = 0) const override { return focalLen; } - double getFocalLen35mm (unsigned int frame = 0) const override { return focalLen35mm; } - float getFocusDist (unsigned int frame = 0) const override { return focusDist; } - double getShutterSpeed (unsigned int frame = 0) const override { return shutter; } - double getExpComp (unsigned int frame = 0) const override { return atof(expcomp.c_str()); } - std::string getMake (unsigned int frame = 0) const override { return camMake; } - std::string getModel (unsigned int frame = 0) const override { return camModel; } - std::string getLens (unsigned int frame = 0) const override { return lens; } - std::string getOrientation (unsigned int frame = 0) const override { return ""; } // TODO + bool hasExif() const override { return false; } + tm getDateTime() const override { return tm{}; } + time_t getDateTimeAsTS() const override { return time_t(-1); } + int getISOSpeed() const override { return iso; } + double getFNumber() const override { return fnumber; } + double getFocalLen() const override { return focalLen; } + double getFocalLen35mm() const override { return focalLen35mm; } + float getFocusDist() const override { return focusDist; } + double getShutterSpeed() const override { return shutter; } + double getExpComp() const override { return atof(expcomp.c_str()); } + std::string getMake() const override { return camMake; } + std::string getModel() const override { return camModel; } + std::string getLens() const override { return lens; } + std::string getOrientation() const override { return ""; } // TODO + Glib::ustring getFileName() const override { return ""; } bool getPixelShift () const override { return isPixelShift; } - bool getHDR (unsigned int frame = 0) const override { return isHDR; } - std::string getImageType (unsigned int frame) const override { return isPixelShift ? "PS" : isHDR ? "HDR" : "STD"; } - rtengine::IIOSampleFormat getSampleFormat (unsigned int frame = 0) const override { return sampleFormat; } + bool getHDR() const override { return isHDR; } + std::string getImageType() const override { return isPixelShift ? "PS" : isHDR ? "HDR" : "STD"; } + rtengine::IIOSampleFormat getSampleFormat() const override { return sampleFormat; } }; #endif diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index a58e28bef..30c9d7e27 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1329,16 +1329,16 @@ void EditorPanel::info_toggled () const rtengine::FramesMetaData* idata = ipc->getInitialImage()->getMetaData(); - if (idata && idata->hasExif(selectedFrame)) { + if (idata && idata->hasExif()) { infoString = Glib::ustring::compose ("%1 + %2\nf/%3 %4s %5%6 %7mm", Glib::ustring (idata->getMake() + " " + idata->getModel()), Glib::ustring (idata->getLens()), - Glib::ustring (idata->apertureToString (idata->getFNumber(selectedFrame))), - Glib::ustring (idata->shutterToString (idata->getShutterSpeed(selectedFrame))), - M ("QINFO_ISO"), idata->getISOSpeed(selectedFrame), - Glib::ustring::format (std::setw (3), std::fixed, std::setprecision (2), idata->getFocalLen(selectedFrame))); + Glib::ustring (idata->apertureToString (idata->getFNumber())), + Glib::ustring (idata->shutterToString (idata->getShutterSpeed())), + M ("QINFO_ISO"), idata->getISOSpeed(), + Glib::ustring::format (std::setw (3), std::fixed, std::setprecision (2), idata->getFocalLen())); - expcomp = Glib::ustring (idata->expcompToString (idata->getExpComp(selectedFrame), true)); // maskZeroexpcomp + expcomp = Glib::ustring (idata->expcompToString (idata->getExpComp(), true)); // maskZeroexpcomp if (!expcomp.empty ()) { infoString = Glib::ustring::compose ("%1 %2EV", @@ -1366,7 +1366,7 @@ void EditorPanel::info_toggled () if (isHDR) { infoString = Glib::ustring::compose ("%1\n" + M("QINFO_HDR"), infoString, numFrames); if (numFrames == 1) { - int sampleFormat = idata->getSampleFormat(selectedFrame); + int sampleFormat = idata->getSampleFormat(); infoString = Glib::ustring::compose ("%1 / %2", infoString, M(Glib::ustring::compose("SAMPLEFORMAT_%1", sampleFormat))); } } else if (isPixelShift) { diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index c5036798e..661118e32 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -21,20 +21,25 @@ #include "guiutils.h" #include "rtimage.h" #include "options.h" +#include "../rtengine/imagedata.h" #include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; -using namespace rtexif; ExifPanel::ExifPanel() : idata(nullptr), changeList(new rtengine::procparams::ExifPairs), defChangeList(new rtengine::procparams::ExifPairs) { - recursiveOp = true; - + editable_ = { + { "Exif.Photo.UserComment", "User Comment" }, + { "Exif.Image.Artist", "Artist" }, + { "Exif.Image.Copyright", "Copyright" }, + { "Exif.Image.ImageDescription", "Image Description"} + }; + exifTree = Gtk::manage (new Gtk::TreeView()); scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow()); @@ -51,11 +56,10 @@ ExifPanel::ExifPanel() : exifTreeModel = Gtk::TreeStore::create (exifColumns); exifTree->set_model (exifTreeModel); exifTree->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_NONE); - exifTree->set_row_separator_func (sigc::mem_fun(*this, &ExifPanel::rowSeperatorFunc)); - - delicon = RTImage::createPixbufFromFile ("cancel-small.png"); + exifTree->set_show_expanders(false); + keepicon = RTImage::createPixbufFromFile ("tick-small.png"); - editicon = RTImage::createPixbufFromFile ("add-small.png"); + editicon = RTImage::createPixbufFromFile("add-small.png"); Gtk::TreeView::Column *viewcol = Gtk::manage (new Gtk::TreeView::Column ("Field Name")); Gtk::CellRendererPixbuf* render_pb = Gtk::manage (new Gtk::CellRendererPixbuf ()); @@ -64,7 +68,7 @@ ExifPanel::ExifPanel() : viewcol->pack_start (*render_pb, false); viewcol->pack_start (*render_txt, true); viewcol->add_attribute (*render_pb, "pixbuf", exifColumns.icon); - viewcol->add_attribute (*render_txt, "markup", exifColumns.field); + viewcol->add_attribute (*render_txt, "markup", exifColumns.label); viewcol->set_expand (true); viewcol->set_resizable (true); viewcol->set_fixed_width (35); @@ -99,24 +103,6 @@ ExifPanel::ExifPanel() : buttons1->set_row_homogeneous (true); buttons1->set_column_homogeneous (true); setExpandAlignProperties (buttons1, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Grid* buttons2 = Gtk::manage (new Gtk::Grid()); - buttons2->set_row_homogeneous (true); - buttons2->set_column_homogeneous (true); - setExpandAlignProperties (buttons2, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - - remove = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_REMOVE") - remove->set_image (*Gtk::manage (new RTImage(delicon))); - remove->set_tooltip_text (M ("EXIFPANEL_REMOVEHINT")); - remove->get_style_context()->add_class ("Left"); - setExpandAlignProperties (remove, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons1->attach_next_to (*remove, Gtk::POS_LEFT, 1, 1); - - keep = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_KEEP") - keep->set_image (*Gtk::manage (new RTImage(keepicon))); - keep->set_tooltip_text (M ("EXIFPANEL_KEEPHINT")); - keep->get_style_context()->add_class ("MiddleH"); - setExpandAlignProperties (keep, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons1->attach_next_to (*keep, Gtk::POS_RIGHT, 1, 1); add = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_ADDEDIT") add->set_image (*Gtk::manage (new RTImage(editicon))); @@ -125,178 +111,152 @@ ExifPanel::ExifPanel() : setExpandAlignProperties (add, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); buttons1->attach_next_to (*add, Gtk::POS_RIGHT, 1, 1); - showAll = Gtk::manage (new Gtk::ToggleButton (M ("EXIFPANEL_SHOWALL"))); - //add->set_tooltip_text (M("EXIFPANEL_SHOWALL")); - showAll->get_style_context()->add_class ("Left"); - setExpandAlignProperties (showAll, false, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - showAll->set_active (options.lastShowAllExif); - buttons2->attach_next_to (*showAll, Gtk::POS_LEFT, 1, 1); - reset = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_RESET") reset->set_image (*Gtk::manage (new RTImage("undo.png", "redo.png"))); reset->set_tooltip_text (M ("EXIFPANEL_RESETHINT")); reset->get_style_context()->add_class ("MiddleH"); setExpandAlignProperties (reset, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons2->attach_next_to (*reset, Gtk::POS_RIGHT, 1, 1); + buttons1->attach_next_to (*reset, Gtk::POS_RIGHT, 1, 1); resetAll = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_RESETALL") resetAll->set_image (*Gtk::manage (new RTImage ("undo-all.png", "redo-all.png"))); resetAll->set_tooltip_text (M ("EXIFPANEL_RESETALLHINT")); resetAll->get_style_context()->add_class ("Right"); setExpandAlignProperties (resetAll, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons2->attach_next_to (*resetAll, Gtk::POS_RIGHT, 1, 1); + buttons1->attach_next_to (*resetAll, Gtk::POS_RIGHT, 1, 1); - pack_end (*buttons2, Gtk::PACK_SHRINK); pack_end (*buttons1, Gtk::PACK_SHRINK); exifTree->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ExifPanel::exifSelectionChanged)); - exifTree->signal_row_activated().connect (sigc::mem_fun (*this, &ExifPanel::row_activated)); + // exifTree->signal_row_activated().connect (sigc::mem_fun (*this, &ExifPanel::row_activated)); - remove->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::removePressed) ); - keep->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::keepPressed) ); reset->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetPressed) ); resetAll->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetAllPressed) ); add->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::addPressed) ); - showAll->signal_toggled().connect ( sigc::mem_fun (*this, &ExifPanel::showAlltoggled) ); show_all (); } + ExifPanel::~ExifPanel () { } + void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); *changeList = pp->exif; setImageData (idata); - applyChangeList (); - exifSelectionChanged (); + refreshTags(); enableListener (); } + void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) { - -// updateChangeList (); pp->exif = *changeList; } + void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { *defChangeList = defParams->exif; } + void ExifPanel::setImageData (const FramesMetaData* id) { idata = id; - exifTreeModel->clear (); - - if (idata) { - for (unsigned int rootNum = 0; rootNum < id->getRootCount (); ++rootNum) { - if ( id->getRootExifData (rootNum)) { - addDirectory (id->getRootExifData (rootNum), exifTreeModel->children(), rootNum > 0); - } - } - } } -Gtk::TreeModel::Children ExifPanel::addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, rtexif::ActionCode action, bool editable) + +Gtk::TreeModel::Children ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited) { + auto root = exifTreeModel->children(); Gtk::TreeModel::Row row = * (exifTreeModel->append (root)); - row[exifColumns.action] = action; row[exifColumns.editable] = editable; - row[exifColumns.edited] = false; - row[exifColumns.field_nopango] = field; + row[exifColumns.edited] = edited; + row[exifColumns.key] = key; + row[exifColumns.label] = label; row[exifColumns.value_nopango] = value; - row[exifColumns.orig_value] = value; + row[exifColumns.value] = value; - if (action == AC_WRITE) { + row[exifColumns.label] = escapeHtmlChars(label); + row[exifColumns.value] = escapeHtmlChars(value); + + if (edited) { + row[exifColumns.icon] = editicon; + } else if (editable) { row[exifColumns.icon] = keepicon; - } else if (action == AC_DONTWRITE) { - row[exifColumns.icon] = delicon; - } - - if (editable) { - row[exifColumns.field] = Glib::ustring ("") + escapeHtmlChars (field) + ""; - row[exifColumns.value] = Glib::ustring ("") + escapeHtmlChars (value) + ""; - } else if (action == AC_SYSTEM) { - row[exifColumns.field] = Glib::ustring ("") + escapeHtmlChars (field) + ""; - row[exifColumns.value] = Glib::ustring ("") + escapeHtmlChars (value) + ""; - } else { - row[exifColumns.field] = escapeHtmlChars (field); - row[exifColumns.value] = escapeHtmlChars (value); } return row.children(); } -Gtk::TreeModel::Children ExifPanel::addSeparator () + +void ExifPanel::refreshTags() { + Glib::RefPtr selection = exifTree->get_selection(); + std::vector sel = selection->get_selected_rows(); + + exifTreeModel->clear(); + + if (!idata) { + return; + } - Gtk::TreeModel::Row row = * (exifTreeModel->append (exifTreeModel->children())); - row[exifColumns.action] = rtexif::ActionCode::AC_INVALID; - row[exifColumns.editable] = false; - row[exifColumns.edited] = false; - row[exifColumns.field_nopango] = ""; - row[exifColumns.value_nopango] = ""; - row[exifColumns.orig_value] = ""; - row[exifColumns.isSeparator] = true; + Glib::ustring fn = idata->getFileName(); + if (fn.empty()) { + return; + } - return row.children(); -} - -void ExifPanel::addDirectory (const TagDirectory* dir, Gtk::TreeModel::Children root, bool checkForSeparator) -{ - - for (int i = 0; i < dir->getCount(); ++i) { - Tag* t = (const_cast (dir))->getTagByIndex (i); - - bool hasContent = false; - - if (checkForSeparator && i == 0) { - for (int j = 0; j < dir->getCount(); ++j) { - Tag* t2 = (const_cast (dir))->getTagByIndex (j); - const TagAttrib* currAttrib = t2->getAttrib(); - - if (currAttrib && (options.lastShowAllExif || currAttrib->action != AC_SYSTEM)) { - addSeparator(); - hasContent = true; - break; - } + std::unordered_set ed; + for (auto &p : editable_) { + ed.insert(p.first); + } + + try { + auto img = open_exiv2(fn); + img->readMetadata(); + auto &exif = img->exifData(); + + for (auto &p : *changeList) { + try { + exif[p.first] = p.second; + } catch (Exiv2::AnyError &exc) { } - } else { - hasContent = true; } - if (!hasContent) { - return; - } - - const TagAttrib* currAttrib = t->getAttrib(); - - if (!options.lastShowAllExif && currAttrib && currAttrib->action == AC_SYSTEM) { - continue; - } - - if (t->isDirectory()) { - for (int j = 0; t->getDirectory (j); j++) { - Gtk::TreeModel::Children ch = addTag (root, t->nameToString (j), M ("EXIFPANEL_SUBDIRECTORY"), currAttrib ? currAttrib->action : AC_DONTWRITE, currAttrib && currAttrib->editable); - addDirectory (t->getDirectory (j), ch); + for (auto &p : editable_) { + auto pos = exif.findKey(Exiv2::ExifKey(p.first)); + if (pos != exif.end() && pos->size()) { + bool edited = changeList->find(pos->key()) != changeList->end(); + addTag(pos->key(), pos->tagLabel(), pos->print(&exif), true, edited); } - } else { - addTag (root, t->nameToString (), t->valueToString (), currAttrib ? (t->getOwnMemory() ? currAttrib->action : AC_SYSTEM) : AC_DONTWRITE, currAttrib && currAttrib->editable); } + for (auto &tag : exif) { + bool editable = ed.find(tag.key()) != ed.end(); + if (!editable && !tag.tagLabel().empty() && tag.typeId() != Exiv2::undefined && + (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { + addTag(tag.key(), tag.tagLabel(), tag.print(&exif), false, false); + } + } + } catch (Exiv2::AnyError &exc) { + return; + } + + for (auto &p : sel) { + exifTree->get_selection()->select(p); } } + void ExifPanel::exifSelectionChanged () { @@ -304,170 +264,53 @@ void ExifPanel::exifSelectionChanged () std::vector sel = selection->get_selected_rows(); if (sel.size() > 1) { - remove->set_sensitive (1); - keep->set_sensitive (1); reset->set_sensitive (1); } else if (sel.size() == 1) { Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (sel[0]); - if (iter->get_value (exifColumns.action) == AC_SYSTEM) { - remove->set_sensitive (0); - keep->set_sensitive (0); - reset->set_sensitive (0); - } else if (!iter->children().empty()) { - remove->set_sensitive (1); - keep->set_sensitive (1); - reset->set_sensitive (1); - } else if (iter->get_value (exifColumns.icon) == delicon) { - remove->set_sensitive (0); - keep->set_sensitive (1); - reset->set_sensitive (1); - } else if (iter->get_value (exifColumns.icon) == keepicon || iter->get_value (exifColumns.icon) == editicon) { - keep->set_sensitive (0); - remove->set_sensitive (1); + if (iter->get_value(exifColumns.icon) == editicon) { reset->set_sensitive (1); } } else { - remove->set_sensitive (0); - keep->set_sensitive (0); reset->set_sensitive (0); } } -void ExifPanel::delIt (Gtk::TreeModel::iterator iter) -{ +void ExifPanel::resetIt (Gtk::TreeModel::iterator iter) +{ if (!iter) { return; } - if (iter->get_value (exifColumns.action) != AC_SYSTEM) { - iter->set_value (exifColumns.icon, delicon); - } - - if (recursiveOp) - for (Gtk::TreeModel::iterator i = iter->children().begin(); i != iter->children().end(); ++i) { - delIt (i); - } + auto key = iter->get_value(exifColumns.key); + changeList->erase(key); } -void ExifPanel::removePressed () -{ - std::vector sel = exifTree->get_selection()->get_selected_rows(); - - for (size_t i = 0; i < sel.size(); i++) { - delIt (exifTreeModel->get_iter (sel[i])); - } - - exifSelectionChanged (); - updateChangeList (); - notifyListener (); -} - -void ExifPanel::keepIt (Gtk::TreeModel::iterator iter) -{ - - if (!iter) { - return; - } - - if (iter->get_value (exifColumns.action) != AC_SYSTEM) { - iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon); - } - - if (recursiveOp) - for (Gtk::TreeModel::iterator i = iter->children().begin(); i != iter->children().end(); ++i) { - keepIt (i); - } -} - -void ExifPanel::keepPressed () -{ - - std::vector sel = exifTree->get_selection()->get_selected_rows(); - - for (size_t i = 0; i < sel.size(); i++) { - keepIt (exifTreeModel->get_iter (sel[i])); - } - - exifSelectionChanged (); - updateChangeList (); - notifyListener (); -} - -/*void ExifPanel::resetIt (Gtk::TreeModel::iterator iter) { - - if (!iter) - return; - - if (iter->get_value (exifColumns.action)!=AC_SYSTEM) - iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon); - if (iter->get_value (exifColumns.edited)) { - iter->set_value (exifColumns.value, Glib::ustring("") + iter->get_value(exifColumns.orig_value) + ""); - iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value)); - iter->set_value (exifColumns.edited, false); - } - if (iter->get_value (exifColumns.action)==AC_INVALID) - exifTreeModel->erase (iter); - else - if (recursiveOp) - for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++) - resetIt (i); -}*/ -Gtk::TreeModel::iterator ExifPanel::resetIt (Gtk::TreeModel::iterator iter) -{ - - if (!iter) { - return iter; - } - - if (iter->get_value (exifColumns.action) != AC_SYSTEM) { - iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon); - } - - if (iter->get_value (exifColumns.edited)) { - iter->set_value (exifColumns.value, Glib::ustring ("") + iter->get_value (exifColumns.orig_value) + ""); - iter->set_value (exifColumns.value_nopango, iter->get_value (exifColumns.orig_value)); - iter->set_value (exifColumns.edited, false); - } - - if (iter->get_value (exifColumns.action) == AC_INVALID) { - return exifTreeModel->erase (iter); - } else if (recursiveOp) { - Gtk::TreeModel::iterator i = iter->children().begin(); - - while (i && i != iter->children().end()) { - i = resetIt (i); - } - } - - return ++iter; -} void ExifPanel::resetPressed () { std::vector sel = exifTree->get_selection()->get_selected_rows(); for (size_t i = 0; i < sel.size(); i++) { - resetIt (exifTreeModel->get_iter (sel[i])); + resetIt(exifTreeModel->get_iter(sel[i])); } - exifSelectionChanged (); - updateChangeList (); - notifyListener (); + refreshTags(); + notifyListener(); } + void ExifPanel::resetAllPressed () { - - setImageData (idata); + setImageData(idata); *changeList = *defChangeList; - applyChangeList (); - exifSelectionChanged (); + refreshTags(); notifyListener (); } + void ExifPanel::addPressed () { @@ -481,10 +324,9 @@ void ExifPanel::addPressed () Gtk::Label* tlabel = new Gtk::Label (M ("EXIFPANEL_ADDTAGDLG_SELECTTAG") + ":"); MyComboBoxText* tcombo = new MyComboBoxText (); - tcombo->append ("Artist"); - tcombo->append ("Copyright"); - tcombo->append ("ImageDescription"); - tcombo->append ("Exif.UserComment"); + for (auto &p : editable_) { + tcombo->append(p.second); + } hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4); hb1->pack_start (*tcombo); @@ -494,21 +336,33 @@ void ExifPanel::addPressed () hb2->pack_start (*vlabel, Gtk::PACK_SHRINK, 4); hb2->pack_start (*ventry); - Glib::ustring sel = getSelection (true); + Glib::ustring sel; + Glib::ustring val; + { + Glib::RefPtr selection = exifTree->get_selection(); + std::vector rows = selection->get_selected_rows(); - if (sel == "") { - tcombo->set_active_text ("Exif.UserComment"); - } else { - tcombo->set_active_text (sel); - - if (!tcombo->get_active ()) { - tcombo->append (sel); - tcombo->set_active_text (sel); + if (rows.size() == 1) { + Gtk::TreeModel::iterator iter = exifTreeModel->get_iter(rows[0]); + if (iter->get_value(exifColumns.editable)) { + sel = iter->get_value(exifColumns.key); + val = iter->get_value(exifColumns.value_nopango); + } } - - ventry->set_text (getSelectedValue ()); } + if (sel == "") { + tcombo->set_active(0); + } else { + for (size_t i = 0; i < editable_.size(); ++i) { + if (editable_[i].first == sel) { + tcombo->set_active(i); + break; + } + } + } + + ventry->set_text(val); ventry->set_activates_default (true); dialog->set_default_response (Gtk::RESPONSE_OK); dialog->get_content_area()->pack_start (*hb1, Gtk::PACK_SHRINK); @@ -521,8 +375,10 @@ void ExifPanel::addPressed () hb2->show (); if (dialog->run () == Gtk::RESPONSE_OK) { - editTag (exifTreeModel->children(), tcombo->get_active_text(), ventry->get_text()); - updateChangeList (); + auto key = editable_[tcombo->get_active_row_number()].first; + auto value = ventry->get_text(); + (*changeList)[key] = value; + refreshTags(); notifyListener (); } @@ -535,186 +391,9 @@ void ExifPanel::addPressed () delete hb2; } -void ExifPanel::showAlltoggled () -{ - options.lastShowAllExif = showAll->get_active(); - setImageData (idata); -} - -bool ExifPanel::rowSeperatorFunc(const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter) -{ - return iter->get_value(exifColumns.isSeparator); -} - -void ExifPanel::editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value) -{ - - Glib::ustring::size_type dp = name.find_first_of ('.'); - Glib::ustring fseg = name.substr (0, dp); - // look up first segment of the path - Gtk::TreeModel::iterator iter; - - for (iter = root.begin(); iter != root.end(); ++iter) - if (iter->get_value (exifColumns.field_nopango) == fseg) { - break; - } - - if (iter == root.end() && value != "#keep" && value != "#delete") { - iter = exifTreeModel->append (root); - iter->set_value (exifColumns.field_nopango, fseg); - iter->set_value (exifColumns.action, AC_INVALID); - - if (dp == Glib::ustring::npos) { - iter->set_value (exifColumns.value, Glib::ustring ("") + value + ""); - iter->set_value (exifColumns.value_nopango, value); - iter->set_value (exifColumns.orig_value, value); - iter->set_value (exifColumns.field, Glib::ustring ("") + fseg + ""); - iter->set_value (exifColumns.edited, true); - iter->set_value (exifColumns.editable, true); - iter->set_value (exifColumns.icon, editicon); - } else { - iter->set_value (exifColumns.value, Glib::ustring (M ("EXIFPANEL_SUBDIRECTORY"))); - iter->set_value (exifColumns.value_nopango, Glib::ustring (M ("EXIFPANEL_SUBDIRECTORY"))); - iter->set_value (exifColumns.field, fseg); - iter->set_value (exifColumns.icon, keepicon); - iter->set_value (exifColumns.orig_value, Glib::ustring (M ("EXIFPANEL_SUBDIRECTORY"))); - } - } - - if (iter == root.end()) { - return; - } - - if (dp == Glib::ustring::npos) { - if (value == "#keep" && iter->get_value (exifColumns.action) != AC_SYSTEM) { - iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon); - } else if (value == "#delete" && iter->get_value (exifColumns.action) != AC_SYSTEM) { - iter->set_value (exifColumns.icon, delicon); - } else { - iter->set_value (exifColumns.value, Glib::ustring ("") + value + ""); - iter->set_value (exifColumns.value_nopango, value); - iter->set_value (exifColumns.edited, true); - iter->set_value (exifColumns.icon, editicon); - } - } else { - editTag (iter->children(), name.substr (dp + 1, Glib::ustring::npos), value); - } -} - -Glib::ustring ExifPanel::getSelectedValue () -{ - - Glib::RefPtr selection = exifTree->get_selection(); - std::vector rows = selection->get_selected_rows(); - - if (rows.size() != 1) { - return ""; - } - - Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]); - - if (iter) { - return iter->get_value (exifColumns.value_nopango); - } - - return ""; -} - -Glib::ustring ExifPanel::getSelection (bool onlyeditable) -{ - - Glib::RefPtr selection = exifTree->get_selection(); - std::vector rows = selection->get_selected_rows(); - - if (rows.size() != 1) { - return ""; - } - - Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]); - - Glib::ustring ret = ""; - bool first = true; - bool editable = false; - - while (iter) { - if (first) { - ret = iter->get_value (exifColumns.field_nopango); - editable = iter->get_value (exifColumns.editable); - } else { - ret = iter->get_value (exifColumns.field_nopango) + "." + ret; - } - - iter = iter->parent (); - first = false; - } - - if (!editable && onlyeditable) { - return ""; - } - - return ret; -} - -void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string prefix) -{ - - if (prefix != "") { - prefix = prefix + "."; - } - - Gtk::TreeModel::iterator iter; - - for (iter = root.begin(); iter != root.end(); ++iter) { - if (iter->get_value (exifColumns.edited)) { - (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = iter->get_value (exifColumns.value_nopango); - } else if (iter->get_value (exifColumns.action) == AC_WRITE && iter->get_value (exifColumns.icon) == delicon) { - (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#delete"; - } else if (iter->get_value (exifColumns.action) == AC_DONTWRITE && iter->get_value (exifColumns.icon) == keepicon) { - (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#keep"; - } - - if (iter->get_value (exifColumns.icon) == keepicon) { - updateChangeList (iter->children(), prefix + iter->get_value (exifColumns.field_nopango)); - } - } -} - -void ExifPanel::updateChangeList () -{ - - changeList->clear (); - updateChangeList (exifTreeModel->children(), ""); -} - -void ExifPanel::applyChangeList () -{ - - for (rtengine::procparams::ExifPairs::const_iterator i = changeList->begin(); i != changeList->end(); ++i) { - editTag (exifTreeModel->children(), i->first, i->second); - } -} - -void ExifPanel::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) -{ - - Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (path); - - if (iter) { - if (!iter->children().empty()) - if (exifTree->row_expanded (path)) { - exifTree->collapse_row (path); - } else { - exifTree->expand_row (path, false); - } else if (iter->get_value (exifColumns.editable)) { - addPressed (); - } - } -} - void ExifPanel::notifyListener () { - if (listener) { listener->panelChanged (EvExif, M ("HISTORY_CHANGED")); } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index c8597a287..97708ab7b 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -20,8 +20,8 @@ #define _EXIFPANEL_ #include - #include +#include #include "toolpanel.h" @@ -32,37 +32,29 @@ private: const rtengine::FramesMetaData* idata; const std::unique_ptr changeList; const std::unique_ptr defChangeList; - bool recursiveOp; class ExifColumns : public Gtk::TreeModelColumnRecord { public: Gtk::TreeModelColumn > icon; - Gtk::TreeModelColumn field; - Gtk::TreeModelColumn field_nopango; + Gtk::TreeModelColumn key; + Gtk::TreeModelColumn label; Gtk::TreeModelColumn value; Gtk::TreeModelColumn value_nopango; - Gtk::TreeModelColumn orig_value; - Gtk::TreeModelColumn action; Gtk::TreeModelColumn editable; Gtk::TreeModelColumn edited; - Gtk::TreeModelColumn isSeparator; ExifColumns() { - add (field); - add (value); - add (icon); - add (action); - add (edited); - add (field_nopango); - add (value_nopango); - add (editable); - add (orig_value); - add (isSeparator); + add(key); + add(label); + add(value); + add(icon); + add(edited); + add(value_nopango); + add(editable); } }; - Glib::RefPtr delicon; Glib::RefPtr keepicon; Glib::RefPtr editicon; @@ -71,32 +63,18 @@ private: Gtk::ScrolledWindow* scrolledWindow; Glib::RefPtr exifTreeModel; - Gtk::Button* remove; - Gtk::Button* keep; Gtk::Button* add; Gtk::Button* reset; Gtk::Button* resetAll; - Gtk::ToggleButton* showAll; - Gtk::TreeModel::Children addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, rtexif::ActionCode action, bool editable); - void editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value); - void updateChangeList (Gtk::TreeModel::Children root, std::string prefix); - void addDirectory (const rtexif::TagDirectory* dir, Gtk::TreeModel::Children root, bool checkForSeparator = false); - Gtk::TreeModel::Children addSeparator(); - Glib::ustring getSelection (bool onlyifeditable = false); - Glib::ustring getSelectedValue(); - void updateChangeList(); - void applyChangeList(); - void keepIt (Gtk::TreeModel::iterator iter); - void delIt (Gtk::TreeModel::iterator iter); - Gtk::TreeModel::iterator resetIt (Gtk::TreeModel::iterator iter); - void removePressed(); - void keepPressed(); + std::vector> editable_; + + Gtk::TreeModel::Children addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited); + void refreshTags(); + void resetIt (Gtk::TreeModel::iterator iter); void resetPressed(); void resetAllPressed(); void addPressed(); - void showAlltoggled(); - bool rowSeperatorFunc(const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter); public: ExifPanel (); @@ -109,7 +87,7 @@ public: void setImageData (const rtengine::FramesMetaData* id); void exifSelectionChanged(); - void row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); + // void row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); void notifyListener(); diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 7347927a0..9e534db2f 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -16,19 +16,66 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include #include "iptcpanel.h" #include "clipboard.h" #include "rtimage.h" +#include "../rtengine/imagedata.h" #include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; -IPTCPanel::IPTCPanel () : +namespace { + +const std::string CAPTION("Iptc.Application2.Caption"); +const std::string CAPTION_WRITER("Iptc.Application2.Writer"); +const std::string CATEGORY("Iptc.Application2.Category"); +const std::string CITY("Iptc.Application2.City"); +const std::string COPYRIGHT("Iptc.Application2.Copyright"); +const std::string COUNTRY("Iptc.Application2.CountryName"); +const std::string CREATOR("Iptc.Application2.Byline"); +const std::string CREATOR_JOB_TITLE("Iptc.Application2.BylineTitle"); +const std::string CREDIT("Iptc.Application2.Credit"); +const std::string DATE_CREATED("Iptc.Application2.DateCreated"); +const std::string HEADLINE("Iptc.Application2.Headline"); +const std::string INSTRUCTIONS("Iptc.Application2.SpecialInstructions"); +const std::string KEYWORDS("Iptc.Application2.Keywords"); +const std::string PROVINCE("Iptc.Application2.ProvinceState"); +const std::string SOURCE("Iptc.Application2.Source"); +const std::string SUPPLEMENTAL_CATEGORIES("Iptc.Application2.SuppCategory"); +const std::string TITLE("Iptc.Application2.ObjectName"); +const std::string TRANS_REFERENCE("Iptc.Application2.TransmissionReference"); + +const std::set iptc_keys = { + CAPTION, + CAPTION_WRITER, + CATEGORY, + CITY, + COPYRIGHT, + COUNTRY, + CREATOR, + CREATOR_JOB_TITLE, + CREDIT, + DATE_CREATED, + HEADLINE, + INSTRUCTIONS, + KEYWORDS, + PROVINCE, + SOURCE, + SUPPLEMENTAL_CATEGORIES, + TITLE, + TRANS_REFERENCE +}; + +} // namespace + + +IPTCPanel::IPTCPanel(): changeList(new rtengine::procparams::IPTCPairs), defChangeList(new rtengine::procparams::IPTCPairs), - embeddedData(new rtengine::procparams::IPTCPairs) + embeddedData(new rtengine::procparams::IPTCPairs) { set_spacing (4); @@ -441,11 +488,20 @@ void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pe void IPTCPanel::setImageData (const FramesMetaData* id) { - + embeddedData->clear(); if (id) { - *embeddedData = id->getIPTCData (); - } else { - embeddedData->clear (); + try { + auto img = open_exiv2(id->getFileName()); + img->readMetadata(); + auto &iptc = img->iptcData(); + for (auto &tag : iptc) { + if (iptc_keys.find(tag.key()) != iptc_keys.end()) { + (*embeddedData)[tag.key()].push_back(tag.toString()); + } + } + } catch (Exiv2::AnyError &exc) { + embeddedData->clear(); + } } file->set_sensitive (!embeddedData->empty()); @@ -570,32 +626,32 @@ void IPTCPanel::updateChangeList () { changeList->clear (); - (*changeList)["Caption" ].push_back (captionText->get_text ()); - (*changeList)["CaptionWriter" ].push_back (captionWriter->get_text ()); - (*changeList)["Headline" ].push_back (headline->get_text ()); - (*changeList)["Instructions" ].push_back (instructions->get_text ()); + (*changeList)[CAPTION].push_back (captionText->get_text ()); + (*changeList)[CAPTION_WRITER].push_back (captionWriter->get_text ()); + (*changeList)[HEADLINE].push_back (headline->get_text ()); + (*changeList)[INSTRUCTIONS].push_back (instructions->get_text ()); for (unsigned int i = 0; i < keywords->size(); i++) { - (*changeList)["Keywords" ].push_back (keywords->get_text (i)); + (*changeList)[KEYWORDS].push_back (keywords->get_text (i)); } - (*changeList)["Category" ].push_back (category->get_entry()->get_text ()); + (*changeList)[CATEGORY].push_back (category->get_entry()->get_text ()); for (unsigned int i = 0; i < suppCategories->size(); i++) { - (*changeList)["SupplementalCategories"].push_back (suppCategories->get_text (i)); + (*changeList)[SUPPLEMENTAL_CATEGORIES].push_back (suppCategories->get_text (i)); } - (*changeList)["Creator" ].push_back (creator->get_text ()); - (*changeList)["CreatorJobTitle"].push_back (creatorJobTitle->get_text ()); - (*changeList)["Credit" ].push_back (credit->get_text ()); - (*changeList)["Source" ].push_back (source->get_text ()); - (*changeList)["Copyright" ].push_back (copyright->get_text ()); - (*changeList)["City" ].push_back (city->get_text ()); - (*changeList)["Province" ].push_back (province->get_text ()); - (*changeList)["Country" ].push_back (country->get_text ()); - (*changeList)["Title" ].push_back (title->get_text ()); - (*changeList)["DateCreated" ].push_back (dateCreated->get_text ()); - (*changeList)["TransReference" ].push_back (transReference->get_text ()); + (*changeList)[CREATOR].push_back (creator->get_text ()); + (*changeList)[CREATOR_JOB_TITLE].push_back (creatorJobTitle->get_text ()); + (*changeList)[CREDIT].push_back (credit->get_text ()); + (*changeList)[SOURCE].push_back (source->get_text ()); + (*changeList)[COPYRIGHT].push_back (copyright->get_text ()); + (*changeList)[CITY].push_back (city->get_text ()); + (*changeList)[PROVINCE].push_back (province->get_text ()); + (*changeList)[COUNTRY].push_back (country->get_text ()); + (*changeList)[TITLE].push_back (title->get_text ()); + (*changeList)[DATE_CREATED].push_back (dateCreated->get_text ()); + (*changeList)[TRANS_REFERENCE].push_back (transReference->get_text ()); notifyListener (); } @@ -629,45 +685,45 @@ void IPTCPanel::applyChangeList () suppCategory->get_entry()->set_text (""); for (rtengine::procparams::IPTCPairs::const_iterator i = changeList->begin(); i != changeList->end(); ++i) { - if (i->first == "Caption" && !i->second.empty()) { + if (i->first == CAPTION && !i->second.empty()) { captionText->set_text (i->second.at(0)); - } else if (i->first == "CaptionWriter" && !i->second.empty()) { + } else if (i->first == CAPTION_WRITER && !i->second.empty()) { captionWriter->set_text (i->second.at(0)); - } else if (i->first == "Headline" && !i->second.empty()) { + } else if (i->first == HEADLINE && !i->second.empty()) { headline->set_text (i->second.at(0)); - } else if (i->first == "Instructions" && !i->second.empty()) { + } else if (i->first == INSTRUCTIONS && !i->second.empty()) { instructions->set_text (i->second.at(0)); - } else if (i->first == "Keywords") + } else if (i->first == KEYWORDS) for (unsigned int j = 0; j < i->second.size(); j++) { keywords->append (i->second.at(j)); } - else if (i->first == "Category" && !i->second.empty()) { + else if (i->first == CATEGORY && !i->second.empty()) { category->get_entry()->set_text (i->second.at(0)); - } else if (i->first == "SupplementalCategories") + } else if (i->first == SUPPLEMENTAL_CATEGORIES) for (unsigned int j = 0; j < i->second.size(); j++) { suppCategories->append (i->second.at(j)); } - else if (i->first == "Creator" && !i->second.empty()) { + else if (i->first == CREATOR && !i->second.empty()) { creator->set_text (i->second.at(0)); - } else if (i->first == "CreatorJobTitle" && !i->second.empty()) { + } else if (i->first == CREATOR_JOB_TITLE && !i->second.empty()) { creatorJobTitle->set_text (i->second.at(0)); - } else if (i->first == "Credit" && !i->second.empty()) { + } else if (i->first == CREDIT && !i->second.empty()) { credit->set_text (i->second.at(0)); - } else if (i->first == "Source" && !i->second.empty()) { + } else if (i->first == SOURCE && !i->second.empty()) { source->set_text (i->second.at(0)); - } else if (i->first == "Copyright" && !i->second.empty()) { + } else if (i->first == COPYRIGHT && !i->second.empty()) { copyright->set_text (i->second.at(0)); - } else if (i->first == "City" && !i->second.empty()) { + } else if (i->first == CITY && !i->second.empty()) { city->set_text (i->second.at(0)); - } else if (i->first == "Province" && !i->second.empty()) { + } else if (i->first == PROVINCE && !i->second.empty()) { province->set_text (i->second.at(0)); - } else if (i->first == "Country" && !i->second.empty()) { + } else if (i->first == COUNTRY && !i->second.empty()) { country->set_text (i->second.at(0)); - } else if (i->first == "Title" && !i->second.empty()) { + } else if (i->first == TITLE && !i->second.empty()) { title->set_text (i->second.at(0)); - } else if (i->first == "DateCreated" && !i->second.empty()) { + } else if (i->first == DATE_CREATED && !i->second.empty()) { dateCreated->set_text (i->second.at(0)); - } else if (i->first == "TransReference" && !i->second.empty()) { + } else if (i->first == TRANS_REFERENCE && !i->second.empty()) { transReference->set_text (i->second.at(0)); } } diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 106715a17..decbfb2f5 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include #include "resize.h" #include "eventmapper.h" diff --git a/rtgui/shcselector.cc b/rtgui/shcselector.cc index d55ce30fd..fe436b5ca 100644 --- a/rtgui/shcselector.cc +++ b/rtgui/shcselector.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ +#include #include "shcselector.h" #include "multilangmgr.h" #include "mycurve.h" diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 757708002..17667ea1a 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -34,6 +34,8 @@ #include "extprog.h" #include "profilestorecombobox.h" #include "procparamchangers.h" +#include "ppversion.h" +#include "version.h" using namespace rtengine::procparams; @@ -153,24 +155,23 @@ void Thumbnail::_generateThumbnailImage () // image out of the RAW. Mark as "quick". // 2. if we don't find that then just grab the real image. bool quick = false; - rtengine::RawMetaDataLocation ri; rtengine::eSensorType sensorType = rtengine::ST_NONE; if ( initial_ && options.internalThumbIfUntouched) { quick = true; - tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, tw, th, 1, TRUE); + tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, sensorType, tw, th, 1, TRUE); } if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, sensorType, tw, th, 1, pparams->wb.equal, TRUE); } cfs.sensortype = sensorType; if (tpp) { cfs.format = FT_Raw; cfs.thumbImgType = quick ? CacheImageData::QUICK_THUMBNAIL : CacheImageData::FULL_THUMBNAIL; - infoFromImage (fname, std::unique_ptr(new rtengine::RawMetaDataLocation(ri))); + infoFromImage (fname); } } @@ -218,6 +219,67 @@ const ProcParams& Thumbnail::getProcParamsU () return *pparams; // there is no valid pp to return, but we have to return something } + +namespace { + +bool CPBDump(const Glib::ustring &commFName, const Glib::ustring &imageFName, + const Glib::ustring &profileFName, const Glib::ustring &defaultPParams, + const CacheImageData* cfs, const bool flagMode) +{ + const auto kf = new Glib::KeyFile; + + if (!kf) { + return false; + } + + FILE *f = nullptr; + + // open the file in write mode + f = g_fopen (commFName.c_str (), "wt"); + + if (f == nullptr) { + printf ("CPBDump(\"%s\") >>> Error: unable to open file with write access!\n", commFName.c_str()); + delete kf; + return false; + } + + try { + + kf->set_string ("RT General", "CachePath", options.cacheBaseDir); + kf->set_string ("RT General", "AppVersion", RTVERSION); + kf->set_integer ("RT General", "ProcParamsVersion", PPVERSION); + kf->set_string ("RT General", "ImageFileName", imageFName); + kf->set_string ("RT General", "OutputProfileFileName", profileFName); + kf->set_string ("RT General", "DefaultProcParams", defaultPParams); + kf->set_boolean ("RT General", "FlaggingMode", flagMode); + + kf->set_integer ("Common Data", "FrameCount", cfs->frameCount); + kf->set_integer ("Common Data", "SampleFormat", cfs->sampleFormat); + kf->set_boolean ("Common Data", "IsHDR", cfs->isHDR); + kf->set_boolean ("Common Data", "IsPixelShift", cfs->isPixelShift); + kf->set_double ("Common Data", "FNumber", cfs->fnumber); + kf->set_double ("Common Data", "Shutter", cfs->shutter); + kf->set_double ("Common Data", "FocalLength", cfs->focalLen); + kf->set_integer ("Common Data", "ISO", cfs->iso); + kf->set_string ("Common Data", "Lens", cfs->lens); + kf->set_string ("Common Data", "Make", cfs->camMake); + kf->set_string ("Common Data", "Model", cfs->camModel); + + } catch (Glib::KeyFileError&) {} + + try { + fprintf (f, "%s", kf->to_data().c_str()); + } catch (Glib::KeyFileError&) {} + + fclose (f); + delete kf; + + return true; +} + + +} // namespace + /** @brief Create default params on demand and returns a new updatable object * * The loaded profile may be partial, but it return a complete ProcParams (i.e. without ParamsEdited) @@ -242,7 +304,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu const CacheImageData* cfs = getCacheImageData(); Glib::ustring defaultPparamsPath = options.findProfilePath(defProf); const bool create = (!hasProcParams() || force); - const bool run_cpb = !options.CPBPath.empty() && !defaultPparamsPath.empty() && cfs && cfs->exifValid && create; + const bool run_cpb = false; //!options.CPBPath.empty() && !defaultPparamsPath.empty() && cfs && cfs->exifValid && create; const Glib::ustring outFName = (options.paramsLoadLocation == PLL_Input && options.saveParamsFile) ? @@ -251,16 +313,8 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu if (!run_cpb) { if (defProf == DEFPROFILE_DYNAMIC && create && cfs && cfs->exifValid) { - rtengine::FramesMetaData* imageMetaData; - if (getType() == FT_Raw) { - // Should we ask all frame's MetaData ? - imageMetaData = rtengine::FramesMetaData::fromFile (fname, std::unique_ptr(new rtengine::RawMetaDataLocation(rtengine::Thumbnail::loadMetaDataFromRaw(fname))), true); - } else { - // Should we ask all frame's MetaData ? - imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true); - } - PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData); - delete imageMetaData; + std::unique_ptr imageMetaData(rtengine::FramesMetaData::fromFile(fname)); + PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData.get()); int err = pp->pparams->save(outFName); pp->deleteInstance(); delete pp; @@ -275,28 +329,11 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu } } else { // First generate the communication file, with general values and EXIF metadata - rtengine::FramesMetaData* imageMetaData; - - if (getType() == FT_Raw) { - // Should we ask all frame's MetaData ? - imageMetaData = rtengine::FramesMetaData::fromFile (fname, std::unique_ptr(new rtengine::RawMetaDataLocation(rtengine::Thumbnail::loadMetaDataFromRaw(fname))), true); - } else { - // Should we ask all frame's MetaData ? - imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true); - } - Glib::ustring tmpFileName( Glib::build_filename(options.cacheBaseDir, Glib::ustring::compose("CPB_temp_%1.txt", index++)) ); - const rtexif::TagDirectory* exifDir = nullptr; - - if (imageMetaData && (exifDir = imageMetaData->getRootExifData())) { - exifDir->CPBDump(tmpFileName, fname, outFName, - defaultPparamsPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(defaultPparamsPath, Glib::path_get_basename(defProf) + paramFileExtension), - cfs, - flaggingMode); - } - delete imageMetaData; - + CPBDump(tmpFileName, fname, outFName, + defaultPparamsPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(defaultPparamsPath, Glib::path_get_basename(defProf) + paramFileExtension), cfs, flaggingMode); + // For the filename etc. do NOT use streams, since they are not UTF8 safe Glib::ustring cmdLine = options.CPBPath + Glib::ustring(" \"") + tmpFileName + Glib::ustring("\""); @@ -778,9 +815,9 @@ ThFileType Thumbnail::getType () return (ThFileType) cfs.format; } -int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptr rml) +int Thumbnail::infoFromImage (const Glib::ustring& fname) { - rtengine::FramesMetaData* idata = rtengine::FramesMetaData::fromFile (fname, std::move(rml)); + rtengine::FramesMetaData* idata = rtengine::FramesMetaData::fromFile (fname); if (!idata) { return 0; diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 0bcdd470a..33bccbf81 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -73,7 +73,7 @@ class Thumbnail void _loadThumbnail (bool firstTrial = true); void _saveThumbnail (); void _generateThumbnailImage (); - int infoFromImage (const Glib::ustring& fname, std::unique_ptr rml = nullptr); + int infoFromImage (const Glib::ustring& fname); void loadThumbnail (bool firstTrial = true); void generateExifDateTimeStrings (); diff --git a/tools/generateRtexifUpdates b/tools/generateRtexifUpdates deleted file mode 100755 index 72a97862e..000000000 --- a/tools/generateRtexifUpdates +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env bash - -# This Bash4 script generates lens ID and other parameter lists for rtexif/*.cc -# using ExifTool. It uses xmlstarlet to parse ExifTool's output. -# -# Run the script from the project root: -# ./tools/generateRtexifUpdates -# -# Manually replace old code in rtexif/* with new from /tmp/rt-generateRtexifUpdates/* -# -# Blame DrSlony -# Please report bugs or enhancements to https://github.com/Beep6581/RawTherapee - -et="$HOME/programs/code-exiftool/exiftool" - -hash "$et" 2>/dev/null || { echo >&2 "ExifTool not found, install it first."; exit 1; } -hash xmlstarlet 2>/dev/null || { echo >&2 "XMLStarlet not found, install it first."; exit 1; } - -unset cam cams - -tmpdir="/tmp/rt-generateRtexifUpdates" - -printf '%s\n' "ExifTool version: $("$et" -ver)" "" "XMLStarlet version: $(xmlstarlet --version)" | sed 's/^/# /' - -if [[ -d ${tmpdir} ]]; then - printf '%s\n' "" "Must remove temp folder from previous run: $tmpdir" - rm -rvI "$tmpdir" || exit 1 -fi -mkdir -p "$tmpdir" || { printf '%s\n' "Error creating $tmpdir" ""; exit 1; } -echo - -#------------------------------------------------------------------------------ -# Canon -printf '%s\n' "Saving ${tmpdir}/canon_lenses" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='LensType']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -canon:all) | sort -fuV > "${tmpdir}/canon_lenses" - -#In :10.1 Sigma 50mm f/2.8 EX -#Out: {10, "Sigma 50mm f/2.8 EX"}, -# delete lines matching '-1n/a' -# replace '10.1Sigma' with '10, "Sigma' -# prepend whitespace -# append closing braces -# replace ' F/11' with ' f/11' -sed -r -i \ - -e '/-1\tn\/a/d' \ - -e 's/([0-9]+)[0-9.]*\t/\1, "/' \ - -e 's/^/ {/' \ - -e 's/$/"},/' \ - -e 's| F/([0-9]+)| f/\1|' \ - "${tmpdir}/canon_lenses" - -#In :16842752 PowerShot A30 -#Out: choices[16842752] = "PowerShot A30"; -# prepend whitespace and 'choices[' -# replace with '] = "' -# append '";' -printf '%s\n' "Saving ${tmpdir}/canon_cameras" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='CanonModelID']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -canon:all) | sort -fuV > "${tmpdir}/canon_cameras" -sed -r -i \ - -e 's/^/ choices[/' \ - -e 's/\t/] = "/' \ - -e 's/$/";/' \ - "${tmpdir}/canon_cameras" - -#------------------------------------------------------------------------------ -# Nikon LensIDs are composite tags -printf '%s\n' "Saving ${tmpdir}/nikon" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='LensID']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -composite:all) > "${tmpdir}/nikon" -sed -r -i -e '/^... /d' -e 's/^/ {"/' -e 's/([A-F0-9]+)[A-F0-9.]*\t/\1", "/' -e 's/$/"},/' -e 's|(.* ")(.*) F([0-9]+)|\1\2 f/\3|' -e 's| F/([0-9]+)| f/\1|' "${tmpdir}/nikon" - -#------------------------------------------------------------------------------ -# Olympus -printf '%s\n' "Saving ${tmpdir}/olympus" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='LensType']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -olympus:all) | sort -fuV > "${tmpdir}/olympus" -sed -r -i -e '/0 00 00\tNone/d' -e 's/^/ lenses["0/' -e 's/\t/"] = "/' -e 's/$/";/' -e 's| F([0-9]+)| f/\1|g' "${tmpdir}/olympus" - -#------------------------------------------------------------------------------ -# Pentax -printf '%s\n' "Saving ${tmpdir}/pentax" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='LensType']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -pentax:all) | sort -fuV > "${tmpdir}/pentax" -sed -r -i -e 's/^/ choices.insert (p_t (256 * /' -e 's/([0-9]+) ([0-9]+)([0-9.]*)/\1 + \2/' -e 's/\t/, "/' -e 's/$/"));/' -e 's| F([0-9]+)| f/\1|' "${tmpdir}/pentax" - -#------------------------------------------------------------------------------ -# Sony -printf '%s\n' "Saving ${tmpdir}/sony" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='LensType']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -sony:all) | sort -fuV > "${tmpdir}/sony" -# Sony has more lenses under the LensType2 tag -printf '%s\n' "Saving ${tmpdir}/sony-lenstype2" -xmlstarlet sel -T -t -m "taginfo/table/tag[@name='LensType2']/values/key" -v "concat(@id,' ',val)" -n < <("$et" -listx -sony:all) | sort -fuV > "${tmpdir}/sony-lenstype2" -sed -r -i -e 's/^/ {/' -e 's/([0-9]+)[0-9.]*\t/\1, "/' -e 's/$/"},/' -e 's| F([0-9]+)| f/\1|g' "${tmpdir}/sony" -sed -r -i -e '/255\tTamron Lens (255)/d' -e 's/([0-9]+)[0-9.]*\t/\1, "/' -e 's/^/ choices.insert (p_t (/' -e 's/$/"));/' -e 's| F([0-9]+)| f/\1|g' "${tmpdir}/sony-lenstype2" - From ba4de904cc5d6a719f7ca3544049b0b15850741a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Fri, 10 May 2019 21:24:22 +0200 Subject: [PATCH 002/110] Cleanups and a few fixes --- rtengine/dcp.cc | 158 ++++++++++++++-------------- rtengine/histmatching.cc | 4 +- rtengine/imagedata.cc | 190 ++++++++++++++++++---------------- rtengine/imagedata.h | 20 ++-- rtengine/imageio.cc | 88 ++++++++++------ rtengine/imageio.h | 47 +++++---- rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 1 - rtengine/improcfun.cc | 1 + rtengine/procparams.cc | 16 +-- rtengine/procparams.h | 100 +++++++++++++++++- rtengine/rawimagesource.cc | 14 +-- rtengine/rtengine.h | 7 +- rtengine/rtthumbnail.cc | 32 +++--- rtengine/simpleprocess.cc | 20 ++-- rtgui/cacheimagedata.h | 1 - rtgui/exifpanel.cc | 87 +++++++++------- rtgui/exifpanel.h | 18 +++- rtgui/iptcpanel.cc | 13 +-- rtgui/resize.cc | 1 + rtgui/shcselector.cc | 2 + rtgui/thumbnail.cc | 174 ++++++++++++++++--------------- 22 files changed, 582 insertions(+), 414 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 0f5b32d34..c6c38077a 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -40,7 +40,8 @@ extern const Settings* settings; using namespace rtengine; -namespace { +namespace +{ // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here @@ -442,8 +443,8 @@ std::map getAliases(const Glib::ustring& profile_dir) return res; } - class DCPMetadata { + // TODO: Review enum TagType { INVALID = 0, BYTE = 1, @@ -465,10 +466,10 @@ class DCPMetadata { INTEL = 0x4949, MOTOROLA = 0x4D4D }; - + public: explicit DCPMetadata(FILE *file): order_(UNKNOWN), file_(file) {} - + bool parse() { int offset = 0; @@ -487,7 +488,7 @@ public: unsigned short bo; fread(&bo, 1, 2, f); order_ = ByteOrder(int(bo)); - + get2(f, order_); if (!offset) { offset = get4(f, order_); @@ -513,12 +514,12 @@ public: return true; } - + bool find(int id) const { return tags_.find(id) != tags_.end(); } - + std::string toString(int id) { auto it = tags_.find(id); @@ -578,12 +579,12 @@ public: return 0; } } - + int toShort(int id, int ofs=0) { return toInt(id, ofs, SHORT); } - + double toDouble(int id, int ofs=0) { auto it = tags_.find(id); @@ -592,7 +593,7 @@ public: } auto &t = it->second; - + union IntFloat { uint32_t i; float f; @@ -651,7 +652,7 @@ private: return s[0] << 8 | s[1]; } } - + static int sget4(unsigned char *s, ByteOrder order) { if (order == INTEL) { @@ -660,21 +661,21 @@ private: return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } } - + static unsigned short get2(FILE* f, ByteOrder order) - { + { unsigned char str[2] = { 0xff, 0xff }; fread (str, 1, 2, f); return sget2(str, order); } - + static int get4(FILE *f, ByteOrder order) - { + { unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff }; fread (str, 1, 4, f); return sget4 (str, order); } - + static short int int2_to_signed(short unsigned int i) { union { @@ -744,7 +745,6 @@ private: } // namespace - struct DCPProfile::ApplyState::Data { float pro_photo[3][3]; float work[3][3]; @@ -778,22 +778,22 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : constexpr int tiff_float_size = 4; enum TagKey { - COLOR_MATRIX_1 = 50721, - COLOR_MATRIX_2 = 50722, - PROFILE_HUE_SAT_MAP_DIMS = 50937, - PROFILE_HUE_SAT_MAP_DATA_1 = 50938, - PROFILE_HUE_SAT_MAP_DATA_2 = 50939, - PROFILE_TONE_CURVE = 50940, - PROFILE_TONE_COPYRIGHT = 50942, - CALIBRATION_ILLUMINANT_1 = 50778, - CALIBRATION_ILLUMINANT_2 = 50779, - FORWARD_MATRIX_1 = 50964, - FORWARD_MATRIX_2 = 50965, - PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant - PROFILE_LOOK_TABLE_DATA = 50982, - PROFILE_HUE_SAT_MAP_ENCODING = 51107, - PROFILE_LOOK_TABLE_ENCODING = 51108, - BASELINE_EXPOSURE_OFFSET = 51109 + TAG_KEY_COLOR_MATRIX_1 = 50721, + TAG_KEY_COLOR_MATRIX_2 = 50722, + TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS = 50937, + TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1 = 50938, + TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2 = 50939, + TAG_KEY_PROFILE_TONE_CURVE = 50940, + TAG_KEY_PROFILE_TONE_COPYRIGHT = 50942, + TAG_KEY_CALIBRATION_ILLUMINANT_1 = 50778, + TAG_KEY_CALIBRATION_ILLUMINANT_2 = 50779, + TAG_KEY_FORWARD_MATRIX_1 = 50964, + TAG_KEY_FORWARD_MATRIX_2 = 50965, + TAG_KEY_PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant + TAG_KEY_PROFILE_LOOK_TABLE_DATA = 50982, + TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING = 51107, + TAG_KEY_PROFILE_LOOK_TABLE_ENCODING = 51108, + TAG_KEY_BASELINE_EXPOSURE_OFFSET = 51109 }; static const float adobe_camera_raw_default_curve[] = { @@ -1065,46 +1065,46 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : DCPMetadata md(file); if (!md.parse()) { - printf ("Unable to load DCP profile '%s' !", filename.c_str()); + printf ("Unable to load DCP profile '%s'.", filename.c_str()); return; } light_source_1 = - md.find(CALIBRATION_ILLUMINANT_1) ? - md.toShort(CALIBRATION_ILLUMINANT_1) : - -1; + md.find(TAG_KEY_CALIBRATION_ILLUMINANT_1) + ? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_1) + : -1; light_source_2 = - md.find(CALIBRATION_ILLUMINANT_2) ? - md.toShort(CALIBRATION_ILLUMINANT_2) : - -1; + md.find(TAG_KEY_CALIBRATION_ILLUMINANT_2) + ? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_2) + : -1; temperature_1 = calibrationIlluminantToTemperature(light_source_1); temperature_2 = calibrationIlluminantToTemperature(light_source_2); - const bool has_second_hue_sat = md.find(PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat + const bool has_second_hue_sat = md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat // Fetch Forward Matrices, if any - has_forward_matrix_1 = md.find(FORWARD_MATRIX_1); + has_forward_matrix_1 = md.find(TAG_KEY_FORWARD_MATRIX_1); if (has_forward_matrix_1) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_1[row][col] = md.toDouble(FORWARD_MATRIX_1, (col + row * 3) * 8); + forward_matrix_1[row][col] = md.toDouble(TAG_KEY_FORWARD_MATRIX_1, (col + row * 3) * 8); } } } - has_forward_matrix_2 = md.find(FORWARD_MATRIX_2); + has_forward_matrix_2 = md.find(TAG_KEY_FORWARD_MATRIX_2); if (has_forward_matrix_2) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_2[row][col] = md.toDouble(FORWARD_MATRIX_2, (col + row * 3) * 8); + forward_matrix_2[row][col] = md.toDouble(TAG_KEY_FORWARD_MATRIX_2, (col + row * 3) * 8); } } } // Color Matrix (one is always there) - if (!md.find(COLOR_MATRIX_1)) { + if (!md.find(TAG_KEY_COLOR_MATRIX_1)) { std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; fclose(file); return; @@ -1114,24 +1114,24 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - color_matrix_1[row][col] = md.toDouble(COLOR_MATRIX_1, (col + row * 3) * 8); + color_matrix_1[row][col] = md.toDouble(TAG_KEY_COLOR_MATRIX_1, (col + row * 3) * 8); } } - if (md.find(PROFILE_LOOK_TABLE_DIMS)) { - look_info.hue_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 0); - look_info.sat_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 4); - look_info.val_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 8); + if (md.find(TAG_KEY_PROFILE_LOOK_TABLE_DIMS)) { + look_info.hue_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 0); + look_info.sat_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 4); + look_info.val_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 8); - look_info.srgb_gamma = md.find(PROFILE_LOOK_TABLE_ENCODING) && md.toInt(PROFILE_LOOK_TABLE_ENCODING); + look_info.srgb_gamma = md.find(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING) && md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING); - look_info.array_count = md.getCount(PROFILE_LOOK_TABLE_DATA) / 3; + look_info.array_count = md.getCount(TAG_KEY_PROFILE_LOOK_TABLE_DATA) / 3; look_table.resize(look_info.array_count); for (unsigned int i = 0; i < look_info.array_count; i++) { - look_table[i].hue_shift = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); - look_table[i].sat_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); - look_table[i].val_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); + look_table[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); + look_table[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); + look_table[i].val_scale = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); } // Precalculated constants for table application @@ -1148,20 +1148,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step; } - if (md.find(PROFILE_HUE_SAT_MAP_DIMS)) { - delta_info.hue_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 0); - delta_info.sat_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 4); - delta_info.val_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 8); + if (md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS)) { + delta_info.hue_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 0); + delta_info.sat_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 4); + delta_info.val_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 8); - delta_info.srgb_gamma = md.find(PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(PROFILE_HUE_SAT_MAP_ENCODING); + delta_info.srgb_gamma = md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING); - delta_info.array_count = md.getCount(PROFILE_HUE_SAT_MAP_DATA_1) / 3; + delta_info.array_count = md.getCount(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1) / 3; deltas_1.resize(delta_info.array_count); for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_1[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); - deltas_1[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); - deltas_1[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); + deltas_1[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); + deltas_1[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); + deltas_1[i].val_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); } delta_info.pc.h_scale = @@ -1181,14 +1181,14 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Second matrix has_color_matrix_2 = true; - bool cm2 = md.find(COLOR_MATRIX_2); + const bool cm2 = md.find(TAG_KEY_COLOR_MATRIX_2); for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { color_matrix_2[row][col] = cm2 - ? md.toDouble(COLOR_MATRIX_2, (col + row * 3) * 8) - : color_matrix_1[row][col]; + ? md.toDouble(TAG_KEY_COLOR_MATRIX_2, (col + row * 3) * 8) + : color_matrix_1[row][col]; } } @@ -1198,20 +1198,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Saturation maps. Need to be unwinded. for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_2[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); - deltas_2[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); - deltas_2[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); + deltas_2[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); + deltas_2[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); + deltas_2[i].val_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); } } } - has_baseline_exposure_offset = md.find(BASELINE_EXPOSURE_OFFSET); + has_baseline_exposure_offset = md.find(TAG_KEY_BASELINE_EXPOSURE_OFFSET); if (has_baseline_exposure_offset) { - baseline_exposure_offset = md.toDouble(BASELINE_EXPOSURE_OFFSET); + baseline_exposure_offset = md.toDouble(TAG_KEY_BASELINE_EXPOSURE_OFFSET); } // Read tone curve points, if any, but disable to RTs own profiles - if (md.find(PROFILE_TONE_CURVE)) { + if (md.find(TAG_KEY_PROFILE_TONE_CURVE)) { std::vector curve_points = { static_cast(DCT_Spline) // The first value is the curve type }; @@ -1219,9 +1219,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Push back each X/Y coordinates in a loop bool curve_is_linear = true; - for (unsigned int i = 0, n = md.getCount(PROFILE_TONE_CURVE); i < n; i += 2) { - const double x = md.toDouble(PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); - const double y = md.toDouble(PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); + for (unsigned int i = 0, n = md.getCount(TAG_KEY_PROFILE_TONE_CURVE); i < n; i += 2) { + const double x = md.toDouble(TAG_KEY_PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); + const double y = md.toDouble(TAG_KEY_PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); if (x != y) { curve_is_linear = false; @@ -1237,7 +1237,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tone_curve.Set(DiagonalCurve(curve_points, CURVES_MIN_POLY_POINTS)); } } else { - if (md.find(PROFILE_TONE_COPYRIGHT) && md.toString(PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { + if (md.find(TAG_KEY_PROFILE_TONE_COPYRIGHT) && md.toString(TAG_KEY_PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { // An Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that std::vector curve_points = { static_cast(DCT_Spline) @@ -2076,7 +2076,7 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) std::deque dirs = { rt_profile_dir, - Glib::build_filename(options.rtdir, "dcpprofiles") + Glib::build_filename(options.rtdir, "dcpprofiles") }; while (!dirs.empty()) { diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 5a17ab6ec..322775ca4 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -280,7 +280,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st { eSensorType sensor_type; int w, h; - std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), sensor_type, w, h, 1, false, true, true)); + const std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), sensor_type, w, h, 1, false, true, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: no thumbnail found, generating a neutral curve" << std::endl; @@ -312,7 +312,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st eSensorType sensor_type; double scale; int w = fw / skip, h = fh / skip; - std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), sensor_type, w, h, 1, false, false, true)); + const std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), sensor_type, w, h, 1, false, false, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index e0f6b50a3..1890739b8 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -17,43 +17,32 @@ * along with RawTherapee. If not, see . */ #include + #include -#include #include + +#include + #include #include "imagedata.h" #include "imagesource.h" #include "rt_math.h" + #pragma GCC diagnostic warning "-Wextra" #define PRINT_HDR_PS_DETECTION 0 using namespace rtengine; - -// namespace { - -// Glib::ustring to_utf8 (const std::string& str) -// { -// try { -// return Glib::locale_to_utf8 (str); -// } catch (Glib::Error&) { -// return Glib::convert_with_fallback (str, "UTF-8", "ISO-8859-1", "?"); -// } -// } - -// } // namespace - - namespace rtengine { extern const Settings *settings; -Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname) +Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) { #ifdef EXV_UNICODE_PATH - auto *ws = g_utf8_to_utf16(fname.c_str(), -1, NULL, NULL, NULL); - std::wstring wfname(ws); + const auto* const ws = g_utf8_to_utf16(fname.c_str(), -1, NULL, NULL, NULL); + const std::wstring wfname(ws); g_free(ws); auto image = Exiv2::ImageFactory::open(wfname); #else @@ -65,13 +54,12 @@ Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname) } // namespace rtengine - FramesMetaData* FramesMetaData::fromFile (const Glib::ustring& fname) { return new FramesData(fname); } -FramesData::FramesData(const Glib::ustring &fname): +FramesData::FramesData(const Glib::ustring &fname) : ok_(false), fname_(fname), dcrawFrameCount(0), @@ -110,7 +98,7 @@ FramesData::FramesData(const Glib::ustring &fname): try { auto image = open_exiv2(fname); image->readMetadata(); - auto &exif = image->exifData(); + const auto& exif = image->exifData(); ok_ = true; // taken and adapted from darktable (src/common/exif.cc) @@ -133,66 +121,72 @@ FramesData::FramesData(const Glib::ustring &fname): You should have received a copy of the GNU General Public License along with darktable. If not, see . */ - + Exiv2::ExifData::const_iterator pos; - + const auto find_exif_tag = - [&](const std::string &name) -> bool + [&exif, &pos](const std::string &name) -> bool { pos = exif.findKey(Exiv2::ExifKey(name)); - return (pos != exif.end() && pos->size()); + return pos != exif.end() && pos->size(); }; const auto find_tag = - [&](decltype(Exiv2::make) func) -> bool + [&exif, &pos](decltype(Exiv2::make) func) -> bool { pos = func(exif); return pos != exif.end() && pos->size(); }; - /* List of tag names taken from exiv2's printSummary() in actions.cpp */ + // List of tag names taken from exiv2's printSummary() in actions.cpp if (find_tag(Exiv2::make)) { make = pos->print(&exif); } - + if (find_tag(Exiv2::model)) { model = pos->print(&exif); } if (make.size() > 0) { for (const auto& corp : { - "Canon", - "NIKON", - "EPSON", - "KODAK", - "Kodak", - "OLYMPUS", - "PENTAX", - "RICOH", - "MINOLTA", - "Minolta", - "Konica", - "CASIO", - "Sinar", - "Phase One", - "SAMSUNG", - "Mamiya", - "MOTOROLA", - "Leaf", - "Panasonic" - }) { + "Canon", + "NIKON", + "EPSON", + "KODAK", + "Kodak", + "OLYMPUS", + "PENTAX", + "RICOH", + "MINOLTA", + "Minolta", + "Konica", + "CASIO", + "Sinar", + "Phase One", + "SAMSUNG", + "Mamiya", + "MOTOROLA", + "Leaf", + "Panasonic" + }) { if (make.find(corp) != std::string::npos) { // Simplify company names make = corp; break; } } - } - make.erase(make.find_last_not_of(' ') + 1); - model.erase(model.find_last_not_of(' ') + 1); + } + std::string::size_type nonspace_pos = make.find_last_not_of(' '); + if (nonspace_pos != std::string::npos && nonspace_pos + 1 < make.size()) { + make.erase(nonspace_pos + 1); + } + nonspace_pos = model.find_last_not_of(' '); + if (nonspace_pos != std::string::npos && nonspace_pos + 1 < model.size()) { + model.erase(nonspace_pos + 1); + } - if (make.length() > 0 && model.find(make + " ") == 0) { - model = model.substr(make.length() + 1); + if (!make.empty() && model.find(make + ' ') == 0) { + model.erase(0, make.size() + 1); } if (find_tag(Exiv2::exposureTime)) { @@ -203,24 +197,28 @@ FramesData::FramesData(const Glib::ustring &fname): aperture = pos->toFloat(); } - /* Read ISO speed - Nikon happens to return a pair for Lo and Hi modes */ + // Read ISO speed - Nikon happens to return a pair for Lo and Hi modes if (find_tag(Exiv2::isoSpeed)) { - // if standard exif iso tag, use the old way of interpreting the return value to be more regression-save - if (strcmp(pos->key().c_str(), "Exif.Photo.ISOSpeedRatings") == 0) { - int isofield = pos->count() > 1 ? 1 : 0; + // If standard exif iso tag, use the old way of interpreting the return value to be more regression-save + if (pos->key() == "Exif.Photo.ISOSpeedRatings") { + const long isofield = pos->count() > 1 ? 1 : 0; iso_speed = pos->toFloat(isofield); } else { - std::string str = pos->print(); - iso_speed = std::atof(str.c_str()); + iso_speed = std::atof(pos->print().c_str()); } } - // some newer cameras support iso settings that exceed the 16 bit of exif's ISOSpeedRatings + // Some newer cameras support iso settings that exceed the 16 bit of exif's ISOSpeedRatings if (iso_speed == 65535 || iso_speed == 0) { if (find_exif_tag("Exif.PentaxDng.ISO") || find_exif_tag("Exif.Pentax.ISO")) { - std::string str = pos->print(); - iso_speed = std::atof(str.c_str()); - } else if((!g_strcmp0(make.c_str(), "SONY") || !g_strcmp0(make.c_str(), "Canon")) - && find_exif_tag("Exif.Photo.RecommendedExposureIndex")) { + iso_speed = std::atof(pos->print().c_str()); + } + else if ( + ( + make == "SONY" + || make == "Canon" + ) + && find_exif_tag("Exif.Photo.RecommendedExposureIndex") + ) { iso_speed = pos->toFloat(); } } @@ -240,9 +238,9 @@ FramesData::FramesData(const Glib::ustring &fname): } if (find_tag(Exiv2::subjectDistance)) { - focus_dist = (0.01 * pow(10, pos->toFloat() / 40)); + focus_dist = (0.01 * std::pow(10, pos->toFloat() / 40)); } - + if (find_tag(Exiv2::orientation)) { orientation = pos->print(&exif); } @@ -257,7 +255,8 @@ FramesData::FramesData(const Glib::ustring &fname): std::string datetime_taken; if (find_exif_tag("Exif.Image.DateTimeOriginal")) { datetime_taken = pos->print(&exif); - } else if(find_exif_tag("Exif.Photo.DateTimeOriginal")) { + } + else if (find_exif_tag("Exif.Photo.DateTimeOriginal")) { datetime_taken = pos->print(&exif); } if (sscanf(datetime_taken.c_str(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { @@ -275,23 +274,23 @@ FramesData::FramesData(const Glib::ustring &fname): // Special file type detection (HDR, PixelShift) // ------------------------ uint16 bitspersample = 0, samplesperpixel = 0, sampleformat = 0, photometric = 0, compression = 0; - auto bps = exif.findKey(Exiv2::ExifKey("Exif.Image.BitsPerSample")); - auto spp = exif.findKey(Exiv2::ExifKey("Exif.Image.SamplesPerPixel")); - auto sf = exif.findKey(Exiv2::ExifKey("Exif.Image.SampleFormat")); - auto pi = exif.findKey(Exiv2::ExifKey("Exif.Image.PhotometricInterpretation")); - auto c = exif.findKey(Exiv2::ExifKey("Exif.Image.Compression")); + const auto bps = exif.findKey(Exiv2::ExifKey("Exif.Image.BitsPerSample")); + const auto spp = exif.findKey(Exiv2::ExifKey("Exif.Image.SamplesPerPixel")); + const auto sf = exif.findKey(Exiv2::ExifKey("Exif.Image.SampleFormat")); + const auto pi = exif.findKey(Exiv2::ExifKey("Exif.Image.PhotometricInterpretation")); + const auto c = exif.findKey(Exiv2::ExifKey("Exif.Image.Compression")); - if ((!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX")))) { -// if (find_exif_tag("Exif.Pentax.HDR") && pos->toLong() > 0) { -// isHDR = true; -// #if PRINT_HDR_PS_DETECTION -// printf("HDR detected ! -> \"HDR\" tag found\n"); -// #endif -// } else + if ( + !make.compare(0, 6, "PENTAX") + || ( + !make.compare(0, 5, "RICOH") + && !model.compare (0, 6, "PENTAX") + ) + ) { if (find_exif_tag("Exif.Pentax.DriveMode")) { std::string buf = pos->toString(3); buf[3] = 0; - if (!strcmp(buf.c_str(), "HDR")) { + if (buf == "HDR") { isHDR = true; #if PRINT_HDR_PS_DETECTION printf("HDR detected ! -> DriveMode = \"HDR\"\n"); @@ -299,8 +298,14 @@ FramesData::FramesData(const Glib::ustring &fname): } } - if (!isHDR && find_exif_tag("Exif.Pentax.Quality") && - (pos->toLong() == 7 || pos->toLong() == 8)) { + if ( + !isHDR + && find_exif_tag("Exif.Pentax.Quality") + && ( + pos->toLong() == 7 + || pos->toLong() == 8 + ) + ) { isPixelShift = true; #if PRINT_HDR_PS_DETECTION printf("PixelShift detected ! -> \"Quality\" = 7\n"); @@ -434,7 +439,7 @@ FramesData::FramesData(const Glib::ustring &fname): #endif } } - } catch(Exiv2::AnyError &e) { + } catch (const Exiv2::AnyError& e) { if (settings->verbose) { std::cerr << "EXIV2 ERROR: " << e.what() << std::endl; } @@ -564,7 +569,7 @@ void FramesData::setDCRawFrameCount(unsigned int frameCount) unsigned int FramesData::getFrameCount() const { - return dcrawFrameCount ? dcrawFrameCount : 1; + return std::max(1U, dcrawFrameCount); } @@ -578,7 +583,7 @@ Glib::ustring FramesData::getFileName() const std::string FramesMetaData::apertureToString(double aperture) { - + // TODO: Replace sprintf() char buffer[256]; sprintf (buffer, "%0.1f", aperture); return buffer; @@ -618,18 +623,21 @@ std::string FramesMetaData::expcompToString(double expcomp, bool maskZeroexpcomp double FramesMetaData::shutterFromString(std::string s) { - size_t i = s.find_first_of ('/'); + const std::string::size_type i = s.find_first_of ('/'); if (i == std::string::npos) { - return atof (s.c_str()); + return std::atof(s.c_str()); } else { - return atof (s.substr(0, i).c_str()) / atof (s.substr(i + 1).c_str()); + const double denominator = std::atof(s.substr(i + 1).c_str()); + return + denominator + ? std::atof(s.substr(0, i).c_str()) / denominator + : 0.0; } } double FramesMetaData::apertureFromString(std::string s) { - return atof(s.c_str()); + return std::atof(s.c_str()); } - diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 6f2147277..eeeefdc58 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -16,24 +16,28 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#ifndef __IMAGEDATA_H__ -#define __IMAGEDATA_H__ +#pragma once #include #include -#include "rawimage.h" #include + #include + #include + +#include "rawimage.h" #include "rtengine.h" namespace rtengine { -Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname); +Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname); // TODO: Global function? -class FramesData : public FramesMetaData { +class FramesData : + public FramesMetaData +{ private: bool ok_; Glib::ustring fname_; @@ -52,9 +56,9 @@ private: IIOSampleFormat sampleFormat; bool isPixelShift; bool isHDR; - + public: - FramesData (const Glib::ustring& fname); + FramesData(const Glib::ustring& fname); void setDCRawFrameCount(unsigned int frameCount); unsigned int getFrameCount() const override; @@ -80,6 +84,4 @@ public: Glib::ustring getFileName() const override; }; - } -#endif diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index f7d95b2df..83ef10b28 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -36,7 +36,6 @@ #endif #include "imageio.h" -//#include "iptcpairs.h" #include "iccjpeg.h" #include "color.h" #include "imagedata.h" @@ -78,27 +77,51 @@ FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname) } -Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."}; - -void ImageIO::setOutputProfile (const char* pdata, int plen) +MetadataInfo::MetadataInfo(const Glib::ustring& src) : + src_(src), + exif_(new rtengine::procparams::ExifPairs), + iptc_(new rtengine::procparams::IPTCPairs) { +} - delete [] profileData; +const Glib::ustring& MetadataInfo::filename() const +{ + return src_; +} - if (pdata) { - profileData = new char [plen]; - memcpy (profileData, pdata, plen); - } else { - profileData = nullptr; - } +const rtengine::procparams::ExifPairs& MetadataInfo::exif() const +{ + return *exif_; +} - profileLength = plen; +const rtengine::procparams::IPTCPairs& MetadataInfo::iptc() const +{ + return *iptc_; +} + +void MetadataInfo::setExif(const rtengine::procparams::ExifPairs &exif) +{ + *exif_ = exif; +} + +void MetadataInfo::setIptc(const rtengine::procparams::IPTCPairs &iptc) +{ + *iptc_ = iptc; +} + +void ImageIO::setMetadata(MetadataInfo info) +{ + metadataInfo = std::move(info); +} + +void ImageIO::setOutputProfile(const std::string& pdata) +{ + profileData = pdata; } ImageIO::ImageIO() : pl(nullptr), embProfile(nullptr), - profileData(nullptr), profileLength(0), loadedProfileData(nullptr), loadedProfileDataJpg(false), @@ -116,8 +139,6 @@ ImageIO::~ImageIO () } deleteLoadedProfileData(); - // delete exifRoot; - delete [] profileData; } void png_read_data(png_struct_def *png_ptr, unsigned char *data, size_t length); @@ -853,7 +874,7 @@ int ImageIO::savePNG (const Glib::ustring &fname, int bps) const #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED) png_set_option(png, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON); #endif - + png_infop info = png_create_info_struct(png); if (!info) { @@ -887,13 +908,13 @@ int ImageIO::savePNG (const Glib::ustring &fname, int bps) const png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); - if (profileData) { + if (!profileData.empty()) { #if PNG_LIBPNG_VER < 10500 - png_charp profdata = reinterpret_cast(profileData); + png_const_charp profdata = reinterpret_cast(profileData.data()); #else - png_bytep profdata = reinterpret_cast(profileData); + png_const_bytep profdata = reinterpret_cast(profileData.data()); #endif - png_set_iCCP(png, info, const_cast("icc"), 0, profdata, profileLength); + png_set_iCCP(png, info, "icc", 0, profdata, profileData.size()); } int rowlen = width * 3 * bps / 8; @@ -1034,8 +1055,8 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con jpeg_start_compress(&cinfo, TRUE); // write icc profile to the output - if (profileData) { - write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength); + if (!profileData.empty()) { + write_icc_profile (&cinfo, reinterpret_cast(profileData.data()), profileData.size()); } // write image data @@ -1115,7 +1136,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u unsigned char* linebuffer = new unsigned char[lineWidth]; // little hack to get libTiff to use proper byte order (see TIFFClienOpen()): - const char *mode = "w"; + const char* const mode = "w"; #ifdef WIN32 FILE *file = g_fopen_withBinaryAndLock (fname); int fileno = _fileno(file); @@ -1153,8 +1174,8 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u if (!uncompressed) { TIFFSetField (out, TIFFTAG_PREDICTOR, (bps == 16 || bps == 32) && isFloat ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL); } - if (profileData) { - TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData); + if (!profileData.empty()) { + TIFFSetField (out, TIFFTAG_ICCPROFILE, profileData.size(), profileData.data()); } for (int row = 0; row < height; row++) { @@ -1338,7 +1359,6 @@ void ImageIO::deleteLoadedProfileData( ) loadedProfileData = nullptr; } - bool ImageIO::saveMetadata(const Glib::ustring &fname) const { if (metadataInfo.filename().empty()) { @@ -1351,15 +1371,16 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const src->readMetadata(); dst->setMetadata(*src); dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; - for (auto &p : metadataInfo.exif()) { + for (const auto& p : metadataInfo.exif()) { try { dst->exifData()[p.first] = p.second; - } catch (Exiv2::AnyError &exc) {} + } catch (const Exiv2::AnyError& exc) { + } } - for (auto &p : metadataInfo.iptc()) { + for (const auto& p : metadataInfo.iptc()) { try { - auto &v = p.second; - if (v.size() >= 1) { + auto& v = p.second; + if (!v.empty()) { dst->iptcData()[p.first] = v[0]; for (size_t j = 1; j < v.size(); ++j) { Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); @@ -1367,11 +1388,12 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const dst->iptcData().add(d); } } - } catch (Exiv2::AnyError &exc) {} + } catch (const Exiv2::AnyError& exc) { + } } dst->writeMetadata(); return true; - } catch (Exiv2::AnyError &exc) { + } catch (const Exiv2::AnyError& exc) { std::cout << "EXIF ERROR: " << exc.what() << std::endl; return false; } diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 0bdb7d43a..f0eafc701 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -31,35 +31,44 @@ #include #include -#include "rtengine.h" -#include "imageformat.h" -#include "imagedimensions.h" -#include "iimage.h" + #include "colortemp.h" -#include "procparams.h" +#include "iimage.h" +#include "imagedimensions.h" +#include "imageformat.h" +#include "rtengine.h" namespace rtengine { +namespace procparams +{ + +class ExifPairs; +class IPTCPairs; + +} + class ProgressListener; class Imagefloat; -class MetadataInfo { +class MetadataInfo final +{ public: - explicit MetadataInfo(const Glib::ustring &src=Glib::ustring()): - src_(src) {} + explicit MetadataInfo(const Glib::ustring& src = {}); - const Glib::ustring &filename() const { return src_; } + const Glib::ustring& filename() const; - const rtengine::procparams::ExifPairs &exif() const { return exif_; } - const rtengine::procparams::IPTCPairs &iptc() const { return iptc_; } - void setExif(const rtengine::procparams::ExifPairs &exif) { exif_ = exif; } - void setIptc(const rtengine::procparams::IPTCPairs &iptc) { iptc_ = iptc; } + const rtengine::procparams::ExifPairs& exif() const; + const rtengine::procparams::IPTCPairs& iptc() const; + + void setExif(const rtengine::procparams::ExifPairs &exif); + void setIptc(const rtengine::procparams::IPTCPairs &iptc); private: Glib::ustring src_; - rtengine::procparams::ExifPairs exif_; - rtengine::procparams::IPTCPairs iptc_; + std::unique_ptr exif_; + std::unique_ptr iptc_; }; class ImageIO : virtual public ImageDatas @@ -68,7 +77,7 @@ class ImageIO : virtual public ImageDatas protected: ProgressListener* pl; cmsHPROFILE embProfile; - char* profileData; + std::string profileData; int profileLength; char* loadedProfileData; bool loadedProfileDataJpg; @@ -82,8 +91,6 @@ private: void deleteLoadedProfileData( ); public: - static Glib::ustring errorMsg[6]; - ImageIO(); ~ImageIO() override; @@ -118,8 +125,8 @@ public: cmsHPROFILE getEmbeddedProfile () const; void getEmbeddedProfileData (int& length, unsigned char*& pdata) const; - void setMetadata(const MetadataInfo &info) { metadataInfo = info; } - void setOutputProfile (const char* pdata, int plen); + void setMetadata(MetadataInfo info); + void setOutputProfile(const std::string& pdata); bool saveMetadata(const Glib::ustring &fname) const; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index a18cca9d7..8ce3ee2e9 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -153,7 +153,7 @@ public: { outCurve = { 0.0 }; } - + double getDirPyrDenoiseExpComp ( ) { return dirpyrdenoiseExpComp; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 079c5cb48..98ed2eaf0 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1403,7 +1403,6 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a im = tempImage; } - // im->setMetadata(imgsrc->getMetaData()->getRootExifData()); im->setMetadata(MetadataInfo(imgsrc->getFileName())); im->saveTIFF(fname, 16, false, true); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 8dd57e74d..669037021 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5656,6 +5656,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_size) { if (fname != "") { + // TODO: std::unique_ptr<> to the rescue int w_raw = -1, h_raw = thumb_size; int w_thumb = -1, h_thumb = thumb_size; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f9daead22..3003cf3e0 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -295,15 +295,14 @@ bool saveToKeyfile( return false; } - -const std::map exif_keys = { +const std::map exif_keys = { {"Copyright", "Exif.Image.Copyright"}, {"Artist", "Exif.Image.Artist"}, {"ImageDescription", "Exif.Image.ImageDescription"}, {"Exif.UserComment", "Exif.Photo.UserComment"} }; -const std::map iptc_keys = { +const std::map iptc_keys = { {"Title", "Iptc.Application2.ObjectName"}, {"Category", "Iptc.Application2.Category"}, {"SupplementalCategories", "Iptc.Application2.SuppCategory"}, @@ -3168,9 +3167,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // Dehaze saveToKeyfile(!pedited || pedited->dehaze.enabled, "Dehaze", "Enabled", dehaze.enabled, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile); // Directional pyramid denoising saveToKeyfile(!pedited || pedited->dirpyrDenoise.enabled, "Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled, keyFile); @@ -3611,7 +3610,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // IPTC change list if (!pedited || pedited->iptc) { - std::map m; + std::map m; for (auto &p : iptc_keys) { m[p.second] = p.first; } @@ -4800,7 +4799,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Dehaze", "ShowDepthMap", pedited, dehaze.showDepthMap, pedited->dehaze.showDepthMap); assignFromKeyfile(keyFile, "Dehaze", "Depth", pedited, dehaze.depth, pedited->dehaze.depth); } - + if (keyFile.has_group("Film Simulation")) { assignFromKeyfile(keyFile, "Film Simulation", "Enabled", pedited, filmSimulation.enabled, pedited->filmSimulation.enabled); assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename); @@ -5193,6 +5192,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (it == iptc_keys.end()) { continue; } + auto kk = it->second; const IPTCPairs::iterator element = iptc.find(kk); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 951b02b1a..07ec2a5fa 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1075,8 +1075,104 @@ struct MetaDataParams { }; -typedef std::map ExifPairs; -typedef std::map> IPTCPairs; +/** + * Minimal wrapper allowing forward declaration for representing a key/value for the exif metadata information + */ +class ExifPairs final +{ +private: + using Pairs = std::map; + +public: + using const_iterator = Pairs::const_iterator; + using size_type = Pairs::size_type; + + const_iterator find(const Glib::ustring& key) const + { + return pairs.find(key); + } + + const_iterator begin() const + { + return pairs.begin(); + } + + const_iterator end() const + { + return pairs.end(); + } + + void clear() + { + pairs.clear(); + } + + size_type erase(const Glib::ustring& key) + { + return pairs.erase(key); + } + + Glib::ustring& operator[](const Glib::ustring& key) + { + return pairs[key]; + } + + bool operator ==(const ExifPairs& other) const + { + return pairs == other.pairs; + } + +private: + Pairs pairs; +}; + +/** + * The IPTC key/value pairs + */ +class IPTCPairs final +{ +public: + using iterator = std::map>::iterator; + using const_iterator = std::map>::const_iterator; + + iterator find(const Glib::ustring& key) + { + return pairs.find(key); + } + + const_iterator begin() const + { + return pairs.begin(); + } + + const_iterator end() const + { + return pairs.end(); + } + + bool empty() const + { + return pairs.empty(); + } + + void clear() + { + pairs.clear(); + } + + std::vector& operator[](const Glib::ustring& key) + { + return pairs[key]; + } + + bool operator ==(const IPTCPairs& other) const + { + return pairs == other.pairs; + } + +private: + std::map> pairs; +}; struct WaveletParams { std::vector ccwcurve; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 5efb3249c..d605e602c 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -726,7 +726,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima rm *= expcomp; gm *= expcomp; bm *= expcomp; - + #ifdef _OPENMP #pragma omp parallel if(!d1x) // omp disabled for D1x to avoid race conditions (see Issue 1088 http://code.google.com/p/rawtherapee/issues/detail?id=1088) { @@ -1693,7 +1693,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) // Load complete Exif information - idata = new FramesData (fname); + idata = new FramesData(fname); // TODO: std::unique_ptr<> idata->setDCRawFrameCount (numFrames); green(W, H); @@ -1931,16 +1931,16 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if (!bitmapBads) { bitmapBads = new PixelsMap(W, H); } - + int n = f.mark(rawData, *bitmapBads); totBP += n; if (n > 0) { if (settings->verbose) { - printf("Marked %d hot pixels from PDAF lines\n", n); + printf("Marked %d hot pixels from PDAF lines\n", n); } - auto &thresh = f.greenEqThreshold(); + auto &thresh = f.greenEqThreshold(); if (numFrames == 4) { for (int i = 0; i < 4; ++i) { green_equilibrate(thresh, *rawDataFrames[i]); @@ -1959,7 +1959,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le CameraConst *cc = ccs->get(ri->get_maker().c_str(), ri->get_model().c_str()); return cc && cc->get_globalGreenEquilibration(); }; - + if ( ri->getSensorType() == ST_BAYER && (raw.bayersensor.greenthresh || (globalGreenEq() && raw.bayersensor.method != RAWParams::BayerSensor::getMethodString( RAWParams::BayerSensor::Method::VNG4))) ) { if (settings->verbose) { printf("Performing global green equilibration...\n"); @@ -4120,7 +4120,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, const ColorManagemen } } } - + lcmsMutex->lock (); switch (camera_icc_type) { diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index b6b7402f9..bdb94fe4a 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -47,15 +47,14 @@ enum RenderingIntent : int; namespace procparams { -typedef std::map ExifPairs; -typedef std::map> IPTCPairs; +class ProcParams; +class IPTCPairs; struct RAWParams; struct ColorManagementParams; struct CropParams; enum class ToneCurveMode : int; -class ProcParams; } @@ -140,7 +139,7 @@ public: * Use it only for raw files. In caseof jpgs and tiffs pass a NULL pointer. * @param firstFrameOnly must be true to get the MetaData of the first frame only, e.g. for a PixelShift file. * @return The metadata */ - static FramesMetaData* fromFile (const Glib::ustring& fname); + static FramesMetaData* fromFile(const Glib::ustring& fname); virtual Glib::ustring getFileName() const = 0; }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index a3c9ec6ba..2a1024609 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -207,7 +207,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, if (std::max(img->getWidth(), img->getHeight()) / std::min(img->getWidth(), img->getHeight()) >= 10) { return nullptr; } - + Thumbnail* tpp = new Thumbnail (); unsigned char* data; @@ -315,7 +315,7 @@ namespace { Image8 *load_inspector_mode(const Glib::ustring &fname, eSensorType &sensorType, int &w, int &h) { BENCHFUN - + RawImageSource src; int err = src.load(fname, true); if (err) { @@ -324,7 +324,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, eSensorType &sensorType, src.getFullSize(w, h); sensorType = src.getSensorType(); - + ProcParams neutral; neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); @@ -389,7 +389,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, eSensorType return tpp; } - + RawImage *ri = new RawImage (fname); unsigned int imageNum = 0; int r = ri->loadRaw (false, imageNum, false); @@ -442,7 +442,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, eSensorType if (!forHistogramMatching && settings->thumbnail_inspector_mode == Settings::ThumbnailInspectorMode::RAW_IF_NOT_JPEG_FULLSIZE && float(std::max(w, h))/float(std::max(ri->get_width(), ri->get_height())) < 0.9f) { delete img; delete ri; - + img = load_inspector_mode(fname, sensorType, w, h); if (!img) { delete tpp; @@ -451,7 +451,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, eSensorType tpp->scale = 1.; tpp->thumbImg = img; - + return tpp; } } else { @@ -1055,12 +1055,12 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int // Full thumbnail processing, second stage if complete profile exists IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& myscale, bool forMonitor, bool forHistogramMatching) { - std::string camName = metadata->getCamera(); - float shutter = metadata->getShutterSpeed(); - float fnumber = metadata->getFNumber(); - float iso = metadata->getISOSpeed(); - float fcomp = metadata->getExpComp(); - + const std::string camName = metadata->getCamera(); + const float shutter = metadata->getShutterSpeed(); + const float fnumber = metadata->getFNumber(); + const float iso = metadata->getISOSpeed(); + const float fcomp = metadata->getExpComp(); + // check if the WB's equalizer value has changed if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4)) { wbEqual = params.wb.equal; @@ -1155,7 +1155,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT float red = baseImg->r (i, j) * rmi; float green = baseImg->g (i, j) * gmi; float blue = baseImg->b (i, j) * bmi; - + // avoid magenta highlights if highlight recovery is enabled if (params.toneCurve.hrenabled && red > MAXVALF && blue > MAXVALF) { baseImg->r(i, j) = baseImg->g(i, j) = baseImg->b(i, j) = CLIP((red + green + blue) / 3.f); @@ -1192,7 +1192,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.dehaze(baseImg); ipf.ToneMapFattal02(baseImg); - + // perform transform if (ipf.needsTransform()) { Imagefloat* trImg = new Imagefloat (fw, fh); @@ -1343,7 +1343,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT } } - + // luminance processing // ipf.EPDToneMap(labView,0,6); @@ -1416,7 +1416,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.ciecam_02float (cieView, adap, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, sk, execsharp, d, dj, yb, rtt); delete cieView; } - + // color processing //ipf.colorCurve (labView, labView); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 64edc5c17..35cf82068 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -776,7 +776,7 @@ private: params.toneCurve.brightness = 0; params.toneCurve.contrast = 0; params.toneCurve.black = 0; - } + } // at this stage, we can flush the raw data to free up quite an important amount of memory // commented out because it makes the application crash when batch processing... @@ -1151,10 +1151,10 @@ private: if (params.colorappearance.enabled) { double adap; - float fnum = imgsrc->getMetaData()->getFNumber (); // F number - float fiso = imgsrc->getMetaData()->getISOSpeed () ; // ISO - float fspeed = imgsrc->getMetaData()->getShutterSpeed () ; //speed - float fcomp = imgsrc->getMetaData()->getExpComp (); //compensation + - + const float fnum = imgsrc->getMetaData()->getFNumber(); // F number + const float fiso = imgsrc->getMetaData()->getISOSpeed() ; // ISO + const float fspeed = imgsrc->getMetaData()->getShutterSpeed() ; // Speed + const float fcomp = imgsrc->getMetaData()->getExpComp(); // Compensation + - if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { adap = 2000.; @@ -1295,12 +1295,12 @@ private: // Sending back the whole first root, which won't necessarily be the selected frame number // and may contain subframe depending on initial raw's hierarchy // readyImg->setMetadata (ii->getMetaData()->getRootExifData ()); - readyImg->setMetadata(info); + readyImg->setMetadata(std::move(info)); break; case MetaDataParams::EDIT: info.setExif(params.exif); info.setIptc(params.iptc); - readyImg->setMetadata(info); + readyImg->setMetadata(std::move(info)); // ask for the correct frame number, but may contain subframe depending on initial raw's hierarchy // readyImg->setMetadata (ii->getMetaData()->getBestExifData(imgsrc, ¶ms.raw), params.exif, params.iptc); break; @@ -1315,7 +1315,7 @@ private: if (!useLCMS) { // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma ProfileContent pc (jprof); - readyImg->setOutputProfile (pc.getData().c_str(), pc.getData().size()); + readyImg->setOutputProfile (pc.getData()); } } else { // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma @@ -1335,11 +1335,11 @@ private: } ProfileContent pc = ICCStore::getInstance()->getContent (params.icm.outputProfile); - readyImg->setOutputProfile (pc.getData().c_str(), pc.getData().size()); + readyImg->setOutputProfile (pc.getData()); } } else { // No ICM - readyImg->setOutputProfile (nullptr, 0); + readyImg->setOutputProfile ({}); } } diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index 397bc1c48..6fe55c460 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -87,7 +87,6 @@ public: // FramesMetaData interface //------------------------------------------------------------------------- - /* unsigned int getRootCount () const override { return -1; } */ unsigned int getFrameCount () const override { return frameCount; } bool hasExif() const override { return false; } tm getDateTime() const override { return tm{}; } diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 661118e32..f4da2d4b1 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -16,13 +16,15 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include + #include "exifpanel.h" #include "guiutils.h" #include "rtimage.h" #include "options.h" -#include "../rtengine/imagedata.h" +#include "../rtengine/imagedata.h" #include "../rtengine/procparams.h" using namespace rtengine; @@ -31,15 +33,15 @@ using namespace rtengine::procparams; ExifPanel::ExifPanel() : idata(nullptr), changeList(new rtengine::procparams::ExifPairs), - defChangeList(new rtengine::procparams::ExifPairs) + defChangeList(new rtengine::procparams::ExifPairs), + editableTags{ + {"Exif.Photo.UserComment", "User Comment"}, + {"Exif.Image.Artist", "Artist"}, + {"Exif.Image.Copyright", "Copyright"}, + {"Exif.Image.ImageDescription", "Image Description"} + } { - editable_ = { - { "Exif.Photo.UserComment", "User Comment" }, - { "Exif.Image.Artist", "Artist" }, - { "Exif.Image.Copyright", "Copyright" }, - { "Exif.Image.ImageDescription", "Image Description"} - }; - + exifTree = Gtk::manage (new Gtk::TreeView()); scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow()); @@ -57,7 +59,7 @@ ExifPanel::ExifPanel() : exifTree->set_model (exifTreeModel); exifTree->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_NONE); exifTree->set_show_expanders(false); - + keepicon = RTImage::createPixbufFromFile ("tick-small.png"); editicon = RTImage::createPixbufFromFile("add-small.png"); @@ -204,54 +206,61 @@ void ExifPanel::refreshTags() { Glib::RefPtr selection = exifTree->get_selection(); std::vector sel = selection->get_selected_rows(); - + exifTreeModel->clear(); - + if (!idata) { return; } - Glib::ustring fn = idata->getFileName(); + const Glib::ustring fn = idata->getFileName(); if (fn.empty()) { return; } std::unordered_set ed; - for (auto &p : editable_) { + for (const auto &p : editableTags) { ed.insert(p.first); } - + try { auto img = open_exiv2(fn); img->readMetadata(); - auto &exif = img->exifData(); - - for (auto &p : *changeList) { + auto& exif = img->exifData(); + + for (const auto& p : *changeList) { try { exif[p.first] = p.second; - } catch (Exiv2::AnyError &exc) { + } catch (const Exiv2::AnyError& exc) { } } - for (auto &p : editable_) { - auto pos = exif.findKey(Exiv2::ExifKey(p.first)); + for (const auto& p : editableTags) { + const auto pos = exif.findKey(Exiv2::ExifKey(p.first)); if (pos != exif.end() && pos->size()) { - bool edited = changeList->find(pos->key()) != changeList->end(); + const bool edited = changeList->find(pos->key()) != changeList->end(); addTag(pos->key(), pos->tagLabel(), pos->print(&exif), true, edited); } } - for (auto &tag : exif) { - bool editable = ed.find(tag.key()) != ed.end(); - if (!editable && !tag.tagLabel().empty() && tag.typeId() != Exiv2::undefined && - (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { + for (const auto& tag : exif) { + const bool editable = ed.find(tag.key()) != ed.end(); + if ( + !editable + && !tag.tagLabel().empty() + && tag.typeId() != Exiv2::undefined + && ( + tag.typeId() == Exiv2::asciiString + || tag.size() < 256 + ) + ) { addTag(tag.key(), tag.tagLabel(), tag.print(&exif), false, false); } } - } catch (Exiv2::AnyError &exc) { + } catch (const Exiv2::AnyError& exc) { return; } - for (auto &p : sel) { + for (const auto& p : sel) { exifTree->get_selection()->select(p); } } @@ -277,13 +286,13 @@ void ExifPanel::exifSelectionChanged () } -void ExifPanel::resetIt (Gtk::TreeModel::iterator iter) +void ExifPanel::resetIt(const Gtk::TreeModel::const_iterator& iter) { if (!iter) { return; } - auto key = iter->get_value(exifColumns.key); + const auto key = iter->get_value(exifColumns.key); changeList->erase(key); } @@ -324,7 +333,7 @@ void ExifPanel::addPressed () Gtk::Label* tlabel = new Gtk::Label (M ("EXIFPANEL_ADDTAGDLG_SELECTTAG") + ":"); MyComboBoxText* tcombo = new MyComboBoxText (); - for (auto &p : editable_) { + for (const auto& p : editableTags) { tcombo->append(p.second); } @@ -339,11 +348,11 @@ void ExifPanel::addPressed () Glib::ustring sel; Glib::ustring val; { - Glib::RefPtr selection = exifTree->get_selection(); - std::vector rows = selection->get_selected_rows(); + const Glib::RefPtr selection = exifTree->get_selection(); + const std::vector rows = selection->get_selected_rows(); if (rows.size() == 1) { - Gtk::TreeModel::iterator iter = exifTreeModel->get_iter(rows[0]); + const Gtk::TreeModel::iterator iter = exifTreeModel->get_iter(rows[0]); if (iter->get_value(exifColumns.editable)) { sel = iter->get_value(exifColumns.key); val = iter->get_value(exifColumns.value_nopango); @@ -351,11 +360,11 @@ void ExifPanel::addPressed () } } - if (sel == "") { + if (sel.empty()) { tcombo->set_active(0); } else { - for (size_t i = 0; i < editable_.size(); ++i) { - if (editable_[i].first == sel) { + for (size_t i = 0; i < editableTags.size(); ++i) { + if (editableTags[i].first == sel) { tcombo->set_active(i); break; } @@ -375,8 +384,8 @@ void ExifPanel::addPressed () hb2->show (); if (dialog->run () == Gtk::RESPONSE_OK) { - auto key = editable_[tcombo->get_active_row_number()].first; - auto value = ventry->get_text(); + auto key = editableTags[tcombo->get_active_row_number()].first; + const auto value = ventry->get_text(); (*changeList)[key] = value; refreshTags(); notifyListener (); diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index 97708ab7b..de2174f6b 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -20,11 +20,23 @@ #define _EXIFPANEL_ #include + #include -#include #include "toolpanel.h" +namespace rtengine +{ + +namespace procparams +{ + +class ExifPairs; + +} + +} + class ExifPanel : public Gtk::VBox, public ToolPanel { @@ -67,11 +79,11 @@ private: Gtk::Button* reset; Gtk::Button* resetAll; - std::vector> editable_; + const std::vector> editableTags; Gtk::TreeModel::Children addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited); void refreshTags(); - void resetIt (Gtk::TreeModel::iterator iter); + void resetIt(const Gtk::TreeModel::const_iterator& iter); void resetPressed(); void resetAllPressed(); void addPressed(); diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 9e534db2f..fcdd97101 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -17,11 +17,13 @@ * along with RawTherapee. If not, see . */ #include + #include "iptcpanel.h" + #include "clipboard.h" #include "rtimage.h" -#include "../rtengine/imagedata.h" +#include "../rtengine/imagedata.h" #include "../rtengine/procparams.h" using namespace rtengine; @@ -71,11 +73,10 @@ const std::set iptc_keys = { } // namespace - IPTCPanel::IPTCPanel(): changeList(new rtengine::procparams::IPTCPairs), defChangeList(new rtengine::procparams::IPTCPairs), - embeddedData(new rtengine::procparams::IPTCPairs) + embeddedData(new rtengine::procparams::IPTCPairs) { set_spacing (4); @@ -493,13 +494,13 @@ void IPTCPanel::setImageData (const FramesMetaData* id) try { auto img = open_exiv2(id->getFileName()); img->readMetadata(); - auto &iptc = img->iptcData(); - for (auto &tag : iptc) { + auto& iptc = img->iptcData(); + for (const auto& tag : iptc) { if (iptc_keys.find(tag.key()) != iptc_keys.end()) { (*embeddedData)[tag.key()].push_back(tag.toString()); } } - } catch (Exiv2::AnyError &exc) { + } catch (const Exiv2::AnyError& exc) { embeddedData->clear(); } } diff --git a/rtgui/resize.cc b/rtgui/resize.cc index decbfb2f5..40d7ace56 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include + #include "resize.h" #include "eventmapper.h" diff --git a/rtgui/shcselector.cc b/rtgui/shcselector.cc index fe436b5ca..55a2ad9dd 100644 --- a/rtgui/shcselector.cc +++ b/rtgui/shcselector.cc @@ -18,7 +18,9 @@ */ #include + #include "shcselector.h" + #include "multilangmgr.h" #include "mycurve.h" diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 17667ea1a..ba335d215 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -15,28 +15,91 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "multilangmgr.h" -#include "thumbnail.h" -#include -#include -#include "options.h" -#include "../rtengine/mytime.h" #include #include +#include +#include + #include -#include "../rtengine/imagedata.h" -#include "../rtengine/procparams.h" + #include -#include "../rtengine/dynamicprofile.h" -#include "guiutils.h" +#include "thumbnail.h" + #include "batchqueue.h" #include "extprog.h" -#include "profilestorecombobox.h" -#include "procparamchangers.h" +#include "guiutils.h" +#include "multilangmgr.h" +#include "options.h" #include "ppversion.h" +#include "procparamchangers.h" +#include "profilestorecombobox.h" #include "version.h" +#include "../rtengine/dynamicprofile.h" +#include "../rtengine/imagedata.h" +#include "../rtengine/mytime.h" +#include "../rtengine/procparams.h" + +namespace { + +bool CPBDump( + const Glib::ustring& commFName, + const Glib::ustring& imageFName, + const Glib::ustring& profileFName, + const Glib::ustring& defaultPParams, + const CacheImageData* cfs, + bool flagMode +) +{ + const std::unique_ptr kf(new Glib::KeyFile); + + if (!kf) { + return false; + } + + // open the file in write mode + const std::unique_ptr f(g_fopen(commFName.c_str (), "wt"), &std::fclose); + + if (!f) { + printf ("CPBDump(\"%s\") >>> Error: unable to open file with write access!\n", commFName.c_str()); + return false; + } + + try { + kf->set_string ("RT General", "CachePath", options.cacheBaseDir); + kf->set_string ("RT General", "AppVersion", RTVERSION); + kf->set_integer ("RT General", "ProcParamsVersion", PPVERSION); + kf->set_string ("RT General", "ImageFileName", imageFName); + kf->set_string ("RT General", "OutputProfileFileName", profileFName); + kf->set_string ("RT General", "DefaultProcParams", defaultPParams); + kf->set_boolean ("RT General", "FlaggingMode", flagMode); + + kf->set_integer ("Common Data", "FrameCount", cfs->frameCount); + kf->set_integer ("Common Data", "SampleFormat", cfs->sampleFormat); + kf->set_boolean ("Common Data", "IsHDR", cfs->isHDR); + kf->set_boolean ("Common Data", "IsPixelShift", cfs->isPixelShift); + kf->set_double ("Common Data", "FNumber", cfs->fnumber); + kf->set_double ("Common Data", "Shutter", cfs->shutter); + kf->set_double ("Common Data", "FocalLength", cfs->focalLen); + kf->set_integer ("Common Data", "ISO", cfs->iso); + kf->set_string ("Common Data", "Lens", cfs->lens); + kf->set_string ("Common Data", "Make", cfs->camMake); + kf->set_string ("Common Data", "Model", cfs->camModel); + + } catch (const Glib::KeyFileError&) { + } + + try { + fprintf (f.get(), "%s", kf->to_data().c_str()); + } catch (const Glib::KeyFileError&) { + } + + return true; +} + +} // namespace + using namespace rtengine::procparams; Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : @@ -219,67 +282,6 @@ const ProcParams& Thumbnail::getProcParamsU () return *pparams; // there is no valid pp to return, but we have to return something } - -namespace { - -bool CPBDump(const Glib::ustring &commFName, const Glib::ustring &imageFName, - const Glib::ustring &profileFName, const Glib::ustring &defaultPParams, - const CacheImageData* cfs, const bool flagMode) -{ - const auto kf = new Glib::KeyFile; - - if (!kf) { - return false; - } - - FILE *f = nullptr; - - // open the file in write mode - f = g_fopen (commFName.c_str (), "wt"); - - if (f == nullptr) { - printf ("CPBDump(\"%s\") >>> Error: unable to open file with write access!\n", commFName.c_str()); - delete kf; - return false; - } - - try { - - kf->set_string ("RT General", "CachePath", options.cacheBaseDir); - kf->set_string ("RT General", "AppVersion", RTVERSION); - kf->set_integer ("RT General", "ProcParamsVersion", PPVERSION); - kf->set_string ("RT General", "ImageFileName", imageFName); - kf->set_string ("RT General", "OutputProfileFileName", profileFName); - kf->set_string ("RT General", "DefaultProcParams", defaultPParams); - kf->set_boolean ("RT General", "FlaggingMode", flagMode); - - kf->set_integer ("Common Data", "FrameCount", cfs->frameCount); - kf->set_integer ("Common Data", "SampleFormat", cfs->sampleFormat); - kf->set_boolean ("Common Data", "IsHDR", cfs->isHDR); - kf->set_boolean ("Common Data", "IsPixelShift", cfs->isPixelShift); - kf->set_double ("Common Data", "FNumber", cfs->fnumber); - kf->set_double ("Common Data", "Shutter", cfs->shutter); - kf->set_double ("Common Data", "FocalLength", cfs->focalLen); - kf->set_integer ("Common Data", "ISO", cfs->iso); - kf->set_string ("Common Data", "Lens", cfs->lens); - kf->set_string ("Common Data", "Make", cfs->camMake); - kf->set_string ("Common Data", "Model", cfs->camModel); - - } catch (Glib::KeyFileError&) {} - - try { - fprintf (f, "%s", kf->to_data().c_str()); - } catch (Glib::KeyFileError&) {} - - fclose (f); - delete kf; - - return true; -} - - -} // namespace - /** @brief Create default params on demand and returns a new updatable object * * The loaded profile may be partial, but it return a complete ProcParams (i.e. without ParamsEdited) @@ -304,7 +306,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu const CacheImageData* cfs = getCacheImageData(); Glib::ustring defaultPparamsPath = options.findProfilePath(defProf); const bool create = (!hasProcParams() || force); - const bool run_cpb = false; //!options.CPBPath.empty() && !defaultPparamsPath.empty() && cfs && cfs->exifValid && create; + const bool run_cpb = false; const Glib::ustring outFName = (options.paramsLoadLocation == PLL_Input && options.saveParamsFile) ? @@ -313,16 +315,24 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu if (!run_cpb) { if (defProf == DEFPROFILE_DYNAMIC && create && cfs && cfs->exifValid) { - std::unique_ptr imageMetaData(rtengine::FramesMetaData::fromFile(fname)); - PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData.get()); - int err = pp->pparams->save(outFName); - pp->deleteInstance(); - delete pp; - if (!err) { + const auto pp_deleter = + [](PartialProfile* pp) + { + pp->deleteInstance(); + delete pp; + }; + const std::unique_ptr imageMetaData(rtengine::FramesMetaData::fromFile(fname)); + const std::unique_ptr pp( + imageMetaData + ? ProfileStore::getInstance()->loadDynamicProfile(imageMetaData.get()) + : nullptr, + pp_deleter + ); + if (pp && !pp->pparams->save(outFName)) { loadProcParams(); } } else if (create && defProf != DEFPROFILE_DYNAMIC) { - const PartialProfile *p = ProfileStore::getInstance()->getProfile(defProf); + const PartialProfile* const p = ProfileStore::getInstance()->getProfile(defProf); if (p && !p->pparams->save(outFName)) { loadProcParams(); } @@ -333,7 +343,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu CPBDump(tmpFileName, fname, outFName, defaultPparamsPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(defaultPparamsPath, Glib::path_get_basename(defProf) + paramFileExtension), cfs, flaggingMode); - + // For the filename etc. do NOT use streams, since they are not UTF8 safe Glib::ustring cmdLine = options.CPBPath + Glib::ustring(" \"") + tmpFileName + Glib::ustring("\""); From 801e7b175e03fd3970ad9db9de08ddc092231f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sun, 19 May 2019 22:12:27 +0200 Subject: [PATCH 003/110] `DCPMetadata` review --- rtengine/dcp.cc | 395 ++++++++++++++++++++++++++++-------------------- 1 file changed, 233 insertions(+), 162 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index c6c38077a..614c5a426 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -443,8 +443,9 @@ std::map getAliases(const Glib::ustring& profile_dir) return res; } -class DCPMetadata { - // TODO: Review +class DCPMetadata +{ +private: enum TagType { INVALID = 0, BYTE = 1, @@ -468,47 +469,46 @@ class DCPMetadata { }; public: - explicit DCPMetadata(FILE *file): order_(UNKNOWN), file_(file) {} + explicit DCPMetadata(FILE* file) : + file_(file), + order_(UNKNOWN) + { + } bool parse() { - int offset = 0; - FILE *f = file_; - - if (!f) { + if (!file_) { #ifndef NDEBUG - std::cerr << "ERROR : no file opened !" << std::endl; + std::cerr << "ERROR: No file opened." << std::endl; #endif return false; } + setlocale(LC_NUMERIC, "C"); // to set decimal point in sscanf // read tiff header - fseek(f, 0, SEEK_SET); - unsigned short bo; - fread(&bo, 1, 2, f); - order_ = ByteOrder(int(bo)); + std::fseek(file_, 0, SEEK_SET); + std::uint16_t bo; + std::fread(&bo, 1, 2, file_); + order_ = ByteOrder(bo); - get2(f, order_); - if (!offset) { - offset = get4(f, order_); - } + get2(); // Skip - // seek to IFD - fseek(f, offset, SEEK_SET); + // Seek to IFD + const std::size_t offset = get4(); + std::fseek(file_, offset, SEEK_SET); - // first read the IFD directory - int numtags = get2(f, order_); + // First read the IFD directory + const std::uint16_t numtags = get2(); - if (numtags <= 0 || numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit + if (numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit return false; } - int base = 0; - for (int i = 0; i < numtags; i++) { - Tag t; - if (parse_tag(t, f, base, order_)) { - tags_[t.id] = std::move(t); + for (std::uint16_t i = 0; i < numtags; ++i) { + Tag tag; + if (parseTag(tag)) { + tags_[tag.id] = std::move(tag); } } @@ -520,227 +520,298 @@ public: return tags_.find(id) != tags_.end(); } - std::string toString(int id) + std::string toString(int id) const { - auto it = tags_.find(id); - if (it != tags_.end()) { - auto &t = it->second; - if (t.type == ASCII) { - std::ostringstream buf; - unsigned char *value = &(t.value[0]); - buf << value; - return buf.str(); + const Tags::const_iterator tag = tags_.find(id); + if (tag != tags_.end()) { + if (tag->second.type == ASCII) { + return std::string(tag->second.value.begin(), tag->second.value.end()).c_str(); } } - return ""; + return {}; } - int toInt(int id, int ofs=0, TagType astype=INVALID) + std::int32_t toInt(int id, std::size_t offset = 0, TagType as_type = INVALID) const { - auto it = tags_.find(id); - if (it == tags_.end()) { + const Tags::const_iterator tag = tags_.find(id); + if (tag == tags_.end()) { return 0; } - auto &t = it->second; - int a; - unsigned char *value = &(t.value[0]); - - if (astype == INVALID) { - astype = t.type; + if (as_type == INVALID) { + as_type = tag->second.type; } - switch (astype) { - case SBYTE: - return reinterpret_cast(value)[ofs]; + switch (as_type) { + case SBYTE: { + if (offset < tag->second.value.size()) { + return static_cast(tag->second.value[offset]); + } + return 0; + } - case BYTE: - return value[ofs]; + case BYTE: { + if (offset < tag->second.value.size()) { + return tag->second.value[offset]; + } + return 0; + } - case SSHORT: - return int2_to_signed(sget2(value + ofs, order_)); + case SSHORT: { + if (offset + 1 < tag->second.value.size()) { + return static_cast(sget2(tag->second.value.data() + offset)); + } + return 0; + } - case SHORT: - return sget2(value + ofs, order_); + case SHORT: { + if (offset + 1 < tag->second.value.size()) { + return sget2(tag->second.value.data() + offset); + } + return 0; + } - case SLONG: - case LONG: - return sget4 (value + ofs, order_); + case SLONG: + case LONG: { + if (offset + 3 < tag->second.value.size()) { + return sget4(tag->second.value.data() + offset); + } + return 0; + } - case SRATIONAL: - case RATIONAL: - a = sget4(value + ofs + 4, order_); - return a == 0 ? 0 : int(sget4(value + ofs, order_)) / a; + case SRATIONAL: + case RATIONAL: { + if (offset + 7 < tag->second.value.size()) { + const std::uint32_t denominator = sget4(tag->second.value.data() + offset + 4); + return + denominator == 0 + ? 0 + : static_cast(sget4(tag->second.value.data() + offset)) / denominator; + } + return 0; + } - case FLOAT: - return toDouble(id, ofs); + case FLOAT: { + return toDouble(id, offset); + } - default: - return 0; + default: { + return 0; + } } } - int toShort(int id, int ofs=0) + int toShort(int id, std::size_t offset = 0) const { - return toInt(id, ofs, SHORT); + return toInt(id, offset, SHORT); } - double toDouble(int id, int ofs=0) + double toDouble(int id, std::size_t offset = 0) const { - auto it = tags_.find(id); - if (it == tags_.end()) { + const Tags::const_iterator tag = tags_.find(id); + if (tag == tags_.end()) { return 0.0; } - auto &t = it->second; + switch (tag->second.type) { + case SBYTE: { + if (offset < tag->second.value.size()) { + return static_cast(tag->second.value[offset]); + } + return 0.0; + } - union IntFloat { - uint32_t i; - float f; - } conv; + case BYTE: { + if (offset < tag->second.value.size()) { + return tag->second.value[offset]; + } + return 0.0; + } - int ud, dd; - unsigned char *value = &(t.value[0]); + case SSHORT: { + if (offset + 1 < tag->second.value.size()) { + return static_cast(sget2(tag->second.value.data() + offset)); + } + return 0.0; + } - switch (t.type) { - case SBYTE: - return int((reinterpret_cast (value))[ofs]); + case SHORT: { + if (offset + 1 < tag->second.value.size()) { + return sget2(tag->second.value.data() + offset); + } + return 0.0; + } - case BYTE: - return int(value[ofs]); + case SLONG: + case LONG: { + if (offset + 3 < tag->second.value.size()) { + return sget4(tag->second.value.data() + offset); + } + return 0.0; + } - case SSHORT: - return int2_to_signed(sget2(value + ofs, order_)); + case SRATIONAL: + case RATIONAL: { + if (offset + 7 < tag->second.value.size()) { + const std::int32_t numerator = sget4(tag->second.value.data() + offset); + const std::int32_t denominator = sget4(tag->second.value.data() + offset + 4); + return + denominator == 0 + ? 0.0 + : static_cast(numerator) / static_cast(denominator); + } + return 0.0; + } - case SHORT: - return sget2(value + ofs, order_); + case FLOAT: { + union IntFloat { + std::uint32_t i; + float f; + } conv; - case SLONG: - case LONG: - return sget4(value + ofs, order_); + conv.i = sget4(tag->second.value.data() + offset); + return conv.f; // IEEE FLOATs are already C format, they just need a recast + } - case SRATIONAL: - case RATIONAL: - ud = sget4(value + ofs, order_); - dd = sget4(value + ofs + 4, order_); - return (dd ? double(ud)/double(dd) : 0.0); - - case FLOAT: - conv.i = sget4(value + ofs, order_); - return conv.f; // IEEE FLOATs are already C format, they just need a recast - - default: - return 0.; + default: { + return 0.0; + } } } - unsigned int getCount(int id) + unsigned int getCount(int id) const { - auto it = tags_.find(id); - if (it != tags_.end()) { - return it->second.count; + const Tags::const_iterator tag = tags_.find(id); + if (tag != tags_.end()) { + return tag->second.count; } return 0; } private: - static unsigned short sget2(unsigned char *s, ByteOrder order) + struct Tag { + int id; + std::vector value; + TagType type; + unsigned int count; + }; + + using Tags = std::unordered_map; + + std::uint16_t sget2(const std::uint8_t* s) const { - if (order == INTEL) { + if (order_ == INTEL) { return s[0] | s[1] << 8; } else { return s[0] << 8 | s[1]; } } - static int sget4(unsigned char *s, ByteOrder order) + std::uint32_t sget4(const std::uint8_t* s) const { - if (order == INTEL) { + if (order_ == INTEL) { return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; } else { return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } } - static unsigned short get2(FILE* f, ByteOrder order) + std::uint16_t get2() { - unsigned char str[2] = { 0xff, 0xff }; - fread (str, 1, 2, f); - return sget2(str, order); + std::uint16_t res = std::numeric_limits::max(); + std::fread(&res, 1, 2, file_); + return sget2(reinterpret_cast(&res)); } - static int get4(FILE *f, ByteOrder order) + std::uint32_t get4() { - unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff }; - fread (str, 1, 4, f); - return sget4 (str, order); - } - - static short int int2_to_signed(short unsigned int i) - { - union { - short unsigned int i; - short int s; - } u; - u.i = i; - return u.s; + std::uint32_t res = std::numeric_limits::max(); + std::fread(&res, 1, 4, file_); + return sget4(reinterpret_cast(&res)); } static int getTypeSize(TagType type) { - return ("11124811248484"[type < 14 ? type : 0] - '0'); - } + switch (type) { + case INVALID: + case BYTE: + case ASCII: + case SBYTE: + case UNDEFINED: { + return 1; + } - struct Tag { - int id; - std::vector value; - TagType type; - unsigned int count; + case SHORT: + case SSHORT: { + return 2; + } - Tag(): id(0), value(), type(INVALID), count(0) {} - }; + case LONG: + case SLONG: + case FLOAT: { + return 4; + } - bool parse_tag(Tag &t, FILE *f, int base, ByteOrder order) - { - t.id = get2(f, order); - t.type = (TagType)get2(f, order); - t.count = get4(f, order); - - if (!t.count) { - t.count = 1; + case RATIONAL: + case SRATIONAL: + case DOUBLE: { + return 8; + } } - // filter out invalid tags - // note the large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, + return 1; + } + + bool parseTag(Tag& tag) + { + tag.id = get2(); + tag.type = TagType(get2()); + tag.count = std::max(1U, get4()); + + // Filter out invalid tags + // Note: The large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, // (only a small part of it will actually be parsed though) - if ((int)t.type < 1 || (int)t.type > 12 || t.count > 10 * 1024 * 1024) { - t.type = INVALID; + if ( + tag.type == INVALID + || tag.type > DOUBLE + || tag.count > 10 * 1024 * 1024 + ) { + tag.type = INVALID; return false; } - // store next Tag's position in file - int save = ftell(f) + 4; + // Store next Tag's position in file + const std::size_t saved_position = std::ftell(file_) + 4; - // load value field (possibly seek before) - int valuesize = t.count * getTypeSize(t.type); + // Load value field (possibly seek before) + const std::size_t value_size = tag.count * getTypeSize(tag.type); - if (valuesize > 4) { - fseek(f, get4(f, order) + base, SEEK_SET); + if (value_size > 4) { + if (std::fseek(file_, get4(), SEEK_SET) == -1) { + tag.type = INVALID; + return false; + } } - // read value - t.value.resize(valuesize + 1); - auto readSize = fread(&(t.value[0]), 1, valuesize, f); - t.value[readSize] = '\0'; + // Read value + tag.value.resize(value_size + 1); + const std::size_t read = std::fread(tag.value.data(), 1, value_size, file_); + if (read != value_size) { + tag.type = INVALID; + return false; + } + tag.value[read] = '\0'; + + // Seek back to the saved position + std::fseek(file_, saved_position, SEEK_SET); - // seek back to the saved position - fseek(f, save, SEEK_SET); return true; } - std::unordered_map tags_; + FILE* const file_; + + Tags tags_; ByteOrder order_; - FILE *file_; }; } // namespace From fa63b2f7a6a2cc949d9c8a072a88eacb57fb353e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 23 May 2019 15:34:06 +0200 Subject: [PATCH 004/110] Fix EXV_UNICODE_PATH `std::wstring` conversion --- rtengine/imagedata.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 1890739b8..6897490ac 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -41,8 +41,13 @@ extern const Settings *settings; Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) { #ifdef EXV_UNICODE_PATH - const auto* const ws = g_utf8_to_utf16(fname.c_str(), -1, NULL, NULL, NULL); - const std::wstring wfname(ws); + glong ws_size = 0; + gunichar2* const ws = g_utf8_to_utf16(fname.c_str(), -1, nullptr, &ws_size, nullptr); + std::wstring wfname; + wfname.reserve(ws_size); + for (glong i = 0; i < ws_size; ++i) { + wfname.push_back(ws[i]); + } g_free(ws); auto image = Exiv2::ImageFactory::open(wfname); #else From d9799ec5de7f047ccee0496d2e9aa62fe2cd00ee Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Fri, 16 Oct 2020 12:39:17 +0200 Subject: [PATCH 005/110] Fix dcp.cc with some help from the implementation in ART --- clean.bat | 1 - rtengine/CMakeLists.txt | 1 - rtengine/dcp.cc | 660 ++++++++++++++++++---------------------- rtengine/dcp.h | 39 +-- rtengine/imageio.cc | 7 +- rtengine/rtengine.h | 6 - rtengine/rtthumbnail.h | 1 - rtgui/exifpanel.h | 1 - 8 files changed, 327 insertions(+), 389 deletions(-) diff --git a/clean.bat b/clean.bat index 52e77f954..7196af4b0 100644 --- a/clean.bat +++ b/clean.bat @@ -20,4 +20,3 @@ del .\rtdata\Makefile del .\rtengine\librtengine.so del .\rtengine\librtengine.a del .\rtgui\rawtherapee -del .\rtexif\librtexif.a diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index a4ab82f3d..43d658e66 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -1,4 +1,3 @@ -<<<<<<< HEAD if(EXTRA_INCDIR) include_directories("${EXTRA_INCDIR}") endif() diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 3c20ea0c1..7d9295c71 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -21,9 +21,7 @@ #include #include #include -#include -#include -#include +#include #include "dcp.h" @@ -35,9 +33,15 @@ #include "rawimagesource.h" #include "rt_math.h" #include "utils.h" -#include "../rtexif/rtexif.h" #include "../rtgui/options.h" +namespace rtengine +{ + +extern const Settings* settings; + +} + using namespace rtengine; namespace @@ -48,7 +52,7 @@ namespace DCPProfile::Matrix invert3x3(const DCPProfile::Matrix& a) { DCPProfile::Matrix res = a; - if (!invertMatrix(a, res)) { + if (!invertMatrix(a, res) && settings->verbose) { std::cerr << "DCP matrix cannot be inverted! Expect weird output." << std::endl; } return res; @@ -333,6 +337,8 @@ double xyCoordToTemperature(const std::array& white_xy) // Search for line pair coordinate is between. double last_dt = 0.0; + double last_dv = 0.0; + double last_du = 0.0; for (uint32_t index = 1; index <= 30; ++index) { // Convert slope to delta-u and delta-v, with length 1. @@ -368,11 +374,23 @@ double xyCoordToTemperature(const std::array& white_xy) // Interpolate the temperature. res = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f)); + + // Find delta from black body point to test coordinate. + uu = u - (temp_table [index - 1].u * f + temp_table [index].u * (1.0 - f)); + vv = v - (temp_table [index - 1].v * f + temp_table [index].v * (1.0 - f)); + // Interpolate vectors along slope. + du = du * (1.0 - f) + last_du * f; + dv = dv * (1.0 - f) + last_dv * f; + len = sqrt (du * du + dv * dv); + du /= len; + dv /= len; break; } // Try next line pair. last_dt = dt; + last_du = du; + last_dv = dv; } return res; @@ -431,7 +449,6 @@ std::map getAliases(const Glib::ustring& profile_dir) class DCPMetadata { -private: enum TagType { INVALID = 0, BYTE = 1, @@ -455,17 +472,17 @@ private: }; public: - explicit DCPMetadata(FILE* file) : - file_(file), - order_(UNKNOWN) - { - } + explicit DCPMetadata(FILE *file): order_(UNKNOWN), file_(file) {} bool parse() { - if (!file_) { + int offset = 0; + FILE *f = file_; + if (!f) { #ifndef NDEBUG - std::cerr << "ERROR: No file opened." << std::endl; + if (settings->verbose) { + std::cerr << "ERROR : no file opened !" << std::endl; + } #endif return false; } @@ -473,28 +490,31 @@ public: setlocale(LC_NUMERIC, "C"); // to set decimal point in sscanf // read tiff header - std::fseek(file_, 0, SEEK_SET); - std::uint16_t bo; - std::fread(&bo, 1, 2, file_); - order_ = ByteOrder(bo); + fseek(f, 0, SEEK_SET); + unsigned short bo; + fread(&bo, 1, 2, f); + order_ = ByteOrder(int(bo)); + + get2(f, order_); + if (!offset) { + offset = get4(f, order_); + } - get2(); // Skip + // seek to IFD + fseek(f, offset, SEEK_SET); - // Seek to IFD - const std::size_t offset = get4(); - std::fseek(file_, offset, SEEK_SET); + // first read the IFD directory + int numtags = get2(f, order_); - // First read the IFD directory - const std::uint16_t numtags = get2(); - - if (numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit + if (numtags <= 0 || numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit return false; } - for (std::uint16_t i = 0; i < numtags; ++i) { - Tag tag; - if (parseTag(tag)) { - tags_[tag.id] = std::move(tag); + int base = 0; + for (int i = 0; i < numtags; i++) { + Tag t; + if (parse_tag(t, f, base, order_)) { + tags_[t.id] = std::move(t); } } @@ -505,304 +525,221 @@ public: { return tags_.find(id) != tags_.end(); } - - std::string toString(int id) const + + std::string toString(int id) { - const Tags::const_iterator tag = tags_.find(id); - if (tag != tags_.end()) { - if (tag->second.type == ASCII) { - return std::string(tag->second.value.begin(), tag->second.value.end()).c_str(); + auto it = tags_.find(id); + if (it != tags_.end()) { + auto &t = it->second; + if (t.type == ASCII) { + std::ostringstream buf; + unsigned char *value = &(t.value[0]); + buf << value; + return buf.str(); } } - return {}; + return ""; } - std::int32_t toInt(int id, std::size_t offset = 0, TagType as_type = INVALID) const + int toInt(int id, int ofs=0, TagType astype=INVALID) { - const Tags::const_iterator tag = tags_.find(id); - if (tag == tags_.end()) { + auto it = tags_.find(id); + if (it == tags_.end()) { return 0; } - if (as_type == INVALID) { - as_type = tag->second.type; + auto &t = it->second; + int a; + unsigned char *value = &(t.value[0]); + + if (astype == INVALID) { + astype = t.type; } - switch (as_type) { - case SBYTE: { - if (offset < tag->second.value.size()) { - return static_cast(tag->second.value[offset]); - } - return 0; - } - - case BYTE: { - if (offset < tag->second.value.size()) { - return tag->second.value[offset]; - } - return 0; - } - - case SSHORT: { - if (offset + 1 < tag->second.value.size()) { - return static_cast(sget2(tag->second.value.data() + offset)); - } - return 0; - } - - case SHORT: { - if (offset + 1 < tag->second.value.size()) { - return sget2(tag->second.value.data() + offset); - } - return 0; - } - - case SLONG: - case LONG: { - if (offset + 3 < tag->second.value.size()) { - return sget4(tag->second.value.data() + offset); - } - return 0; - } - - case SRATIONAL: - case RATIONAL: { - if (offset + 7 < tag->second.value.size()) { - const std::uint32_t denominator = sget4(tag->second.value.data() + offset + 4); - return - denominator == 0 - ? 0 - : static_cast(sget4(tag->second.value.data() + offset)) / denominator; - } - return 0; - } - - case FLOAT: { - return toDouble(id, offset); - } - - default: { - return 0; - } + switch (astype) { + case SBYTE: + return reinterpret_cast(value)[ofs]; + case BYTE: + return value[ofs]; + case SSHORT: + return int2_to_signed(sget2(value + ofs, order_)); + case SHORT: + return sget2(value + ofs, order_); + case SLONG: + case LONG: + return sget4 (value + ofs, order_); + case SRATIONAL: + case RATIONAL: + a = sget4(value + ofs + 4, order_); + return a == 0 ? 0 : int(sget4(value + ofs, order_)) / a; + case FLOAT: + return toDouble(id, ofs); + default: + return 0; + } } - - int toShort(int id, std::size_t offset = 0) const + + int toShort(int id, int ofs=0) { - return toInt(id, offset, SHORT); + return toInt(id, ofs, SHORT); } - - double toDouble(int id, std::size_t offset = 0) const + + double toDouble(int id, int ofs=0) { - const Tags::const_iterator tag = tags_.find(id); - if (tag == tags_.end()) { + auto it = tags_.find(id); + if (it == tags_.end()) { return 0.0; } - switch (tag->second.type) { - case SBYTE: { - if (offset < tag->second.value.size()) { - return static_cast(tag->second.value[offset]); - } - return 0.0; - } + auto &t = it->second; + + union IntFloat { + uint32_t i; + float f; + } conv; - case BYTE: { - if (offset < tag->second.value.size()) { - return tag->second.value[offset]; - } - return 0.0; - } - - case SSHORT: { - if (offset + 1 < tag->second.value.size()) { - return static_cast(sget2(tag->second.value.data() + offset)); - } - return 0.0; - } - - case SHORT: { - if (offset + 1 < tag->second.value.size()) { - return sget2(tag->second.value.data() + offset); - } - return 0.0; - } - - case SLONG: - case LONG: { - if (offset + 3 < tag->second.value.size()) { - return sget4(tag->second.value.data() + offset); - } - return 0.0; - } - - case SRATIONAL: - case RATIONAL: { - if (offset + 7 < tag->second.value.size()) { - const std::int32_t numerator = sget4(tag->second.value.data() + offset); - const std::int32_t denominator = sget4(tag->second.value.data() + offset + 4); - return - denominator == 0 - ? 0.0 - : static_cast(numerator) / static_cast(denominator); - } - return 0.0; - } - - case FLOAT: { - union IntFloat { - std::uint32_t i; - float f; - } conv; - - conv.i = sget4(tag->second.value.data() + offset); - return conv.f; // IEEE FLOATs are already C format, they just need a recast - } - - default: { - return 0.0; - } + int ud, dd; + unsigned char *value = &(t.value[0]); + + switch (t.type) { + case SBYTE: + return int((reinterpret_cast (value))[ofs]); + case BYTE: + return int(value[ofs]); + case SSHORT: + return int2_to_signed(sget2(value + ofs, order_)); + case SHORT: + return sget2(value + ofs, order_); + case SLONG: + case LONG: + return sget4(value + ofs, order_); + case SRATIONAL: + case RATIONAL: + ud = sget4(value + ofs, order_); + dd = sget4(value + ofs + 4, order_); + return (dd ? double(ud)/double(dd) : 0.0); + case FLOAT: + conv.i = sget4(value + ofs, order_); + return conv.f; // IEEE FLOATs are already C format, they just need a recast + default: + return 0.; + } } - unsigned int getCount(int id) const + unsigned int getCount(int id) { - const Tags::const_iterator tag = tags_.find(id); - if (tag != tags_.end()) { - return tag->second.count; + auto it = tags_.find(id); + if (it != tags_.end()) { + return it->second.count; } return 0; } private: - struct Tag { - int id; - std::vector value; - TagType type; - unsigned int count; - }; - - using Tags = std::unordered_map; - - std::uint16_t sget2(const std::uint8_t* s) const + static unsigned short sget2(unsigned char *s, ByteOrder order) { - if (order_ == INTEL) { + if (order == INTEL) { return s[0] | s[1] << 8; } else { return s[0] << 8 | s[1]; } } - - std::uint32_t sget4(const std::uint8_t* s) const + + static int sget4(unsigned char *s, ByteOrder order) { - if (order_ == INTEL) { + if (order == INTEL) { return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; } else { return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } } - - std::uint16_t get2() - { - std::uint16_t res = std::numeric_limits::max(); - std::fread(&res, 1, 2, file_); - return sget2(reinterpret_cast(&res)); + + static unsigned short get2(FILE* f, ByteOrder order) + { + unsigned char str[2] = { 0xff, 0xff }; + fread (str, 1, 2, f); + return sget2(str, order); } - - std::uint32_t get4() + + static int get4(FILE *f, ByteOrder order) + { + unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff }; + fread (str, 1, 4, f); + return sget4 (str, order); + } + + static short int int2_to_signed(short unsigned int i) { - std::uint32_t res = std::numeric_limits::max(); - std::fread(&res, 1, 4, file_); - return sget4(reinterpret_cast(&res)); + union { + short unsigned int i; + short int s; + } u; + u.i = i; + return u.s; } static int getTypeSize(TagType type) { - switch (type) { - case INVALID: - case BYTE: - case ASCII: - case SBYTE: - case UNDEFINED: { - return 1; - } - - case SHORT: - case SSHORT: { - return 2; - } - - case LONG: - case SLONG: - case FLOAT: { - return 4; - } - - case RATIONAL: - case SRATIONAL: - case DOUBLE: { - return 8; - } - } - - return 1; + return ("11124811248484"[type < 14 ? type : 0] - '0'); } - bool parseTag(Tag& tag) + struct Tag { + int id; + std::vector value; + TagType type; + unsigned int count; + + Tag(): id(0), value(), type(INVALID), count(0) {} + }; + + bool parse_tag(Tag &t, FILE *f, int base, ByteOrder order) { - tag.id = get2(); - tag.type = TagType(get2()); - tag.count = std::max(1U, get4()); + t.id = get2(f, order); + t.type = (TagType)get2(f, order); + t.count = get4(f, order); - // Filter out invalid tags - // Note: The large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, + if (!t.count) { + t.count = 1; + } + + // filter out invalid tags + // note the large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, // (only a small part of it will actually be parsed though) - if ( - tag.type == INVALID - || tag.type > DOUBLE - || tag.count > 10 * 1024 * 1024 - ) { - tag.type = INVALID; + if ((int)t.type < 1 || (int)t.type > 12 || t.count > 10 * 1024 * 1024) { + t.type = INVALID; return false; } - // Store next Tag's position in file - const std::size_t saved_position = std::ftell(file_) + 4; + // store next Tag's position in file + int save = ftell(f) + 4; - // Load value field (possibly seek before) - const std::size_t value_size = tag.count * getTypeSize(tag.type); + // load value field (possibly seek before) + int valuesize = t.count * getTypeSize(t.type); - if (value_size > 4) { - if (std::fseek(file_, get4(), SEEK_SET) == -1) { - tag.type = INVALID; - return false; - } + if (valuesize > 4) { + fseek(f, get4(f, order) + base, SEEK_SET); } - // Read value - tag.value.resize(value_size + 1); - const std::size_t read = std::fread(tag.value.data(), 1, value_size, file_); - if (read != value_size) { - tag.type = INVALID; - return false; - } - tag.value[read] = '\0'; - - // Seek back to the saved position - std::fseek(file_, saved_position, SEEK_SET); + // read value + t.value.resize(valuesize + 1); + auto readSize = fread(&(t.value[0]), 1, valuesize, f); + t.value[readSize] = '\0'; + // seek back to the saved position + fseek(f, save, SEEK_SET); return true; } - FILE* const file_; - - Tags tags_; + std::unordered_map tags_; ByteOrder order_; + FILE *file_; }; } // namespace -struct DCPProfileApplyState::Data { +struct DCPProfile::ApplyState::Data { float pro_photo[3][3]; float work[3][3]; bool already_pro_photo; @@ -811,12 +748,14 @@ struct DCPProfileApplyState::Data { float bl_scale; }; -DCPProfileApplyState::DCPProfileApplyState() : +DCPProfile::ApplyState::ApplyState() : data(new Data{}) { } -DCPProfileApplyState::~DCPProfileApplyState() = default; +DCPProfile::ApplyState::~ApplyState() +{ +} DCPProfile::DCPProfile(const Glib::ustring& filename) : has_color_matrix_1(false), @@ -833,22 +772,22 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : constexpr int tiff_float_size = 4; enum TagKey { - TAG_KEY_COLOR_MATRIX_1 = 50721, - TAG_KEY_COLOR_MATRIX_2 = 50722, - TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS = 50937, - TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1 = 50938, - TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2 = 50939, - TAG_KEY_PROFILE_TONE_CURVE = 50940, - TAG_KEY_PROFILE_TONE_COPYRIGHT = 50942, - TAG_KEY_CALIBRATION_ILLUMINANT_1 = 50778, - TAG_KEY_CALIBRATION_ILLUMINANT_2 = 50779, - TAG_KEY_FORWARD_MATRIX_1 = 50964, - TAG_KEY_FORWARD_MATRIX_2 = 50965, - TAG_KEY_PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant - TAG_KEY_PROFILE_LOOK_TABLE_DATA = 50982, - TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING = 51107, - TAG_KEY_PROFILE_LOOK_TABLE_ENCODING = 51108, - TAG_KEY_BASELINE_EXPOSURE_OFFSET = 51109 + COLOR_MATRIX_1 = 50721, + COLOR_MATRIX_2 = 50722, + PROFILE_HUE_SAT_MAP_DIMS = 50937, + PROFILE_HUE_SAT_MAP_DATA_1 = 50938, + PROFILE_HUE_SAT_MAP_DATA_2 = 50939, + PROFILE_TONE_CURVE = 50940, + PROFILE_TONE_COPYRIGHT = 50942, + CALIBRATION_ILLUMINANT_1 = 50778, + CALIBRATION_ILLUMINANT_2 = 50779, + FORWARD_MATRIX_1 = 50964, + FORWARD_MATRIX_2 = 50965, + PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant + PROFILE_LOOK_TABLE_DATA = 50982, + PROFILE_HUE_SAT_MAP_ENCODING = 51107, + PROFILE_LOOK_TABLE_ENCODING = 51108, + BASELINE_EXPOSURE_OFFSET = 51109 }; static const float adobe_camera_raw_default_curve[] = { @@ -1114,53 +1053,55 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : FILE* const file = g_fopen(filename.c_str(), "rb"); if (file == nullptr) { - printf ("Unable to load DCP profile '%s' !", filename.c_str()); + //printf ("Unable to load DCP profile '%s' !", filename.c_str()); return; } DCPMetadata md(file); if (!md.parse()) { - printf ("Unable to load DCP profile '%s'.", filename.c_str()); + //printf ("Unable to load DCP profile '%s'.", filename.c_str()); return; } light_source_1 = - md.find(TAG_KEY_CALIBRATION_ILLUMINANT_1) - ? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_1) - : -1; + md.find(CALIBRATION_ILLUMINANT_1) ? + md.toShort(CALIBRATION_ILLUMINANT_1) : + -1; light_source_2 = - md.find(TAG_KEY_CALIBRATION_ILLUMINANT_2) - ? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_2) - : -1; + md.find(CALIBRATION_ILLUMINANT_2) ? + md.toShort(CALIBRATION_ILLUMINANT_2) : + -1; temperature_1 = calibrationIlluminantToTemperature(light_source_1); temperature_2 = calibrationIlluminantToTemperature(light_source_2); - const bool has_second_hue_sat = md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat + const bool has_second_hue_sat = md.find(PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat // Fetch Forward Matrices, if any - has_forward_matrix_1 = md.find(TAG_KEY_FORWARD_MATRIX_1); + has_forward_matrix_1 = md.find(FORWARD_MATRIX_1); if (has_forward_matrix_1) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_1[row][col] = md.toDouble(TAG_KEY_FORWARD_MATRIX_1, (col + row * 3) * 8); + forward_matrix_1[row][col] = md.toDouble(FORWARD_MATRIX_1, (col + row * 3) * 8); } } } - has_forward_matrix_2 = md.find(TAG_KEY_FORWARD_MATRIX_2); + has_forward_matrix_2 = md.find(FORWARD_MATRIX_2); if (has_forward_matrix_2) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_2[row][col] = md.toDouble(TAG_KEY_FORWARD_MATRIX_2, (col + row * 3) * 8); + forward_matrix_2[row][col] = md.toDouble(FORWARD_MATRIX_2, (col + row * 3) * 8); } } } // Color Matrix (one is always there) - if (!md.find(TAG_KEY_COLOR_MATRIX_1)) { - std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; + if (!md.find(COLOR_MATRIX_1)) { + if (settings->verbose) { + std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; + } fclose(file); return; } @@ -1169,24 +1110,24 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - color_matrix_1[row][col] = md.toDouble(TAG_KEY_COLOR_MATRIX_1, (col + row * 3) * 8); + color_matrix_1[row][col] = md.toDouble(COLOR_MATRIX_1, (col + row * 3) * 8); } } - if (md.find(TAG_KEY_PROFILE_LOOK_TABLE_DIMS)) { - look_info.hue_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 0); - look_info.sat_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 4); - look_info.val_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 8); + if (md.find(PROFILE_LOOK_TABLE_DIMS)) { + look_info.hue_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 0); + look_info.sat_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 4); + look_info.val_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 8); - look_info.srgb_gamma = md.find(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING) && md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING); + look_info.srgb_gamma = md.find(PROFILE_LOOK_TABLE_ENCODING) && md.toInt(PROFILE_LOOK_TABLE_ENCODING); - look_info.array_count = md.getCount(TAG_KEY_PROFILE_LOOK_TABLE_DATA) / 3; + look_info.array_count = md.getCount(PROFILE_LOOK_TABLE_DATA) / 3; look_table.resize(look_info.array_count); for (unsigned int i = 0; i < look_info.array_count; i++) { - look_table[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); - look_table[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); - look_table[i].val_scale = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); + look_table[i].hue_shift = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); + look_table[i].sat_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); + look_table[i].val_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); } // Precalculated constants for table application @@ -1203,20 +1144,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step; } - if (md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS)) { - delta_info.hue_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 0); - delta_info.sat_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 4); - delta_info.val_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 8); + if (md.find(PROFILE_HUE_SAT_MAP_DIMS)) { + delta_info.hue_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 0); + delta_info.sat_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 4); + delta_info.val_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 8); - delta_info.srgb_gamma = md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING); + delta_info.srgb_gamma = md.find(PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(PROFILE_HUE_SAT_MAP_ENCODING); - delta_info.array_count = md.getCount(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1) / 3; + delta_info.array_count = md.getCount(PROFILE_HUE_SAT_MAP_DATA_1) / 3; deltas_1.resize(delta_info.array_count); for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_1[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); - deltas_1[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); - deltas_1[i].val_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); + deltas_1[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); + deltas_1[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); + deltas_1[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); } delta_info.pc.h_scale = @@ -1236,14 +1177,14 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Second matrix has_color_matrix_2 = true; - const bool cm2 = md.find(TAG_KEY_COLOR_MATRIX_2); + bool cm2 = md.find(COLOR_MATRIX_2); for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { color_matrix_2[row][col] = cm2 - ? md.toDouble(TAG_KEY_COLOR_MATRIX_2, (col + row * 3) * 8) - : color_matrix_1[row][col]; + ? md.toDouble(COLOR_MATRIX_2, (col + row * 3) * 8) + : color_matrix_1[row][col]; } } @@ -1253,20 +1194,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Saturation maps. Need to be unwinded. for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_2[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); - deltas_2[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); - deltas_2[i].val_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); + deltas_2[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); + deltas_2[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); + deltas_2[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); } } } - has_baseline_exposure_offset = md.find(TAG_KEY_BASELINE_EXPOSURE_OFFSET); + has_baseline_exposure_offset = md.find(BASELINE_EXPOSURE_OFFSET); if (has_baseline_exposure_offset) { - baseline_exposure_offset = md.toDouble(TAG_KEY_BASELINE_EXPOSURE_OFFSET); + baseline_exposure_offset = md.toDouble(BASELINE_EXPOSURE_OFFSET); } // Read tone curve points, if any, but disable to RTs own profiles - if (md.find(TAG_KEY_PROFILE_TONE_CURVE)) { + if (md.find(PROFILE_TONE_CURVE)) { std::vector curve_points = { static_cast(DCT_Spline) // The first value is the curve type }; @@ -1274,9 +1215,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Push back each X/Y coordinates in a loop bool curve_is_linear = true; - for (unsigned int i = 0, n = md.getCount(TAG_KEY_PROFILE_TONE_CURVE); i < n; i += 2) { - const double x = md.toDouble(TAG_KEY_PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); - const double y = md.toDouble(TAG_KEY_PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); + for (unsigned int i = 0, n = md.getCount(PROFILE_TONE_CURVE); i < n; i += 2) { + const double x = md.toDouble(PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); + const double y = md.toDouble(PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); if (x != y) { curve_is_linear = false; @@ -1292,7 +1233,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tone_curve.Set(DiagonalCurve(curve_points, CURVES_MIN_POLY_POINTS)); } } else { - if (md.find(TAG_KEY_PROFILE_TONE_COPYRIGHT) && md.toString(TAG_KEY_PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { + if (md.find(PROFILE_TONE_COPYRIGHT) && md.toString(PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { // An Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that std::vector curve_points = { static_cast(DCT_Spline) @@ -1390,31 +1331,32 @@ void DCPProfile::apply( const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool apply_hue_sat_map + bool apply_hue_sat_map, + bool apply_look_table ) const { const TMatrix work_matrix = ICCStore::getInstance()->workingSpaceInverseMatrix(working_space); - const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix - const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); if (delta_base.empty()) { apply_hue_sat_map = false; } + const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, apply_hue_sat_map || apply_look_table); // Camera RGB to XYZ D50 matrix + if (!apply_hue_sat_map) { // The fast path: No LUT --> Calculate matrix for direct conversion raw -> working space float mat[3][3] = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - double temp = 0.0; + for (int k = 0; k < 3; ++k) { - temp += work_matrix[i][k] * xyz_cam[k][j]; + mat[i][j] += work_matrix[i][k] * xyz_cam[k][j]; } - mat[i][j] = temp; + } } @@ -1440,11 +1382,11 @@ void DCPProfile::apply( for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - double temp = 0.0; + for (int k = 0; k < 3; ++k) { - temp += prophoto_xyz[i][k] * xyz_cam[k][j]; + pro_photo[i][j] += prophoto_xyz[i][k] * xyz_cam[k][j]; } - pro_photo[i][j] = temp; + } } @@ -1452,11 +1394,11 @@ void DCPProfile::apply( for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - double temp = 0.0; + for (int k = 0; k < 3; ++k) { - temp += work_matrix[i][k] * xyz_prophoto[k][j]; + work[i][j] += work_matrix[i][k] * xyz_prophoto[k][j]; } - work[i][j] = temp; + } } @@ -1498,7 +1440,7 @@ void DCPProfile::apply( } } -void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, DCPProfileApplyState& as_out) +void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out) { as_out.data->use_tone_curve = use_tone_curve; as_out.data->apply_look_table = apply_look_table; @@ -1527,11 +1469,9 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - double temp = 0.0; for (int k = 0; k < 3; k++) { - temp += prophoto_xyz[i][k] * mWork[k][j]; + as_out.data->pro_photo[i][j] += prophoto_xyz[i][k] * mWork[k][j]; } - as_out.data->pro_photo[i][j] = temp; } } @@ -1540,20 +1480,18 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - double temp = 0.0; for (int k = 0; k < 3; k++) { - temp += mWork[i][k] * xyz_prophoto[k][j]; + as_out.data->work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; } - as_out.data->work[i][j] = temp; } } } } -void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int height, int tile_width, const DCPProfileApplyState& as_in) const +void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int height, int tile_width, const ApplyState& as_in) const { -#define FCLIP(a) ((a)>0.f?((a)<65535.5f?(a):65535.5f):0.f) +#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) #define CLIP01(a) ((a)>0?((a)<1?(a):1):0) float exp_scale = as_in.data->bl_scale; @@ -1992,7 +1930,7 @@ std::vector DCPProfile::makeHueSatMap(const ColorTemp& wh return res; } -inline void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const +void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const { // Apply the HueSatMap. Ported from Adobes reference implementation. float hue_shift; @@ -2177,7 +2115,8 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) && lastdot <= sname.size() - 4 && !sname.casefold().compare(lastdot, 4, ".dcp") ) { - file_std_profiles[sname.substr(0, lastdot).casefold_collate_key()] = fname; // They will be loaded and cached on demand + const Glib::ustring cam_short_name = sname.substr(0, lastdot).uppercase(); + file_std_profiles[cam_short_name] = fname; // They will be loaded and cached on demand } } else { // Directory @@ -2188,10 +2127,11 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) for (const auto& alias : getAliases(rt_profile_dir)) { const Glib::ustring alias_name = Glib::ustring(alias.first).uppercase(); - const std::map::const_iterator real = file_std_profiles.find(Glib::ustring(alias.second).casefold_collate_key()); + const Glib::ustring real_name = Glib::ustring(alias.second).uppercase(); + const std::map::const_iterator real = file_std_profiles.find(real_name); if (real != file_std_profiles.end()) { - file_std_profiles[alias_name.casefold_collate_key()] = real->second; + file_std_profiles[alias_name] = real->second; } } } @@ -2213,20 +2153,20 @@ bool DCPStore::isValidDCPFileName(const Glib::ustring& filename) const DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const { - const auto key = filename.casefold_collate_key(); MyMutex::MyLock lock(mutex); - const std::map::const_iterator iter = profile_cache.find(key); - if (iter != profile_cache.end()) { - return iter->second; + const std::map::iterator r = profile_cache.find(filename); + + if (r != profile_cache.end()) { + return r->second; } DCPProfile* const res = new DCPProfile(filename); if (res->isValid()) { // Add profile - profile_cache[key] = res; - if (settings->verbose) { + profile_cache[filename] = res; + if (options.rtSettings.verbose) { printf("DCP profile '%s' loaded from disk\n", filename.c_str()); } return res; @@ -2238,9 +2178,13 @@ DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const DCPProfile* DCPStore::getStdProfile(const Glib::ustring& requested_cam_short_name) const { - const std::map::const_iterator iter = file_std_profiles.find(requested_cam_short_name.casefold_collate_key()); - if (iter != file_std_profiles.end()) { - return getProfile(iter->second); + const Glib::ustring name = requested_cam_short_name.uppercase(); + + // Warning: do NOT use map.find(), since it does not seem to work reliably here + for (const auto& file_std_profile : file_std_profiles) { + if (file_std_profile.first == name) { + return getProfile(file_std_profile.second); + } } // profile not found, looking if we're in loadAll=false mode diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 573349348..c818d9b6c 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -41,6 +41,20 @@ class DCPProfileApplyState; class DCPProfile final { public: + class ApplyState final + { + public: + ApplyState(); + ~ApplyState(); + + private: + struct Data; + + std::unique_ptr data; + + friend class DCPProfile; + }; + struct Illuminants { short light_source_1; short light_source_2; @@ -72,10 +86,11 @@ public: const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool apply_hue_sat_map = true + bool apply_hue_sat_map, + bool apply_look_table ) const; - void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, DCPProfileApplyState& as_out); - void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const DCPProfileApplyState& as_in) const; + void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out); + void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const; private: struct HsbModify { @@ -136,20 +151,6 @@ private: AdobeToneCurve tone_curve; }; -class DCPProfileApplyState final -{ -public: - DCPProfileApplyState(); - ~DCPProfileApplyState(); - -private: - struct Data; - - const std::unique_ptr data; - - friend class DCPProfile; -}; - class DCPStore final : public NonCopyable { @@ -171,10 +172,10 @@ private: std::vector profileDir; // these contain standard profiles from RT. keys are all in uppercase, file path is value - std::map file_std_profiles; + std::map file_std_profiles; // Maps file name to profile as cache - mutable std::map profile_cache; + mutable std::map profile_cache; }; } diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 37ab1f6b4..4975a6854 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -29,7 +29,6 @@ #include "utils.h" #include "../rtgui/options.h" #include "../rtgui/version.h" -#include "../rtexif/rtexif.h" #ifdef WIN32 #include @@ -1177,6 +1176,10 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_ADOBE_DEFLATE); TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, (bps == 16 || bps == 32) && isFloat ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT); + /* + + TODO: Re-apply fix from #5787 + [out]() { const std::vector default_tags = rtexif::ExifManager::getDefaultTIFFTags(nullptr); @@ -1188,7 +1191,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u for (auto default_tag : default_tags) { delete default_tag; } - }(); + }();*/ if (!uncompressed) { TIFFSetField (out, TIFFTAG_PREDICTOR, (bps == 16 || bps == 32) && isFloat ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL); diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index b56e3b17f..a63e52ab7 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -47,12 +47,6 @@ class LUT; using LUTu = LUT; class EditDataProvider; -namespace rtexif -{ - -class TagDirectory; - -} namespace rtengine { diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index e1ebf2893..698b8f411 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -24,7 +24,6 @@ #include "image8.h" #include "imagefloat.h" #include "LUT.h" -#include "rawmetadatalocation.h" #include "../rtgui/threadutils.h" diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index ce6a6ba42..fc0cad111 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -23,7 +23,6 @@ #include #include "toolpanel.h" -#include "../rtexif/rtexif.h" namespace rtengine { From 9ee48d83f912d27e06670e38e30a5af4c8f65220 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Fri, 16 Oct 2020 12:43:59 +0200 Subject: [PATCH 006/110] Fix references to DCPProfile::ApplyState --- rtengine/dcp.h | 1 - rtengine/dcrop.cc | 2 +- rtengine/imagesource.h | 4 ++-- rtengine/improccoordinator.cc | 2 +- rtengine/improcfun.cc | 4 ++-- rtengine/improcfun.h | 6 +++--- rtengine/rawimagesource.h | 2 +- rtengine/rtthumbnail.cc | 2 +- rtengine/simpleprocess.cc | 2 +- 9 files changed, 12 insertions(+), 13 deletions(-) diff --git a/rtengine/dcp.h b/rtengine/dcp.h index c818d9b6c..69020c23b 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -36,7 +36,6 @@ namespace rtengine class ColorTemp; class Imagefloat; -class DCPProfileApplyState; class DCPProfile final { diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index d5596c8ce..ae183ba63 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -820,7 +820,7 @@ void Crop::update(int todo) } */ double rrm, ggm, bbm; - DCPProfileApplyState as; + DCPProfile::ApplyState as; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, as); LUTu histToneCurve; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 31ba98f81..32e8e0b5d 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -42,7 +42,7 @@ namespace rtengine class ColorTemp; class DCPProfile; -class DCPProfileApplyState; +class DCPProfile::ApplyState; class Imagefloat; class RetinexgaintransmissionCurve; class RetinextransmissionCurve; @@ -140,7 +140,7 @@ public: virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW () const = 0; - virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) + virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfile::ApplyState &as) { return nullptr; }; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 30d2d6433..9a6c2e1b2 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -942,7 +942,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) double ggm = 33.; double bbm = 33.; - DCPProfileApplyState as; + DCPProfile::ApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params->icm, as); ipf.rgbProc(oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params->toneCurve.saturation, diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 6b6dbe16d..862939b66 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2011,7 +2011,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, - double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { rgbProc(working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, @@ -2025,7 +2025,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, - DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) + DCPProfile *dcpProf, const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { std::unique_ptr stop; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index d3ee81701..c98e77b29 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -49,7 +49,7 @@ namespace rtengine class ColorAppearance; class ColorGradientCurve; class DCPProfile; -class DCPProfileApplyState; +class DCPProfile::ApplyState; class FlatCurve; class FramesMetaData; class LensCorrection; @@ -157,13 +157,13 @@ public: const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clcurve, const LUTf& cl2curve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, - const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); + const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clcurve, const LUTf& cl2curve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, - int hlcomprthresh, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); + int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); void labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]); void toning2col(float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float rl, float gl, float bl, float rh, float gh, float bh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect); void toningsmh(float r, float g, float b, float &ro, float &go, float &bo, float RedLow, float GreenLow, float BlueLow, float RedMed, float GreenMed, float BlueMed, float RedHigh, float GreenHigh, float BlueHigh, float reducac, int mode, float strProtect); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 12db6be74..6db38d8e1 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -186,7 +186,7 @@ public: void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) override; - DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override; + DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfile::ApplyState &as) override; void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index d45f1b646..2adcf956a 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1329,7 +1329,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT LabImage* labView = new LabImage (fw, fh); DCPProfile *dcpProf = nullptr; - DCPProfileApplyState as; + DCPProfile::ApplyState as; if (isRaw) { cmsHPROFILE dummy; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index d45398d66..f68ee3b76 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1001,7 +1001,7 @@ private: } autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) - DCPProfileApplyState as; + DCPProfile::ApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as); LUTu histToneCurve; From badf92ba644dee87d3c8024a3ba902b76b8f6333 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Fri, 16 Oct 2020 13:30:47 +0200 Subject: [PATCH 007/110] Fix for declared near() function, backport from ART. Various other minor changes. --- rtengine/ashift_dt.c | 3 +++ rtengine/dcp.cc | 7 +++---- rtengine/dcp.h | 3 +-- rtengine/imagedata.cc | 6 ++---- rtengine/imagesource.h | 4 ++-- rtengine/improcfun.h | 1 - 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/rtengine/ashift_dt.c b/rtengine/ashift_dt.c index ce19b6808..c7cd01ef1 100644 --- a/rtengine/ashift_dt.c +++ b/rtengine/ashift_dt.c @@ -103,6 +103,9 @@ using namespace std; //----------------------------------------------------------------------------- // RT: BEGIN COMMENT +#ifdef near +# undef near +#endif #if 0 DT_MODULE_INTROSPECTION(4, dt_iop_ashift_params_t) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 7d9295c71..8f829635b 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1059,7 +1059,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : DCPMetadata md(file); if (!md.parse()) { - //printf ("Unable to load DCP profile '%s'.", filename.c_str()); + //printf ("Unable to load DCP profile '%s' !", filename.c_str()); return; } @@ -1331,8 +1331,7 @@ void DCPProfile::apply( const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool apply_hue_sat_map, - bool apply_look_table + bool apply_hue_sat_map ) const { @@ -1344,7 +1343,7 @@ void DCPProfile::apply( apply_hue_sat_map = false; } - const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, apply_hue_sat_map || apply_look_table); // Camera RGB to XYZ D50 matrix + const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix if (!apply_hue_sat_map) { // The fast path: No LUT --> Calculate matrix for direct conversion raw -> working space diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 69020c23b..d05fdb4cc 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -85,8 +85,7 @@ public: const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool apply_hue_sat_map, - bool apply_look_table + bool apply_hue_sat_map ) const; void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out); void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const; diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 351303bda..3478bfc9f 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -68,11 +68,9 @@ const std::string& validateUft8(const std::string& str, const std::string& on_er return on_error; } -} - -FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) +FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname) { - return new FramesData(fname, std::move(rml), firstFrameOnly); + return new FramesData(fname); } FramesData::FramesData(const Glib::ustring &fname) : diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 32e8e0b5d..87ec9cdb6 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -28,6 +28,7 @@ #include "rtengine.h" #include "colortemp.h" #include "array2D.h" +#include "dcp.h" template class LUT; @@ -41,9 +42,8 @@ namespace rtengine { class ColorTemp; -class DCPProfile; -class DCPProfile::ApplyState; class Imagefloat; +class DCPProfile; class RetinexgaintransmissionCurve; class RetinextransmissionCurve; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index c98e77b29..8672c7159 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -49,7 +49,6 @@ namespace rtengine class ColorAppearance; class ColorGradientCurve; class DCPProfile; -class DCPProfile::ApplyState; class FlatCurve; class FramesMetaData; class LensCorrection; From c8ef1ee6286404ae001ec55467fb04dcc887b75d Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Fri, 16 Oct 2020 16:15:10 +0200 Subject: [PATCH 008/110] Final changes, branch now buildable --- rtengine/rawimagesource.cc | 2 +- rtengine/simpleprocess.cc | 4 ++-- rtgui/controllines.cc | 2 +- rtgui/controllines.h | 5 +++-- rtgui/controlspotpanel.cc | 8 ++++---- rtgui/editwidgets.cc | 14 +++++++------- rtgui/editwidgets.h | 6 +++--- rtgui/exifpanel.cc | 7 ++++--- rtgui/filmnegative.cc | 10 +++++----- rtgui/thumbnail.cc | 9 +++------ rtgui/thumbnail.h | 1 + 11 files changed, 34 insertions(+), 34 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 78864d1ff..870f39d0f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -930,7 +930,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima } } -DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, DCPProfileApplyState &as) +DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, DCPProfile::ApplyState &as) { if (cmp.inputProfile == "(camera)" || cmp.inputProfile == "(none)") { return nullptr; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index f68ee3b76..f32ce35b3 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1719,11 +1719,11 @@ private: } ProfileContent pc = ICCStore::getInstance()->getContent(params.icm.outputProfile); - readyImg->setOutputProfile(pc.getData().c_str(), pc.getData().size()); + readyImg->setOutputProfile(pc.getData()); } } else { // No ICM - readyImg->setOutputProfile(nullptr, 0); + readyImg->setOutputProfile({}); } // t2.set(); diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index 573b3263f..18da514cc 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -31,7 +31,7 @@ using namespace rtengine; ControlLineManager::ControlLineManager(): EditSubscriber(ET_OBJECTS), - canvas_area(new Rectangle()), + canvas_area(new EditRectangle()), cursor(CSHandOpen), draw_mode(false), drawing_line(false), diff --git a/rtgui/controllines.h b/rtgui/controllines.h index 0ff449092..61bc17678 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -26,9 +26,10 @@ class Circle; class Line; class OPIcon; -class Rectangle; +class EditRectangle; class RTSurface; + struct ControlLine { static constexpr int OBJ_COUNT = 4; std::unique_ptr line; @@ -45,7 +46,7 @@ class ControlLineManager: EditSubscriber protected: /** Hidden object for capturing mouse events. */ - std::unique_ptr canvas_area; + std::unique_ptr canvas_area; rtengine::Coord drag_delta; std::vector> control_lines; CursorShape cursor; diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index 9ed4c95ee..8a08c1d64 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -1852,8 +1852,8 @@ void ControlSpotPanel::addControlSpotCurve(Gtk::TreeModel::Row& row) shape_ellipse = new Ellipse(); shape_ellipse->datum = Geometry::IMAGE; shape_ellipse->radiusInImageSpace = true; - Rectangle* shape_rectangle; - shape_rectangle = new Rectangle(); + EditRectangle* shape_rectangle; + shape_rectangle = new EditRectangle(); shape_rectangle->datum = Geometry::IMAGE; EditSubscriber::visibleGeometry.push_back(centerCircle); // (curveid - 1) * 7 EditSubscriber::visibleGeometry.push_back(shape_ellipse); // (curveid - 1) * 7 + 1 @@ -1887,7 +1887,7 @@ void ControlSpotPanel::addControlSpotCurve(Gtk::TreeModel::Row& row) shape_ellipse = new Ellipse(); shape_ellipse->datum = Geometry::IMAGE; shape_ellipse->radiusInImageSpace = true; - shape_rectangle = new Rectangle(); + shape_rectangle = new EditRectangle(); shape_rectangle->datum = Geometry::IMAGE; EditSubscriber::mouseOverGeometry.push_back(centerCircle); // (curveid - 1) * 7 EditSubscriber::mouseOverGeometry.push_back(shape_ellipse); // (curveid - 1) * 7 + 1 @@ -1957,7 +1957,7 @@ void ControlSpotPanel::updateControlSpotCurve(const Gtk::TreeModel::Row& row) }; const auto updateRectangle = [&](Geometry * geometry) { - const auto rectangle = static_cast(geometry); + const auto rectangle = static_cast(geometry); rectangle->bottomRight.x = origin.x + decayX; rectangle->bottomRight.y = origin.y + decayY; rectangle->topLeft.x = origin.x - decayXL; diff --git a/rtgui/editwidgets.cc b/rtgui/editwidgets.cc index fccdb874a..6611ff519 100644 --- a/rtgui/editwidgets.cc +++ b/rtgui/editwidgets.cc @@ -471,31 +471,31 @@ void Polyline::drawToMOChannel (Cairo::RefPtr &cr, unsigned shor } } -void Rectangle::setXYWH(int left, int top, int width, int height) +void EditRectangle::setXYWH(int left, int top, int width, int height) { topLeft.set(left, top); bottomRight.set(left + width, top + height); } -void Rectangle::setXYXY(int left, int top, int right, int bottom) +void EditRectangle::setXYXY(int left, int top, int right, int bottom) { topLeft.set(left, top); bottomRight.set(right, bottom); } -void Rectangle::setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight) +void EditRectangle::setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight) { this->topLeft = topLeft; this->bottomRight = topLeft + widthHeight; } -void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight) +void EditRectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight) { this->topLeft = topLeft; this->bottomRight = bottomRight; } -void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +void EditRectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && state != INSENSITIVE) { RGBColor color; @@ -538,7 +538,7 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuf } } -void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +void EditRectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_VISIBLE) { if (state != INSENSITIVE) { @@ -602,7 +602,7 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuf } } -void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +void EditRectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_HOVERABLE) { cr->set_line_width( getMouseOverLineWidth() ); diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index c86949cb4..7add435b9 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -307,14 +307,14 @@ public: void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; }; -class Rectangle : public Geometry +class EditRectangle : public Geometry // New class name to avoid conflict elsewhere (exiv2), would be nicer to put in namespace? { public: rtengine::Coord topLeft; rtengine::Coord bottomRight; bool filled; - Rectangle (); + EditRectangle (); void setXYWH(int left, int top, int width, int height); void setXYXY(int left, int top, int right, int bottom); @@ -528,7 +528,7 @@ inline Circle::Circle () : false) { } -inline Rectangle::Rectangle () : +inline EditRectangle::EditRectangle () : topLeft (0, 0), bottomRight (10, 10), filled (false) { } diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index f4ce89f77..a2217086d 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -175,9 +175,10 @@ void ExifPanel::setImageData (const FramesMetaData* id) Gtk::TreeModel::Children ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited) { - if (!value.validate()) { - value = "???"; - } + // TODO Re-fix #5923 if necessary + //if (!value.validate()) { + // value = "???"; + //} auto root = exifTreeModel->children(); diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index d70c2a067..c13f09320 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -124,14 +124,14 @@ FilmNegative::FilmNegative() : filmBaseSpotButton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::baseSpotToggled)); // Editing geometry; create the spot rectangle - Rectangle* const spotRect = new Rectangle(); + EditRectangle* const spotRect = new EditRectangle(); spotRect->filled = false; visibleGeometry.push_back(spotRect); // Stick a dummy rectangle over the whole image in mouseOverGeometry. // This is to make sure the getCursor() call is fired everywhere. - Rectangle* const imgRect = new Rectangle(); + EditRectangle* const imgRect = new EditRectangle(); imgRect->filled = true; mouseOverGeometry.push_back(imgRect); @@ -284,7 +284,7 @@ CursorShape FilmNegative::getCursor(int objectID) const bool FilmNegative::mouseOver(int modifierKey) { EditDataProvider* const provider = getEditProvider(); - Rectangle* const spotRect = static_cast(visibleGeometry.at(0)); + EditRectangle* const spotRect = static_cast(visibleGeometry.at(0)); spotRect->setXYWH(provider->posImage.x - 16, provider->posImage.y - 16, 32, 32); return true; @@ -386,7 +386,7 @@ void FilmNegative::editToggled() // Stick a dummy rectangle over the whole image in mouseOverGeometry. // This is to make sure the getCursor() call is fired everywhere. - Rectangle* const imgRect = static_cast(mouseOverGeometry.at(0)); + EditRectangle* const imgRect = static_cast(mouseOverGeometry.at(0)); imgRect->setXYWH(0, 0, w, h); } else { refSpotCoords.clear(); @@ -408,7 +408,7 @@ void FilmNegative::baseSpotToggled() // Stick a dummy rectangle over the whole image in mouseOverGeometry. // This is to make sure the getCursor() call is fired everywhere. - Rectangle* const imgRect = static_cast(mouseOverGeometry.at(0)); + EditRectangle* const imgRect = static_cast(mouseOverGeometry.at(0)); imgRect->setXYWH(0, 0, w, h); } else { refSpotCoords.clear(); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index fed520acd..10eb28fae 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -41,15 +41,14 @@ #include "md5helper.h" #include "pathutils.h" #include "paramsedited.h" - +#include "ppversion.h" #include "procparamchangers.h" #include "profilestorecombobox.h" #include "version.h" -#include "../rtengine/dynamicprofile.h" -#include "../rtengine/imagedata.h" #include "../rtengine/mytime.h" -#include "../rtengine/procparams.h" + +using namespace rtengine::procparams; namespace { @@ -110,8 +109,6 @@ bool CPBDump( } // namespace -using namespace rtengine::procparams; - Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : fname(fname), cfs(*cf), diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 834c9c297..aa9416f26 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -26,6 +26,7 @@ #include "cacheimagedata.h" #include "threadutils.h" #include "thumbnaillistener.h" +#include "../rtengine/procparams.h" namespace rtengine { From 9fcf45dca5e52ff9133e7c53d1b8e6795a680b37 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Tue, 27 Apr 2021 21:35:43 +0200 Subject: [PATCH 009/110] Several fixes and changes made by Floessie earlier --- rtengine/dcp.cc | 518 +++++++++++++++++++++----------------- rtengine/hilite_recon.cc | 12 +- rtengine/histmatching.cc | 2 +- rtengine/iplocallab.cc | 17 +- rtengine/simpleprocess.cc | 2 +- rtgui/exifpanel.cc | 1 - rtgui/thumbnail.cc | 5 +- 7 files changed, 307 insertions(+), 250 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 8f829635b..feca2422a 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -449,6 +449,7 @@ std::map getAliases(const Glib::ustring& profile_dir) class DCPMetadata { +private: enum TagType { INVALID = 0, BYTE = 1, @@ -472,16 +473,18 @@ class DCPMetadata }; public: - explicit DCPMetadata(FILE *file): order_(UNKNOWN), file_(file) {} + explicit DCPMetadata(FILE *file) : + file_(file), + order_(UNKNOWN) + { + } bool parse() { - int offset = 0; - FILE *f = file_; - if (!f) { + if (!file_) { #ifndef NDEBUG if (settings->verbose) { - std::cerr << "ERROR : no file opened !" << std::endl; + std::cerr << "ERROR: No file opened." << std::endl; } #endif return false; @@ -490,31 +493,28 @@ public: setlocale(LC_NUMERIC, "C"); // to set decimal point in sscanf // read tiff header - fseek(f, 0, SEEK_SET); - unsigned short bo; - fread(&bo, 1, 2, f); - order_ = ByteOrder(int(bo)); + std::fseek(file_, 0, SEEK_SET); + std::uint16_t bo; + std::fread(&bo, 1, 2, file_); + order_ = ByteOrder(bo); - get2(f, order_); - if (!offset) { - offset = get4(f, order_); - } + get2(); // Skip - // seek to IFD - fseek(f, offset, SEEK_SET); + // Seek to IFD + const std::size_t offset = get4(); + std::fseek(file_, offset, SEEK_SET); - // first read the IFD directory - int numtags = get2(f, order_); + // First read the IFD directory + const std::uint16_t numtags = get2(); - if (numtags <= 0 || numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit + if (numtags > 1000) { // KodakIfd has lots of tags, thus 1000 as the limit return false; } - int base = 0; - for (int i = 0; i < numtags; i++) { - Tag t; - if (parse_tag(t, f, base, order_)) { - tags_[t.id] = std::move(t); + for (std::uint16_t i = 0; i < numtags; ++i) { + Tag tag; + if (parseTag(tag)) { + tags_[tag.id] = std::move(tag); } } @@ -526,215 +526,283 @@ public: return tags_.find(id) != tags_.end(); } - std::string toString(int id) + std::string toString(int id) const { - auto it = tags_.find(id); - if (it != tags_.end()) { - auto &t = it->second; - if (t.type == ASCII) { - std::ostringstream buf; - unsigned char *value = &(t.value[0]); - buf << value; - return buf.str(); + const Tags::const_iterator tag = tags_.find(id); + if (tag != tags_.end()) { + if (tag->second.type == ASCII) { + return std::string(tag->second.value.begin(), tag->second.value.end()).c_str(); } } - return ""; + return {}; } - int toInt(int id, int ofs=0, TagType astype=INVALID) + std::int32_t toInt(int id, std::size_t offset = 0, TagType as_type = INVALID) const { - auto it = tags_.find(id); - if (it == tags_.end()) { + const Tags::const_iterator tag = tags_.find(id); + if (tag == tags_.end()) { return 0; } - auto &t = it->second; - int a; - unsigned char *value = &(t.value[0]); - - if (astype == INVALID) { - astype = t.type; + if (as_type == INVALID) { + as_type = tag->second.type; } - switch (astype) { - case SBYTE: - return reinterpret_cast(value)[ofs]; - case BYTE: - return value[ofs]; - case SSHORT: - return int2_to_signed(sget2(value + ofs, order_)); - case SHORT: - return sget2(value + ofs, order_); - case SLONG: - case LONG: - return sget4 (value + ofs, order_); - case SRATIONAL: - case RATIONAL: - a = sget4(value + ofs + 4, order_); - return a == 0 ? 0 : int(sget4(value + ofs, order_)) / a; - case FLOAT: - return toDouble(id, ofs); - default: - return 0; - + switch (as_type) { + case SBYTE: { + if (offset < tag->second.value.size()) { + return static_cast(tag->second.value[offset]); + } + return 0; + } + case BYTE: { + if (offset < tag->second.value.size()) { + return tag->second.value[offset]; + } + return 0; + } + case SSHORT: { + if (offset + 1 < tag->second.value.size()) { + return static_cast(sget2(tag->second.value.data() + offset)); + } + return 0; + } + case SHORT: { + if (offset + 1 < tag->second.value.size()) { + return sget2(tag->second.value.data() + offset); + } + return 0; + } + case SLONG: + case LONG: { + if (offset + 3 < tag->second.value.size()) { + return sget4(tag->second.value.data() + offset); + } + return 0; + } + case SRATIONAL: + case RATIONAL: { + if (offset + 7 < tag->second.value.size()) { + const std::uint32_t denominator = sget4(tag->second.value.data() + offset + 4); + return + denominator == 0 + ? 0 + : static_cast(sget4(tag->second.value.data() + offset)) / denominator; + } + return 0; + } + case FLOAT: { + return toDouble(id, offset); + } + default: { + return 0; + } } } - int toShort(int id, int ofs=0) + int toShort(int id, std::size_t offset = 0) const { - return toInt(id, ofs, SHORT); + return toInt(id, offset, SHORT); } - double toDouble(int id, int ofs=0) + double toDouble(int id, std::size_t offset = 0) const { - auto it = tags_.find(id); - if (it == tags_.end()) { + const Tags::const_iterator tag = tags_.find(id); + if (tag == tags_.end()) { return 0.0; } - - auto &t = it->second; - union IntFloat { - uint32_t i; - float f; - } conv; - - int ud, dd; - unsigned char *value = &(t.value[0]); - - switch (t.type) { - case SBYTE: - return int((reinterpret_cast (value))[ofs]); - case BYTE: - return int(value[ofs]); - case SSHORT: - return int2_to_signed(sget2(value + ofs, order_)); - case SHORT: - return sget2(value + ofs, order_); - case SLONG: - case LONG: - return sget4(value + ofs, order_); - case SRATIONAL: - case RATIONAL: - ud = sget4(value + ofs, order_); - dd = sget4(value + ofs + 4, order_); - return (dd ? double(ud)/double(dd) : 0.0); - case FLOAT: - conv.i = sget4(value + ofs, order_); - return conv.f; // IEEE FLOATs are already C format, they just need a recast - default: - return 0.; - + switch (tag->second.type) { + case SBYTE: { + if (offset < tag->second.value.size()) { + return static_cast(tag->second.value[offset]); + } + return 0.0; + } + case BYTE: { + if (offset < tag->second.value.size()) { + return tag->second.value[offset]; + } + return 0.0; + } + case SSHORT: { + if (offset + 1 < tag->second.value.size()) { + return static_cast(sget2(tag->second.value.data() + offset)); + } + return 0.0; + } + case SHORT: { + if (offset + 1 < tag->second.value.size()) { + return sget2(tag->second.value.data() + offset); + } + return 0.0; + } + case SLONG: + case LONG: { + if (offset + 3 < tag->second.value.size()) { + return sget4(tag->second.value.data() + offset); + } + return 0.0; + } + case SRATIONAL: + case RATIONAL: { + if (offset + 7 < tag->second.value.size()) { + const std::int32_t numerator = sget4(tag->second.value.data() + offset); + const std::int32_t denominator = sget4(tag->second.value.data() + offset + 4); + return + denominator == 0 + ? 0.0 + : static_cast(numerator) / static_cast(denominator); + } + return 0.0; + } + case FLOAT: { + union IntFloat { + std::uint32_t i; + float f; + } conv; + conv.i = sget4(tag->second.value.data() + offset); + return conv.f; // IEEE FLOATs are already C format, they just need a recast + } + default: { + return 0.0; + } } } - unsigned int getCount(int id) + unsigned int getCount(int id) const { - auto it = tags_.find(id); - if (it != tags_.end()) { - return it->second.count; + const Tags::const_iterator tag = tags_.find(id); + if (tag != tags_.end()) { + return tag->second.count; } return 0; } private: - static unsigned short sget2(unsigned char *s, ByteOrder order) + struct Tag { + int id; + std::vector value; + TagType type; + unsigned int count; + }; + + using Tags = std::unordered_map; + + std::uint16_t sget2(const std::uint8_t* s) const { - if (order == INTEL) { + if (order_ == INTEL) { return s[0] | s[1] << 8; } else { return s[0] << 8 | s[1]; } } - static int sget4(unsigned char *s, ByteOrder order) + std::uint32_t sget4(const std::uint8_t* s) const { - if (order == INTEL) { + if (order_ == INTEL) { return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; } else { return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } } - static unsigned short get2(FILE* f, ByteOrder order) + std::uint16_t get2() { - unsigned char str[2] = { 0xff, 0xff }; - fread (str, 1, 2, f); - return sget2(str, order); + std::uint16_t res = std::numeric_limits::max(); + std::fread(&res, 1, 2, file_); + return sget2(reinterpret_cast(&res)); } - static int get4(FILE *f, ByteOrder order) + std::uint32_t get4() { - unsigned char str[4] = { 0xff, 0xff, 0xff, 0xff }; - fread (str, 1, 4, f); - return sget4 (str, order); - } - - static short int int2_to_signed(short unsigned int i) - { - union { - short unsigned int i; - short int s; - } u; - u.i = i; - return u.s; + std::uint32_t res = std::numeric_limits::max(); + std::fread(&res, 1, 4, file_); + return sget4(reinterpret_cast(&res)); } static int getTypeSize(TagType type) { - return ("11124811248484"[type < 14 ? type : 0] - '0'); + switch (type) { + case INVALID: + case BYTE: + case ASCII: + case SBYTE: + case UNDEFINED: { + return 1; + } + + case SHORT: + case SSHORT: { + return 2; + } + + case LONG: + case SLONG: + case FLOAT: { + return 4; + } + + case RATIONAL: + case SRATIONAL: + case DOUBLE: { + return 8; + } + } + + return 1; } - struct Tag { - int id; - std::vector value; - TagType type; - unsigned int count; - - Tag(): id(0), value(), type(INVALID), count(0) {} - }; - - bool parse_tag(Tag &t, FILE *f, int base, ByteOrder order) + bool parseTag(Tag& tag) { - t.id = get2(f, order); - t.type = (TagType)get2(f, order); - t.count = get4(f, order); + tag.id = get2(); + tag.type = TagType(get2()); + tag.count = std::max(1U, get4()); - if (!t.count) { - t.count = 1; - } - - // filter out invalid tags - // note the large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, + // Filter out invalid tags + // Note: The large count is to be able to pass LeafData ASCII tag which can be up to almost 10 megabytes, // (only a small part of it will actually be parsed though) - if ((int)t.type < 1 || (int)t.type > 12 || t.count > 10 * 1024 * 1024) { - t.type = INVALID; + if ( + tag.type == INVALID + || tag.type > DOUBLE + || tag.count > 10 * 1024 * 1024 + ) { + tag.type = INVALID; return false; } - // store next Tag's position in file - int save = ftell(f) + 4; + // Store next Tag's position in file + const std::size_t saved_position = std::ftell(file_) + 4; - // load value field (possibly seek before) - int valuesize = t.count * getTypeSize(t.type); + // Load value field (possibly seek before) + const std::size_t value_size = tag.count * getTypeSize(tag.type); - if (valuesize > 4) { - fseek(f, get4(f, order) + base, SEEK_SET); + if (value_size > 4) { + if (std::fseek(file_, get4(), SEEK_SET) == -1) { + tag.type = INVALID; + return false; + } } - // read value - t.value.resize(valuesize + 1); - auto readSize = fread(&(t.value[0]), 1, valuesize, f); - t.value[readSize] = '\0'; + // Read value + tag.value.resize(value_size + 1); + const std::size_t read = std::fread(tag.value.data(), 1, value_size, file_); + if (read != value_size) { + tag.type = INVALID; + return false; + } + tag.value[read] = '\0'; - // seek back to the saved position - fseek(f, save, SEEK_SET); + // Seek back to the saved position + std::fseek(file_, saved_position, SEEK_SET); + return true; } - - std::unordered_map tags_; + + FILE* const file_; + + Tags tags_; ByteOrder order_; - FILE *file_; }; } // namespace @@ -772,22 +840,22 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : constexpr int tiff_float_size = 4; enum TagKey { - COLOR_MATRIX_1 = 50721, - COLOR_MATRIX_2 = 50722, - PROFILE_HUE_SAT_MAP_DIMS = 50937, - PROFILE_HUE_SAT_MAP_DATA_1 = 50938, - PROFILE_HUE_SAT_MAP_DATA_2 = 50939, - PROFILE_TONE_CURVE = 50940, - PROFILE_TONE_COPYRIGHT = 50942, - CALIBRATION_ILLUMINANT_1 = 50778, - CALIBRATION_ILLUMINANT_2 = 50779, - FORWARD_MATRIX_1 = 50964, - FORWARD_MATRIX_2 = 50965, - PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant - PROFILE_LOOK_TABLE_DATA = 50982, - PROFILE_HUE_SAT_MAP_ENCODING = 51107, - PROFILE_LOOK_TABLE_ENCODING = 51108, - BASELINE_EXPOSURE_OFFSET = 51109 + TAG_KEY_COLOR_MATRIX_1 = 50721, + TAG_KEY_COLOR_MATRIX_2 = 50722, + TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS = 50937, + TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1 = 50938, + TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2 = 50939, + TAG_KEY_PROFILE_TONE_CURVE = 50940, + TAG_KEY_PROFILE_TONE_COPYRIGHT = 50942, + TAG_KEY_CALIBRATION_ILLUMINANT_1 = 50778, + TAG_KEY_CALIBRATION_ILLUMINANT_2 = 50779, + TAG_KEY_FORWARD_MATRIX_1 = 50964, + TAG_KEY_FORWARD_MATRIX_2 = 50965, + TAG_KEY_PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant + TAG_KEY_PROFILE_LOOK_TABLE_DATA = 50982, + TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING = 51107, + TAG_KEY_PROFILE_LOOK_TABLE_ENCODING = 51108, + TAG_KEY_BASELINE_EXPOSURE_OFFSET = 51109 }; static const float adobe_camera_raw_default_curve[] = { @@ -1059,46 +1127,46 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : DCPMetadata md(file); if (!md.parse()) { - //printf ("Unable to load DCP profile '%s' !", filename.c_str()); + printf ("Unable to load DCP profile '%s'.", filename.c_str()); return; } light_source_1 = - md.find(CALIBRATION_ILLUMINANT_1) ? - md.toShort(CALIBRATION_ILLUMINANT_1) : - -1; + md.find(TAG_KEY_CALIBRATION_ILLUMINANT_1) + ? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_1) + : -1; light_source_2 = - md.find(CALIBRATION_ILLUMINANT_2) ? - md.toShort(CALIBRATION_ILLUMINANT_2) : - -1; + md.find(TAG_KEY_CALIBRATION_ILLUMINANT_2) + ? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_2) + : -1; temperature_1 = calibrationIlluminantToTemperature(light_source_1); temperature_2 = calibrationIlluminantToTemperature(light_source_2); - const bool has_second_hue_sat = md.find(PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat + const bool has_second_hue_sat = md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2); // Some profiles have two matrices, but just one huesat // Fetch Forward Matrices, if any - has_forward_matrix_1 = md.find(FORWARD_MATRIX_1); + has_forward_matrix_1 = md.find(TAG_KEY_FORWARD_MATRIX_1); if (has_forward_matrix_1) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_1[row][col] = md.toDouble(FORWARD_MATRIX_1, (col + row * 3) * 8); + forward_matrix_1[row][col] = md.toDouble(TAG_KEY_FORWARD_MATRIX_1, (col + row * 3) * 8); } } } - has_forward_matrix_2 = md.find(FORWARD_MATRIX_2); + has_forward_matrix_2 = md.find(TAG_KEY_FORWARD_MATRIX_2); if (has_forward_matrix_2) { for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - forward_matrix_2[row][col] = md.toDouble(FORWARD_MATRIX_2, (col + row * 3) * 8); + forward_matrix_2[row][col] = md.toDouble(TAG_KEY_FORWARD_MATRIX_2, (col + row * 3) * 8); } } } // Color Matrix (one is always there) - if (!md.find(COLOR_MATRIX_1)) { + if (!md.find(TAG_KEY_COLOR_MATRIX_1)) { if (settings->verbose) { std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; } @@ -1110,24 +1178,24 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - color_matrix_1[row][col] = md.toDouble(COLOR_MATRIX_1, (col + row * 3) * 8); + color_matrix_1[row][col] = md.toDouble(TAG_KEY_COLOR_MATRIX_1, (col + row * 3) * 8); } } - if (md.find(PROFILE_LOOK_TABLE_DIMS)) { - look_info.hue_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 0); - look_info.sat_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 4); - look_info.val_divisions = md.toInt(PROFILE_LOOK_TABLE_DIMS, 8); + if (md.find(TAG_KEY_PROFILE_LOOK_TABLE_DIMS)) { + look_info.hue_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 0); + look_info.sat_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 4); + look_info.val_divisions = md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_DIMS, 8); - look_info.srgb_gamma = md.find(PROFILE_LOOK_TABLE_ENCODING) && md.toInt(PROFILE_LOOK_TABLE_ENCODING); + look_info.srgb_gamma = md.find(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING) && md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING); - look_info.array_count = md.getCount(PROFILE_LOOK_TABLE_DATA) / 3; + look_info.array_count = md.getCount(TAG_KEY_PROFILE_LOOK_TABLE_DATA) / 3; look_table.resize(look_info.array_count); for (unsigned int i = 0; i < look_info.array_count; i++) { - look_table[i].hue_shift = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); - look_table[i].sat_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); - look_table[i].val_scale = md.toDouble(PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); + look_table[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3) * tiff_float_size); + look_table[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3 + 1) * tiff_float_size); + look_table[i].val_scale = md.toDouble(TAG_KEY_PROFILE_LOOK_TABLE_DATA, (i * 3 + 2) * tiff_float_size); } // Precalculated constants for table application @@ -1144,20 +1212,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step; } - if (md.find(PROFILE_HUE_SAT_MAP_DIMS)) { - delta_info.hue_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 0); - delta_info.sat_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 4); - delta_info.val_divisions = md.toInt(PROFILE_HUE_SAT_MAP_DIMS, 8); + if (md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS)) { + delta_info.hue_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 0); + delta_info.sat_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 4); + delta_info.val_divisions = md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_DIMS, 8); - delta_info.srgb_gamma = md.find(PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(PROFILE_HUE_SAT_MAP_ENCODING); + delta_info.srgb_gamma = md.find(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING); - delta_info.array_count = md.getCount(PROFILE_HUE_SAT_MAP_DATA_1) / 3; + delta_info.array_count = md.getCount(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1) / 3; deltas_1.resize(delta_info.array_count); for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_1[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); - deltas_1[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); - deltas_1[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); + deltas_1[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3) * tiff_float_size); + deltas_1[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 1) * tiff_float_size); + deltas_1[i].val_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_1, (i * 3 + 2) * tiff_float_size); } delta_info.pc.h_scale = @@ -1177,14 +1245,14 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Second matrix has_color_matrix_2 = true; - bool cm2 = md.find(COLOR_MATRIX_2); + const bool cm2 = md.find(TAG_KEY_COLOR_MATRIX_2); for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { color_matrix_2[row][col] = cm2 - ? md.toDouble(COLOR_MATRIX_2, (col + row * 3) * 8) - : color_matrix_1[row][col]; + ? md.toDouble(TAG_KEY_COLOR_MATRIX_2, (col + row * 3) * 8) + : color_matrix_1[row][col]; } } @@ -1194,20 +1262,20 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Saturation maps. Need to be unwinded. for (unsigned int i = 0; i < delta_info.array_count; ++i) { - deltas_2[i].hue_shift = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); - deltas_2[i].sat_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); - deltas_2[i].val_scale = md.toDouble(PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); + deltas_2[i].hue_shift = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3) * tiff_float_size); + deltas_2[i].sat_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 1) * tiff_float_size); + deltas_2[i].val_scale = md.toDouble(TAG_KEY_PROFILE_HUE_SAT_MAP_DATA_2, (i * 3 + 2) * tiff_float_size); } } } - has_baseline_exposure_offset = md.find(BASELINE_EXPOSURE_OFFSET); + has_baseline_exposure_offset = md.find(TAG_KEY_BASELINE_EXPOSURE_OFFSET); if (has_baseline_exposure_offset) { - baseline_exposure_offset = md.toDouble(BASELINE_EXPOSURE_OFFSET); + baseline_exposure_offset = md.toDouble(TAG_KEY_BASELINE_EXPOSURE_OFFSET); } // Read tone curve points, if any, but disable to RTs own profiles - if (md.find(PROFILE_TONE_CURVE)) { + if (md.find(TAG_KEY_PROFILE_TONE_CURVE)) { std::vector curve_points = { static_cast(DCT_Spline) // The first value is the curve type }; @@ -1215,9 +1283,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Push back each X/Y coordinates in a loop bool curve_is_linear = true; - for (unsigned int i = 0, n = md.getCount(PROFILE_TONE_CURVE); i < n; i += 2) { - const double x = md.toDouble(PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); - const double y = md.toDouble(PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); + for (unsigned int i = 0, n = md.getCount(TAG_KEY_PROFILE_TONE_CURVE); i < n; i += 2) { + const double x = md.toDouble(TAG_KEY_PROFILE_TONE_CURVE, (i + 0) * tiff_float_size); + const double y = md.toDouble(TAG_KEY_PROFILE_TONE_CURVE, (i + 1) * tiff_float_size); if (x != y) { curve_is_linear = false; @@ -1233,7 +1301,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tone_curve.Set(DiagonalCurve(curve_points, CURVES_MIN_POLY_POINTS)); } } else { - if (md.find(PROFILE_TONE_COPYRIGHT) && md.toString(PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { + if (md.find(TAG_KEY_PROFILE_TONE_COPYRIGHT) && md.toString(TAG_KEY_PROFILE_TONE_COPYRIGHT).find("Adobe Systems") != std::string::npos) { // An Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that std::vector curve_points = { static_cast(DCT_Spline) diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc index a45e5d345..86fdd6800 100644 --- a/rtengine/hilite_recon.cc +++ b/rtengine/hilite_recon.cc @@ -1175,27 +1175,27 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue {2.0f, 3.0f, 0.001f} }; - const float rad1 = vals[blur][0]; - const float rad2 = vals[blur][1]; + const float radius1 = vals[blur][0]; + const float radius2 = vals[blur][1]; const float th = vals[blur][2]; - guidedFilter(guide, mask, mask, rad1, th, true, 1); + guidedFilter(guide, mask, mask, radius1, th, true, 1); if (plistener) { progress += 0.03; plistener->setProgress(progress); } if (blur > 0) { //no use of 2nd guidedFilter if Blur = 0 (slider to 1)..speed-up and very small differences. - guidedFilter(guide, rbuf, rbuf, rad2, 0.01f * 65535.f, true, 1); + guidedFilter(guide, rbuf, rbuf, radius2, 0.01f * 65535.f, true, 1); if (plistener) { progress += 0.03; plistener->setProgress(progress); } - guidedFilter(guide, gbuf, gbuf, rad2, 0.01f * 65535.f, true, 1); + guidedFilter(guide, gbuf, gbuf, radius2, 0.01f * 65535.f, true, 1); if (plistener) { progress += 0.03; plistener->setProgress(progress); } - guidedFilter(guide, bbuf, bbuf, rad2, 0.01f * 65535.f, true, 1); + guidedFilter(guide, bbuf, bbuf, radius2, 0.01f * 65535.f, true, 1); if (plistener) { progress += 0.03; plistener->setProgress(progress); diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 386c6faec..d9c57bc84 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -279,7 +279,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st { eSensorType sensor_type; int w = 0, h = 0; - std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true, true)); + const std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), sensor_type, w, h, 1, false, true, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: no thumbnail found, generating a neutral curve" << std::endl; diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 7ff84b632..c97c0c3a6 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2148,20 +2148,11 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, //calculate La - Absolute luminance shooting const FramesMetaData* metaData = imgsrc->getMetaData(); - int imgNum = 0; - - if (imgsrc->isRAW()) { - if (imgsrc->getSensorType() == ST_BAYER) { - imgNum = rtengine::LIM(params->raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); - } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { - //imgNum = rtengine::LIM(params->raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); - } - } - float fnum = metaData->getFNumber(imgNum); // F number - float fiso = metaData->getISOSpeed(imgNum) ; // ISO - float fspeed = metaData->getShutterSpeed(imgNum) ; // Speed - double fcomp = metaData->getExpComp(imgNum); // Compensation +/- + float fnum = metaData->getFNumber(); // F number + float fiso = metaData->getISOSpeed() ; // ISO + float fspeed = metaData->getShutterSpeed() ; // Speed + double fcomp = metaData->getExpComp(); // Compensation +/- double adap; if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 53e581468..87b97807c 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1282,7 +1282,7 @@ private: } autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) - DCPProfileApplyState as; + DCPProfile::ApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as); LUTu histToneCurve; diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 844291a24..f452c2491 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -42,7 +42,6 @@ ExifPanel::ExifPanel() : } { set_orientation(Gtk::ORIENTATION_VERTICAL); - recursiveOp = true; exifTree = Gtk::manage (new Gtk::TreeView()); scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow()); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 598fc5efe..b05605350 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -46,9 +46,6 @@ #include "profilestorecombobox.h" #include "version.h" -#include "../rtengine/mytime.h" - -using namespace rtengine::procparams; namespace { @@ -109,6 +106,8 @@ bool CPBDump( } // namespace +using namespace rtengine::procparams; + Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : fname(fname), cfs(*cf), From 4223f114cbec46812082e3168c9ee0efaf9d0fc2 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 3 Dec 2022 17:49:26 -0800 Subject: [PATCH 010/110] Clean up merge --- rtengine/dcp.cc | 31 ++++++++++++++----------------- rtengine/dcp.h | 4 ++-- rtengine/imagedata.cc | 26 +++++++++++++++----------- rtengine/imagedata.h | 16 +++++++++++----- rtengine/imageio.cc | 1 - rtengine/improcfun.cc | 2 +- rtengine/simpleprocess.cc | 5 ----- rtgui/thumbnail.cc | 1 - rtgui/thumbnail.h | 1 - 9 files changed, 43 insertions(+), 44 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index feca2422a..5fe078fa3 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include "dcp.h" @@ -2182,8 +2185,7 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) && lastdot <= sname.size() - 4 && !sname.casefold().compare(lastdot, 4, ".dcp") ) { - const Glib::ustring cam_short_name = sname.substr(0, lastdot).uppercase(); - file_std_profiles[cam_short_name] = fname; // They will be loaded and cached on demand + file_std_profiles[sname.substr(0, lastdot).casefold_collate_key()] = fname; // They will be loaded and cached on demand } } else { // Directory @@ -2194,11 +2196,10 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) for (const auto& alias : getAliases(rt_profile_dir)) { const Glib::ustring alias_name = Glib::ustring(alias.first).uppercase(); - const Glib::ustring real_name = Glib::ustring(alias.second).uppercase(); - const std::map::const_iterator real = file_std_profiles.find(real_name); + const std::map::const_iterator real = file_std_profiles.find(Glib::ustring(alias.second).casefold_collate_key()); if (real != file_std_profiles.end()) { - file_std_profiles[alias_name] = real->second; + file_std_profiles[alias_name.casefold_collate_key()] = real->second; } } } @@ -2220,19 +2221,19 @@ bool DCPStore::isValidDCPFileName(const Glib::ustring& filename) const DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const { + const auto key = filename.casefold_collate_key(); MyMutex::MyLock lock(mutex); + const std::map::const_iterator iter = profile_cache.find(key); - const std::map::iterator r = profile_cache.find(filename); - - if (r != profile_cache.end()) { - return r->second; + if (iter != profile_cache.end()) { + return iter->second; } DCPProfile* const res = new DCPProfile(filename); if (res->isValid()) { // Add profile - profile_cache[filename] = res; + profile_cache[key] = res; if (options.rtSettings.verbose) { printf("DCP profile '%s' loaded from disk\n", filename.c_str()); } @@ -2245,13 +2246,9 @@ DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const DCPProfile* DCPStore::getStdProfile(const Glib::ustring& requested_cam_short_name) const { - const Glib::ustring name = requested_cam_short_name.uppercase(); - - // Warning: do NOT use map.find(), since it does not seem to work reliably here - for (const auto& file_std_profile : file_std_profiles) { - if (file_std_profile.first == name) { - return getProfile(file_std_profile.second); - } + const std::map::const_iterator iter = file_std_profiles.find(requested_cam_short_name.casefold_collate_key()); + if (iter != file_std_profiles.end()) { + return getProfile(iter->second); } // profile not found, looking if we're in loadAll=false mode diff --git a/rtengine/dcp.h b/rtengine/dcp.h index d05fdb4cc..378a70bf1 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -170,10 +170,10 @@ private: std::vector profileDir; // these contain standard profiles from RT. keys are all in uppercase, file path is value - std::map file_std_profiles; + std::map file_std_profiles; // Maps file name to profile as cache - mutable std::map profile_cache; + mutable std::map profile_cache; }; } diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 3478bfc9f..eb8fed1d8 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -26,7 +26,6 @@ #include "imagedata.h" #include "imagesource.h" -#include "procparams.h" #include "rt_math.h" #include "utils.h" @@ -35,6 +34,20 @@ using namespace rtengine; +namespace +{ + +const std::string& validateUft8(const std::string& str, const std::string& on_error = "???") +{ + if (Glib::ustring(str).validate()) { + return str; + } + + return on_error; +} + +} + namespace rtengine { extern const Settings *settings; @@ -59,15 +72,6 @@ Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) } // namespace rtengine -const std::string& validateUft8(const std::string& str, const std::string& on_error = "???") -{ - if (Glib::ustring(str).validate()) { - return str; - } - - return on_error; -} - FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname) { return new FramesData(fname); @@ -644,7 +648,7 @@ std::string FramesMetaData::expcompToString(double expcomp, bool maskZeroexpcomp double FramesMetaData::shutterFromString(std::string s) { - const std::string::size_type i = s.find_first_of ('/'); + const std::string::size_type i = s.find_first_of('/'); if (i == std::string::npos) { return std::atof(s.c_str()); diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index cd1922c6f..f692d4267 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -21,18 +21,24 @@ #include #include #include -#include + #include -#include "rawimage.h" -#include "rtengine.h" +#include "imageio.h" + +namespace Glib +{ + +class ustring; + +} namespace rtengine { Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname); // TODO: Global function? -class FramesData : +class FramesData final : public FramesMetaData { private: @@ -56,7 +62,7 @@ private: bool isHDR; public: - FramesData(const Glib::ustring& fname); + explicit FramesData(const Glib::ustring& fname); void setDCRawFrameCount(unsigned int frameCount); unsigned int getFrameCount() const override; diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index f95d5db24..26ea87a44 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "rt_math.h" #include "procparams.h" diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index a5bf9ddd4..a1f115820 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5589,7 +5589,7 @@ double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size int w_thumb = -1, h_thumb = thumb_size; eSensorType sensorType = rtengine::ST_NONE; - Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, sensorType, w_thumb, h_thumb, 1, FALSE); + Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw(fname, sensorType, w_thumb, h_thumb, 1, FALSE); if (!thumb) { return 0.0; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 87b97807c..596720e80 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1733,17 +1733,12 @@ private: MetadataInfo info(imgsrc->getFileName()); switch (params.metadata.mode) { case MetaDataParams::TUNNEL: - // Sending back the whole first root, which won't necessarily be the selected frame number - // and may contain subframe depending on initial raw's hierarchy - // readyImg->setMetadata (ii->getMetaData()->getRootExifData ()); readyImg->setMetadata(std::move(info)); break; case MetaDataParams::EDIT: info.setExif(params.exif); info.setIptc(params.iptc); readyImg->setMetadata(std::move(info)); - // ask for the correct frame number, but may contain subframe depending on initial raw's hierarchy - // readyImg->setMetadata (ii->getMetaData()->getBestExifData(imgsrc, ¶ms.raw), params.exif, params.iptc); break; default: // case MetaDataParams::STRIP // nothing to do diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index b05605350..e50d7ac77 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -43,7 +43,6 @@ #include "paramsedited.h" #include "ppversion.h" #include "procparamchangers.h" -#include "profilestorecombobox.h" #include "version.h" diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 17e26e3c9..93d1deb93 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -26,7 +26,6 @@ #include "cacheimagedata.h" #include "threadutils.h" #include "thumbnaillistener.h" -#include "../rtengine/procparams.h" namespace rtengine { From ec84e172246f6c9121b326c3a9a6372ab71c70a4 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 3 Dec 2022 22:21:30 -0800 Subject: [PATCH 011/110] Restore cleanups to rtengine/dcp.* --- rtengine/dcp.cc | 140 ++++++++++++++++------------------ rtengine/dcp.h | 35 ++++----- rtengine/dcrop.cc | 2 +- rtengine/imagesource.h | 6 +- rtengine/improccoordinator.cc | 2 +- rtengine/improcfun.cc | 4 +- rtengine/improcfun.h | 5 +- rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/rtthumbnail.cc | 2 +- rtengine/simpleprocess.cc | 2 +- 11 files changed, 98 insertions(+), 104 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 5fe078fa3..a858a0e71 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -38,13 +38,6 @@ #include "utils.h" #include "../rtgui/options.h" -namespace rtengine -{ - -extern const Settings* settings; - -} - using namespace rtengine; namespace @@ -55,7 +48,7 @@ namespace DCPProfile::Matrix invert3x3(const DCPProfile::Matrix& a) { DCPProfile::Matrix res = a; - if (!invertMatrix(a, res) && settings->verbose) { + if (!invertMatrix(a, res)) { std::cerr << "DCP matrix cannot be inverted! Expect weird output." << std::endl; } return res; @@ -340,8 +333,6 @@ double xyCoordToTemperature(const std::array& white_xy) // Search for line pair coordinate is between. double last_dt = 0.0; - double last_dv = 0.0; - double last_du = 0.0; for (uint32_t index = 1; index <= 30; ++index) { // Convert slope to delta-u and delta-v, with length 1. @@ -377,23 +368,11 @@ double xyCoordToTemperature(const std::array& white_xy) // Interpolate the temperature. res = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f)); - - // Find delta from black body point to test coordinate. - uu = u - (temp_table [index - 1].u * f + temp_table [index].u * (1.0 - f)); - vv = v - (temp_table [index - 1].v * f + temp_table [index].v * (1.0 - f)); - // Interpolate vectors along slope. - du = du * (1.0 - f) + last_du * f; - dv = dv * (1.0 - f) + last_dv * f; - len = sqrt (du * du + dv * dv); - du /= len; - dv /= len; break; } // Try next line pair. last_dt = dt; - last_du = du; - last_dv = dv; } return res; @@ -486,9 +465,7 @@ public: { if (!file_) { #ifndef NDEBUG - if (settings->verbose) { - std::cerr << "ERROR: No file opened." << std::endl; - } + std::cerr << "ERROR: No file opened." << std::endl; #endif return false; } @@ -500,7 +477,7 @@ public: std::uint16_t bo; std::fread(&bo, 1, 2, file_); order_ = ByteOrder(bo); - + get2(); // Skip // Seek to IFD @@ -528,7 +505,7 @@ public: { return tags_.find(id) != tags_.end(); } - + std::string toString(int id) const { const Tags::const_iterator tag = tags_.find(id); @@ -558,24 +535,28 @@ public: } return 0; } + case BYTE: { if (offset < tag->second.value.size()) { return tag->second.value[offset]; } return 0; } + case SSHORT: { if (offset + 1 < tag->second.value.size()) { return static_cast(sget2(tag->second.value.data() + offset)); } return 0; } + case SHORT: { if (offset + 1 < tag->second.value.size()) { return sget2(tag->second.value.data() + offset); } return 0; } + case SLONG: case LONG: { if (offset + 3 < tag->second.value.size()) { @@ -583,6 +564,7 @@ public: } return 0; } + case SRATIONAL: case RATIONAL: { if (offset + 7 < tag->second.value.size()) { @@ -594,27 +576,29 @@ public: } return 0; } + case FLOAT: { return toDouble(id, offset); } + default: { return 0; } } } - + int toShort(int id, std::size_t offset = 0) const { return toInt(id, offset, SHORT); } - + double toDouble(int id, std::size_t offset = 0) const { const Tags::const_iterator tag = tags_.find(id); if (tag == tags_.end()) { return 0.0; } - + switch (tag->second.type) { case SBYTE: { if (offset < tag->second.value.size()) { @@ -622,24 +606,28 @@ public: } return 0.0; } + case BYTE: { if (offset < tag->second.value.size()) { return tag->second.value[offset]; } return 0.0; } + case SSHORT: { if (offset + 1 < tag->second.value.size()) { return static_cast(sget2(tag->second.value.data() + offset)); } return 0.0; } + case SHORT: { if (offset + 1 < tag->second.value.size()) { return sget2(tag->second.value.data() + offset); } return 0.0; } + case SLONG: case LONG: { if (offset + 3 < tag->second.value.size()) { @@ -647,6 +635,7 @@ public: } return 0.0; } + case SRATIONAL: case RATIONAL: { if (offset + 7 < tag->second.value.size()) { @@ -659,14 +648,17 @@ public: } return 0.0; } + case FLOAT: { union IntFloat { std::uint32_t i; float f; } conv; + conv.i = sget4(tag->second.value.data() + offset); - return conv.f; // IEEE FLOATs are already C format, they just need a recast + return conv.f; // IEEE FLOATs are already C format, they just need a recast } + default: { return 0.0; } @@ -689,9 +681,9 @@ private: TagType type; unsigned int count; }; - + using Tags = std::unordered_map; - + std::uint16_t sget2(const std::uint8_t* s) const { if (order_ == INTEL) { @@ -700,7 +692,7 @@ private: return s[0] << 8 | s[1]; } } - + std::uint32_t sget4(const std::uint8_t* s) const { if (order_ == INTEL) { @@ -709,16 +701,16 @@ private: return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } } - + std::uint16_t get2() - { + { std::uint16_t res = std::numeric_limits::max(); std::fread(&res, 1, 2, file_); return sget2(reinterpret_cast(&res)); } - + std::uint32_t get4() - { + { std::uint32_t res = std::numeric_limits::max(); std::fread(&res, 1, 4, file_); return sget4(reinterpret_cast(&res)); @@ -734,32 +726,32 @@ private: case UNDEFINED: { return 1; } - + case SHORT: case SSHORT: { return 2; } - + case LONG: case SLONG: case FLOAT: { return 4; } - + case RATIONAL: case SRATIONAL: case DOUBLE: { return 8; } } - + return 1; } bool parseTag(Tag& tag) { tag.id = get2(); - tag.type = TagType(get2()); + tag.type = TagType(get2()); tag.count = std::max(1U, get4()); // Filter out invalid tags @@ -767,7 +759,7 @@ private: // (only a small part of it will actually be parsed though) if ( tag.type == INVALID - || tag.type > DOUBLE + || tag.type > DOUBLE || tag.count > 10 * 1024 * 1024 ) { tag.type = INVALID; @@ -798,19 +790,19 @@ private: // Seek back to the saved position std::fseek(file_, saved_position, SEEK_SET); - + return true; } - + FILE* const file_; - + Tags tags_; ByteOrder order_; }; } // namespace -struct DCPProfile::ApplyState::Data { +struct DCPProfileApplyState::Data { float pro_photo[3][3]; float work[3][3]; bool already_pro_photo; @@ -819,14 +811,12 @@ struct DCPProfile::ApplyState::Data { float bl_scale; }; -DCPProfile::ApplyState::ApplyState() : +DCPProfileApplyState::DCPProfileApplyState() : data(new Data{}) { } -DCPProfile::ApplyState::~ApplyState() -{ -} +DCPProfileApplyState::~DCPProfileApplyState() = default; DCPProfile::DCPProfile(const Glib::ustring& filename) : has_color_matrix_1(false), @@ -1124,7 +1114,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : FILE* const file = g_fopen(filename.c_str(), "rb"); if (file == nullptr) { - //printf ("Unable to load DCP profile '%s' !", filename.c_str()); + printf ("Unable to load DCP profile '%s' !", filename.c_str()); return; } @@ -1170,9 +1160,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Color Matrix (one is always there) if (!md.find(TAG_KEY_COLOR_MATRIX_1)) { - if (settings->verbose) { - std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; - } + std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; fclose(file); return; } @@ -1408,25 +1396,25 @@ void DCPProfile::apply( const TMatrix work_matrix = ICCStore::getInstance()->workingSpaceInverseMatrix(working_space); + const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix + const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); if (delta_base.empty()) { apply_hue_sat_map = false; } - const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix - if (!apply_hue_sat_map) { // The fast path: No LUT --> Calculate matrix for direct conversion raw -> working space float mat[3][3] = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - + double temp = 0.0; for (int k = 0; k < 3; ++k) { - mat[i][j] += work_matrix[i][k] * xyz_cam[k][j]; + temp += work_matrix[i][k] * xyz_cam[k][j]; } - + mat[i][j] = temp; } } @@ -1452,11 +1440,11 @@ void DCPProfile::apply( for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - + double temp = 0.0; for (int k = 0; k < 3; ++k) { - pro_photo[i][j] += prophoto_xyz[i][k] * xyz_cam[k][j]; + temp += prophoto_xyz[i][k] * xyz_cam[k][j]; } - + pro_photo[i][j] = temp; } } @@ -1464,11 +1452,11 @@ void DCPProfile::apply( for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - + double temp = 0.0; for (int k = 0; k < 3; ++k) { - work[i][j] += work_matrix[i][k] * xyz_prophoto[k][j]; + temp += work_matrix[i][k] * xyz_prophoto[k][j]; } - + work[i][j] = temp; } } @@ -1510,7 +1498,7 @@ void DCPProfile::apply( } } -void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out) +void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, DCPProfileApplyState& as_out) { as_out.data->use_tone_curve = use_tone_curve; as_out.data->apply_look_table = apply_look_table; @@ -1539,9 +1527,11 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { + double temp = 0.0; for (int k = 0; k < 3; k++) { - as_out.data->pro_photo[i][j] += prophoto_xyz[i][k] * mWork[k][j]; + temp += prophoto_xyz[i][k] * mWork[k][j]; } + as_out.data->pro_photo[i][j] = temp; } } @@ -1550,18 +1540,20 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { + double temp = 0.0; for (int k = 0; k < 3; k++) { - as_out.data->work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + temp += mWork[i][k] * xyz_prophoto[k][j]; } + as_out.data->work[i][j] = temp; } } } } -void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int height, int tile_width, const ApplyState& as_in) const +void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int height, int tile_width, const DCPProfileApplyState& as_in) const { -#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) +#define FCLIP(a) ((a)>0.f?((a)<65535.5f?(a):65535.5f):0.f) #define CLIP01(a) ((a)>0?((a)<1?(a):1):0) float exp_scale = as_in.data->bl_scale; @@ -2000,7 +1992,7 @@ std::vector DCPProfile::makeHueSatMap(const ColorTemp& wh return res; } -void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const +inline void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const { // Apply the HueSatMap. Ported from Adobes reference implementation. float hue_shift; @@ -2234,7 +2226,7 @@ DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const if (res->isValid()) { // Add profile profile_cache[key] = res; - if (options.rtSettings.verbose) { + if (settings->verbose) { printf("DCP profile '%s' loaded from disk\n", filename.c_str()); } return res; diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 378a70bf1..573349348 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -36,24 +36,11 @@ namespace rtengine class ColorTemp; class Imagefloat; +class DCPProfileApplyState; class DCPProfile final { public: - class ApplyState final - { - public: - ApplyState(); - ~ApplyState(); - - private: - struct Data; - - std::unique_ptr data; - - friend class DCPProfile; - }; - struct Illuminants { short light_source_1; short light_source_2; @@ -85,10 +72,10 @@ public: const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool apply_hue_sat_map + bool apply_hue_sat_map = true ) const; - void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out); - void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const; + void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, DCPProfileApplyState& as_out); + void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const DCPProfileApplyState& as_in) const; private: struct HsbModify { @@ -149,6 +136,20 @@ private: AdobeToneCurve tone_curve; }; +class DCPProfileApplyState final +{ +public: + DCPProfileApplyState(); + ~DCPProfileApplyState(); + +private: + struct Data; + + const std::unique_ptr data; + + friend class DCPProfile; +}; + class DCPStore final : public NonCopyable { diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index d644d2d1e..790a2bf0d 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -1152,7 +1152,7 @@ void Crop::update(int todo) } */ double rrm, ggm, bbm; - DCPProfile::ApplyState as; + DCPProfileApplyState as; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, as); LUTu histToneCurve; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 67bec48dd..d89681137 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -28,7 +28,6 @@ #include "rtengine.h" #include "colortemp.h" #include "array2D.h" -#include "dcp.h" template class LUT; @@ -42,8 +41,9 @@ namespace rtengine { class ColorTemp; -class Imagefloat; class DCPProfile; +class DCPProfileApplyState; +class Imagefloat; class RetinexgaintransmissionCurve; class RetinextransmissionCurve; @@ -137,7 +137,7 @@ public: virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW () const = 0; - virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfile::ApplyState &as) + virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) { return nullptr; }; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 128420359..804e81ac0 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1300,7 +1300,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) double ggm = 33.; double bbm = 33.; - DCPProfile::ApplyState as; + DCPProfileApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params->icm, as); ipf.rgbProc(oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params->toneCurve.saturation, diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index a1f115820..861cc8d7d 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2021,7 +2021,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, - double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState& asIn, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { rgbProc(working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, @@ -2035,7 +2035,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, - DCPProfile *dcpProf, const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) + DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { std::unique_ptr stop; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index f21e9d7be..c11f0810b 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -49,6 +49,7 @@ namespace rtengine class ColorAppearance; class ColorGradientCurve; class DCPProfile; +class DCPProfileApplyState; class FlatCurve; class FramesMetaData; class LensCorrection; @@ -168,13 +169,13 @@ enum class BlurType { const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clcurve, const LUTf& cl2curve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, - const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); + const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clcurve, const LUTf& cl2curve, const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, - int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); + int hlcomprthresh, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); void labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]); void toning2col(float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float rl, float gl, float bl, float rh, float gh, float bh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect); void toningsmh(float r, float g, float b, float &ro, float &go, float &bo, float RedLow, float GreenLow, float BlueLow, float RedMed, float GreenMed, float BlueMed, float RedHigh, float GreenHigh, float BlueHigh, float reducac, int mode, float strProtect); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 21258c9a7..8f8a71553 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -980,7 +980,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima } } -DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, DCPProfile::ApplyState &as) +DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, DCPProfileApplyState &as) { if (cmp.inputProfile == "(camera)" || cmp.inputProfile == "(none)") { return nullptr; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index fecde5d96..16677b1da 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -184,7 +184,7 @@ public: void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) override; - DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfile::ApplyState &as) override; + DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override; void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 5d6fa3aeb..30855b1f1 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1355,7 +1355,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT LabImage* labView = new LabImage (fw, fh); DCPProfile *dcpProf = nullptr; - DCPProfile::ApplyState as; + DCPProfileApplyState as; if (isRaw) { cmsHPROFILE dummy; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 596720e80..6ae805d94 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1282,7 +1282,7 @@ private: } autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) - DCPProfile::ApplyState as; + DCPProfileApplyState as; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as); LUTu histToneCurve; From caa23df465745006ff1c45104b7e240a4f2adc83 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 6 May 2019 09:27:44 +0200 Subject: [PATCH 012/110] report "Unknown" for unknown lenses (cherry picked from commit 36d7710ee270d776729d926b7c4ba028713bdb06) --- rtengine/imagedata.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index eb8fed1d8..1977061db 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -283,6 +283,9 @@ FramesData::FramesData(const Glib::ustring &fname) : if (lens.empty()) { lens = "Unknown"; } + if (lens.empty()) { + lens = "Unknown"; + } std::string datetime_taken; if (find_exif_tag("Exif.Image.DateTimeOriginal")) { From 1a771fa2110b4d537d612291fbdcb7665805ad2b Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 14 May 2019 07:03:07 -0700 Subject: [PATCH 013/110] more work on synchronizing metadata with xmp sidecars (cherry picked from commit 81bbff6e6ae87bd35e8050a1cc621297ca24939b) --- rtengine/CMakeLists.txt | 1 + rtengine/imagedata.cc | 28 +--- rtengine/imagedata.h | 4 - rtengine/imageio.cc | 92 ++++------- rtengine/imageio.h | 24 +-- rtengine/improccoordinator.cc | 63 ++++---- rtengine/metadata.cc | 291 ++++++++++++++++++++++++++++++++++ rtengine/metadata.h | 80 ++++++++++ rtengine/procparams.h | 5 + rtengine/settings.h | 16 +- rtengine/simpleprocess.cc | 29 ++-- rtgui/exifpanel.cc | 7 +- rtgui/iptcpanel.cc | 7 +- rtgui/options.cc | 53 ++++++- rtgui/preferences.cc | 47 +++++- rtgui/preferences.h | 3 + rtgui/thumbnail.cc | 32 ++++ rtgui/thumbnail.h | 2 + 18 files changed, 611 insertions(+), 173 deletions(-) create mode 100644 rtengine/metadata.cc create mode 100644 rtengine/metadata.h diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index c50abb88c..01424543b 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -145,6 +145,7 @@ set(RTENGINESOURCEFILES lj92.c lmmse_demosaic.cc loadinitial.cc + metadata.cc munselllch.cc myfile.cc panasonic_decoders.cc diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 1977061db..e7cf2b4c2 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -22,11 +22,11 @@ #include #include #include -#include #include "imagedata.h" #include "imagesource.h" #include "rt_math.h" +#include "metadata.h" #include "utils.h" #pragma GCC diagnostic warning "-Wextra" @@ -52,24 +52,6 @@ namespace rtengine { extern const Settings *settings; -Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) -{ -#ifdef EXV_UNICODE_PATH - glong ws_size = 0; - gunichar2* const ws = g_utf8_to_utf16(fname.c_str(), -1, nullptr, &ws_size, nullptr); - std::wstring wfname; - wfname.reserve(ws_size); - for (glong i = 0; i < ws_size; ++i) { - wfname.push_back(ws[i]); - } - g_free(ws); - auto image = Exiv2::ImageFactory::open(wfname); -#else - auto image = Exiv2::ImageFactory::open(fname); -#endif - return image; -} - } // namespace rtengine FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname) @@ -106,9 +88,9 @@ FramesData::FramesData(const Glib::ustring &fname) : lens.clear(); try { - auto image = open_exiv2(fname); - image->readMetadata(); - const auto& exif = image->exifData(); + Exiv2Metadata meta(fname); + meta.load(); + const auto& exif = meta.exifData(); ok_ = true; // taken and adapted from darktable (src/common/exif.cc) @@ -189,7 +171,7 @@ FramesData::FramesData(const Glib::ustring &fname) : /* TODO: Implement ratings in exiv2 situations. See PR #5325 - + // Look for Rating metadata in the following order: // 1. EXIF // 2. XMP diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index f692d4267..b1a29dc39 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -22,8 +22,6 @@ #include #include -#include - #include "imageio.h" namespace Glib @@ -36,8 +34,6 @@ class ustring; namespace rtengine { -Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname); // TODO: Global function? - class FramesData final : public FramesMetaData { diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 26ea87a44..475792e83 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -79,39 +79,7 @@ FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname) } -MetadataInfo::MetadataInfo(const Glib::ustring& src) : - src_(src), - exif_(new rtengine::procparams::ExifPairs), - iptc_(new rtengine::procparams::IPTCPairs) -{ -} - -const Glib::ustring& MetadataInfo::filename() const -{ - return src_; -} - -const rtengine::procparams::ExifPairs& MetadataInfo::exif() const -{ - return *exif_; -} - -const rtengine::procparams::IPTCPairs& MetadataInfo::iptc() const -{ - return *iptc_; -} - -void MetadataInfo::setExif(const rtengine::procparams::ExifPairs &exif) -{ - *exif_ = exif; -} - -void MetadataInfo::setIptc(const rtengine::procparams::IPTCPairs &iptc) -{ - *iptc_ = iptc; -} - -void ImageIO::setMetadata(MetadataInfo info) +void ImageIO::setMetadata(Exiv2Metadata info) { metadataInfo = std::move(info); } @@ -1181,9 +1149,9 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, (bps == 16 || bps == 32) && isFloat ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT); /* - + TODO: Re-apply fix from #5787 - + [out]() { const std::vector default_tags = rtexif::ExifManager::getDefaultTIFFTags(nullptr); @@ -1388,32 +1356,34 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const } try { - auto src = open_exiv2(metadataInfo.filename()); - auto dst = open_exiv2(fname); - src->readMetadata(); - dst->setMetadata(*src); - dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; - for (const auto& p : metadataInfo.exif()) { - try { - dst->exifData()[p.first] = p.second; - } catch (const Exiv2::AnyError& exc) { - } - } - for (const auto& p : metadataInfo.iptc()) { - try { - auto& v = p.second; - if (!v.empty()) { - dst->iptcData()[p.first] = v[0]; - for (size_t j = 1; j < v.size(); ++j) { - Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); - d.setValue(v[j]); - dst->iptcData().add(d); - } - } - } catch (const Exiv2::AnyError& exc) { - } - } - dst->writeMetadata(); + metadataInfo.load(); + metadataInfo.saveToImage(fname); + // auto src = open_exiv2(metadataInfo.filename()); + // auto dst = open_exiv2(fname); + // src->readMetadata(); + // dst->setMetadata(*src); + // dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; + // for (const auto& p : metadataInfo.exif()) { + // try { + // dst->exifData()[p.first] = p.second; + // } catch (const Exiv2::AnyError& exc) { + // } + // } + // for (const auto& p : metadataInfo.iptc()) { + // try { + // auto& v = p.second; + // if (!v.empty()) { + // dst->iptcData()[p.first] = v[0]; + // for (size_t j = 1; j < v.size(); ++j) { + // Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); + // d.setValue(v[j]); + // dst->iptcData().add(d); + // } + // } + // } catch (const Exiv2::AnyError& exc) { + // } + // } + // dst->writeMetadata(); return true; } catch (const Exiv2::AnyError& exc) { std::cout << "EXIF ERROR: " << exc.what() << std::endl; diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 3283d5816..26e7164e6 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -24,6 +24,7 @@ #include "iimage.h" #include "imagedimensions.h" #include "imageformat.h" +#include "metadata.h" #include "rtengine.h" enum { @@ -52,25 +53,6 @@ class ColorTemp; class ProgressListener; class Imagefloat; -class MetadataInfo final -{ -public: - explicit MetadataInfo(const Glib::ustring& src = {}); - - const Glib::ustring& filename() const; - - const rtengine::procparams::ExifPairs& exif() const; - const rtengine::procparams::IPTCPairs& iptc() const; - - void setExif(const rtengine::procparams::ExifPairs &exif); - void setIptc(const rtengine::procparams::IPTCPairs &iptc); - -private: - Glib::ustring src_; - std::unique_ptr exif_; - std::unique_ptr iptc_; -}; - class ImageIO : virtual public ImageDatas { @@ -84,7 +66,7 @@ protected: MyMutex imutex; IIOSampleFormat sampleFormat; IIOSampleArrangement sampleArrangement; - MetadataInfo metadataInfo; + Exiv2Metadata metadataInfo; private: void deleteLoadedProfileData( ); @@ -124,7 +106,7 @@ public: cmsHPROFILE getEmbeddedProfile () const; void getEmbeddedProfileData (int& length, unsigned char*& pdata) const; - void setMetadata(MetadataInfo info); + void setMetadata(Exiv2Metadata info); void setOutputProfile(const std::string& pdata); bool saveMetadata(const Glib::ustring &fname) const; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 804e81ac0..b74a137ff 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -31,6 +31,7 @@ #include "image8.h" #include "imagefloat.h" #include "improcfun.h" +#include "metadata.h" #include "labimage.h" #include "lcp.h" #include "procparams.h" @@ -320,7 +321,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) RAWParams rp = params->raw; ColorManagementParams cmp = params->icm; LCurveParams lcur = params->labCurve; - + if (!highDetailNeeded) { // if below 100% magnification, take a fast path if (rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE) && rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)) { @@ -528,8 +529,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) lastAwbauto = ""; autoWB.useDefaults(params->wb.equal); } - - + + } currWB = autoWB; @@ -542,11 +543,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (autowb && awbListener && params->wb.method == "autitcgreen") { awbListener->WBChanged(params->wb.temperature, params->wb.green, studgood); - } + } if (autowb && awbListener && params->wb.method == "autold") { awbListener->WBChanged(params->wb.temperature, params->wb.green, -1.f); - } + } /* GammaValues g_a; @@ -748,7 +749,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) whiteev = new float[sizespot]; bool *Autogr = nullptr; Autogr = new bool[sizespot]; - + float *locx = nullptr; locx = new float[sizespot]; float *locy = nullptr; @@ -761,7 +762,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) centx = new float[sizespot]; float *centy = nullptr; centy = new float[sizespot]; - + for (int sp = 0; sp < sizespot; sp++) { log[sp] = params->locallab.spots.at(sp).explog; autocomput[sp] = params->locallab.spots.at(sp).autocompute; @@ -865,7 +866,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // if ((todo & (M_LUMINANCE + M_COLOR)) || (todo & M_AUTOEXP)) { // if (todo & M_RGBCURVE) { if (((todo & (M_AUTOEXP | M_RGBCURVE)) || (todo & M_CROP)) && params->locallab.enabled && !params->locallab.spots.empty()) { - + ipf.rgb2lab(*oprevi, *oprevl, params->icm.workingProfile); nprevl->CopyFrom(oprevl); @@ -964,7 +965,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) const bool llmaslogutili = locllmaslogCurve.Set(params->locallab.spots.at(sp).LLmaskcurveL); const bool lcmaslogutili = locccmaslogCurve.Set(params->locallab.spots.at(sp).CCmaskcurveL); const bool lhmaslogutili = lochhmaslogCurve.Set(params->locallab.spots.at(sp).HHmaskcurveL); - + const bool lcmas_utili = locccmas_Curve.Set(params->locallab.spots.at(sp).CCmask_curve); const bool llmas_utili = locllmas_Curve.Set(params->locallab.spots.at(sp).LLmask_curve); const bool lhmas_utili = lochhmas_Curve.Set(params->locallab.spots.at(sp).HHmask_curve); @@ -1053,7 +1054,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) int xxe = xend * ww; int yys = ysta * hh; int yye = yend * hh; - + if(istm) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt ipf.mean_sig (nprevl->L, meantme, stdtme, xxs, xxe, yys, yye); } @@ -1073,7 +1074,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float stdtm = stdtms[sp] = stdtme; float meanreti = meanretis[sp] = meanretie; float stdreti = stdretis[sp] = stdretie; - + CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumar, hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, avg, sca); @@ -1125,7 +1126,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili, locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili, locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili, - + locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili, lochhhmas_Curve, lhhmas_utili, loclmasCurveblwav, lmasutiliblwav, @@ -1145,13 +1146,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) meantm, stdtm, meanreti, stdreti); - + if(istm) { //calculate mean and sigma on full image for use by normalize_mean_dt float meanf = 0.f; float stdf = 0.f; ipf.mean_sig (savenormtm.get()->L, meanf, stdf, xxs, xxe, yys, yye); - - //using 2 unused variables noiselumc and softradiustm + + //using 2 unused variables noiselumc and softradiustm params->locallab.spots.at(sp).noiselumc = (int) meanf; params->locallab.spots.at(sp).softradiustm = stdf ; } @@ -1160,7 +1161,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float meanf = 0.f; float stdf = 0.f; ipf.mean_sig (savenormreti.get()->L, meanf, stdf,xxs, xxe, yys, yye ); - //using 2 unused variables sensihs and sensiv + //using 2 unused variables sensihs and sensiv params->locallab.spots.at(sp).sensihs = (int) meanf; params->locallab.spots.at(sp).sensiv = (int) stdf; } @@ -1207,9 +1208,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) //************************************************************* // end locallab //************************************************************* - + } - + if ((todo & M_RGBCURVE) || (todo & M_CROP)) { //complexCurve also calculated pre-curves histogram depending on crop CurveFactory::complexCurve(params->toneCurve.expcomp, params->toneCurve.black / 65535.0, @@ -1412,7 +1413,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) bool proedge = WaveParams.expedge; bool profin = WaveParams.expfinal; bool proton = WaveParams.exptoning; - bool pronois = WaveParams.expnoise; + bool pronois = WaveParams.expnoise; if(WaveParams.showmask) { // WaveParams.showmask = false; @@ -1436,7 +1437,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) WaveParams.expedge = false; WaveParams.expfinal = false; WaveParams.exptoning = false; - WaveParams.expnoise = false; + WaveParams.expnoise = false; } ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); @@ -1449,7 +1450,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) WaveParams.expfinal = profin; WaveParams.exptoning = proton; WaveParams.expnoise = pronois; - + if (WaveParams.softrad > 0.f) { array2D ble(pW, pH); @@ -1479,7 +1480,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) tmpImage->b(ir, jr) = Z; ble[ir][jr] = Y / 32768.f; } - + double epsilmax = 0.0001; double epsilmin = 0.00001; double aepsil = (epsilmax - epsilmin) / 100.f; @@ -1505,11 +1506,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) Color::XYZ2Lab(X, Y, Z, L, a, b); nprevl->L[ir][jr] = L; } - + delete tmpImage; } - + } if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { @@ -1518,7 +1519,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float mL0; float mC0; float background = 0.f; - int show = 0; + int show = 0; @@ -1560,8 +1561,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) delete unshar; unshar = NULL; - - + + /* if (WaveParams.softrad > 0.f) { array2D ble(pW, pH); @@ -1606,7 +1607,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } - + } ipf.softLight(nprevl, params->softlight); @@ -1689,7 +1690,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // acListener->wbCamChanged(params->wb.temperature, params->wb.green); //real temp and tint // acListener->wbCamChanged(params->wb.temperature, 1.f); //real temp and tint = 1. // } - + } else { // CIECAM is disabled, we free up its image buffer to save some space if (ncie) { @@ -2127,7 +2128,7 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou // Issue 2500 MyMutex::MyLock lock(minit); // Also used in crop window double rm, gm, bm; params->wb.method = "autold";//same result as before muliple Auto WB - + // imgsrc->getAutoWBMultipliers(rm, gm, bm); double tempitc = 5000.; double greenitc = 1.; @@ -2374,7 +2375,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a im = tempImage; } - im->setMetadata(MetadataInfo(imgsrc->getFileName())); + im->setMetadata(Exiv2Metadata(imgsrc->getFileName(), false)); im->saveTIFF(fname, 16, false, true); delete im; diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc new file mode 100644 index 000000000..15ab7db44 --- /dev/null +++ b/rtengine/metadata.cc @@ -0,0 +1,291 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Alberto Griggio + * + * RawTherapee 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. + * + * RawTherapee 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 RawTherapee. If not, see . + */ + +#include +#include +#include "metadata.h" +#include "settings.h" +#include "../rtgui/version.h" +#include "../rtgui/pathutils.h" + + +namespace rtengine { + +extern const Settings *settings; + + +namespace { + +Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) +{ +#ifdef EXV_UNICODE_PATH + glong ws_size = 0; + gunichar2* const ws = g_utf8_to_utf16(fname.c_str(), -1, nullptr, &ws_size, nullptr); + std::wstring wfname; + wfname.reserve(ws_size); + for (glong i = 0; i < ws_size; ++i) { + wfname.push_back(ws[i]); + } + g_free(ws); + auto image = Exiv2::ImageFactory::open(wfname); +#else + auto image = Exiv2::ImageFactory::open(Glib::filename_from_utf8(fname)); +#endif + return image; +} + +} // namespace + + +Exiv2Metadata::Exiv2Metadata(): + src_(""), + merge_xmp_(false), + image_(nullptr), + exif_(new rtengine::procparams::ExifPairs), + iptc_(new rtengine::procparams::IPTCPairs) +{ +} + + +Exiv2Metadata::Exiv2Metadata(const Glib::ustring &path): + src_(""), + merge_xmp_(settings->metadata_xmp_sync != Settings::MetadataXmpSync::NONE), + image_(nullptr), + exif_(new rtengine::procparams::ExifPairs), + iptc_(new rtengine::procparams::IPTCPairs) +{ +} + + +Exiv2Metadata::Exiv2Metadata(const Glib::ustring &path, bool merge_xmp_sidecar): + src_(path), + merge_xmp_(merge_xmp_sidecar), + image_(nullptr), + exif_(new rtengine::procparams::ExifPairs), + iptc_(new rtengine::procparams::IPTCPairs) +{ +} + + +void Exiv2Metadata::load() const +{ + if (!src_.empty() && !image_.get()) { + auto img = open_exiv2(src_); + image_.reset(img.release()); + image_->readMetadata(); + + if (merge_xmp_) { + do_merge_xmp(image_.get()); + } + } +} + +Exiv2::ExifData& Exiv2Metadata::exifData() +{ + return image_.get() ? image_->exifData() : exif_data_; +} + +const Exiv2::ExifData& Exiv2Metadata::exifData() const +{ + return const_cast(this)->exifData(); +} + +Exiv2::IptcData& Exiv2Metadata::iptcData() +{ + return image_.get() ? image_->iptcData() : iptc_data_; +} + +const Exiv2::IptcData& Exiv2Metadata::iptcData() const +{ + return const_cast(this)->iptcData(); +} + +Exiv2::XmpData& Exiv2Metadata::xmpData() +{ + return image_.get() ? image_->xmpData() : xmp_data_; +} + +const Exiv2::XmpData& Exiv2Metadata::xmpData() const +{ + return const_cast(this)->xmpData(); +} + +const Glib::ustring& Exiv2Metadata::filename() const +{ + return src_; +} + +const rtengine::procparams::ExifPairs& Exiv2Metadata::exif() const +{ + return *exif_; +} + +const rtengine::procparams::IPTCPairs& Exiv2Metadata::iptc() const +{ + return *iptc_; +} + +void Exiv2Metadata::setExif(const rtengine::procparams::ExifPairs &exif) +{ + *exif_ = exif; +} + +void Exiv2Metadata::setIptc(const rtengine::procparams::IPTCPairs &iptc) +{ + *iptc_ = iptc; +} + +void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const +{ + auto xmp = getXmpSidecar(src_); + Exiv2::ExifData exif; + Exiv2::IptcData iptc; + Exiv2::moveXmpToExif(xmp, exif); + Exiv2::moveXmpToIptc(xmp, iptc); + + for (auto &datum : exif) { + dst->exifData()[datum.key()] = datum; + } + for (auto &datum : iptc) { + dst->iptcData()[datum.key()] = datum; + } + for (auto &datum : xmp) { + dst->xmpData()[datum.key()] = datum; + } +} + + +void Exiv2Metadata::saveToImage(const Glib::ustring &path) const +{ + auto dst = open_exiv2(path); + dst->readMetadata(); + if (image_.get()) { + dst->setMetadata(*image_); + if (merge_xmp_) { + do_merge_xmp(dst.get()); + } + } else { + dst->setExifData(exif_data_); + dst->setIptcData(iptc_data_); + dst->setXmpData(xmp_data_); + } + + dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; + import_exif_pairs(dst->exifData()); + import_iptc_pairs(dst->iptcData()); + dst->writeMetadata(); +} + + +void Exiv2Metadata::import_exif_pairs(Exiv2::ExifData &out) const +{ + for (auto &p : *exif_) { + try { + out[p.first] = p.second; + } catch (Exiv2::AnyError &exc) {} + } +} + + +void Exiv2Metadata::import_iptc_pairs(Exiv2::IptcData &out) const +{ + for (auto &p : *iptc_) { + try { + auto &v = p.second; + if (v.size() >= 1) { + out[p.first] = v[0]; + for (size_t j = 1; j < v.size(); ++j) { + Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); + d.setValue(v[j]); + out.add(d); + } + } + } catch (Exiv2::AnyError &exc) {} + } +} + + +void Exiv2Metadata::saveToXmp(const Glib::ustring &path) const +{ + Exiv2::XmpData xmp; + Exiv2::copyExifToXmp(exifData(), xmp); + Exiv2::copyIptcToXmp(iptcData(), xmp); + for (auto &datum : xmpData()) { + xmp[datum.key()] = datum; + } + Exiv2::ExifData exif; + Exiv2::IptcData iptc; + import_exif_pairs(exif); + import_iptc_pairs(iptc); + Exiv2::copyExifToXmp(exif, xmp); + Exiv2::copyIptcToXmp(iptc, xmp); + + std::string data; + bool err = false; + if (Exiv2::XmpParser::encode(data, xmp, Exiv2::XmpParser::omitPacketWrapper|Exiv2::XmpParser::useCompactFormat) != 0) { + err = true; + } else { + FILE *out = g_fopen(path.c_str(), "wb"); + if (!out || fputs(data.c_str(), out) == EOF) { + err = true; + } + if (out) { + fclose(out); + } + } + + class Error: public Exiv2::AnyError { + public: + Error(const std::string &msg): msg_(msg) {} + const char *what() const throw() { return msg_.c_str(); } + int code() const throw() { return 0; } + + private: + std::string msg_; + }; + if (err) { + throw Error("error saving XMP sidecar " + path); + } +} + + +Glib::ustring Exiv2Metadata::xmpSidecarPath(const Glib::ustring &path) +{ + Glib::ustring fn = path; + if (settings->xmp_sidecar_style == Settings::XmpSidecarStyle::STD) { + fn = removeExtension(fn); + } + return fn + ".xmp"; +} + + +Exiv2::XmpData Exiv2Metadata::getXmpSidecar(const Glib::ustring &path) +{ + Exiv2::XmpData ret; + auto fname = xmpSidecarPath(path); + if (Glib::file_test(fname, Glib::FILE_TEST_EXISTS)) { + auto image = open_exiv2(fname); + image->readMetadata(); + ret = image->xmpData(); + } + return ret; +} + +} // namespace rtengine diff --git a/rtengine/metadata.h b/rtengine/metadata.h new file mode 100644 index 000000000..8de384479 --- /dev/null +++ b/rtengine/metadata.h @@ -0,0 +1,80 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Alberto Griggio + * + * RawTherapee 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. + * + * RawTherapee 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 RawTherapee. If not, see . + */ + +#pragma once + +#include +#include +#include +#include "procparams.h" + +namespace rtengine { + +class Exiv2Metadata final +{ +public: + Exiv2Metadata(); + explicit Exiv2Metadata(const Glib::ustring& path); + Exiv2Metadata(const Glib::ustring& path, bool merge_xmp_sidecar); + + void load() const; + + Exiv2::ExifData& exifData(); + const Exiv2::ExifData& exifData() const; + + Exiv2::IptcData& iptcData(); + const Exiv2::IptcData& iptcData() const; + + Exiv2::XmpData& xmpData(); + const Exiv2::XmpData& xmpData() const; + + const Glib::ustring& filename() const; + const rtengine::procparams::ExifPairs& exif() const; + const rtengine::procparams::IPTCPairs& iptc() const; + void setExif(const rtengine::procparams::ExifPairs& exif); + void setIptc(const rtengine::procparams::IPTCPairs& iptc); + + void saveToImage(const Glib::ustring& path) const; + void saveToXmp(const Glib::ustring& path) const; + + static Glib::ustring xmpSidecarPath(const Glib::ustring& path); + static Exiv2::XmpData getXmpSidecar(const Glib::ustring& path); + +private: + void do_merge_xmp(Exiv2::Image* dst) const; + void import_exif_pairs(Exiv2::ExifData& out) const; + void import_iptc_pairs(Exiv2::IptcData& out) const; + + Glib::ustring src_; + bool merge_xmp_; + mutable std::shared_ptr image_; + std::unique_ptr exif_; + std::unique_ptr iptc_; + Exiv2::ExifData exif_data_; + Exiv2::IptcData iptc_data_; + Exiv2::XmpData xmp_data_; +}; + +// Glib::ustring get_xmp_sidecar_path(const Glib::ustring &path); +// Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname, +// bool merge_xmp_sidecar); +// Exiv2::XmpData read_exiv2_xmp(const Glib::ustring &fname); + +} // namespace rtengine diff --git a/rtengine/procparams.h b/rtengine/procparams.h index f72d12f81..4a1eb47e3 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1773,6 +1773,11 @@ public: return pairs.erase(key); } + bool empty() const + { + return pairs.empty(); + } + Glib::ustring& operator[](const Glib::ustring& key) { return pairs[key]; diff --git a/rtengine/settings.h b/rtengine/settings.h index 0fb4996df..f9ba55257 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -1,4 +1,5 @@ -/* +/* -*- C++ -*- + * * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath @@ -112,6 +113,19 @@ public: }; ThumbnailInspectorMode thumbnail_inspector_mode; + enum class XmpSidecarStyle { + STD, // FILENAME.xmp for FILENAME.ext + EXT // FILENAME.ext.xmp for FILENAME.ext + }; + XmpSidecarStyle xmp_sidecar_style; + + enum class MetadataXmpSync { + NONE, + READ, + READ_WRITE + }; + MetadataXmpSync metadata_xmp_sync; + /** Creates a new instance of Settings. * @return a pointer to the new Settings instance. */ static Settings* create(); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 6ae805d94..0b6406b62 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -37,6 +37,7 @@ #include "mytime.h" #include "guidedfilter.h" #include "color.h" +#include "metadata.h" #undef THREAD_PRIORITY_NORMAL @@ -945,10 +946,10 @@ private: if (params.locallab.enabled && params.locallab.spots.size() > 0) { ipf.rgb2lab(*baseImg, *labView, params.icm.workingProfile); - + MyTime t1, t2; t1.set(); - + const std::unique_ptr reservView(new LabImage(*labView, true)); const std::unique_ptr lastorigView(new LabImage(*labView, true)); std::unique_ptr savenormtmView; @@ -994,7 +995,7 @@ private: LocLLmaskCurve locllmas_Curve; LocHHmaskCurve lochhmas_Curve; LocHHmaskCurve lochhhmas_Curve; - + LocwavCurve loclmasCurveblwav; LocwavCurve loclmasCurvecolwav; LocwavCurve loclmasCurve_wav; @@ -1073,7 +1074,7 @@ private: const bool lcmaslogutili = locccmaslogCurve.Set(params.locallab.spots.at(sp).CCmaskcurveL); const bool llmaslogutili = locllmaslogCurve.Set(params.locallab.spots.at(sp).LLmaskcurveL); const bool lhmaslogutili = lochhmaslogCurve.Set(params.locallab.spots.at(sp).HHmaskcurveL); - + const bool lcmas_utili = locccmas_Curve.Set(params.locallab.spots.at(sp).CCmask_curve); const bool llmas_utili = locllmas_Curve.Set(params.locallab.spots.at(sp).LLmask_curve); const bool lhmas_utili = lochhmas_Curve.Set(params.locallab.spots.at(sp).HHmask_curve); @@ -1129,7 +1130,7 @@ private: float stdtme; float meanretie; float stdretie; - + if (params.locallab.spots.at(sp).spotMethod == "exc") { ipf.calc_ref(sp, reservView.get(), reservView.get(), 0, 0, fw, fh, 1, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); } else { @@ -1148,8 +1149,8 @@ private: float Tmax; // No Locallab mask is shown in exported picture - ipf.Lab_Local(2, sp, shbuffer, labView, labView, reservView.get(), savenormtmView.get(), savenormretiView.get(), lastorigView.get(), 0, 0, fw, fh, 1, locRETgainCurve, locRETtransCurve, - lllocalcurve, locallutili, + ipf.Lab_Local(2, sp, shbuffer, labView, labView, reservView.get(), savenormtmView.get(), savenormretiView.get(), lastorigView.get(), 0, 0, fw, fh, 1, locRETgainCurve, locRETtransCurve, + lllocalcurve, locallutili, cllocalcurve, localclutili, lclocalcurve, locallcutili, loclhCurve, lochhCurve, locchCurve, @@ -1164,7 +1165,7 @@ private: lmasklclocalcurve, localmasklcutili, lmaskloglocalcurve, localmasklogutili, lmasklocal_curve, localmask_utili, - + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili, @@ -1428,8 +1429,8 @@ private: bool proedge = WaveParams.expedge; bool profin = WaveParams.expfinal; bool proton = WaveParams.exptoning; - bool pronois = WaveParams.expnoise; - + bool pronois = WaveParams.expnoise; + /* if(WaveParams.showmask) { WaveParams.showmask = false; @@ -1456,7 +1457,7 @@ private: WaveParams.expedge = false; WaveParams.expfinal = false; WaveParams.exptoning = false; - WaveParams.expnoise = false; + WaveParams.expnoise = false; } ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); @@ -1468,7 +1469,7 @@ private: WaveParams.expfinal = profin; WaveParams.exptoning = proton; WaveParams.expnoise = pronois; - + if (WaveParams.softrad > 0.f) { array2D ble(fw, fh); array2D guid(fw, fh); @@ -1523,7 +1524,7 @@ private: } delete tmpImage; } - + } if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { @@ -1730,7 +1731,7 @@ private: readyImg = tempImage; } - MetadataInfo info(imgsrc->getFileName()); + Exiv2Metadata info(imgsrc->getFileName()); switch (params.metadata.mode) { case MetaDataParams::TUNNEL: readyImg->setMetadata(std::move(info)); diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index f452c2491..7438240e9 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -25,6 +25,7 @@ #include "options.h" #include "../rtengine/imagedata.h" +#include "../rtengine/metadata.h" #include "../rtengine/procparams.h" using namespace rtengine; @@ -225,9 +226,9 @@ void ExifPanel::refreshTags() } try { - auto img = open_exiv2(fn); - img->readMetadata(); - auto& exif = img->exifData(); + rtengine::Exiv2Metadata meta(fn); + meta.load(); + auto& exif = meta.exifData(); for (const auto& p : *changeList) { try { diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 0f8471b92..724b54aa1 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -24,6 +24,7 @@ #include "rtimage.h" #include "../rtengine/imagedata.h" +#include "../rtengine/metadata.h" #include "../rtengine/procparams.h" using namespace rtengine; @@ -493,9 +494,9 @@ void IPTCPanel::setImageData (const FramesMetaData* id) embeddedData->clear(); if (id) { try { - auto img = open_exiv2(id->getFileName()); - img->readMetadata(); - auto& iptc = img->iptcData(); + rtengine::Exiv2Metadata meta(id->getFileName()); + meta.load(); + auto& iptc = meta.iptcData(); for (const auto& tag : iptc) { if (iptc_keys.find(tag.key()) != iptc_keys.end()) { (*embeddedData)[tag.key()].push_back(tag.toString()); diff --git a/rtgui/options.cc b/rtgui/options.cc index ce03db434..cf2cbaad3 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -626,7 +626,7 @@ void Options::setDefaults() rtSettings.edghi = 3.0;//1.1 and 5. rtSettings.edglo = 0.5;//0.1 and 0.95 rtSettings.limrad = 20.;//1 and 60 - + rtSettings.protectred = 60; rtSettings.protectredh = 0.3; @@ -682,6 +682,9 @@ void Options::setDefaults() cropAutoFit = false; rtSettings.thumbnail_inspector_mode = rtengine::Settings::ThumbnailInspectorMode::JPEG; + + rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::STD; + rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::NONE; } Options* Options::copyFrom(Options* other) @@ -1488,11 +1491,11 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("GUI", "CurveBBoxPosition")) { curvebboxpos = keyFile.get_integer("GUI", "CurveBBoxPosition"); } - + if (keyFile.has_key("GUI", "Complexity")) { complexity = keyFile.get_integer("GUI", "Complexity"); } - + if (keyFile.has_key("GUI", "InspectorWindow")) { inspectorWindow = keyFile.get_boolean("GUI", "InspectorWindow"); } @@ -1755,8 +1758,8 @@ void Options::readFromFile(Glib::ustring fname) } } - - + + if (keyFile.has_group("ICC Profile Creator")) { if (keyFile.has_key("ICC Profile Creator", "PimariesPreset")) { ICCPC_primariesPreset = keyFile.get_string("ICC Profile Creator", "PimariesPreset"); @@ -2030,6 +2033,27 @@ void Options::readFromFile(Glib::ustring fname) } } + if (keyFile.has_group("Metadata")) { + if (keyFile.has_key("Metadata", "XMPSidecarStyle")) { + std::string val = keyFile.get_string("Metadata", "XMPSidecarStyle"); + if (val == "ext") { + rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::EXT; + } else { + rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::STD; + } + } + if (keyFile.has_key("Metadata", "XMPSynchronization")) { + std::string val = keyFile.get_string("Metadata", "XMPSynchronization"); + if (val == "read") { + rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::READ; + } else if (val == "readwrite") { + rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::READ_WRITE; + } else { + rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::NONE; + } + } + } + // -------------------------------------------------------------------------------------------------------- filterOutParsedExtensions(); @@ -2448,6 +2472,25 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("Lensfun", "DBDirectory", rtSettings.lensfunDbDirectory); + switch (rtSettings.xmp_sidecar_style) { + case rtengine::Settings::XmpSidecarStyle::EXT: + keyFile.set_string("Metadata", "XMPSidecarStyle", "ext"); + break; + default: + keyFile.set_string("Metadata", "XMPSidecarStyle", "std"); + } + + switch (rtSettings.metadata_xmp_sync) { + case rtengine::Settings::MetadataXmpSync::READ: + keyFile.set_string("Metadata", "XMPSynchronization", "read"); + break; + case rtengine::Settings::MetadataXmpSync::READ_WRITE: + keyFile.set_string("Metadata", "XMPSynchronization", "readwrite"); + break; + default: + keyFile.set_string("Metadata", "XMPSynchronization", "none"); + } + keyData = keyFile.to_data(); } catch (Glib::KeyFileError &e) { diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 9d9603297..62c243802 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -527,7 +527,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () iprofiles->set_size_request(50, -1); setExpandAlignProperties(iprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); ipconn = iprofiles->signal_changed().connect(sigc::mem_fun(*this, &Preferences::forImageComboChanged)); - + Gtk::Grid* defpt = Gtk::manage(new Gtk::Grid()); defpt->set_row_spacing(2); defpt->attach(*drlab, 0, 0, 1, 1); @@ -535,7 +535,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () defpt->attach(*drimg, 0, 1, 1, 1); defpt->attach(*iprofiles, 1, 1, 1, 1); vbpp->pack_start(*defpt, Gtk::PACK_SHRINK, 4); - + useBundledProfiles = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_USEBUNDLEDPROFILES"))); bpconn = useBundledProfiles->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::bundledProfilesChanged)); vbpp->pack_start(*useBundledProfiles, Gtk::PACK_SHRINK, 4); @@ -581,9 +581,36 @@ Gtk::Widget* Preferences::getImageProcessingPanel () fdp->add(*vbdp); vbImageProcessing->pack_start (*fdp, Gtk::PACK_SHRINK, 4); -// Gtk::Frame* fdf = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_DARKFRAME")) ); -// Gtk::Box* hb42 = Gtk::manage (new Gtk::Box ()); -// darkFrameDir = Gtk::manage (new Gtk::FileChooserButton (M ("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + // Metadata + Gtk::Frame *mf = Gtk::manage(new Gtk::Frame(M("PREFERENCES_METADATA"))); + Gtk::Grid *mtbl = Gtk::manage(new Gtk::Grid()); + setExpandAlignProperties(mtbl, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + metadataSyncCombo = Gtk::manage(new Gtk::ComboBoxText()); + metadataSyncCombo->set_active(0); + metadataSyncCombo->append(M("PREFERENCES_METADATA_SYNC_NONE")); + metadataSyncCombo->append(M("PREFERENCES_METADATA_SYNC_READ")); + metadataSyncCombo->append(M("PREFERENCES_METADATA_SYNC_READWRITE")); + Gtk::Label *mlbl = Gtk::manage(new Gtk::Label(M("PREFERENCES_METADATA_SYNC") + ": ")); + mtbl->attach(*mlbl, 0, 0, 1, 1); + mtbl->attach_next_to(*metadataSyncCombo, *mlbl, Gtk::POS_RIGHT, 1, 1); + setExpandAlignProperties(mlbl, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(metadataSyncCombo, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + xmpSidecarCombo = Gtk::manage(new Gtk::ComboBoxText()); + xmpSidecarCombo->set_active(0); + xmpSidecarCombo->append(M("PREFERENCES_XMP_SIDECAR_MODE_STD")); + xmpSidecarCombo->append(M("PREFERENCES_XMP_SIDECAR_MODE_EXT")); + + mlbl = Gtk::manage(new Gtk::Label(M("PREFERENCES_XMP_SIDECAR_MODE") + ": ")); + mtbl->attach(*mlbl, 0, 2, 1, 1); + mtbl->attach_next_to(*xmpSidecarCombo, *mlbl, Gtk::POS_RIGHT, 1, 1); + setExpandAlignProperties(mlbl, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(xmpSidecarCombo, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + mf->add(*mtbl); + vbImageProcessing->pack_start(*mf, Gtk::PACK_SHRINK, 4); + // Directories Gtk::Frame* cdf = Gtk::manage(new Gtk::Frame(M("PREFERENCES_DIRECTORIES"))); Gtk::Grid* dirgrid = Gtk::manage(new Gtk::Grid()); @@ -1104,7 +1131,7 @@ Gtk::Widget* Preferences::getGeneralPanel() setExpandAlignProperties(pseudoHiDPI, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); Gtk::Separator *vSep = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)); - + appearanceGrid->attach(*themeLbl, 0, 0, 1, 1); appearanceGrid->attach(*themeCBT, 1, 0, 1, 1); @@ -1870,6 +1897,9 @@ void Preferences::storePreferences() moptions.cropGuides = Options::CropGuidesMode(cropGuidesCombo->get_active_row_number()); moptions.cropAutoFit = cropAutoFitCB->get_active(); + + moptions.rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync(metadataSyncCombo->get_active_row_number()); + moptions.rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle(xmpSidecarCombo->get_active_row_number()); } void Preferences::fillPreferences() @@ -2053,7 +2083,7 @@ void Preferences::fillPreferences() } curveBBoxPosC->set_active(moptions.curvebboxpos); - complexitylocal->set_active(moptions.complexity); + complexitylocal->set_active(moptions.complexity); inspectorWindowCB->set_active(moptions.inspectorWindow); zoomOnScrollCB->set_active(moptions.zoomOnScroll); @@ -2120,6 +2150,9 @@ void Preferences::fillPreferences() txtSndLngEditProcDone->set_text(moptions.sndLngEditProcDone); spbSndLngEditProcDoneSecs->set_value(moptions.sndLngEditProcDoneSecs); #endif + + metadataSyncCombo->set_active(int(moptions.rtSettings.metadata_xmp_sync)); + xmpSidecarCombo->set_active(int(moptions.rtSettings.xmp_sidecar_style)); } /* diff --git a/rtgui/preferences.h b/rtgui/preferences.h index df4e3327a..86e81424d 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -223,6 +223,9 @@ class Preferences final : Gtk::ComboBoxText *cropGuidesCombo; Gtk::CheckButton *cropAutoFitCB; + Gtk::ComboBoxText *metadataSyncCombo; + Gtk::ComboBoxText *xmpSidecarCombo; + Glib::ustring storedValueRaw; Glib::ustring storedValueImg; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index e50d7ac77..31ca8bc1f 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -33,6 +33,7 @@ #include #include "../rtengine/dynamicprofile.h" +#include "../rtengine/metadata.h" #include "../rtengine/profilestore.h" #include "../rtengine/settings.h" #include "guiutils.h" @@ -1026,6 +1027,10 @@ void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) if (updateCacheImageData) { cfs.save (getCacheFileName ("data", ".txt")); } + + if (updatePParams && pparamsValid) { + saveMetadata(); + } } Thumbnail::~Thumbnail () @@ -1204,6 +1209,33 @@ void Thumbnail::getCamWB(double& temp, double& green) const } } +void Thumbnail::saveMetadata() +{ + if (options.rtSettings.metadata_xmp_sync != rtengine::Settings::MetadataXmpSync::READ_WRITE) { + return; + } + + if (pparams->exif.empty() && pparams->iptc.empty()) { + return; + } + + auto fn = rtengine::Exiv2Metadata::xmpSidecarPath(fname); + try { + auto xmp = rtengine::Exiv2Metadata::getXmpSidecar(fname); + rtengine::Exiv2Metadata meta; + meta.xmpData() = std::move(xmp); + meta.setExif(pparams->exif); + meta.setIptc(pparams->iptc); + meta.saveToXmp(fn); + if (options.rtSettings.verbose) { + std::cout << "saved edited metadata for " << fname << " to " + << fn << std::endl; + } + } catch (Exiv2::AnyError &exc) { + std::cerr << "ERROR saving metadata for " << fname << " to " << fn + << ": " << exc.what() << std::endl; + } +} void Thumbnail::getSpotWB(int x, int y, int rect, double& temp, double& green) { if (tpp) { diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 93d1deb93..85701142d 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -88,6 +88,8 @@ class Thumbnail Glib::ustring getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fext) const; + void saveMetadata(); + public: Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf); Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5); From a4b08016463546245724296fc22e00f29ee8b53f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 15 May 2019 05:57:14 -0700 Subject: [PATCH 014/110] fixed bugs in metadata saving (cherry picked from commit 880b1d3d865a7820051cf3023cc58802daca28b0) --- rtdata/languages/default | 84 ++++++++++++++++++++++------------------ rtengine/init.cc | 4 ++ rtengine/metadata.cc | 49 ++++++++++++++++------- rtengine/metadata.h | 3 ++ 4 files changed, 88 insertions(+), 52 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 595f03e7e..3f51e1d90 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1644,7 +1644,7 @@ PARTIALPASTE_LENSPROFILE;Profiled lens correction PARTIALPASTE_LOCALCONTRAST;Local contrast PARTIALPASTE_LOCALLAB;Local Adjustments PARTIALPASTE_LOCALLABGROUP;Local Adjustments Settings -PARTIALPASTE_LOCGROUP;Local +PARTIALPASTE_LOCGROUP;Local PARTIALPASTE_METADATA;Metadata mode PARTIALPASTE_METAGROUP;Metadata settings PARTIALPASTE_PCVIGNETTE;Vignette filter @@ -1789,6 +1789,11 @@ PREFERENCES_MENUGROUPLABEL;Group "Color label" PREFERENCES_MENUGROUPPROFILEOPERATIONS;Group "Processing profile operations" PREFERENCES_MENUGROUPRANK;Group "Rank" PREFERENCES_MENUOPTIONS;Context Menu Options +PREFERENCES_METADATA;Metadata +PREFERENCES_METADATA_SYNC;Metadata synchronization with XMP sidecars +PREFERENCES_METADATA_SYNC_NONE;Off +PREFERENCES_METADATA_SYNC_READ;Read only +PREFERENCES_METADATA_SYNC_READWRITE;Bidirectional PREFERENCES_MONINTENT;Default rendering intent PREFERENCES_MONITOR;Monitor PREFERENCES_MONPROFILE;Default color profile @@ -1864,6 +1869,9 @@ PREFERENCES_TP_LABEL;Tool panel: PREFERENCES_TP_VSCROLLBAR;Hide vertical scrollbar PREFERENCES_USEBUNDLEDPROFILES;Use bundled profiles PREFERENCES_WORKFLOW;Layout +PREFERENCES_XMP_SIDECAR_MODE;XMP sidecar style +PREFERENCES_XMP_SIDECAR_MODE_STD;Standard (FILENAME.xmp for FILENAME.ext) +PREFERENCES_XMP_SIDECAR_MODE_EXT;Darktable-like (FILENAME.ext.xmp for FILENAME.ext) PREFERENCES_ZOOMONSCROLL;Zoom images by scrolling PROFILEPANEL_COPYPPASTE;Parameters to copy PROFILEPANEL_GLOBALPROFILES;Bundled profiles @@ -2057,7 +2065,7 @@ TP_COLORAPP_CHROMA_S;Saturation (S) TP_COLORAPP_CHROMA_S_TOOLTIP;Saturation in CIECAM02/16 corresponds to the color of a stimulus in relation to its own brightness, differs from L*a*b* and RGB saturation. TP_COLORAPP_CHROMA_TOOLTIP;Chroma in CIECAM02/16 corresponds to the color of a stimulus relative to the clarity of a stimulus that appears white under identical conditions, differs from L*a*b* and RGB chroma. TP_COLORAPP_CIECAT_DEGREE;CAT02/16 adaptation -TP_COLORAPP_CONTRAST;Contrast (J) +TP_COLORAPP_CONTRAST;Contrast (J) TP_COLORAPP_CONTRAST_Q;Contrast (Q) TP_COLORAPP_CONTRAST_Q_TOOLTIP;Contrast (Q) in CIECAM02/16 is based on brightness, differs from L*a*b* and RGB contrast. TP_COLORAPP_CONTRAST_TOOLTIP;Contrast (J) in CIECAM02/16 is based on lightness, differs from L*a*b* and RGB contrast. @@ -2104,7 +2112,7 @@ TP_COLORAPP_MOD16;CIECAM16 TP_COLORAPP_NEUTRAL;Reset TP_COLORAPP_NEUTRAL_TIP;Reset all sliders checkbox and curves to their default values TP_COLORAPP_PRESETCAT02;Preset cat02/16 automatic - Symmetric mode -TP_COLORAPP_PRESETCAT02_TIP;Set combobox, sliders, temp, green so that Cat02/16 automatic is preset.\nYou can change illuminant shooting conditions.\nYou must change Cat02/16 adaptation Viewing conditions if needed.\nYou can change Temperature and Tint Viewing conditions if needed, and other settings if needed.\nAll auto checkbox are disabled +TP_COLORAPP_PRESETCAT02_TIP;Set combobox, sliders, temp, green so that Cat02/16 automatic is preset.\nYou can change illuminant shooting conditions.\nYou must change Cat02/16 adaptation Viewing conditions if needed.\nYou can change Temperature and Tint Viewing conditions if needed, and other settings if needed.\nAll auto checkbox are disabled TP_COLORAPP_RSTPRO;Red & skin-tones protection TP_COLORAPP_RSTPRO_TOOLTIP;Red & skin-tones protection affects both sliders and curves. TP_COLORAPP_SOURCEF_TOOLTIP;Corresponds to the shooting conditions and how to bring the conditions and data back to a "normal" area. Normal" means average or standard conditions and data, i.e. without taking into account CIECAM corrections. @@ -2522,13 +2530,13 @@ TP_LOCALLAB_BLURCOL;Radius TP_LOCALLAB_BLURCOLDE_TOOLTIP;The image used to calculate dE is blurred slightly to avoid taking isolated pixels into account. TP_LOCALLAB_BLURDE;Blur shape detection TP_LOCALLAB_BLURLC;Luminance only -TP_LOCALLAB_BLURLEVELFRA;Blur levels +TP_LOCALLAB_BLURLEVELFRA;Blur levels TP_LOCALLAB_BLURMASK_TOOLTIP;Uses a large-radius blur to create a mask that allows you to vary the contrast of the image and/or darken/lighten parts of it. TP_LOCALLAB_BLURRESIDFRA;Blur Residual TP_LOCALLAB_BLURRMASK_TOOLTIP;Allows you to vary the "radius" of the Gaussian blur (0 to 1000) TP_LOCALLAB_BLUR_TOOLNAME;Blur/Grain & Denoise TP_LOCALLAB_BLWH;All changes forced in Black-and-White -TP_LOCALLAB_BLWH_TOOLTIP;Force color components "a" and "b" to zero.\nUseful for black and white processing, or film simulation. +TP_LOCALLAB_BLWH_TOOLTIP;Force color components "a" and "b" to zero.\nUseful for black and white processing, or film simulation. TP_LOCALLAB_BUTTON_ADD;Add TP_LOCALLAB_BUTTON_DEL;Delete TP_LOCALLAB_BUTTON_DUPL;Duplicate @@ -2553,11 +2561,11 @@ TP_LOCALLAB_CHROMASKCOL;Chroma TP_LOCALLAB_CHROMASK_TOOLTIP;Changes the chroma of the mask if one exists (i.e. C(C) or LC(H) is activated). TP_LOCALLAB_CHRRT;Chroma TP_LOCALLAB_CIEC;Use Ciecam environment parameters -TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nThe first Ciecam process 'Scene conditions' is carried out by Log encoding, it also uses 'Absolute luminance' at the time of shooting.\nThe second Ciecam process 'Image adjustments' is simplified and uses only 3 variables (local contrast, contrast J, saturation s).\nThe third Ciecam process 'Viewing conditions' adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. +TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nThe first Ciecam process 'Scene conditions' is carried out by Log encoding, it also uses 'Absolute luminance' at the time of shooting.\nThe second Ciecam process 'Image adjustments' is simplified and uses only 3 variables (local contrast, contrast J, saturation s).\nThe third Ciecam process 'Viewing conditions' adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. TP_LOCALLAB_CIRCRADIUS;Spot size TP_LOCALLAB_CIRCRAD_TOOLTIP;Contains the references of the RT-spot, useful for shape detection (hue, luma, chroma, Sobel).\nLow values may be useful for processing foliage.\nHigh values may be useful for processing skin. TP_LOCALLAB_CLARICRES;Merge chroma -TP_LOCALLAB_CLARIFRA;Clarity & Sharp mask/Blend & Soften Images +TP_LOCALLAB_CLARIFRA;Clarity & Sharp mask/Blend & Soften Images TP_LOCALLAB_CLARILRES;Merge luma TP_LOCALLAB_CLARISOFT;Soft radius TP_LOCALLAB_CLARISOFT_TOOLTIP;The ‘Soft radius’ slider (guided filter algorithm) reduces halos and irregularities for both Clarity and Sharp Mask and for all pyramid wavelet processes. To deactivate, set slider to zero. @@ -2589,7 +2597,7 @@ TP_LOCALLAB_CONTRESID;Contrast TP_LOCALLAB_CONTTHMASK_TOOLTIP;Allows you to determine which parts of the image will be impacted based on the texture. TP_LOCALLAB_CONTTHR;Contrast Threshold TP_LOCALLAB_CONTWFRA;Local contrast -TP_LOCALLAB_CSTHRESHOLD;Wavelet levels +TP_LOCALLAB_CSTHRESHOLD;Wavelet levels TP_LOCALLAB_CSTHRESHOLDBLUR;Wavelet level selection TP_LOCALLAB_CURV;Lightness - Contrast - Chrominance "Super" TP_LOCALLAB_CURVCURR;Normal @@ -2613,19 +2621,19 @@ TP_LOCALLAB_DELTAD;Delta balance TP_LOCALLAB_DELTAEC;ΔE Image mask TP_LOCALLAB_DENOIBILAT_TOOLTIP;Allows you to reduce impulse or ‘salt & pepper’ noise. TP_LOCALLAB_DENOICHROC_TOOLTIP;Allows you to deal with blotches and packets of noise. -TP_LOCALLAB_DENOICHRODET_TOOLTIP;Allows you to recover chrominance detail by progressively applying a Fourier transform (DCT). +TP_LOCALLAB_DENOICHRODET_TOOLTIP;Allows you to recover chrominance detail by progressively applying a Fourier transform (DCT). TP_LOCALLAB_DENOICHROF_TOOLTIP;Allows you to adjust fine-detail chrominance noise TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP;Allows you to direct the chroma noise reduction towards either the blue-yellow or red-green colors. TP_LOCALLAB_DENOIEQUAL_TOOLTIP;Allows you to carry out more or less noise reduction in either the shadows or the highlights. TP_LOCALLAB_DENOI1_EXP;Denoise based on luminance mask TP_LOCALLAB_DENOI2_EXP;Recovery based on luminance mask -TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;Allows you to recover luminance detail by progressively applying a Fourier transform (DCT). +TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;Allows you to recover luminance detail by progressively applying a Fourier transform (DCT). TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. Aggressive mode removes low frequency detail.\nConservative and Aggressive modes use wavelets and DCT and can be used in conjunction with ‘Non-local Means – Luminance’. TP_LOCALLAB_DENOIS;Denoise -TP_LOCALLAB_DENOITHR_TOOLTIP;Adjusts edge detection to help reduce noise in uniform, low-contrast areas. +TP_LOCALLAB_DENOITHR_TOOLTIP;Adjusts edge detection to help reduce noise in uniform, low-contrast areas. TP_LOCALLAB_DENOI_EXP;Denoise TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (deltaE). -TP_LOCALLAB_DEPTH;Depth +TP_LOCALLAB_DEPTH;Depth TP_LOCALLAB_DETAIL;Local contrast TP_LOCALLAB_DETAILFRA;Edge detection - DCT TP_LOCALLAB_DETAILSH;Details @@ -2663,12 +2671,12 @@ TP_LOCALLAB_EXPCHROMA_TOOLTIP;Use in association with ‘Exposure compensation f TP_LOCALLAB_EXPCOLOR_TOOLTIP;Adjust color, lightness, contrast and correct small defects such as red-eye, sensor dust etc. TP_LOCALLAB_EXPCOMP;Exposure compensation ƒ TP_LOCALLAB_EXPCOMPINV;Exposure compensation -TP_LOCALLAB_EXPCOMP_TOOLTIP;For portraits or images with a low color gradient. You can change ‘Shape detection’ in "Settings":\n\nIncrease 'ΔE scope threshold'\nReduce 'ΔE decay'\nIncrease 'ab-L balance (ΔE)’ -TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;See the documentation for Wavelet Levels.\nThere are some differences in the Locallab version: more tools and more possibilities for working on individual detail levels.\ne.g. Wavelet-level tone mapping. +TP_LOCALLAB_EXPCOMP_TOOLTIP;For portraits or images with a low color gradient. You can change ‘Shape detection’ in "Settings":\n\nIncrease 'ΔE scope threshold'\nReduce 'ΔE decay'\nIncrease 'ab-L balance (ΔE)’ +TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;See the documentation for Wavelet Levels.\nThere are some differences in the Locallab version: more tools and more possibilities for working on individual detail levels.\ne.g. Wavelet-level tone mapping. TP_LOCALLAB_EXPCONTRAST_TOOLTIP;Avoid spots that are too small ( < 32x32 pixels).\nUse low ‘Transition value’ and high ‘Transition decay’ and ‘Scope’ to simulate small RT-spots and deal with defects.\nUse 'Clarity and Sharp mask and Blend and Soften Images' if necessary by adjusting 'Soft radius' to reduce artifacts. TP_LOCALLAB_EXPCURV;Curves TP_LOCALLAB_EXPGRAD;Graduated Filter -TP_LOCALLAB_EXPGRADCOL_TOOLTIP;A graduated filter is available in Color and Light (luminance, chrominance & hue gradients, and "Merge file") Exposure (luminance grad.), Exposure Mask (luminance grad.), Shadows/Highlights (luminance grad.), Vibrance (luminance, chrominance & hue gradients), Local contrast & wavelet pyramid (local contrast grad.).\nFeather is located in Settings. +TP_LOCALLAB_EXPGRADCOL_TOOLTIP;A graduated filter is available in Color and Light (luminance, chrominance & hue gradients, and "Merge file") Exposure (luminance grad.), Exposure Mask (luminance grad.), Shadows/Highlights (luminance grad.), Vibrance (luminance, chrominance & hue gradients), Local contrast & wavelet pyramid (local contrast grad.).\nFeather is located in Settings. TP_LOCALLAB_EXPLAPBAL_TOOLTIP;Changes the transformed/original image blend TP_LOCALLAB_EXPLAPGAMM_TOOLTIP;Changes the behaviour for images with too much or too little contrast by adding a gamma curve before and after the Laplace transform TP_LOCALLAB_EXPLAPLIN_TOOLTIP;Changes the behaviour for underexposed images by adding a linear component prior to applying the Laplace transform @@ -2711,10 +2719,10 @@ TP_LOCALLAB_GRADANG;Gradient angle TP_LOCALLAB_GRADANG_TOOLTIP;Rotation angle in degrees : -180 0 +180 TP_LOCALLAB_GRADFRA;Graduated Filter Mask TP_LOCALLAB_GRADGEN_TOOLTIP;Adjusts luminance gradient strength -TP_LOCALLAB_GRADLOGFRA;Graduated Filter Luminance +TP_LOCALLAB_GRADLOGFRA;Graduated Filter Luminance TP_LOCALLAB_GRADSTR;Gradient strength TP_LOCALLAB_GRADSTRAB_TOOLTIP;Adjusts chroma gradient strength -TP_LOCALLAB_GRADSTRCHRO;Chroma gradient strength +TP_LOCALLAB_GRADSTRCHRO;Chroma gradient strength TP_LOCALLAB_GRADSTRHUE;Hue gradient strength TP_LOCALLAB_GRADSTRHUE2;Hue gradient strength TP_LOCALLAB_GRADSTRHUE_TOOLTIP;Adjusts hue gradient strength @@ -2758,7 +2766,7 @@ TP_LOCALLAB_LAPMASKCOL;Laplacian threshold TP_LOCALLAB_LAPRAD1_TOOLTIP;Increases the contrast of the mask by increasing the luminance values of the lighter areas. Can be used in conjunction with the L(L) and LC(H) curves. TP_LOCALLAB_LAPRAD2_TOOLTIP;Smooth radius uses a guided filter to decrease artifacts and smooth out the transition TP_LOCALLAB_LAPRAD_TOOLTIP;Smooth radius uses a guided filter to decrease artifacts and smooth out the transition -TP_LOCALLAB_LAP_MASK_TOOLTIP;Solves PDEs for all Laplacian masks.\nIf enabled the Laplacian threshold mask reduces artifacts and smooths the result.\nIf disabled the response is linear. +TP_LOCALLAB_LAP_MASK_TOOLTIP;Solves PDEs for all Laplacian masks.\nIf enabled the Laplacian threshold mask reduces artifacts and smooths the result.\nIf disabled the response is linear. TP_LOCALLAB_LC_FFTW_TOOLTIP;FFT improves quality and allows the use of large radii, but increases processing time (depends on the area to be processed). Preferable to use only for large radii. The size of the area can be reduced by a few pixels to optimize the FFTW. This can reduce the processing time by a factor of 1.5 to 10. TP_LOCALLAB_LC_TOOLNAME;Local Contrast & Wavelets TP_LOCALLAB_LEVELBLUR;Maximum blur levels @@ -2804,9 +2812,9 @@ TP_LOCALLAB_LOGFRA;Scene Conditions TP_LOCALLAB_LOGFRAME_TOOLTIP;Allows you to calculate and adjust the Ev levels and the 'Mean luminance Yb%' (source gray point) for the spot area. The resulting values will be used by all Lab operations and most RGB operations in the pipeline.\nTakes into account exposure compensation in the main-menu Exposure tab.\nAlso calculates the absolute luminance at the time of shooting. TP_LOCALLAB_LOGIMAGE_TOOLTIP;Takes into account corresponding Ciecam variables (mainly Contrast 'J' and Saturation 's', and also Contrast (Q) , Brightness (Q), Lightness (J), Colorfulness (M) in Advanced mode). TP_LOCALLAB_LOGLIGHTL;Lightness (J) -TP_LOCALLAB_LOGLIGHTL_TOOLTIP;Close to lightness (L*a*b*), takes into account the increase in perceived coloration. +TP_LOCALLAB_LOGLIGHTL_TOOLTIP;Close to lightness (L*a*b*), takes into account the increase in perceived coloration. TP_LOCALLAB_LOGLIGHTQ;Brightness (Q) -TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;Perceived amount of light emanating from a stimulus.\nIndicator that a stimulus appears to be more or less bright, clear. +TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;Perceived amount of light emanating from a stimulus.\nIndicator that a stimulus appears to be more or less bright, clear. TP_LOCALLAB_LOGLIN;Logarithm mode TP_LOCALLAB_LOGPFRA;Relative Exposure Levels TP_LOCALLAB_LOGREPART;Strength @@ -2877,16 +2885,16 @@ TP_LOCALLAB_MASKLOWTHRESRETI_TOOLTIP;Dark-tone limit below which the Retinex (Lu TP_LOCALLAB_MASKLOWTHRESTM_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Tone Mapping settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. TP_LOCALLAB_MASKLOWTHRESVIB_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Vibrance and Warm Cool settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. TP_LOCALLAB_MASKLOWTHRESWAV_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Local contrast and Wavelet settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. -TP_LOCALLAB_MASKLCTHRMID;Gray area luma denoise -TP_LOCALLAB_MASKLCTHRMIDCH;Gray area chroma denoise +TP_LOCALLAB_MASKLCTHRMID;Gray area luma denoise +TP_LOCALLAB_MASKLCTHRMIDCH;Gray area chroma denoise TP_LOCALLAB_MASKUSABLE;Mask enabled (Mask & modifications) TP_LOCALLAB_MASKUNUSABLE;Mask disabled (Mask & modifications) TP_LOCALLAB_MASKRECOTHRES;Recovery threshold -TP_LOCALLAB_MASK_TOOLTIP;You can enable multiple masks for a tool by activating another tool and using only the mask (set the tool sliders to 0 ).\n\nYou can also duplicate the RT-spot and place it close to the first spot. The small variations in the spot references allows you to make fine adjustments. +TP_LOCALLAB_MASK_TOOLTIP;You can enable multiple masks for a tool by activating another tool and using only the mask (set the tool sliders to 0 ).\n\nYou can also duplicate the RT-spot and place it close to the first spot. The small variations in the spot references allows you to make fine adjustments. TP_LOCALLAB_MED;Medium TP_LOCALLAB_MEDIAN;Median Low TP_LOCALLAB_MEDIANITER_TOOLTIP;The number of successive iterations carried out by the median filter. -TP_LOCALLAB_MEDIAN_TOOLTIP;You can choose a median value in the range 3x3 to 9x9 pixels. Higher values increase noise reduction and blur. +TP_LOCALLAB_MEDIAN_TOOLTIP;You can choose a median value in the range 3x3 to 9x9 pixels. Higher values increase noise reduction and blur. TP_LOCALLAB_MEDNONE;None TP_LOCALLAB_MERCOL;Color TP_LOCALLAB_MERDCOL;Merge background (ΔE) @@ -2935,7 +2943,7 @@ TP_LOCALLAB_MRFOU;Previous Spot TP_LOCALLAB_MRONE;None TP_LOCALLAB_MRTHR;Original Image TP_LOCALLAB_MRTWO;Short Curves 'L' Mask -TP_LOCALLAB_MULTIPL_TOOLTIP;Wide-range tone adjustment: -18EV to +4EV. The first slider acts on very dark tones between -18EV and -6EV. The last slider acts on light tones up to 4EV +TP_LOCALLAB_MULTIPL_TOOLTIP;Wide-range tone adjustment: -18EV to +4EV. The first slider acts on very dark tones between -18EV and -6EV. The last slider acts on light tones up to 4EV TP_LOCALLAB_NEIGH;Radius TP_LOCALLAB_NLDENOISE_TOOLTIP;“Detail recovery” acts on a Laplacian transform to target uniform areas rather than areas with detail. TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP;Use this slider to adapt the amount of denoise to the size of the objects to be processed. @@ -3009,10 +3017,10 @@ TP_LOCALLAB_RETIM;Original Retinex TP_LOCALLAB_RETITOOLFRA;Retinex Tools TP_LOCALLAB_RETI_FFTW_TOOLTIP;FFT improve quality and allow big radius, but increases the treatment time.\nThe treatment time depends on the surface to be treated\nThe treatment time depends on the value of scale (be carefull to high values).\nTo be used preferably for large radius.\n\nDimensions can be reduced by a few pixels to optimize FFTW.\nThis optimization can reduce the treatment time by a factor of 1.5 to 10.\nOptimization not used in Preview TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP;Has no effect when the value of "Lightness = 1" or "Darkness =2".\nFor other values, the last step of a "Multiple scale Retinex" algorithm (similar to "local contrast") is applied. These 2 cursors, associated with "Strength" allow you to make adjustments upstream of local contrast -TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP;Adjusts the internal parameters to optimize the response.\nPreferable to keep the "Restored data" values close to Min=0 and Max=32768 (log mode), but other values are possible. +TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP;Adjusts the internal parameters to optimize the response.\nPreferable to keep the "Restored data" values close to Min=0 and Max=32768 (log mode), but other values are possible. TP_LOCALLAB_RETI_LOGLIN_TOOLTIP;Logarithm mode introduces more contrast but will also generate more halos. TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP;The radius and variance sliders allow you adjust haze and target either the foreground or the background. -TP_LOCALLAB_RETI_SCALE_TOOLTIP;If Scale=1, Retinex behaves like local contrast with additional possibilities.\nIncreasing the value of Scale increases the intensity of the recursive action at the expense of processing time. +TP_LOCALLAB_RETI_SCALE_TOOLTIP;If Scale=1, Retinex behaves like local contrast with additional possibilities.\nIncreasing the value of Scale increases the intensity of the recursive action at the expense of processing time. TP_LOCALLAB_RET_TOOLNAME;Dehaze & Retinex TP_LOCALLAB_REWEI;Reweighting iterates TP_LOCALLAB_RGB;RGB Tone Curve @@ -3097,14 +3105,14 @@ TP_LOCALLAB_SOFTM;Soft Light TP_LOCALLAB_SOFTMETHOD_TOOLTIP;Apply a Soft-light blend (identical to the global adjustment). Carry out dodge and burn using the original Retinex algorithm. TP_LOCALLAB_SOFTRADIUSCOL;Soft radius TP_LOCALLAB_SOFTRADIUSCOL_TOOLTIP;Applies a guided filter to the output image to reduce possible artifacts. -TP_LOCALLAB_SOFTRETI;Reduce ΔE artifacts +TP_LOCALLAB_SOFTRETI;Reduce ΔE artifacts TP_LOCALLAB_SOFTRETI_TOOLTIP;Take into account deltaE to improve Transmission map TP_LOCALLAB_SOFT_TOOLNAME;Soft Light & Original Retinex TP_LOCALLAB_SOURCE_ABS;Absolute luminance TP_LOCALLAB_SOURCE_GRAY;Mean luminance (Yb%) TP_LOCALLAB_SPECCASE;Specific cases TP_LOCALLAB_SPECIAL;Special use of RGB curves -TP_LOCALLAB_SPECIAL_TOOLTIP;The checkbox allows you to remove all other actions i.e. ‘Scope’, masks, sliders etc., (except for transitions) and use just the effect of the RGB tone-curve. +TP_LOCALLAB_SPECIAL_TOOLTIP;The checkbox allows you to remove all other actions i.e. ‘Scope’, masks, sliders etc., (except for transitions) and use just the effect of the RGB tone-curve. TP_LOCALLAB_SPOTNAME;New Spot TP_LOCALLAB_STD;Standard TP_LOCALLAB_STR;Strength @@ -3119,7 +3127,7 @@ TP_LOCALLAB_STRRETI_TOOLTIP;if Strength Retinex < 0.2 only Dehaze is enabled.\ni TP_LOCALLAB_STRUC;Structure TP_LOCALLAB_STRUCCOL;Spot structure TP_LOCALLAB_STRUCCOL1;Spot structure -TP_LOCALLAB_STRUCT_TOOLTIP;Uses the Sobel algorithm to take into account structure for shape detection.\nActivate ‘Mask and modifications’ > ‘Show spot structure’ (Advanced mode) to see a preview of the mask (without modifications).\n\nCan be used in conjunction with the Structure Mask, Blur Mask and ‘Local contrast’ (by wavelet level) to improve edge detection.\n\nEffects of adjustments using Lightness, Contrast, Chrominance, Exposure or other non-mask-related tools visible using either ‘Show modified image’ or ‘Show modified areas with mask’. +TP_LOCALLAB_STRUCT_TOOLTIP;Uses the Sobel algorithm to take into account structure for shape detection.\nActivate ‘Mask and modifications’ > ‘Show spot structure’ (Advanced mode) to see a preview of the mask (without modifications).\n\nCan be used in conjunction with the Structure Mask, Blur Mask and ‘Local contrast’ (by wavelet level) to improve edge detection.\n\nEffects of adjustments using Lightness, Contrast, Chrominance, Exposure or other non-mask-related tools visible using either ‘Show modified image’ or ‘Show modified areas with mask’. TP_LOCALLAB_STRUMASKCOL;Structure mask strength TP_LOCALLAB_STRUMASK_TOOLTIP;Structure mask (slider) with the checkbox 'Structure mask as tool' unchecked: In this case a mask showing the structure will be generated even if none of the 3 curves is activated. Structure masks are available for mask (Blur and denoise") and mask(Color & Light). TP_LOCALLAB_STRUSTRMASK_TOOLTIP;Moderate use of this slider is recommended! @@ -3129,7 +3137,7 @@ TP_LOCALLAB_SYM;Symmetrical (mouse) TP_LOCALLAB_SYMSL;Symmetrical (mouse + sliders) TP_LOCALLAB_TARGET_GRAY;Mean luminance (Yb%) TP_LOCALLAB_THRES;Threshold structure -TP_LOCALLAB_THRESDELTAE;ΔE scope threshold +TP_LOCALLAB_THRESDELTAE;ΔE scope threshold TP_LOCALLAB_THRESRETI;Threshold TP_LOCALLAB_THRESWAV;Balance threshold TP_LOCALLAB_TLABEL;TM Min=%1 Max=%2 Mean=%3 Sig=%4 @@ -3154,7 +3162,7 @@ TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Allows you to vary the y-axis transition TP_LOCALLAB_TRANSITVALUE;Transition value TP_LOCALLAB_TRANSITWEAK;Transition decay (linear-log) TP_LOCALLAB_TRANSITWEAK_TOOLTIP;Adjust transition decay function: 1 linear , 2 parabolic, 3 cubic up to ^25.\nCan be used in conjunction with very low transition values to reduce defects (CBDL, Wavelets, Color & Light) -TP_LOCALLAB_TRANSIT_TOOLTIP;Adjust smoothness of transition between affected and unaffected areas as a percentage of the "radius" +TP_LOCALLAB_TRANSIT_TOOLTIP;Adjust smoothness of transition between affected and unaffected areas as a percentage of the "radius" TP_LOCALLAB_TRANSMISSIONGAIN;Transmission gain TP_LOCALLAB_TRANSMISSIONMAP;Transmission map TP_LOCALLAB_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positive values (max).\nOrdinate: amplification or reduction.\nYou can adjust this curve to change the Transmission and reduce artifacts @@ -3186,13 +3194,13 @@ TP_LOCALLAB_WAT_SIGMALC_TOOLTIP;The effect of the local contrast adjustment is s TP_LOCALLAB_WAT_STRENGTHW_TOOLTIP;Intensity of edge-effect detection. TP_LOCALLAB_WAT_STRWAV_TOOLTIP;Allows the local contrast to be varied according to a chosen gradient and angle. The variation of the luminance signal is taken into account and not the luminance. TP_LOCALLAB_WAT_THRESHOLDWAV_TOOLTIP;Range of wavelet levels used throughout the ‘Wavelets’ module. -TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP;Allows you to blur each level of decomposition.\nThe finest to coarsest levels of decomposition are from left to right. +TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP;Allows you to blur each level of decomposition.\nThe finest to coarsest levels of decomposition are from left to right. TP_LOCALLAB_WAT_WAVCBDL_TOOLTIP;Similar to Contrast By Detail Levels. Fine to coarse detail levels from left to right on the x-axis. TP_LOCALLAB_WAT_WAVDELTABAL_TOOLTIP;Acts on the balance of the three directions (horizontal, vertical and diagonal) based on the luminance of the image.\nBy default the shadows or highlights are reduced to avoid artifacts. TP_LOCALLAB_WAT_WAVESHOW_TOOLTIP;Shows all of the ‘Edge sharpness’ tools. It is advisable to read the Wavelet Levels documentation. TP_LOCALLAB_WAT_WAVLEVELBLUR_TOOLTIP;Allows you to adjust the maximum effect of blurring on the levels. TP_LOCALLAB_WAT_WAVSHAPE_TOOLTIP;Low to high local contrast from left to right on the x-axis\nIncrease or decrease local contrast on the y-axis. -TP_LOCALLAB_WAT_WAVTM_TOOLTIP;The lower (negative) part compresses each level of decomposition creating a tone mapping effect.\nThe upper (positive) part attenuates the contrast by level.\nThe finest to coarsest levels of decomposition are from left to right on the x-axis. +TP_LOCALLAB_WAT_WAVTM_TOOLTIP;The lower (negative) part compresses each level of decomposition creating a tone mapping effect.\nThe upper (positive) part attenuates the contrast by level.\nThe finest to coarsest levels of decomposition are from left to right on the x-axis. TP_LOCALLAB_WAV;Local contrast TP_LOCALLAB_WAVBLUR_TOOLTIP;Allows you to blur each level of the decomposition, as well as the residual image. TP_LOCALLAB_WAVCOMP;Compression by level @@ -3453,7 +3461,7 @@ TP_RETINEX_TLABEL;TM Datas Min=%1 Max=%2 Mean=%3 Sigma=%4 TP_RETINEX_TLABEL2;TM Effective Tm=%1 TM=%2 TP_RETINEX_TLABEL_TOOLTIP;ransmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map.\nYou can normalize the results with the threshold slider. TP_RETINEX_TRANF;Transmission -TP_RETINEX_TRANSMISSION;Transmission map +TP_RETINEX_TRANSMISSION;Transmission map TP_RETINEX_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positives values (max).\nOrdinate: amplification or reduction. TP_RETINEX_UNIFORM;Uniform TP_RETINEX_VARIANCE;Contrast @@ -3777,11 +3785,11 @@ TP_WAVELET_STRENGTH;Strength TP_WAVELET_SUPE;Extra TP_WAVELET_THR;Shadows threshold TP_WAVELET_THRDEN_TOOLTIP;Generates a stepped curve used to guide the noise reduction as a function of local contrast. The denoise will be applied to uniform low local-contrast areas. Areas with detail (higher local contrast) will be preserved. -TP_WAVELET_THREND;Local contrast threshold +TP_WAVELET_THREND;Local contrast threshold TP_WAVELET_THRESHOLD;Finer levels TP_WAVELET_THRESHOLD2;Coarser levels TP_WAVELET_THRESHOLD2_TOOLTIP;Only levels from the chosen value to the selected number of ‘wavelet levels’ will be affected by the Shadow luminance range. -TP_WAVELET_THRESHOLD_TOOLTIP;Only levels below and including the chosen value will be affected by the Highlight luminance range. +TP_WAVELET_THRESHOLD_TOOLTIP;Only levels below and including the chosen value will be affected by the Highlight luminance range. TP_WAVELET_THRESWAV;Balance threshold TP_WAVELET_THRH;Highlights threshold TP_WAVELET_TILESBIG;Tiles @@ -3863,7 +3871,7 @@ ZOOMPANEL_ZOOMFITCROPSCREEN;Fit crop to screen\nShortcut: f ZOOMPANEL_ZOOMFITSCREEN;Fit whole image to screen\nShortcut: Alt-f ZOOMPANEL_ZOOMIN;Zoom In\nShortcut: + ZOOMPANEL_ZOOMOUT;Zoom Out\nShortcut: - -//TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nOnly the third Ciecam process (Viewing conditions - Target) is taken into account, as well as part of the second (contrast J, saturation s) , as well as some data from the first process (Scene conditions - Source) which is used for the Log encoding.\nIt also adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. +//TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nOnly the third Ciecam process (Viewing conditions - Target) is taken into account, as well as part of the second (contrast J, saturation s) , as well as some data from the first process (Scene conditions - Source) which is used for the Log encoding.\nIt also adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. //TP_WAVELET_DENH;Low levels (1234)- Finest details //TP_WAVELET_DENL;High levels - Coarsest details //TP_WAVELET_DENLH;Guided threshold for detail levels 1-4 diff --git a/rtengine/init.cc b/rtengine/init.cc index 1a00f7ff6..a73118e46 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -33,6 +33,7 @@ #include "profilestore.h" #include "../rtgui/threadutils.h" #include "rtlensfun.h" +#include "metadata.h" #include "procparams.h" namespace rtengine @@ -103,6 +104,8 @@ int init (const Settings* s, const Glib::ustring& baseDir, const Glib::ustring& } Color::init (); + Exiv2Metadata::init(); + delete lcmsMutex; lcmsMutex = new MyMutex; fftwMutex = new MyMutex; @@ -111,6 +114,7 @@ int init (const Settings* s, const Glib::ustring& baseDir, const Glib::ustring& void cleanup () { + Exiv2Metadata::cleanup(); ProcParams::cleanup (); Color::cleanup (); RawImageSource::cleanup (); diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 15ab7db44..35ffb8ad5 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -20,6 +20,8 @@ #include #include +#include + #include "metadata.h" #include "settings.h" #include "../rtgui/version.h" @@ -65,7 +67,7 @@ Exiv2Metadata::Exiv2Metadata(): Exiv2Metadata::Exiv2Metadata(const Glib::ustring &path): - src_(""), + src_(path), merge_xmp_(settings->metadata_xmp_sync != Settings::MetadataXmpSync::NONE), image_(nullptr), exif_(new rtengine::procparams::ExifPairs), @@ -154,20 +156,27 @@ void Exiv2Metadata::setIptc(const rtengine::procparams::IPTCPairs &iptc) void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const { - auto xmp = getXmpSidecar(src_); - Exiv2::ExifData exif; - Exiv2::IptcData iptc; - Exiv2::moveXmpToExif(xmp, exif); - Exiv2::moveXmpToIptc(xmp, iptc); + try { + auto xmp = getXmpSidecar(src_); + Exiv2::ExifData exif; + Exiv2::IptcData iptc; + Exiv2::moveXmpToIptc(xmp, iptc); + Exiv2::moveXmpToExif(xmp, exif); - for (auto &datum : exif) { - dst->exifData()[datum.key()] = datum; - } - for (auto &datum : iptc) { - dst->iptcData()[datum.key()] = datum; - } - for (auto &datum : xmp) { - dst->xmpData()[datum.key()] = datum; + for (auto &datum : exif) { + dst->exifData()[datum.key()] = datum; + } + for (auto &datum : iptc) { + dst->iptcData()[datum.key()] = datum; + } + for (auto &datum : xmp) { + dst->xmpData()[datum.key()] = datum; + } + } catch (Exiv2::AnyError &exc) { + if (settings->verbose) { + std::cerr << "Error loading metadata from XMP sidecar: " + << exc.what() << std::endl; + } } } @@ -288,4 +297,16 @@ Exiv2::XmpData Exiv2Metadata::getXmpSidecar(const Glib::ustring &path) return ret; } + +void Exiv2Metadata::init() +{ + Exiv2::XmpParser::initialize(); +} + + +void Exiv2Metadata::cleanup() +{ + Exiv2::XmpParser::terminate(); +} + } // namespace rtengine diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 8de384479..2b7851dd4 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -56,6 +56,9 @@ public: static Glib::ustring xmpSidecarPath(const Glib::ustring& path); static Exiv2::XmpData getXmpSidecar(const Glib::ustring& path); + + static void init(); + static void cleanup(); private: void do_merge_xmp(Exiv2::Image* dst) const; From 2d412d74047922707ac7a34eded5b2a08b044892 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 19 May 2019 22:55:28 +0200 Subject: [PATCH 015/110] metadata: do not copy exif rotate info from the original image -- it might just be plain wrong (cherry picked from commit 8f14684588b3c0aec1aab37f4225c99954f6f587) --- rtengine/metadata.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 35ffb8ad5..7e3bdbf05 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -187,6 +187,11 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const dst->readMetadata(); if (image_.get()) { dst->setMetadata(*image_); + auto it = + dst->exifData().findKey(Exiv2::ExifKey("Exif.Image.Orientation")); + if (it != dst->exifData().end()) { + dst->exifData().erase(it); + } if (merge_xmp_) { do_merge_xmp(dst.get()); } From 77d7e633e5a221d340928b33360acf96d35a8d06 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 19 May 2019 14:42:52 -0700 Subject: [PATCH 016/110] metadata: erase also jpeg thumbnail (cherry picked from commit 88661755506cd48393e69e809cf0559572cb213d) --- rtengine/metadata.cc | 23 ++++++++++++++++++----- rtengine/metadata.h | 1 + 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 7e3bdbf05..c5049229d 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -187,11 +187,7 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const dst->readMetadata(); if (image_.get()) { dst->setMetadata(*image_); - auto it = - dst->exifData().findKey(Exiv2::ExifKey("Exif.Image.Orientation")); - if (it != dst->exifData().end()) { - dst->exifData().erase(it); - } + remove_unwanted(dst.get()); if (merge_xmp_) { do_merge_xmp(dst.get()); } @@ -208,6 +204,23 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const } +void Exiv2Metadata::remove_unwanted(Exiv2::Image *dst) const +{ + static const std::vector keys = { + "Exif.Image.Orientation", + "Exif.Photo.MakerNote" + }; + for (auto &k : keys) { + auto it = dst->exifData().findKey(Exiv2::ExifKey(k)); + if (it != dst->exifData().end()) { + dst->exifData().erase(it); + } + } + Exiv2::ExifThumb thumb(dst->exifData()); + thumb.erase(); +} + + void Exiv2Metadata::import_exif_pairs(Exiv2::ExifData &out) const { for (auto &p : *exif_) { diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 2b7851dd4..5f19fa5a1 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -64,6 +64,7 @@ private: void do_merge_xmp(Exiv2::Image* dst) const; void import_exif_pairs(Exiv2::ExifData& out) const; void import_iptc_pairs(Exiv2::IptcData& out) const; + void remove_unwanted(Exiv2::Image* dst) const; Glib::ustring src_; bool merge_xmp_; From 38d87bae72313a4c24b389ed383bb947a794dc04 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 20 May 2019 09:20:02 +0200 Subject: [PATCH 017/110] metadata: keep makernotes (cherry picked from commit 494ae069d4f9d985b65375e104513f9c85453d5b) --- rtengine/metadata.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index c5049229d..6006f5abe 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -207,8 +207,7 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const void Exiv2Metadata::remove_unwanted(Exiv2::Image *dst) const { static const std::vector keys = { - "Exif.Image.Orientation", - "Exif.Photo.MakerNote" + "Exif.Image.Orientation" }; for (auto &k : keys) { auto it = dst->exifData().findKey(Exiv2::ExifKey(k)); From b01b0fbef08f04b5769f57148a0ac7abdec94793 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 20 May 2019 01:56:38 -0700 Subject: [PATCH 018/110] metadata: initialize thumbnail rating from exif (cherry picked from commit 96bd2db0d2e127678bded3bee7aa3275332826c0) --- rtengine/imagedata.cc | 16 ++++++++++------ rtengine/imagedata.h | 2 +- rtengine/rtengine.h | 5 +++-- rtgui/thumbnail.cc | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index e7cf2b4c2..df043c86f 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -287,6 +287,10 @@ FramesData::FramesData(const Glib::ustring &fname) : expcomp = pos->toFloat(); } + if (find_exif_tag("Exif.Image.Rating")) { + rating = pos->toLong(); + } + // ----------------------- // Special file type detection (HDR, PixelShift) // ------------------------ @@ -567,12 +571,6 @@ std::string FramesData::getOrientation() const } -int FramesData::getRating() const -{ - return rating; -} - - void FramesData::setDCRawFrameCount(unsigned int frameCount) { dcrawFrameCount = frameCount; @@ -589,6 +587,12 @@ Glib::ustring FramesData::getFileName() const return fname_; } + +int FramesData::getRating() const +{ + return rating; +} + //------inherited functions--------------// std::string FramesMetaData::apertureToString(double aperture) diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index b1a29dc39..306c3b6f9 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -81,8 +81,8 @@ public: std::string getLens() const override; std::string getSerialNumber() const; std::string getOrientation() const override; - int getRating() const override; Glib::ustring getFileName() const override; + int getRating() const override; }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index ceb27a504..91ef0a436 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -1,4 +1,5 @@ -/* +/* -*- C++ -*- + * * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath @@ -122,7 +123,7 @@ public: /** @return the orientation of the image */ virtual std::string getOrientation() const = 0; /** @return the rating of the image */ - virtual int getRating () const = 0; + virtual int getRating() const = 0; /** @return true if the file is a PixelShift shot (Pentax and Sony bodies) */ virtual bool getPixelShift () const = 0; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 31ca8bc1f..32f80a193 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -387,7 +387,7 @@ void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt) * The result is a complete ProcParams with default values merged with the values * from the loaded ProcParams (sidecar or cache file). */ -void Thumbnail::loadProcParams () +void Thumbnail::loadProcParams() { MyMutex::MyLock lock(mutex); From 0e019b745b730f66f71e4f5f2a62d470d3dd4d5e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 7 Jul 2019 18:00:24 +0200 Subject: [PATCH 019/110] metadata: translate "----" to "Unknown" in lens identification (cherry picked from commit 9b0dce535c7eeda2d20c0ef1fa342b00238a48a1) --- rtengine/imagedata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index df043c86f..c1a5b898d 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -265,7 +265,7 @@ FramesData::FramesData(const Glib::ustring &fname) : if (lens.empty()) { lens = "Unknown"; } - if (lens.empty()) { + if (lens.empty() || lens.find_first_not_of('-') == std::string::npos) { lens = "Unknown"; } From 45acb120a6278cdc0c8731ed763018ebdee8b79d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 26 Jul 2019 08:31:08 -0700 Subject: [PATCH 020/110] improved lens info for fixed-lens cameras (cherry picked from commit a1bcb1a2a65514ae1c8e0bcd3489f83f7a68ead5) --- rtengine/imagedata.cc | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index c1a5b898d..915f723a3 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -261,9 +261,26 @@ FramesData::FramesData(const Glib::ustring &fname) : if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? - } - if (lens.empty()) { - lens = "Unknown"; + } else if (find_exif_tag("Exif.Photo.LensSpecification") && pos->count() == 4) { + const auto round = + [](float f) -> float + { + return int(f * 10.f + 0.5f) / 10.f; + }; + float fl_lo = round(pos->toFloat(0)); + float fl_hi = round(pos->toFloat(1)); + float fn_lo = round(pos->toFloat(2)); + float fn_hi = round(pos->toFloat(3)); + std::ostringstream buf; + buf << fl_lo; + if (fl_lo < fl_hi) { + buf << "-" << fl_hi; + } + buf << "mm F" << fn_lo; + if (fn_lo < fn_hi) { + buf << "-" << fn_hi; + } + lens = buf.str(); } if (lens.empty() || lens.find_first_not_of('-') == std::string::npos) { lens = "Unknown"; From e5c8ceac5f1d8b58d4cbd6292a898759e24cd1b1 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 27 Aug 2019 05:47:15 -0700 Subject: [PATCH 021/110] metadata: fixed detection of Pentax DNG pixelshift images (cherry picked from commit 2bdd3a6c5d79dc61fca39ea39ecd90ba9a12dee5) --- rtengine/imagedata.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 915f723a3..2434fc42b 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -338,7 +338,10 @@ FramesData::FramesData(const Glib::ustring &fname) : if ( !isHDR - && find_exif_tag("Exif.Pentax.Quality") + && ( + find_exif_tag("Exif.Pentax.Quality") + || find_exif_tag("Exif.PentaxDng.Quality") + ) && ( pos->toLong() == 7 || pos->toLong() == 8 From df39e13cf7f50654f8aa9f19d2d6d8efcce46fdf Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 16 Sep 2019 01:30:52 -0700 Subject: [PATCH 022/110] properly handle exif orientation translate the tag value to string using the exiftool way, to be compatible with RT. Fixes issue #4 (cherry picked from commit a4621f54b2ac82b679cf9d865a0a3e4a2ed9c468) --- rtengine/imagedata.cc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 2434fc42b..3b61d2baa 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -256,7 +256,23 @@ FramesData::FramesData(const Glib::ustring &fname) : } if (find_tag(Exiv2::orientation)) { - orientation = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + static const std::vector ormap = { + "Unknown", + "Horizontal (normal)", + "Mirror horizontal", + "Rotate 180", + "Mirror vertical", + "Mirror horizontal and rotate 270 CW", + "Rotate 90 CW", + "Mirror horizontal and rotate 90 CW", + "Rotate 270 CW", + "Unknown" + }; + auto idx = pos->toLong(); + if (idx >= 0 && idx < long(ormap.size())) { + orientation = ormap[idx]; + } + //orientation = pos->print(&exif); } if (find_tag(Exiv2::lensName)) { From 7c39f35317f275a50b763f56eb88e662a72e94df Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 18 Sep 2019 11:58:01 +0200 Subject: [PATCH 023/110] metadata: removed some harmful tags from the exported images (cherry picked from commit 94c3e87113384f4c20b10f467a1c35e90709d161) --- rtengine/metadata.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 6006f5abe..c8aa3061d 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -207,7 +207,9 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const void Exiv2Metadata::remove_unwanted(Exiv2::Image *dst) const { static const std::vector keys = { - "Exif.Image.Orientation" + "Exif.Image.Orientation", + "Exif.Image2.JPEGInterchangeFormat", + "Exif.Image2.JPEGInterchangeFormatLength" }; for (auto &k : keys) { auto it = dst->exifData().findKey(Exiv2::ExifKey(k)); From 25d67c12c1c39235f5b4cb78e9c4c7c35a214c9e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 4 Nov 2019 09:14:53 +0100 Subject: [PATCH 024/110] metadata: remove unwanted tags *after* merging XMP sidecars, not before (cherry picked from commit b45666f61ac9c6083bdc22811351d72bf35497bb) --- rtengine/metadata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index c8aa3061d..bfcb3080e 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -187,10 +187,10 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const dst->readMetadata(); if (image_.get()) { dst->setMetadata(*image_); - remove_unwanted(dst.get()); if (merge_xmp_) { do_merge_xmp(dst.get()); } + remove_unwanted(dst.get()); } else { dst->setExifData(exif_data_); dst->setIptcData(iptc_data_); From e3f3b8ae91bb306b07c8aec7b6308a87ad7239c6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 18 Nov 2019 08:02:46 -0800 Subject: [PATCH 025/110] Get date taken from time digitized Used as the fallback if the original data-time isn't available. Original commit message: metadata: use exiftool as a fallback for files not yet supported by exiv2 (e.g cr3) (cherry picked from commit bdcebdecef8cca82b0d8ad7a24d267308b12e04d) --- rtengine/imagedata.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 3b61d2baa..368f46bf8 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -309,6 +309,9 @@ FramesData::FramesData(const Glib::ustring &fname) : else if (find_exif_tag("Exif.Photo.DateTimeOriginal")) { datetime_taken = pos->print(&exif); } + else if (find_exif_tag("Exif.Photo.DateTimeDigitized")) { + datetime_taken = pos->print(&exif); + } if (sscanf(datetime_taken.c_str(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { time.tm_year -= 1900; time.tm_mon -= 1; From e7fdad875a568a93d8f7438c875d42d77748462b Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 9 Dec 2019 04:27:13 -0800 Subject: [PATCH 026/110] metadata: cache recent files for faster operation (cherry picked from commit 6ee014ddb7ab77537289e1f41f13345e5db54710) --- rtengine/metadata.cc | 22 ++++++++++++++++++---- rtengine/metadata.h | 10 +++++----- rtgui/procparamchangers.h | 15 ++++++++------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index bfcb3080e..70e8b785a 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "metadata.h" #include "settings.h" @@ -32,9 +33,12 @@ namespace rtengine { extern const Settings *settings; +std::unique_ptr Exiv2Metadata::cache_(nullptr); namespace { +constexpr size_t IMAGE_CACHE_SIZE = 200; + Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) { #ifdef EXV_UNICODE_PATH @@ -88,10 +92,19 @@ Exiv2Metadata::Exiv2Metadata(const Glib::ustring &path, bool merge_xmp_sidecar): void Exiv2Metadata::load() const { - if (!src_.empty() && !image_.get()) { - auto img = open_exiv2(src_); - image_.reset(img.release()); - image_->readMetadata(); + if (!src_.empty() && !image_.get() && Glib::file_test(src_.c_str(), Glib::FILE_TEST_EXISTS)) { + CacheVal val; + auto finfo = Gio::File::create_for_path(src_)->query_info(G_FILE_ATTRIBUTE_TIME_MODIFIED); + if (cache_ && cache_->get(src_, val) && val.second >= finfo->modification_time()) { + image_ = val.first; + } else { + auto img = open_exiv2(src_); + image_.reset(img.release()); + image_->readMetadata(); + if (cache_) { + cache_->set(src_, CacheVal(image_, finfo->modification_time())); + } + } if (merge_xmp_) { do_merge_xmp(image_.get()); @@ -319,6 +332,7 @@ Exiv2::XmpData Exiv2Metadata::getXmpSidecar(const Glib::ustring &path) void Exiv2Metadata::init() { + cache_.reset(new ImageCache(IMAGE_CACHE_SIZE)); Exiv2::XmpParser::initialize(); } diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 5f19fa5a1..57904d4a4 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -24,6 +24,7 @@ #include #include #include "procparams.h" +#include "cache.h" namespace rtengine { @@ -74,11 +75,10 @@ private: Exiv2::ExifData exif_data_; Exiv2::IptcData iptc_data_; Exiv2::XmpData xmp_data_; + + typedef std::pair, Glib::TimeVal> CacheVal; + typedef Cache ImageCache; + static std::unique_ptr cache_; }; -// Glib::ustring get_xmp_sidecar_path(const Glib::ustring &path); -// Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname, -// bool merge_xmp_sidecar); -// Exiv2::XmpData read_exiv2_xmp(const Glib::ustring &fname); - } // namespace rtengine diff --git a/rtgui/procparamchangers.h b/rtgui/procparamchangers.h index 8dd3769c6..0ca76a0eb 100644 --- a/rtgui/procparamchangers.h +++ b/rtgui/procparamchangers.h @@ -1,4 +1,5 @@ -/* +/* -*- C++ -*- + * * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath @@ -16,9 +17,9 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#define UNKNOWN -1 -#define FILEBROWSER 1 -#define EDITOR 2 -#define BATCHEDITOR 3 -#define CACHEMGR 4 -#define SAFETYUPDATE 5 +constexpr int UNKNOWN = -1; +constexpr int FILEBROWSER = 1; +constexpr int EDITOR = 2; +constexpr int BATCHEDITOR = 3; +constexpr int CACHEMGR = 4; +constexpr int SAFETYUPDATE = 5; From e90ffe979b2d8d41e6d88788f514e8c5cf6a3dc5 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 4 Jan 2020 07:13:24 -0800 Subject: [PATCH 027/110] metadata: catch std::exception instead of Exiv2::AnyError for better robustness (cherry picked from commit 0e2d9332f633b060bd4d5cbcd9d47009bab0c46c) --- rtengine/imagedata.cc | 2 +- rtengine/imageio.cc | 2 +- rtengine/metadata.cc | 6 +++--- rtgui/exifpanel.cc | 4 ++-- rtgui/iptcpanel.cc | 2 +- rtgui/thumbnail.cc | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 368f46bf8..a810bc925 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -499,7 +499,7 @@ FramesData::FramesData(const Glib::ustring &fname) : #endif } } - } catch (const Exiv2::AnyError& e) { + } catch (const std::exception& e) { if (settings->verbose) { std::cerr << "EXIV2 ERROR: " << e.what() << std::endl; } diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 475792e83..b0510e817 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1385,7 +1385,7 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const // } // dst->writeMetadata(); return true; - } catch (const Exiv2::AnyError& exc) { + } catch (const std::exception& exc) { std::cout << "EXIF ERROR: " << exc.what() << std::endl; return false; } diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 70e8b785a..ecf4c444f 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -185,7 +185,7 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const for (auto &datum : xmp) { dst->xmpData()[datum.key()] = datum; } - } catch (Exiv2::AnyError &exc) { + } catch (std::exception &exc) { if (settings->verbose) { std::cerr << "Error loading metadata from XMP sidecar: " << exc.what() << std::endl; @@ -240,7 +240,7 @@ void Exiv2Metadata::import_exif_pairs(Exiv2::ExifData &out) const for (auto &p : *exif_) { try { out[p.first] = p.second; - } catch (Exiv2::AnyError &exc) {} + } catch (std::exception &exc) {} } } @@ -258,7 +258,7 @@ void Exiv2Metadata::import_iptc_pairs(Exiv2::IptcData &out) const out.add(d); } } - } catch (Exiv2::AnyError &exc) {} + } catch (std::exception &exc) {} } } diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 7438240e9..5cc4af341 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -233,7 +233,7 @@ void ExifPanel::refreshTags() for (const auto& p : *changeList) { try { exif[p.first] = p.second; - } catch (const Exiv2::AnyError& exc) { + } catch (const std::exception& exc) { } } @@ -258,7 +258,7 @@ void ExifPanel::refreshTags() addTag(tag.key(), tag.tagLabel(), tag.print(&exif), false, false); } } - } catch (const Exiv2::AnyError& exc) { + } catch (const std::exception& exc) { return; } diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 724b54aa1..f476e7513 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -502,7 +502,7 @@ void IPTCPanel::setImageData (const FramesMetaData* id) (*embeddedData)[tag.key()].push_back(tag.toString()); } } - } catch (const Exiv2::AnyError& exc) { + } catch (const std::exception& exc) { embeddedData->clear(); } } diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 32f80a193..ce5138d28 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -1231,7 +1231,7 @@ void Thumbnail::saveMetadata() std::cout << "saved edited metadata for " << fname << " to " << fn << std::endl; } - } catch (Exiv2::AnyError &exc) { + } catch (std::exception &exc) { std::cerr << "ERROR saving metadata for " << fname << " to " << fn << ": " << exc.what() << std::endl; } From 200779aa8489d675801c372bdfbb2e9e6d0324a4 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 5 Jan 2020 09:26:29 -0800 Subject: [PATCH 028/110] metadata: better error handling (cherry picked from commit 0e26c15a730854883ae31d164b460d70393c2848) --- rtengine/metadata.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index ecf4c444f..3e5ac9a1e 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -54,6 +54,10 @@ Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) #else auto image = Exiv2::ImageFactory::open(Glib::filename_from_utf8(fname)); #endif + image->readMetadata(); + if (!image->good()) { + throw Exiv2::Error(Exiv2::kerErrorMessage, "exiv2: invalid image"); + } return image; } @@ -100,7 +104,6 @@ void Exiv2Metadata::load() const } else { auto img = open_exiv2(src_); image_.reset(img.release()); - image_->readMetadata(); if (cache_) { cache_->set(src_, CacheVal(image_, finfo->modification_time())); } @@ -197,7 +200,6 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const void Exiv2Metadata::saveToImage(const Glib::ustring &path) const { auto dst = open_exiv2(path); - dst->readMetadata(); if (image_.get()) { dst->setMetadata(*image_); if (merge_xmp_) { @@ -323,7 +325,6 @@ Exiv2::XmpData Exiv2Metadata::getXmpSidecar(const Glib::ustring &path) auto fname = xmpSidecarPath(path); if (Glib::file_test(fname, Glib::FILE_TEST_EXISTS)) { auto image = open_exiv2(fname); - image->readMetadata(); ret = image->xmpData(); } return ret; From e205ff86cc65930c750f5b1bf26470955d170d84 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 5 Feb 2020 11:52:42 +0100 Subject: [PATCH 029/110] fixed compilation problem with exiv2 < 0.27 (cherry picked from commit b4d178fdab61814be8ab93f0ecd7d74f78c4087f) --- rtengine/metadata.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 3e5ac9a1e..40cdffdb1 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -56,7 +56,12 @@ Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) #endif image->readMetadata(); if (!image->good()) { - throw Exiv2::Error(Exiv2::kerErrorMessage, "exiv2: invalid image"); +#if EXIV2_TEST_VERSION(0,27,0) + auto error_code = Exiv2::kerErrorMessage; +#else + auto error_code = 1; +#endif + throw Exiv2::Error(error_code, "exiv2: invalid image"); } return image; } From ea3cf2fe8fc7f8bed057860a48c47064071bb64d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 10 Mar 2020 08:16:39 -0700 Subject: [PATCH 030/110] imageio: do not fail in saving an image if no metadata is available (cherry picked from commit 86d48be88b6f9fe36e5e25185ec4fda7696efc25) --- rtengine/imageio.cc | 75 +++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index b0510e817..af945949f 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -41,6 +41,7 @@ #include "iccjpeg.h" #include "color.h" #include "imagedata.h" +#include "settings.h" #include "jpeg.h" @@ -48,6 +49,8 @@ using namespace std; using namespace rtengine; using namespace rtengine::procparams; +namespace rtengine { extern const Settings *settings; } + namespace { @@ -1355,38 +1358,50 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const return true; } + bool has_meta = true; try { metadataInfo.load(); - metadataInfo.saveToImage(fname); - // auto src = open_exiv2(metadataInfo.filename()); - // auto dst = open_exiv2(fname); - // src->readMetadata(); - // dst->setMetadata(*src); - // dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; - // for (const auto& p : metadataInfo.exif()) { - // try { - // dst->exifData()[p.first] = p.second; - // } catch (const Exiv2::AnyError& exc) { - // } - // } - // for (const auto& p : metadataInfo.iptc()) { - // try { - // auto& v = p.second; - // if (!v.empty()) { - // dst->iptcData()[p.first] = v[0]; - // for (size_t j = 1; j < v.size(); ++j) { - // Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); - // d.setValue(v[j]); - // dst->iptcData().add(d); - // } - // } - // } catch (const Exiv2::AnyError& exc) { - // } - // } - // dst->writeMetadata(); - return true; } catch (const std::exception& exc) { - std::cout << "EXIF ERROR: " << exc.what() << std::endl; - return false; + if (settings->verbose) { + std::cout << "EXIF LOAD ERROR: " << exc.what() << std::endl; + } + has_meta = false; } + + if (has_meta) { + try { + metadataInfo.saveToImage(fname); + // auto src = open_exiv2(metadataInfo.filename()); + // auto dst = open_exiv2(fname); + // src->readMetadata(); + // dst->setMetadata(*src); + // dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; + // for (const auto& p : metadataInfo.exif()) { + // try { + // dst->exifData()[p.first] = p.second; + // } catch (const Exiv2::AnyError& exc) { + // } + // } + // for (const auto& p : metadataInfo.iptc()) { + // try { + // auto& v = p.second; + // if (!v.empty()) { + // dst->iptcData()[p.first] = v[0]; + // for (size_t j = 1; j < v.size(); ++j) { + // Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); + // d.setValue(v[j]); + // dst->iptcData().add(d); + // } + // } + // } catch (const Exiv2::AnyError& exc) { + // } + // } + // dst->writeMetadata(); + } catch (const std::exception& exc) { + std::cout << "EXIF ERROR: " << exc.what() << std::endl; + return false; + } + } + + return true; } From dcc00b40d15974fe8d4b3e1041b0d1d541b5091b Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 14 Mar 2020 21:02:20 +0100 Subject: [PATCH 031/110] metadata: do not include makernotes on export Fixes #31 (cherry picked from commit 3a8d8ece897eb4df61887160a30722bd07a77174) --- rtengine/metadata.cc | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 40cdffdb1..e4d955738 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -229,7 +229,8 @@ void Exiv2Metadata::remove_unwanted(Exiv2::Image *dst) const static const std::vector keys = { "Exif.Image.Orientation", "Exif.Image2.JPEGInterchangeFormat", - "Exif.Image2.JPEGInterchangeFormatLength" + "Exif.Image2.JPEGInterchangeFormatLength", + "Exif.Photo.MakerNote" }; for (auto &k : keys) { auto it = dst->exifData().findKey(Exiv2::ExifKey(k)); @@ -237,6 +238,26 @@ void Exiv2Metadata::remove_unwanted(Exiv2::Image *dst) const dst->exifData().erase(it); } } + static const std::vector patterns = { + "Exif.Image.", + "Exif.Photo.", + "Exif.GPSInfo." + }; + for (auto it = dst->exifData().begin(); it != dst->exifData().end(); ) { + bool found = false; + for (auto &pp : patterns) { + if (it->key().find(pp) == 0) { + found = true; + break; + } + } + if (!found) { + it = dst->exifData().erase(it); + } else { + ++it; + } + } + Exiv2::ExifThumb thumb(dst->exifData()); thumb.erase(); } From c1719fbd7d1bb805ea7759b216bae6dfde7a9d7f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 5 Apr 2020 05:04:45 -0700 Subject: [PATCH 032/110] metadata: better handling of makernote tags Tentative fix for #37 (cherry picked from commit 7310eb64978bb1138edbdf02fa58fb64a9326e17) --- rtengine/metadata.cc | 66 +++++++++++++++++++------------------------- rtengine/metadata.h | 2 +- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index e4d955738..dbc1e178a 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -37,6 +37,17 @@ std::unique_ptr Exiv2Metadata::cache_(nullptr); namespace { +class Error: public Exiv2::AnyError { +public: + Error(const std::string &msg): msg_(msg) {} + const char *what() const throw() { return msg_.c_str(); } + int code() const throw() { return 0; } + +private: + std::string msg_; +}; + + constexpr size_t IMAGE_CACHE_SIZE = 200; Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) @@ -206,11 +217,14 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const { auto dst = open_exiv2(path); if (image_.get()) { - dst->setMetadata(*image_); + dst->setIptcData(image_->iptcData()); + dst->setXmpData(image_->xmpData()); if (merge_xmp_) { do_merge_xmp(dst.get()); } - remove_unwanted(dst.get()); + auto srcexif = image_->exifData(); + remove_unwanted(srcexif); + dst->setExifData(srcexif); } else { dst->setExifData(exif_data_); dst->setIptcData(iptc_data_); @@ -224,42 +238,29 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const } -void Exiv2Metadata::remove_unwanted(Exiv2::Image *dst) const -{ - static const std::vector keys = { - "Exif.Image.Orientation", - "Exif.Image2.JPEGInterchangeFormat", - "Exif.Image2.JPEGInterchangeFormatLength", - "Exif.Photo.MakerNote" - }; - for (auto &k : keys) { - auto it = dst->exifData().findKey(Exiv2::ExifKey(k)); - if (it != dst->exifData().end()) { - dst->exifData().erase(it); - } - } - static const std::vector patterns = { +void Exiv2Metadata::remove_unwanted(Exiv2::ExifData &dst) const +{ + Exiv2::ExifThumb thumb(dst); + thumb.erase(); + + static const std::vector badpatterns = { "Exif.Image.", - "Exif.Photo.", - "Exif.GPSInfo." + "Exif.SubImage" }; - for (auto it = dst->exifData().begin(); it != dst->exifData().end(); ) { + + for (auto it = dst.begin(); it != dst.end(); ) { bool found = false; - for (auto &pp : patterns) { - if (it->key().find(pp) == 0) { + for (auto &p : badpatterns) { + if (it->key().find(p) == 0) { + it = dst.erase(it); found = true; break; } } if (!found) { - it = dst->exifData().erase(it); - } else { ++it; } - } - - Exiv2::ExifThumb thumb(dst->exifData()); - thumb.erase(); + } } @@ -320,15 +321,6 @@ void Exiv2Metadata::saveToXmp(const Glib::ustring &path) const } } - class Error: public Exiv2::AnyError { - public: - Error(const std::string &msg): msg_(msg) {} - const char *what() const throw() { return msg_.c_str(); } - int code() const throw() { return 0; } - - private: - std::string msg_; - }; if (err) { throw Error("error saving XMP sidecar " + path); } diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 57904d4a4..7439d6b36 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -65,7 +65,7 @@ private: void do_merge_xmp(Exiv2::Image* dst) const; void import_exif_pairs(Exiv2::ExifData& out) const; void import_iptc_pairs(Exiv2::IptcData& out) const; - void remove_unwanted(Exiv2::Image* dst) const; + void remove_unwanted(Exiv2::ExifData& dst) const; Glib::ustring src_; bool merge_xmp_; From 9735ba5768f8961e525551695c0ad78b18808382 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 5 Apr 2020 07:13:33 -0700 Subject: [PATCH 033/110] metadata: preserve standard exif tags (accidentally broken by 7310eb64978bb1138edbdf02fa58fb64a9326e17) (cherry picked from commit 75a49b8cb9db957dfe13e6911dcf6c83bb92045d) --- rtengine/metadata.cc | 86 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index dbc1e178a..e2bc4dc42 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include "metadata.h" #include "settings.h" @@ -243,22 +244,87 @@ void Exiv2Metadata::remove_unwanted(Exiv2::ExifData &dst) const Exiv2::ExifThumb thumb(dst); thumb.erase(); + static const std::set badtags = { + "Exif.Image.Orientation", + "Exif.Image2.JPEGInterchangeFormat", + "Exif.Image2.JPEGInterchangeFormatLength", + "Exif.Image.NewSubfileType", + "Exif.Image.SubfileType", + "Exif.Image.ImageWidth", + "Exif.Image.ImageLength", + "Exif.Image.BitsPerSample", + "Exif.Image.Compression", + "Exif.Image.PhotometricInterpretation", + "Exif.Image.Thresholding", + "Exif.Image.CellWidth", + "Exif.Image.CellLength", + "Exif.Image.FillOrder", + "Exif.Image.StripOffsets", + "Exif.Image.Orientation", + "Exif.Image.SamplesPerPixel", + "Exif.Image.RowsPerStrip", + "Exif.Image.StripByteCounts", + "Exif.Image.XResolution", + "Exif.Image.YResolution", + "Exif.Image.PlanarConfiguration", + "Exif.Image.GrayResponseUnit", + "Exif.Image.GrayResponseCurve", + "Exif.Image.T4Options", + "Exif.Image.T6Options", + "Exif.Image.ResolutionUnit", + "Exif.Image.PageNumber", + "Exif.Image.Predictor", + "Exif.Image.TileWidth", + "Exif.Image.TileLength", + "Exif.Image.TileOffsets", + "Exif.Image.TileByteCounts", + "Exif.Image.SubIFDs", + "Exif.Image.ExtraSamples", + "Exif.Image.SampleFormat", + "Exif.Image.SMinSampleValue", + "Exif.Image.SMaxSampleValue", + "Exif.Image.Indexed", + "Exif.Image.JPEGTables", + "Exif.Image.OPIProxy", + "Exif.Image.JPEGProc", + "Exif.Image.JPEGInterchangeFormat", + "Exif.Image.JPEGInterchangeFormatLength", + "Exif.Image.JPEGRestartInterval", + "Exif.Image.JPEGLosslessPredictors", + "Exif.Image.JPEGPointTransforms", + "Exif.Image.JPEGQTables", + "Exif.Image.JPEGDCTables", + "Exif.Image.JPEGACTables", + "Exif.Image.TIFFEPStandardID", + "Exif.Image.DNGVersion", + "Exif.Image.DNGBackwardVersion", + "Exif.Image.DNGPrivateData", + "Exif.Image.OriginalRawFileData", + "Exif.Image.SubTileBlockSize", + "Exif.Image.RowInterleaveFactor", + "Exif.Photo.ComponentsConfiguration", + "Exif.Photo.CompressedBitsPerPixel" + }; + static const std::vector badpatterns = { - "Exif.Image.", "Exif.SubImage" }; for (auto it = dst.begin(); it != dst.end(); ) { - bool found = false; - for (auto &p : badpatterns) { - if (it->key().find(p) == 0) { - it = dst.erase(it); - found = true; - break; + if (badtags.find(it->key()) != badtags.end()) { + it = dst.erase(it); + } else { + bool found = false; + for (auto &p : badpatterns) { + if (it->key().find(p) == 0) { + it = dst.erase(it); + found = true; + break; + } + } + if (!found) { + ++it; } - } - if (!found) { - ++it; } } } From f62f6807a7c03d33a7d4c4969604806e62cb8b0f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 7 Apr 2020 09:48:14 -0700 Subject: [PATCH 034/110] exifpanel: sort the list of exif tags (cherry picked from commit 88e5ec5dc6a47d3a9cc751d2902aadc540ce0826) --- rtgui/exifpanel.cc | 17 ++++++++++++----- rtgui/exifpanel.h | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 5cc4af341..5b93f25c8 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -174,7 +174,7 @@ void ExifPanel::setImageData (const FramesMetaData* id) idata = id; } -Gtk::TreeModel::Children ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited) +void ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited) { // TODO Re-fix #5923 if necessary @@ -184,7 +184,7 @@ Gtk::TreeModel::Children ExifPanel::addTag(const std::string &key, const Glib::u auto root = exifTreeModel->children(); - Gtk::TreeModel::Row row = * (exifTreeModel->append (root)); + Gtk::TreeModel::Row row = *(exifTreeModel->append(root)); row[exifColumns.editable] = editable; row[exifColumns.edited] = edited; row[exifColumns.key] = key; @@ -200,8 +200,6 @@ Gtk::TreeModel::Children ExifPanel::addTag(const std::string &key, const Glib::u } else if (editable) { row[exifColumns.icon] = keepicon; } - - return row.children(); } void ExifPanel::refreshTags() @@ -244,6 +242,7 @@ void ExifPanel::refreshTags() addTag(pos->key(), pos->tagLabel(), pos->print(&exif), true, edited); } } + std::map keymap; for (const auto& tag : exif) { const bool editable = ed.find(tag.key()) != ed.end(); if ( @@ -255,9 +254,17 @@ void ExifPanel::refreshTags() || tag.size() < 256 ) ) { - addTag(tag.key(), tag.tagLabel(), tag.print(&exif), false, false); + std::string lbl = tag.tagLabel(); + for (auto &c : lbl) { + c = std::tolower(c); + } + keymap[lbl] = tag.key(); } } + for (auto &p : keymap) { + auto &tag = *(exif.findKey(Exiv2::ExifKey(p.second))); + addTag(tag.key(), tag.tagLabel(), tag.print(&exif), false, false); + } } catch (const std::exception& exc) { return; } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index 47ad33c83..cfcf77e4d 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -82,7 +82,7 @@ private: const std::vector> editableTags; - Gtk::TreeModel::Children addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited); + void addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited); void refreshTags(); void resetIt(const Gtk::TreeModel::const_iterator& iter); void resetPressed(); From 5fdff8dab4650903c162e673e349f072202f7ce9 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 7 Apr 2020 09:48:43 -0700 Subject: [PATCH 035/110] file browser: pick up star ratings from the image metadata if available (cherry picked from commit 98f0675b2e419d18bd88259997b81bcbcc4e5c96) --- rtengine/imagedata.cc | 5 +++++ rtengine/procparams.cc | 42 ++++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index a810bc925..42286cd40 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -325,6 +325,11 @@ FramesData::FramesData(const Glib::ustring &fname) : if (find_exif_tag("Exif.Image.Rating")) { rating = pos->toLong(); + } else { + auto it = meta.xmpData().findKey(Exiv2::XmpKey("Xmp.xmp.Rating")); + if (it != meta.xmpData().end() && it->size()) { + rating = it->toLong(); + } } // ----------------------- diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 8794fe0e8..f3068c18e 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1363,7 +1363,7 @@ bool WBParams::isPanningRelatedChange(const WBParams& other) const enabled == other.enabled && ( ( - method == "Camera" + method == "Camera" && other.method == "Camera" ) || ( @@ -2327,25 +2327,25 @@ WaveletParams::WaveletParams() : }, blcurve{ static_cast(FCT_MinMaxCPoints), - 0.0, - 0.0, - 0.0, - 0.35, - 0.5, - 0., + 0.0, + 0.0, + 0.0, + 0.35, + 0.5, + 0., 0.35, 0.35, 1.0, 0.0, 0.35, 0.35 -/* +/* 0.0, - 0.35, - 0.35, - 1.0, - 0.0, - 0.35, + 0.35, + 0.35, + 1.0, + 0.0, + 0.35, 0.35 */ }, @@ -5418,7 +5418,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo keyFile.set_string("Version", "AppVersion", RTVERSION); keyFile.set_integer("Version", "Version", PPVERSION); - saveToKeyfile(!pedited || pedited->general.rank, "General", "Rank", rank, keyFile); + if (rank >= 0) { + saveToKeyfile(!pedited || pedited->general.rank, "General", "Rank", rank, keyFile); + } saveToKeyfile(!pedited || pedited->general.colorlabel, "General", "ColorLabel", colorlabel, keyFile); saveToKeyfile(!pedited || pedited->general.intrash, "General", "InTrash", inTrash, keyFile); @@ -5710,9 +5712,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // Dehaze saveToKeyfile(!pedited || pedited->dehaze.enabled, "Dehaze", "Enabled", dehaze.enabled, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile); saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Saturation", dehaze.saturation, keyFile); // Directional pyramid denoising @@ -6834,7 +6836,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "GreenBase", filmNegative.refInput.g, keyFile); saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "BlueBase", filmNegative.refInput.b, keyFile); } - + saveToKeyfile(!pedited || pedited->filmNegative.colorSpace, "Film Negative", "ColorSpace", toUnderlying(filmNegative.colorSpace), keyFile); saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "RefInput", filmNegative.refInput, keyFile); saveToKeyfile(!pedited || pedited->filmNegative.refOutput, "Film Negative", "RefOutput", filmNegative.refOutput, keyFile); @@ -7352,7 +7354,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) pedited->colorappearance.complexmethod = true; } } - + if (keyFile.has_key("Color appearance", "ModelCat")) { assignFromKeyfile(keyFile, "Color appearance", "ModelCat", pedited, colorappearance.modelmethod, pedited->colorappearance.modelmethod); } else if (colorappearance.enabled) { @@ -7362,7 +7364,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } assignFromKeyfile(keyFile, "Color appearance", "CatCat", pedited, colorappearance.catmethod, pedited->colorappearance.catmethod); - + assignFromKeyfile(keyFile, "Color appearance", "Surround", pedited, colorappearance.surround, pedited->colorappearance.surround); assignFromKeyfile(keyFile, "Color appearance", "Surrsrc", pedited, colorappearance.surrsrc, pedited->colorappearance.surrsrc); assignFromKeyfile(keyFile, "Color appearance", "AdaptLum", pedited, colorappearance.adaplum, pedited->colorappearance.adaplum); From abb052e51bc4a9001d5af9403707d18c69ba57db Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 8 Apr 2020 11:48:36 -0700 Subject: [PATCH 036/110] metadata: allow to select which metadata tags to include in the output image (cherry picked from commit ed64206cb8b4455870815e2c51aecbd5c09e4054) --- rtdata/images/svg/add.svg | 14 +-- rtdata/images/svg/box.svg | 110 ++++++++++++++++++++ rtdata/images/svg/tick.svg | 12 +-- rtengine/metadata.cc | 12 +++ rtengine/metadata.h | 5 + rtengine/procparams.cc | 31 +++++- rtengine/procparams.h | 1 + rtengine/simpleprocess.cc | 3 + rtgui/exifpanel.cc | 202 +++++++++++++++++++++++++++---------- rtgui/exifpanel.h | 17 ++++ rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 1 + 12 files changed, 347 insertions(+), 67 deletions(-) create mode 100644 rtdata/images/svg/box.svg diff --git a/rtdata/images/svg/add.svg b/rtdata/images/svg/add.svg index c45f9f584..41fa7cc39 100644 --- a/rtdata/images/svg/add.svg +++ b/rtdata/images/svg/add.svg @@ -17,7 +17,7 @@ inkscape:export-filename="/tmp/template.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" - inkscape:version="0.92.2 2405546, 2018-03-11" + inkscape:version="0.91 r13725" sodipodi:docname="add.svg"> image/svg+xml - + Maciej Dworak @@ -120,8 +120,8 @@ style="opacity:0.7;fill:none;fill-opacity:0.53333285;fill-rule:nonzero;stroke:#2a7fff;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" /> diff --git a/rtdata/images/svg/box.svg b/rtdata/images/svg/box.svg new file mode 100644 index 000000000..2ebee4b8c --- /dev/null +++ b/rtdata/images/svg/box.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + image/svg+xml + + + + + Maciej Dworak + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/tick.svg b/rtdata/images/svg/tick.svg index 8ab7a2e27..dd4ab4bdd 100644 --- a/rtdata/images/svg/tick.svg +++ b/rtdata/images/svg/tick.svg @@ -17,8 +17,8 @@ inkscape:export-filename="/tmp/template.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" - inkscape:version="0.92.2 2405546, 2018-03-11" - sodipodi:docname="tick-large.svg"> + inkscape:version="0.91 r13725" + sodipodi:docname="tick.svg"> image/svg+xml - + Maciej Dworak @@ -103,7 +103,7 @@ sodipodi:nodetypes="ccccccc" inkscape:connector-curvature="0" id="path2996-6" - d="M 4.6666624,10.166665 8.3333305,13.833335 19.333336,2.833329 23.000006,6.4999972 8.3333305,21.166671 0.99999442,13.833335 Z" + d="M 6.0000005,10.299997 9.0000007,13.533332 18.000004,3.833329 21.000006,7.066663 9.0000007,20 3,13.533332 Z" style="opacity:0.7;fill:#2a7fff;fill-opacity:1;stroke:none;stroke-width:2.30911016" /> diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index e2bc4dc42..af2a7ef8a 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -313,6 +313,8 @@ void Exiv2Metadata::remove_unwanted(Exiv2::ExifData &dst) const for (auto it = dst.begin(); it != dst.end(); ) { if (badtags.find(it->key()) != badtags.end()) { it = dst.erase(it); + } else if (exif_keys_ && exif_keys_->find(it->key()) == exif_keys_->end()) { + it = dst.erase(it); } else { bool found = false; for (auto &p : badpatterns) { @@ -393,6 +395,16 @@ void Exiv2Metadata::saveToXmp(const Glib::ustring &path) const } +void Exiv2Metadata::setExifKeys(const std::vector *keys) +{ + exif_keys_.reset(); + if (keys) { + exif_keys_ = std::make_shared>(); + exif_keys_->insert(keys->begin(), keys->end()); + } +} + + Glib::ustring Exiv2Metadata::xmpSidecarPath(const Glib::ustring &path) { Glib::ustring fn = path; diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 7439d6b36..57484d234 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "procparams.h" #include "cache.h" @@ -55,6 +56,8 @@ public: void saveToImage(const Glib::ustring& path) const; void saveToXmp(const Glib::ustring& path) const; + void setExifKeys(const std::vector *keys); + static Glib::ustring xmpSidecarPath(const Glib::ustring& path); static Exiv2::XmpData getXmpSidecar(const Glib::ustring& path); @@ -76,6 +79,8 @@ private: Exiv2::IptcData iptc_data_; Exiv2::XmpData xmp_data_; + std::shared_ptr> exif_keys_; + typedef std::pair, Glib::TimeVal> CacheVal; typedef Cache ImageCache; static std::unique_ptr cache_; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f3068c18e..5076e147f 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -178,6 +178,17 @@ void getFromKeyfile( } } +void getFromKeyfile( + const Glib::KeyFile& keyfile, + const Glib::ustring& group_name, + const Glib::ustring& key, + std::vector& value +) +{ + auto tmpval = keyfile.get_string_list(group_name, key); + value.assign(tmpval.begin(), tmpval.end()); +} + template bool assignFromKeyfile( const Glib::KeyFile& keyfile, @@ -306,6 +317,17 @@ void putToKeyfile( keyfile.set_double_list(group_name, key, list); } +void putToKeyfile( + const Glib::ustring& group_name, + const Glib::ustring& key, + const std::vector& value, + Glib::KeyFile& keyfile +) +{ + const Glib::ArrayHandle list = value; + keyfile.set_string_list(group_name, key, list); +} + void putToKeyfile( const Glib::ustring& group_name, const Glib::ustring& key, @@ -5226,13 +5248,15 @@ Glib::ustring RAWParams::getFlatFieldBlurTypeString(FlatFieldBlurType type) MetaDataParams::MetaDataParams(): - mode(MetaDataParams::TUNNEL) + mode(MetaDataParams::TUNNEL), + exifKeys{"ALL"} { } bool MetaDataParams::operator==(const MetaDataParams &other) const { - return mode == other.mode; + return mode == other.mode + && exifKeys == other.exifKeys; } bool MetaDataParams::operator!=(const MetaDataParams &other) const @@ -6823,6 +6847,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // MetaData saveToKeyfile(!pedited || pedited->metadata.mode, "MetaData", "Mode", metadata.mode, keyFile); + saveToKeyfile(!pedited || pedited->metadata.exifKeys, "MetaData", "ExifKeys", metadata.exifKeys, keyFile); // Film negative saveToKeyfile(!pedited || pedited->filmNegative.enabled, "Film Negative", "Enabled", filmNegative.enabled, keyFile); @@ -9350,6 +9375,8 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (mode >= int(MetaDataParams::TUNNEL) && mode <= int(MetaDataParams::STRIP)) { metadata.mode = static_cast(mode); } + + assignFromKeyfile(keyFile, "MetaData", "ExifKeys", pedited, metadata.exifKeys, pedited->metadata.exifKeys); } if (keyFile.has_group("Exif")) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 4a1eb47e3..dd6872630 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1728,6 +1728,7 @@ struct MetaDataParams { STRIP }; Mode mode; + std::vector exifKeys; MetaDataParams(); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 0b6406b62..c8ee5e147 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1739,6 +1739,9 @@ private: case MetaDataParams::EDIT: info.setExif(params.exif); info.setIptc(params.iptc); + if (!(params.metadata.exifKeys.size() == 1 && params.metadata.exifKeys[0] == "ALL")) { + info.setExifKeys(&(params.metadata.exifKeys)); + } readyImg->setMetadata(std::move(info)); break; default: // case MetaDataParams::STRIP diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 5b93f25c8..f63541e5f 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -51,16 +51,17 @@ ExifPanel::ExifPanel() : exifTree->set_rules_hint (false); exifTree->set_reorderable (false); exifTree->set_enable_search (false); - exifTree->get_selection()->set_mode (Gtk::SELECTION_MULTIPLE); - scrolledWindow->set_shadow_type (Gtk::SHADOW_NONE); - scrolledWindow->set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); + exifTree->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); + scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE); + scrolledWindow->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); scrolledWindow->property_window_placement().set_value (Gtk::CORNER_TOP_LEFT); - scrolledWindow->add (*exifTree); + scrolledWindow->add(*exifTree); - exifTreeModel = Gtk::TreeStore::create (exifColumns); - exifTree->set_model (exifTreeModel); - exifTree->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_NONE); + exifTreeModel = Gtk::TreeStore::create(exifColumns); + exifTree->set_model(exifTreeModel); + exifTree->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_NONE); exifTree->set_show_expanders(false); + exifTree->set_tooltip_column(0); keepicon = RTImage::createPixbufFromFile ("tick-small.png"); editicon = RTImage::createPixbufFromFile("add-small.png"); @@ -69,25 +70,32 @@ ExifPanel::ExifPanel() : Gtk::CellRendererPixbuf* render_pb = Gtk::manage (new Gtk::CellRendererPixbuf ()); Gtk::CellRendererText *render_txt = Gtk::manage (new Gtk::CellRendererText()); render_txt->property_ellipsize() = Pango::ELLIPSIZE_END; - viewcol->pack_start (*render_pb, false); - viewcol->pack_start (*render_txt, true); - viewcol->add_attribute (*render_pb, "pixbuf", exifColumns.icon); - viewcol->add_attribute (*render_txt, "markup", exifColumns.label); - viewcol->set_expand (true); - viewcol->set_resizable (true); - viewcol->set_fixed_width (35); - viewcol->set_min_width (35); - viewcol->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + viewcol->pack_start(*render_pb, false); + viewcol->pack_start(*render_txt, true); + viewcol->add_attribute(*render_pb, "pixbuf", exifColumns.icon); + viewcol->add_attribute(*render_txt, "markup", exifColumns.label); + viewcol->set_expand(true); + viewcol->set_resizable(true); + viewcol->set_fixed_width(35); + viewcol->set_min_width(35); + viewcol->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); render_pb->property_ypad() = 0; render_txt->property_ypad() = 0; render_pb->property_yalign() = 0; render_txt->property_yalign() = 0; - exifTree->append_column (*viewcol); + exif_active_renderer_.property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE; + exif_active_renderer_.signal_toggled().connect(sigc::mem_fun(this, &ExifPanel::onKeyActiveToggled)); + exif_active_column_.pack_start(exif_active_renderer_); + exif_active_column_.set_cell_data_func(exif_active_renderer_, sigc::mem_fun(this, &ExifPanel::setKeyActive)); - Gtk::TreeView::Column *viewcolv = Gtk::manage (new Gtk::TreeView::Column ("Value")); - Gtk::CellRendererText *render_txtv = Gtk::manage (new Gtk::CellRendererText()); + exifTree->append_column(exif_active_column_); + + exifTree->append_column(*viewcol); + + Gtk::TreeView::Column *viewcolv = Gtk::manage(new Gtk::TreeView::Column ("Value")); + Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText()); render_txtv->property_ellipsize() = Pango::ELLIPSIZE_END; viewcolv->pack_start (*render_txtv, true); viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value); @@ -108,26 +116,23 @@ ExifPanel::ExifPanel() : buttons1->set_column_homogeneous (true); setExpandAlignProperties (buttons1, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - add = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_ADDEDIT") - add->set_image (*Gtk::manage (new RTImage(editicon))); - add->set_tooltip_text (M ("EXIFPANEL_ADDEDITHINT")); - add->get_style_context()->add_class ("Right"); - setExpandAlignProperties (add, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons1->attach_next_to (*add, Gtk::POS_RIGHT, 1, 1); + const auto addbtn = + [&](const Glib::ustring &tip, const Glib::ustring &icon1, const Glib::ustring &icon2=Glib::ustring()) -> Gtk::Button * + { + Gtk::Button *b = Gtk::manage(new Gtk::Button()); + b->set_image(*Gtk::manage(new RTImage(icon1, icon2))); + b->set_tooltip_text(M(tip)); + b->get_style_context()->add_class("Right"); + setExpandAlignProperties(b, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + buttons1->attach_next_to(*b, Gtk::POS_RIGHT, 1, 1); + return b; + }; - reset = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_RESET") - reset->set_image (*Gtk::manage (new RTImage("undo.png", "redo.png"))); - reset->set_tooltip_text (M ("EXIFPANEL_RESETHINT")); - reset->get_style_context()->add_class ("MiddleH"); - setExpandAlignProperties (reset, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons1->attach_next_to (*reset, Gtk::POS_RIGHT, 1, 1); - - resetAll = Gtk::manage (new Gtk::Button ()); // M("EXIFPANEL_RESETALL") - resetAll->set_image (*Gtk::manage (new RTImage ("undo-all.png", "redo-all.png"))); - resetAll->set_tooltip_text (M ("EXIFPANEL_RESETALLHINT")); - resetAll->get_style_context()->add_class ("Right"); - setExpandAlignProperties (resetAll, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - buttons1->attach_next_to (*resetAll, Gtk::POS_RIGHT, 1, 1); + activate_all_ = addbtn("EXIFPANEL_ACTIVATE_ALL_HINT", "tick.png"); + activate_none_ = addbtn("EXIFPANEL_ACTIVATE_NONE_HINT", "box.png"); + add = addbtn("EXIFPANEL_ADDEDIT", "add.png"); + reset = addbtn("EXIFPANEL_RESETHINT", "undo.png", "redo.png"); + resetAll = addbtn("EXIFPANEL_RESETALLHINT", "undo-all.png", "redo-all.png"); pack_end (*buttons1, Gtk::PACK_SHRINK); @@ -137,6 +142,8 @@ ExifPanel::ExifPanel() : reset->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetPressed) ); resetAll->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetAllPressed) ); add->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::addPressed) ); + activate_all_->signal_clicked().connect(sigc::mem_fun(*this, &ExifPanel::activateAllPressed)); + activate_none_->signal_clicked().connect(sigc::mem_fun(*this, &ExifPanel::activateNonePressed)); show_all (); } @@ -147,24 +154,56 @@ ExifPanel::~ExifPanel () void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); + disableListener(); *changeList = pp->exif; - setImageData (idata); + initial_active_keys_.clear(); + initial_active_keys_.insert(pp->metadata.exifKeys.begin(), pp->metadata.exifKeys.end()); + cur_active_keys_ = initial_active_keys_; + setImageData(idata); refreshTags(); - enableListener (); + enableListener(); } void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) { pp->exif = *changeList; + + std::unordered_set prev; + bool all_active = (cur_active_keys_.size() == 1 && *(cur_active_keys_.begin()) == "ALL"); + + if (!all_active) { + prev = cur_active_keys_; + } + + pp->metadata.exifKeys.clear(); + + bool none_active = true; + + auto root = exifTreeModel->children(); + for (auto &entry : root->children()) { + Glib::ustring key = entry[exifColumns.key]; + prev.erase(key); + if (entry[exifColumns.active]) { + pp->metadata.exifKeys.push_back(key); + none_active = false; + } else { + all_active = false; + } + } + + if (all_active) { + pp->metadata.exifKeys = { "ALL" }; + } else if (!none_active) { + pp->metadata.exifKeys.insert(pp->metadata.exifKeys.end(), prev.begin(), prev.end()); + } + std::sort(pp->metadata.exifKeys.begin(), pp->metadata.exifKeys.end()); } void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - *defChangeList = defParams->exif; } @@ -195,6 +234,9 @@ void ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const row[exifColumns.label] = escapeHtmlChars(label); row[exifColumns.value] = escapeHtmlChars(value); + bool active = (cur_active_keys_.size() == 1 && *(cur_active_keys_.begin()) == "ALL") || cur_active_keys_.find(key) != cur_active_keys_.end(); + row[exifColumns.active] = active; + if (edited) { row[exifColumns.icon] = editicon; } else if (editable) { @@ -223,6 +265,17 @@ void ExifPanel::refreshTags() ed.insert(p.first); } + const auto to_label = + [](const Exiv2::Exifdatum &tag) -> Glib::ustring + { + auto s = tag.key(); + auto pos = s.find('.'); + if (pos != std::string::npos) { + s = s.substr(pos+1); + } + return s; + }; + try { rtengine::Exiv2Metadata meta(fn); meta.load(); @@ -239,10 +292,10 @@ void ExifPanel::refreshTags() const auto pos = exif.findKey(Exiv2::ExifKey(p.first)); if (pos != exif.end() && pos->size()) { const bool edited = changeList->find(pos->key()) != changeList->end(); - addTag(pos->key(), pos->tagLabel(), pos->print(&exif), true, edited); + addTag(pos->key(), to_label(*pos), pos->print(&exif), true, edited); } } - std::map keymap; + std::multimap keymap; for (const auto& tag : exif) { const bool editable = ed.find(tag.key()) != ed.end(); if ( @@ -254,16 +307,16 @@ void ExifPanel::refreshTags() || tag.size() < 256 ) ) { - std::string lbl = tag.tagLabel(); + std::string lbl = to_label(tag); for (auto &c : lbl) { c = std::tolower(c); } - keymap[lbl] = tag.key(); + keymap.insert(std::make_pair(lbl, tag.key())); } } for (auto &p : keymap) { auto &tag = *(exif.findKey(Exiv2::ExifKey(p.second))); - addTag(tag.key(), tag.tagLabel(), tag.print(&exif), false, false); + addTag(tag.key(), to_label(tag), tag.print(&exif), false, false); } } catch (const std::exception& exc) { return; @@ -303,7 +356,7 @@ void ExifPanel::resetIt(const Gtk::TreeModel::const_iterator& iter) changeList->erase(key); } -void ExifPanel::resetPressed () +void ExifPanel::resetPressed() { std::vector sel = exifTree->get_selection()->get_selected_rows(); @@ -320,8 +373,9 @@ void ExifPanel::resetAllPressed () { setImageData(idata); *changeList = *defChangeList; + cur_active_keys_ = initial_active_keys_; refreshTags(); - notifyListener (); + notifyListener(); } void ExifPanel::addPressed () @@ -391,8 +445,9 @@ void ExifPanel::addPressed () auto key = editableTags[tcombo->get_active_row_number()].first; const auto value = ventry->get_text(); (*changeList)[key] = value; + cur_active_keys_.insert(key); refreshTags(); - notifyListener (); + notifyListener(); } delete dialog; @@ -404,9 +459,52 @@ void ExifPanel::addPressed () delete hb2; } -void ExifPanel::notifyListener () +void ExifPanel::activateAllPressed() +{ + disableListener(); + auto root = exifTreeModel->children(); + for (auto &row : root->children()) { + row[exifColumns.active] = true; + } + enableListener(); + notifyListener(); +} + + +void ExifPanel::activateNonePressed() +{ + disableListener(); + auto root = exifTreeModel->children(); + for (auto &row : root->children()) { + row[exifColumns.active] = false; + } + enableListener(); + notifyListener(); +} + + +void ExifPanel::notifyListener() { if (listener) { - listener->panelChanged (EvExif, M ("HISTORY_CHANGED")); + listener->panelChanged(EvExif, M("HISTORY_CHANGED")); } } + + +void ExifPanel::onKeyActiveToggled(const Glib::ustring &path) +{ + auto it = exifTreeModel->get_iter(path); + if (it) { + auto row = *it; + row[exifColumns.active] = !row[exifColumns.active]; + notifyListener(); + } +} + + +void ExifPanel::setKeyActive(Gtk::CellRenderer *renderer, const Gtk::TreeModel::iterator &it) +{ + auto row = *it; + static_cast(renderer)->set_active(row[exifColumns.active]); +} + diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index cfcf77e4d..1f9378fa3 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -21,6 +21,7 @@ #include #include +#include #include "toolpanel.h" @@ -56,6 +57,7 @@ private: Gtk::TreeModelColumn value_nopango; Gtk::TreeModelColumn editable; Gtk::TreeModelColumn edited; + Gtk::TreeModelColumn active; ExifColumns() { @@ -66,6 +68,7 @@ private: add(edited); add(value_nopango); add(editable); + add(active); } }; Glib::RefPtr keepicon; @@ -79,15 +82,29 @@ private: Gtk::Button* add; Gtk::Button* reset; Gtk::Button* resetAll; + Gtk::Button *activate_all_; + Gtk::Button *activate_none_; + + Gtk::CellRendererToggle exif_active_renderer_; + Gtk::TreeView::Column exif_active_column_; const std::vector> editableTags; + std::unordered_set initial_active_keys_; + std::unordered_set cur_active_keys_; + void addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited); void refreshTags(); void resetIt(const Gtk::TreeModel::const_iterator& iter); void resetPressed(); void resetAllPressed(); void addPressed(); + void activateAllPressed(); + void activateNonePressed(); + + void setKeyActive(Gtk::CellRenderer *renderer, const Gtk::TreeModel::iterator &it); + void onKeyActiveToggled(const Glib::ustring &path); + public: ExifPanel (); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 1fdefc0a3..8459d4013 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -675,6 +675,7 @@ void ParamsEdited::set(bool v) dehaze.depth = v; dehaze.saturation = v; metadata.mode = v; + metadata.exifKeys = v; filmNegative.enabled = v; filmNegative.redRatio = v; filmNegative.greenExp = v; @@ -1931,6 +1932,7 @@ void ParamsEdited::initFrom(const std::vector& dehaze.depth = dehaze.depth && p.dehaze.depth == other.dehaze.depth; dehaze.saturation = dehaze.saturation && p.dehaze.saturation == other.dehaze.saturation; metadata.mode = metadata.mode && p.metadata.mode == other.metadata.mode; + metadata.exifKeys = metadata.exifKeys && p.metadata.exifKeys == other.metadata.exifKeys; filmNegative.enabled = filmNegative.enabled && p.filmNegative.enabled == other.filmNegative.enabled; filmNegative.redRatio = filmNegative.redRatio && p.filmNegative.redRatio == other.filmNegative.redRatio; filmNegative.greenExp = filmNegative.greenExp && p.filmNegative.greenExp == other.filmNegative.greenExp; @@ -6569,6 +6571,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.metadata.mode = mods.metadata.mode; } + if (metadata.exifKeys) { + toEdit.metadata.exifKeys = mods.metadata.exifKeys; + } + if (filmNegative.enabled) { toEdit.filmNegative.enabled = mods.filmNegative.enabled; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 95fc76407..a7306ba68 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -1361,6 +1361,7 @@ struct RAWParamsEdited { struct MetaDataParamsEdited { bool mode; + bool exifKeys; }; struct FilmNegativeParamsEdited { From a26e6272821b3235741a482e60f18085a8e94e4a Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 9 Apr 2020 10:06:00 -0700 Subject: [PATCH 037/110] Add EXIF panel activate buttons hints Original commit message: updated French and Brazilian translations (cherry picked from commit 63db950a767737181b25e1888534cfac1cc40899) --- rtdata/languages/default | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index 3f51e1d90..4c0087cd3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -62,6 +62,8 @@ EXIFFILTER_ISO;ISO EXIFFILTER_LENS;Lens EXIFFILTER_METADATAFILTER;Enable metadata filters EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ACTIVATE_ALL_HINT;Select all tags +EXIFPANEL_ACTIVATE_NONE_HINT;Unselect all tags EXIFPANEL_ADDEDIT;Add/Edit EXIFPANEL_ADDEDITHINT;Add new tag or edit tag. EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value From 8a5aa6c1194b3de93608bba43632e2c5267aa1c3 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 9 Apr 2020 08:33:18 -0700 Subject: [PATCH 038/110] exif panel: further tweaks to the metadata selection (cherry picked from commit 207e51b64726367f2d932c000060f00b2697523f) --- rtgui/exifpanel.cc | 150 +++++++++++++++++++++++++++++++-------------- rtgui/exifpanel.h | 6 +- 2 files changed, 109 insertions(+), 47 deletions(-) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index f63541e5f..ba612f615 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -39,11 +39,11 @@ ExifPanel::ExifPanel() : {"Exif.Photo.UserComment", "User Comment"}, {"Exif.Image.Artist", "Artist"}, {"Exif.Image.Copyright", "Copyright"}, - {"Exif.Image.ImageDescription", "Image Description"} + {"Exif.Image.ImageDescription", "Image Description"}, + { "Exif.Photo.LensModel", "Lens Model" } } { set_orientation(Gtk::ORIENTATION_VERTICAL); - exifTree = Gtk::manage (new Gtk::TreeView()); scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow()); @@ -54,13 +54,13 @@ ExifPanel::ExifPanel() : exifTree->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE); scrolledWindow->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); - scrolledWindow->property_window_placement().set_value (Gtk::CORNER_TOP_LEFT); + scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT); scrolledWindow->add(*exifTree); exifTreeModel = Gtk::TreeStore::create(exifColumns); exifTree->set_model(exifTreeModel); exifTree->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_NONE); - exifTree->set_show_expanders(false); + //exifTree->set_show_expanders(false); exifTree->set_tooltip_column(0); keepicon = RTImage::createPixbufFromFile ("tick-small.png"); @@ -93,6 +93,7 @@ ExifPanel::ExifPanel() : exifTree->append_column(exif_active_column_); exifTree->append_column(*viewcol); + exifTree->set_expander_column(*viewcol); Gtk::TreeView::Column *viewcolv = Gtk::manage(new Gtk::TreeView::Column ("Value")); Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText()); @@ -107,7 +108,7 @@ ExifPanel::ExifPanel() : render_txtv->property_ypad() = 0; - exifTree->append_column (*viewcolv); + exifTree->append_column(*viewcolv); pack_start (*scrolledWindow); @@ -183,14 +184,26 @@ void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) bool none_active = true; auto root = exifTreeModel->children(); - for (auto &entry : root->children()) { - Glib::ustring key = entry[exifColumns.key]; - prev.erase(key); - if (entry[exifColumns.active]) { - pp->metadata.exifKeys.push_back(key); - none_active = false; - } else { - all_active = false; + // for (auto &entry : root->children()) { + // Glib::ustring key = entry[exifColumns.key]; + // prev.erase(key); + // if (entry[exifColumns.active]) { + // pp->metadata.exifKeys.push_back(key); + // none_active = false; + // } else { + // all_active = false; + // } + // } + for (auto &group : root->children()) { + for (auto &entry : group.children()) { + std::string key = entry[exifColumns.key]; + prev.erase(key); + if (entry[exifColumns.active]) { + pp->metadata.exifKeys.push_back(key); + none_active = false; + } else { + all_active = false; + } } } @@ -209,11 +222,10 @@ void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pe void ExifPanel::setImageData (const FramesMetaData* id) { - idata = id; } -void ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited) +void ExifPanel::addTag(const std::string &key, const std::pair &label, const Glib::ustring &value, bool editable, bool edited) { // TODO Re-fix #5923 if necessary @@ -221,18 +233,47 @@ void ExifPanel::addTag(const std::string &key, const Glib::ustring &label, const // value = "???"; //} - auto root = exifTreeModel->children(); +// auto root = exifTreeModel->children(); + + const auto getgroup = + [&]() -> Gtk::TreeNodeChildren + { + auto root = exifTreeModel->children(); + + for (auto it = root.rbegin(), end = root.rend(); it != end; ++it) { + auto row = *it; + std::string key = row[exifColumns.key]; + if (row[exifColumns.is_group] && key == label.first) { + return it->children(); + } + } + auto it = exifTreeModel->append(root); + auto row = *it; + + row[exifColumns.editable] = false; + row[exifColumns.edited] = false; + row[exifColumns.key] = label.first; + row[exifColumns.label] = "" + label.first + ""; + row[exifColumns.value_nopango] = ""; + row[exifColumns.value] = ""; + row[exifColumns.is_group] = true; + + return it->children(); + }; + + auto root = getgroup(); Gtk::TreeModel::Row row = *(exifTreeModel->append(root)); row[exifColumns.editable] = editable; row[exifColumns.edited] = edited; row[exifColumns.key] = key; - row[exifColumns.label] = label; + row[exifColumns.is_group] = false; + //row[exifColumns.label] = label.second; row[exifColumns.value_nopango] = value; - row[exifColumns.value] = value; + //row[exifColumns.value] = value; - row[exifColumns.label] = escapeHtmlChars(label); - row[exifColumns.value] = escapeHtmlChars(value); + row[exifColumns.label] = escapeHtmlChars(label.second); + row[exifColumns.value] = value;//escapeHtmlChars(value); bool active = (cur_active_keys_.size() == 1 && *(cur_active_keys_.begin()) == "ALL") || cur_active_keys_.find(key) != cur_active_keys_.end(); row[exifColumns.active] = active; @@ -266,14 +307,20 @@ void ExifPanel::refreshTags() } const auto to_label = - [](const Exiv2::Exifdatum &tag) -> Glib::ustring + [](const Exiv2::Exifdatum &tag) -> std::pair { auto s = tag.key(); auto pos = s.find('.'); if (pos != std::string::npos) { s = s.substr(pos+1); } - return s; + Glib::ustring g = ""; + pos = s.find('.'); + if (pos != std::string::npos) { + g = s.substr(0, pos); + s = s.substr(pos+1); + } + return std::make_pair(g, Glib::ustring(s)); }; try { @@ -281,6 +328,17 @@ void ExifPanel::refreshTags() meta.load(); auto& exif = meta.exifData(); + const auto to_value = + [&](Exiv2::Exifdatum &tag) -> Glib::ustring + { + if (!tag.tagLabel().empty() && tag.typeId() != Exiv2::undefined && + (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { + return escapeHtmlChars(tag.print(&exif)); + } + return "(Not shown)"; + }; + + for (const auto& p : *changeList) { try { exif[p.first] = p.second; @@ -295,28 +353,16 @@ void ExifPanel::refreshTags() addTag(pos->key(), to_label(*pos), pos->print(&exif), true, edited); } } - std::multimap keymap; + std::set keyset; for (const auto& tag : exif) { const bool editable = ed.find(tag.key()) != ed.end(); - if ( - !editable - && !tag.tagLabel().empty() - && tag.typeId() != Exiv2::undefined - && ( - tag.typeId() == Exiv2::asciiString - || tag.size() < 256 - ) - ) { - std::string lbl = to_label(tag); - for (auto &c : lbl) { - c = std::tolower(c); - } - keymap.insert(std::make_pair(lbl, tag.key())); + if (!editable) { + keyset.insert(tag.key()); } } - for (auto &p : keymap) { - auto &tag = *(exif.findKey(Exiv2::ExifKey(p.second))); - addTag(tag.key(), to_label(tag), tag.print(&exif), false, false); + for (auto &k : keyset) { + auto &tag = *(exif.findKey(Exiv2::ExifKey(k))); + addTag(tag.key(), to_label(tag), to_value(tag), false, false); } } catch (const std::exception& exc) { return; @@ -325,6 +371,8 @@ void ExifPanel::refreshTags() for (const auto& p : sel) { exifTree->get_selection()->select(p); } + + exifTree->expand_all(); } void ExifPanel::exifSelectionChanged () @@ -463,8 +511,11 @@ void ExifPanel::activateAllPressed() { disableListener(); auto root = exifTreeModel->children(); - for (auto &row : root->children()) { - row[exifColumns.active] = true; + for (auto &group : root->children()) { + group[exifColumns.active] = true; + for (auto &row : group.children()) { + row[exifColumns.active] = true; + } } enableListener(); notifyListener(); @@ -475,8 +526,11 @@ void ExifPanel::activateNonePressed() { disableListener(); auto root = exifTreeModel->children(); - for (auto &row : root->children()) { - row[exifColumns.active] = false; + for (auto &group : root->children()) { + group[exifColumns.active] = false; + for (auto &row : group.children()) { + row[exifColumns.active] = false; + } } enableListener(); notifyListener(); @@ -496,7 +550,13 @@ void ExifPanel::onKeyActiveToggled(const Glib::ustring &path) auto it = exifTreeModel->get_iter(path); if (it) { auto row = *it; - row[exifColumns.active] = !row[exifColumns.active]; + bool b = !row[exifColumns.active]; + row[exifColumns.active] = b; + if (row[exifColumns.is_group]) { + for (auto &c : row.children()) { + c[exifColumns.active] = b; + } + } notifyListener(); } } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index 1f9378fa3..32ce10dc7 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -51,13 +51,14 @@ private: { public: Gtk::TreeModelColumn > icon; - Gtk::TreeModelColumn key; + Gtk::TreeModelColumn key; Gtk::TreeModelColumn label; Gtk::TreeModelColumn value; Gtk::TreeModelColumn value_nopango; Gtk::TreeModelColumn editable; Gtk::TreeModelColumn edited; Gtk::TreeModelColumn active; + Gtk::TreeModelColumn is_group; ExifColumns() { @@ -69,6 +70,7 @@ private: add(value_nopango); add(editable); add(active); + add(is_group); } }; Glib::RefPtr keepicon; @@ -93,7 +95,7 @@ private: std::unordered_set initial_active_keys_; std::unordered_set cur_active_keys_; - void addTag(const std::string &key, const Glib::ustring &label, const Glib::ustring &value, bool editable, bool edited); + void addTag(const std::string &key, const std::pair &label, const Glib::ustring &value, bool editable, bool edited); void refreshTags(); void resetIt(const Gtk::TreeModel::const_iterator& iter); void resetPressed(); From b92e77fb961fa84b4d3e09c37e3ccdd0c340ea0d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 10 Apr 2020 05:54:40 -0700 Subject: [PATCH 039/110] improved support for metadata editing (cherry picked from commit 85da0b51ecf7ece768c0267aead71dd94404d4dc) --- rtdata/images/svg/edit-small.svg | 128 +++++++++++++++++ rtdata/images/svg/edit.svg | 136 ++++++++++++++++++ rtdata/languages/default | 5 +- rtengine/imagedata.cc | 33 +++++ rtengine/imagedata.h | 3 + rtengine/metadata.cc | 11 ++ rtengine/procparams.cc | 154 +++++++++++++-------- rtengine/procparams.h | 46 ++++--- rtengine/simpleprocess.cc | 6 +- rtgui/exifpanel.cc | 227 ++++++++++++++++++++----------- rtgui/exifpanel.h | 19 ++- rtgui/iptcpanel.cc | 8 +- rtgui/paramsedited.cc | 8 +- rtgui/thumbnail.cc | 6 +- rtgui/toolpanelcoord.cc | 8 +- 15 files changed, 615 insertions(+), 183 deletions(-) create mode 100644 rtdata/images/svg/edit-small.svg create mode 100644 rtdata/images/svg/edit.svg diff --git a/rtdata/images/svg/edit-small.svg b/rtdata/images/svg/edit-small.svg new file mode 100644 index 000000000..6306f06df --- /dev/null +++ b/rtdata/images/svg/edit-small.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + image/svg+xml + + + + + Maciej Dworak + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/edit.svg b/rtdata/images/svg/edit.svg new file mode 100644 index 000000000..71f3d0b06 --- /dev/null +++ b/rtdata/images/svg/edit.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + image/svg+xml + + + + + Maciej Dworak + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/languages/default b/rtdata/languages/default index 4c0087cd3..a5ce4fa54 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -77,8 +77,7 @@ EXIFPANEL_RESET;Reset EXIFPANEL_RESETALL;Reset All EXIFPANEL_RESETALLHINT;Reset all tags to their original values. EXIFPANEL_RESETHINT;Reset the selected tags to their original values. -EXIFPANEL_SHOWALL;Show all -EXIFPANEL_SUBDIRECTORY;Subdirectory +EXIFPANEL_BASIC_GROUP;Basic EXPORT_BYPASS;Processing steps to bypass EXPORT_BYPASS_ALL;Select / Unselect All EXPORT_BYPASS_DEFRINGE;Bypass Defringe @@ -1548,7 +1547,7 @@ MAIN_TAB_COLOR;Color MAIN_TAB_COLOR_TOOLTIP;Shortcut: Alt-c MAIN_TAB_DETAIL;Detail MAIN_TAB_DETAIL_TOOLTIP;Shortcut: Alt-d -MAIN_TAB_DEVELOP; Batch Edit +MAIN_TAB_DEVELOP; Batch Edit MAIN_TAB_EXIF;Exif MAIN_TAB_EXPORT; Fast Export MAIN_TAB_EXPOSURE;Exposure diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 42286cd40..52a9fa297 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -699,3 +699,36 @@ double FramesMetaData::apertureFromString(std::string s) return std::atof(s.c_str()); } + + +namespace { + +template +void set_exif(Exiv2::ExifData &exif, const std::string &key, T val) +{ + try { + exif[key] = val; + } catch (std::exception &exc) {} +} + +} // namespace + +void FramesData::fillBasicTags(Exiv2::ExifData &exif) const +{ + if (!hasExif()) { + return; + } + set_exif(exif, "Exif.Photo.ISOSpeedRatings", getISOSpeed()); + set_exif(exif, "Exif.Photo.FNumber", Exiv2::DoubleValue(getFNumber())); + //set_exif(exif, "Exif.Photo.ExposureTime", Exiv2::DoubleValue(getShutterSpeed())); + set_exif(exif, "Exif.Photo.ExposureTime", shutterToString(getShutterSpeed())); + set_exif(exif, "Exif.Photo.FocalLength", Exiv2::DoubleValue(getFocalLen())); + set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::DoubleValue(getExpComp())); + set_exif(exif, "Exif.Image.Make", getMake()); + set_exif(exif, "Exif.Image.Model", getModel()); + set_exif(exif, "Exif.Photo.LensModel", getLens()); + char buf[256]; + auto t = getDateTime(); + strftime(buf, 256, "%Y:%m:%d %H:%M:%S", &t); + set_exif(exif, "Exif.Photo.DateTimeOriginal", buf); +} diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 306c3b6f9..3a915c15d 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -23,6 +23,7 @@ #include #include "imageio.h" +#include "metadata.h" namespace Glib { @@ -83,6 +84,8 @@ public: std::string getOrientation() const override; Glib::ustring getFileName() const override; int getRating() const override; + + void fillBasicTags(Exiv2::ExifData &exif) const; }; } diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index af2a7ef8a..d04b979fe 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -26,6 +26,7 @@ #include "metadata.h" #include "settings.h" +#include "imagedata.h" #include "../rtgui/version.h" #include "../rtgui/pathutils.h" @@ -309,6 +310,16 @@ void Exiv2Metadata::remove_unwanted(Exiv2::ExifData &dst) const static const std::vector badpatterns = { "Exif.SubImage" }; + + if (exif_keys_ && !src_.empty()) { + try { + FramesData fd(src_); + fd.fillBasicTags(dst); + } catch (std::exception &exc) { + std::cout << "Error reading metadata from " << src_ + << std::endl; + } + } for (auto it = dst.begin(); it != dst.end(); ) { if (badtags.find(it->key()) != badtags.end()) { diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5076e147f..06ea2be6a 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -379,33 +379,6 @@ bool saveToKeyfile( return false; } -const std::map exif_keys = { - {"Copyright", "Exif.Image.Copyright"}, - {"Artist", "Exif.Image.Artist"}, - {"ImageDescription", "Exif.Image.ImageDescription"}, - {"Exif.UserComment", "Exif.Photo.UserComment"} -}; - -const std::map iptc_keys = { - {"Title", "Iptc.Application2.ObjectName"}, - {"Category", "Iptc.Application2.Category"}, - {"SupplementalCategories", "Iptc.Application2.SuppCategory"}, - {"Keywords", "Iptc.Application2.Keywords"}, - {"Instructions", "Iptc.Application2.SpecialInstructions"}, - {"DateCreated", "Iptc.Application2.DateCreated"}, - {"Creator", "Iptc.Application2.Byline"}, - {"CreatorJobTitle", "Iptc.Application2.BylineTitle"}, - {"City", "Iptc.Application2.City"}, - {"Province", "Iptc.Application2.ProvinceState"}, - {"Country", "Iptc.Application2.CountryName"}, - {"TransReference", "Iptc.Application2.TransmissionReference"}, - {"Headline", "Iptc.Application2.Headline"}, - {"Credit", "Iptc.Application2.Credit"}, - {"Source", "Iptc.Application2.Source"}, - {"Copyright", "Iptc.Application2.Copyright"}, - {"Caption", "Iptc.Application2.Caption"}, - {"CaptionWriter", "Iptc.Application2.Writer"} -}; } // namespace @@ -5247,23 +5220,6 @@ Glib::ustring RAWParams::getFlatFieldBlurTypeString(FlatFieldBlurType type) } -MetaDataParams::MetaDataParams(): - mode(MetaDataParams::TUNNEL), - exifKeys{"ALL"} -{ -} - -bool MetaDataParams::operator==(const MetaDataParams &other) const -{ - return mode == other.mode - && exifKeys == other.exifKeys; -} - -bool MetaDataParams::operator!=(const MetaDataParams &other) const -{ - return !(*this == other); -} - FilmNegativeParams::FilmNegativeParams() : enabled(false), redRatio(1.36), @@ -5316,6 +5272,90 @@ bool FilmNegativeParams::operator !=(const FilmNegativeParams& other) const return !(*this == other); } + +namespace { + +const std::map exif_keys = { + {"Copyright", "Exif.Image.Copyright"}, + {"Artist", "Exif.Image.Artist"}, + {"ImageDescription", "Exif.Image.ImageDescription"}, + {"Exif.UserComment", "Exif.Photo.UserComment"}, + {"ISOSpeed", "Exif.Photo.ISOSpeedRatings"}, + {"FNumber", "Exif.Photo.FNumber"}, + {"ShutterSpeed", "Exif.Photo.ExposureTime"}, + {"FocalLength", "Exif.Photo.FocalLength"}, + {"ExpComp", "Exif.Photo.ExposureBiasValue"}, + {"Flash", "Exif.Photo.Flash"}, + {"Make", "Exif.Image.Make"}, + {"Model", "Exif.Image.Model"}, + {"Lens", "Exif.Photo.LensModel"}, + {"DateTime", "Exif.Photo.DateTimeOriginal"} +}; + +const std::map iptc_keys = { + {"Title", "Iptc.Application2.ObjectName"}, + {"Category", "Iptc.Application2.Category"}, + {"SupplementalCategories", "Iptc.Application2.SuppCategory"}, + {"Keywords", "Iptc.Application2.Keywords"}, + {"Instructions", "Iptc.Application2.SpecialInstructions"}, + {"DateCreated", "Iptc.Application2.DateCreated"}, + {"Creator", "Iptc.Application2.Byline"}, + {"CreatorJobTitle", "Iptc.Application2.BylineTitle"}, + {"City", "Iptc.Application2.City"}, + {"Province", "Iptc.Application2.ProvinceState"}, + {"Country", "Iptc.Application2.CountryName"}, + {"TransReference", "Iptc.Application2.TransmissionReference"}, + {"Headline", "Iptc.Application2.Headline"}, + {"Credit", "Iptc.Application2.Credit"}, + {"Source", "Iptc.Application2.Source"}, + {"Copyright", "Iptc.Application2.Copyright"}, + {"Caption", "Iptc.Application2.Caption"}, + {"CaptionWriter", "Iptc.Application2.Writer"} +}; + +} // namespace + + +std::vector MetaDataParams::basicExifKeys = { + "Exif.Image.Copyright", + "Exif.Image.Artist", + "Exif.Image.ImageDescription", + "Exif.Photo.UserComment", + "Exif.Image.Make", + "Exif.Image.Model", + "Exif.Photo.LensModel", + "Exif.Photo.FNumber", + "Exif.Photo.ExposureTime", + "Exif.Photo.FocalLength", + "Exif.Photo.ISOSpeedRatings", + "Exif.Photo.ExposureBiasValue", + "Exif.Photo.Flash", + "Exif.Photo.DateTimeOriginal" +}; + + +MetaDataParams::MetaDataParams(): + mode(MetaDataParams::TUNNEL), + exifKeys{"*"}, + exif{}, + iptc{} +{ +} + +bool MetaDataParams::operator==(const MetaDataParams &other) const +{ + return mode == other.mode + && exifKeys == other.exifKeys + && exif == other.exif + && iptc == other.iptc; +} + +bool MetaDataParams::operator!=(const MetaDataParams &other) const +{ + return !(*this == other); +} + + ProcParams::ProcParams() { setDefaults(); @@ -5414,8 +5454,8 @@ void ProcParams::setDefaults() raw = {}; metadata = {}; - exif.clear(); - iptc.clear(); + //exif.clear(); + //iptc.clear(); // -1 means that there's no pp3 data with rank yet. In this case, the // embedded Rating metadata should take precedence. -1 should never be @@ -6876,10 +6916,10 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo for (auto &p : exif_keys) { m[p.second] = p.first; } - for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); ++i) { - auto it = m.find(i->first); + for (auto &p : metadata.exif) { + auto it = m.find(p.first); if (it != m.end()) { - keyFile.set_string("Exif", it->second, i->second); + keyFile.set_string("Exif", it->second, p.second); } } } @@ -6890,10 +6930,10 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo for (auto &p : iptc_keys) { m[p.second] = p.first; } - for (IPTCPairs::const_iterator i = iptc.begin(); i != iptc.end(); ++i) { - auto it = m.find(i->first); + for (auto &p : metadata.iptc) { + auto it = m.find(p.first); if (it != m.end()) { - Glib::ArrayHandle values = i->second; + Glib::ArrayHandle values = p.second; keyFile.set_string_list("IPTC", it->second, values); } } @@ -9383,7 +9423,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) for (const auto& key : keyFile.get_keys("Exif")) { auto it = exif_keys.find(key); if (it != exif_keys.end()) { - exif[it->second] = keyFile.get_string("Exif", key); + metadata.exif[it->second] = keyFile.get_string("Exif", key); if (pedited) { pedited->exif = true; @@ -9413,16 +9453,16 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } auto kk = it->second; - const IPTCPairs::iterator element = iptc.find(kk); + const IPTCPairs::iterator element = metadata.iptc.find(kk); - if (element != iptc.end()) { + if (element != metadata.iptc.end()) { // it already exist so we cleanup the values element->second.clear(); } // TODO: look out if merging Keywords and SupplementalCategories from the procparams chain would be interesting for (const auto& currLoadedTagValue : keyFile.get_string_list("IPTC", key)) { - iptc[kk].push_back(currLoadedTagValue); + metadata.iptc[kk].push_back(currLoadedTagValue); } if (pedited) { @@ -9500,8 +9540,6 @@ bool ProcParams::operator ==(const ProcParams& other) const && rgbCurves == other.rgbCurves && colorToning == other.colorToning && metadata == other.metadata - && exif == other.exif - && iptc == other.iptc && dehaze == other.dehaze && filmNegative == other.filmNegative; } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index dd6872630..d874a9b13 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1718,25 +1718,6 @@ struct ColorManagementParams { bool operator !=(const ColorManagementParams& other) const; }; -/** - * Parameters for metadata handling - */ -struct MetaDataParams { - enum Mode { - TUNNEL, - EDIT, - STRIP - }; - Mode mode; - std::vector exifKeys; - - MetaDataParams(); - - bool operator ==(const MetaDataParams &other) const; - bool operator !=(const MetaDataParams &other) const; -}; - - /** * Minimal wrapper allowing forward declaration for representing a key/value for the exif metadata information */ @@ -1841,6 +1822,29 @@ private: std::map> pairs; }; +/** + * Parameters for metadata handling + */ +struct MetaDataParams { + enum Mode { + TUNNEL, + EDIT, + STRIP + }; + Mode mode; + std::vector exifKeys; + ExifPairs exif; + IPTCPairs iptc; + + MetaDataParams(); + + bool operator ==(const MetaDataParams &other) const; + bool operator !=(const MetaDataParams &other) const; + + static std::vector basicExifKeys; +}; + + struct WaveletParams { std::vector ccwcurve; std::vector wavdenoise; @@ -2355,8 +2359,8 @@ public: int ppVersion; ///< Version of the PP file from which the parameters have been read MetaDataParams metadata; ///< Metadata parameters - ExifPairs exif; ///< List of modifications appplied on the exif tags of the input image - IPTCPairs iptc; ///< The IPTC tags and values to be saved to the output image + // ExifPairs exif; ///< List of modifications appplied on the exif tags of the input image + // IPTCPairs iptc; ///< The IPTC tags and values to be saved to the output image /** * The constructor only sets the hand-wired defaults. diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c8ee5e147..ef5592074 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1737,9 +1737,9 @@ private: readyImg->setMetadata(std::move(info)); break; case MetaDataParams::EDIT: - info.setExif(params.exif); - info.setIptc(params.iptc); - if (!(params.metadata.exifKeys.size() == 1 && params.metadata.exifKeys[0] == "ALL")) { + info.setExif(params.metadata.exif); + info.setIptc(params.metadata.iptc); + if (!(params.metadata.exifKeys.size() == 1 && params.metadata.exifKeys[0] == "*")) { info.setExifKeys(&(params.metadata.exifKeys)); } readyImg->setMetadata(std::move(info)); diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index ba612f615..a130a09b8 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -34,15 +34,12 @@ using namespace rtengine::procparams; ExifPanel::ExifPanel() : idata(nullptr), changeList(new rtengine::procparams::ExifPairs), - defChangeList(new rtengine::procparams::ExifPairs), - editableTags{ - {"Exif.Photo.UserComment", "User Comment"}, - {"Exif.Image.Artist", "Artist"}, - {"Exif.Image.Copyright", "Copyright"}, - {"Exif.Image.ImageDescription", "Image Description"}, - { "Exif.Photo.LensModel", "Lens Model" } - } + defChangeList(new rtengine::procparams::ExifPairs) { + for (auto &k : MetaDataParams::basicExifKeys) { + editableTags.push_back(std::make_pair(k, "")); + } + set_orientation(Gtk::ORIENTATION_VERTICAL); exifTree = Gtk::manage (new Gtk::TreeView()); scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow()); @@ -60,11 +57,29 @@ ExifPanel::ExifPanel() : exifTreeModel = Gtk::TreeStore::create(exifColumns); exifTree->set_model(exifTreeModel); exifTree->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_NONE); - //exifTree->set_show_expanders(false); + exifTree->set_show_expanders(false); exifTree->set_tooltip_column(0); + exifTree->set_enable_search(false); - keepicon = RTImage::createPixbufFromFile ("tick-small.png"); - editicon = RTImage::createPixbufFromFile("add-small.png"); + //keepicon = RTImage::createPixbufFromFile("tick-small.png"); + editicon = RTImage::createPixbufFromFile("edit-small.png"); + open_icon_ = RTImage::createPixbufFromFile("expander-open-small.png"); + closed_icon_ = RTImage::createPixbufFromFile("expander-closed-small.png"); + + exif_active_renderer_.property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE; + exif_active_renderer_.signal_toggled().connect(sigc::mem_fun(this, &ExifPanel::onKeyActiveToggled)); + exif_active_column_.pack_start(exif_active_renderer_); + exif_active_column_.set_cell_data_func(exif_active_renderer_, sigc::mem_fun(this, &ExifPanel::setKeyActive)); + + exifTree->append_column(exif_active_column_); + + // { + // Gtk::TreeView::Column *c = Gtk::manage(new Gtk::TreeView::Column("")); + // Gtk::CellRendererPixbuf *pb = Gtk::manage(new Gtk::CellRendererPixbuf()); + // c->pack_start(*pb, false); + // c->add_attribute(*pb, "pixbuf", exifColumns.expander_icon); + // exifTree->append_column(*c); + // } Gtk::TreeView::Column *viewcol = Gtk::manage (new Gtk::TreeView::Column ("Field Name")); Gtk::CellRendererPixbuf* render_pb = Gtk::manage (new Gtk::CellRendererPixbuf ()); @@ -85,15 +100,8 @@ ExifPanel::ExifPanel() : render_pb->property_yalign() = 0; render_txt->property_yalign() = 0; - exif_active_renderer_.property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE; - exif_active_renderer_.signal_toggled().connect(sigc::mem_fun(this, &ExifPanel::onKeyActiveToggled)); - exif_active_column_.pack_start(exif_active_renderer_); - exif_active_column_.set_cell_data_func(exif_active_renderer_, sigc::mem_fun(this, &ExifPanel::setKeyActive)); - - exifTree->append_column(exif_active_column_); - exifTree->append_column(*viewcol); - exifTree->set_expander_column(*viewcol); + //exifTree->set_expander_column(*viewcol); Gtk::TreeView::Column *viewcolv = Gtk::manage(new Gtk::TreeView::Column ("Value")); Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText()); @@ -131,14 +139,14 @@ ExifPanel::ExifPanel() : activate_all_ = addbtn("EXIFPANEL_ACTIVATE_ALL_HINT", "tick.png"); activate_none_ = addbtn("EXIFPANEL_ACTIVATE_NONE_HINT", "box.png"); - add = addbtn("EXIFPANEL_ADDEDIT", "add.png"); + add = addbtn("EXIFPANEL_ADDEDIT", "edit.png"); reset = addbtn("EXIFPANEL_RESETHINT", "undo.png", "redo.png"); resetAll = addbtn("EXIFPANEL_RESETALLHINT", "undo-all.png", "redo-all.png"); pack_end (*buttons1, Gtk::PACK_SHRINK); exifTree->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ExifPanel::exifSelectionChanged)); - // exifTree->signal_row_activated().connect (sigc::mem_fun (*this, &ExifPanel::row_activated)); + exifTree->signal_row_activated().connect(sigc::mem_fun(*this, &ExifPanel::onExifRowActivated)); reset->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetPressed) ); resetAll->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetAllPressed) ); @@ -146,6 +154,10 @@ ExifPanel::ExifPanel() : activate_all_->signal_clicked().connect(sigc::mem_fun(*this, &ExifPanel::activateAllPressed)); activate_none_->signal_clicked().connect(sigc::mem_fun(*this, &ExifPanel::activateNonePressed)); + exifTree->signal_button_press_event().connect_notify(sigc::mem_fun(*this, &ExifPanel::onExifTreeClick)); + exifTree->signal_row_expanded().connect(sigc::mem_fun(*this, &ExifPanel::onExifRowExpanded)); + exifTree->signal_row_collapsed().connect(sigc::mem_fun(*this, &ExifPanel::onExifRowCollapsed)); + show_all (); } @@ -157,7 +169,7 @@ void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener(); - *changeList = pp->exif; + *changeList = pp->metadata.exif; initial_active_keys_.clear(); initial_active_keys_.insert(pp->metadata.exifKeys.begin(), pp->metadata.exifKeys.end()); cur_active_keys_ = initial_active_keys_; @@ -170,54 +182,15 @@ void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) { - pp->exif = *changeList; - - std::unordered_set prev; - bool all_active = (cur_active_keys_.size() == 1 && *(cur_active_keys_.begin()) == "ALL"); - - if (!all_active) { - prev = cur_active_keys_; - } - - pp->metadata.exifKeys.clear(); - - bool none_active = true; - - auto root = exifTreeModel->children(); - // for (auto &entry : root->children()) { - // Glib::ustring key = entry[exifColumns.key]; - // prev.erase(key); - // if (entry[exifColumns.active]) { - // pp->metadata.exifKeys.push_back(key); - // none_active = false; - // } else { - // all_active = false; - // } - // } - for (auto &group : root->children()) { - for (auto &entry : group.children()) { - std::string key = entry[exifColumns.key]; - prev.erase(key); - if (entry[exifColumns.active]) { - pp->metadata.exifKeys.push_back(key); - none_active = false; - } else { - all_active = false; - } - } - } - - if (all_active) { - pp->metadata.exifKeys = { "ALL" }; - } else if (!none_active) { - pp->metadata.exifKeys.insert(pp->metadata.exifKeys.end(), prev.begin(), prev.end()); - } + pp->metadata.exif = *changeList; + cur_active_keys_ = get_active_keys(); + pp->metadata.exifKeys.assign(cur_active_keys_.begin(), cur_active_keys_.end()); std::sort(pp->metadata.exifKeys.begin(), pp->metadata.exifKeys.end()); } void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - *defChangeList = defParams->exif; + *defChangeList = defParams->metadata.exif; } void ExifPanel::setImageData (const FramesMetaData* id) @@ -240,11 +213,13 @@ void ExifPanel::addTag(const std::string &key, const std::pairchildren(); - for (auto it = root.rbegin(), end = root.rend(); it != end; ++it) { - auto row = *it; + // for (auto it = root.rbegin(), end = root.rend(); it != end; ++it) { + // auto row = *it; + for (auto &row : root) { + // auto row = *it; std::string key = row[exifColumns.key]; if (row[exifColumns.is_group] && key == label.first) { - return it->children(); + return row./*it->*/children(); } } auto it = exifTreeModel->append(root); @@ -253,7 +228,7 @@ void ExifPanel::addTag(const std::string &key, const std::pair"; + row[exifColumns.label] = "" + label.first + ""; row[exifColumns.value_nopango] = ""; row[exifColumns.value] = ""; row[exifColumns.is_group] = true; @@ -275,13 +250,13 @@ void ExifPanel::addTag(const std::string &key, const std::pair Glib::ustring @@ -338,6 +314,9 @@ void ExifPanel::refreshTags() return "(Not shown)"; }; + if (const rtengine::FramesData *fd = dynamic_cast(idata)) { + fd->fillBasicTags(exif); + } for (const auto& p : *changeList) { try { @@ -346,12 +325,18 @@ void ExifPanel::refreshTags() } } - for (const auto& p : editableTags) { - const auto pos = exif.findKey(Exiv2::ExifKey(p.first)); + for (auto& p : editableTags) { + Exiv2::ExifKey k(p.first); + const auto pos = exif.findKey(k); + bool edited = false; + Glib::ustring value = ""; + auto lbl = std::make_pair(M("EXIFPANEL_BASIC_GROUP"), k.tagLabel()); + p.second = k.tagLabel(); if (pos != exif.end() && pos->size()) { - const bool edited = changeList->find(pos->key()) != changeList->end(); - addTag(pos->key(), to_label(*pos), pos->print(&exif), true, edited); + edited = changeList->find(pos->key()) != changeList->end(); + value = pos->print(&exif); } + addTag(p.first, lbl, value, true, edited); } std::set keyset; for (const auto& tag : exif) { @@ -406,6 +391,7 @@ void ExifPanel::resetIt(const Gtk::TreeModel::const_iterator& iter) void ExifPanel::resetPressed() { + cur_active_keys_ = get_active_keys(); std::vector sel = exifTree->get_selection()->get_selected_rows(); @@ -490,10 +476,13 @@ void ExifPanel::addPressed () hb2->show (); if (dialog->run () == Gtk::RESPONSE_OK) { + cur_active_keys_ = get_active_keys(); auto key = editableTags[tcombo->get_active_row_number()].first; const auto value = ventry->get_text(); (*changeList)[key] = value; - cur_active_keys_.insert(key); + if (!all_keys_active()) { + cur_active_keys_.insert(key); + } refreshTags(); notifyListener(); } @@ -556,6 +545,11 @@ void ExifPanel::onKeyActiveToggled(const Glib::ustring &path) for (auto &c : row.children()) { c[exifColumns.active] = b; } + } else if (!b) { + it = row.parent(); + if (it) { + (*it)[exifColumns.active] = b; + } } notifyListener(); } @@ -568,3 +562,78 @@ void ExifPanel::setKeyActive(Gtk::CellRenderer *renderer, const Gtk::TreeModel:: static_cast(renderer)->set_active(row[exifColumns.active]); } + +bool ExifPanel::all_keys_active() const +{ + return (cur_active_keys_.size() == 1 && *(cur_active_keys_.begin()) == "*"); +} + + +std::unordered_set ExifPanel::get_active_keys() const +{ + bool all_active = true; + std::unordered_set ret; + auto root = exifTreeModel->children(); + for (auto &group : root->children()) { + for (auto &entry : group.children()) { + std::string key = entry[exifColumns.key]; + if (entry[exifColumns.active]) { + ret.insert(key); + } else { + all_active = false; + } + } + } + if (all_active) { + ret.clear(); + ret.insert("*"); + } + return ret; +} + +void ExifPanel::onExifTreeClick(GdkEventButton *event) +{ + Gtk::TreeModel::Path pth; + Gtk::TreeViewColumn *col; + int cell_x; + int cell_y; + if (exifTree->get_path_at_pos(event->x, event->y, pth, col, cell_x, cell_y) && col == exifTree->get_column(1) && cell_x <= 22) { + auto it = exifTreeModel->get_iter(pth); + auto row = *it; + if (row[exifColumns.is_group]) { + if (exifTree->row_expanded(pth)) { + exifTree->collapse_row(pth); + } else { + exifTree->expand_row(pth, false); + } + } + } +} + + +void ExifPanel::onExifRowExpanded(const Gtk::TreeModel::iterator &it, const Gtk::TreeModel::Path &path) +{ + auto row = *it; + if (row[exifColumns.is_group]) { + row[exifColumns.icon] = open_icon_; + } +} + + +void ExifPanel::onExifRowCollapsed(const Gtk::TreeModel::iterator &it, const Gtk::TreeModel::Path &path) +{ + auto row = *it; + if (row[exifColumns.is_group]) { + row[exifColumns.icon] = closed_icon_; + } +} + + +void ExifPanel::onExifRowActivated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) +{ + auto it = exifTreeModel->get_iter(path); + auto row = *it; + if (row[exifColumns.editable]) { + addPressed(); + } +} diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index 32ce10dc7..da4cc1e37 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -50,7 +50,8 @@ private: class ExifColumns : public Gtk::TreeModelColumnRecord { public: - Gtk::TreeModelColumn > icon; + // Gtk::TreeModelColumn> expander_icon; + Gtk::TreeModelColumn> icon; Gtk::TreeModelColumn key; Gtk::TreeModelColumn label; Gtk::TreeModelColumn value; @@ -71,10 +72,13 @@ private: add(editable); add(active); add(is_group); + // add(expander_icon); } }; - Glib::RefPtr keepicon; + //Glib::RefPtr keepicon; Glib::RefPtr editicon; + Glib::RefPtr open_icon_; + Glib::RefPtr closed_icon_; ExifColumns exifColumns; Gtk::TreeView* exifTree; @@ -90,7 +94,7 @@ private: Gtk::CellRendererToggle exif_active_renderer_; Gtk::TreeView::Column exif_active_column_; - const std::vector> editableTags; + std::vector> editableTags; std::unordered_set initial_active_keys_; std::unordered_set cur_active_keys_; @@ -106,7 +110,14 @@ private: void setKeyActive(Gtk::CellRenderer *renderer, const Gtk::TreeModel::iterator &it); void onKeyActiveToggled(const Glib::ustring &path); - + + bool all_keys_active() const; + std::unordered_set get_active_keys() const; + + void onExifTreeClick(GdkEventButton *event); + void onExifRowExpanded(const Gtk::TreeModel::iterator &it, const Gtk::TreeModel::Path &path); + void onExifRowCollapsed(const Gtk::TreeModel::iterator &it, const Gtk::TreeModel::Path &path); + void onExifRowActivated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column); public: ExifPanel (); diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index f476e7513..bee7ec74a 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -467,8 +467,8 @@ void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) disableListener (); changeList->clear(); - if (!pp->iptc.empty()) { - *changeList = pp->iptc; + if (!pp->metadata.iptc.empty()) { + *changeList = pp->metadata.iptc; } else { *changeList = *embeddedData; } @@ -480,13 +480,13 @@ void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) void IPTCPanel::write (ProcParams* pp, ParamsEdited* pedited) { - pp->iptc = *changeList; + pp->metadata.iptc = *changeList; } void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - *defChangeList = defParams->iptc; + *defChangeList = defParams->metadata.iptc; } void IPTCPanel::setImageData (const FramesMetaData* id) diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 8459d4013..98abe2869 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -6612,15 +6612,15 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng // Exif changes are added to the existing ones if (exif) { - for (procparams::ExifPairs::const_iterator i = mods.exif.begin(); i != mods.exif.end(); ++i) { - toEdit.exif[i->first] = i->second; + for (procparams::ExifPairs::const_iterator i = mods.metadata.exif.begin(); i != mods.metadata.exif.end(); ++i) { + toEdit.metadata.exif[i->first] = i->second; } } // IPTC changes are added to the existing ones if (iptc) { - for (procparams::IPTCPairs::const_iterator i = mods.iptc.begin(); i != mods.iptc.end(); ++i) { - toEdit.iptc[i->first] = i->second; + for (procparams::IPTCPairs::const_iterator i = mods.metadata.iptc.begin(); i != mods.metadata.iptc.end(); ++i) { + toEdit.metadata.iptc[i->first] = i->second; } } } diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index ce5138d28..dfc1bfeb7 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -1215,7 +1215,7 @@ void Thumbnail::saveMetadata() return; } - if (pparams->exif.empty() && pparams->iptc.empty()) { + if (pparams->metadata.exif.empty() && pparams->metadata.iptc.empty()) { return; } @@ -1224,8 +1224,8 @@ void Thumbnail::saveMetadata() auto xmp = rtengine::Exiv2Metadata::getXmpSidecar(fname); rtengine::Exiv2Metadata meta; meta.xmpData() = std::move(xmp); - meta.setExif(pparams->exif); - meta.setIptc(pparams->iptc); + meta.setExif(pparams->metadata.exif); + meta.setIptc(pparams->metadata.iptc); meta.saveToXmp(fn); if (options.rtSettings.verbose) { std::cout << "saved edited metadata for " << fname << " to " diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 920585aed..fde949606 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -141,7 +141,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (detailsPanel, dehaze); addfavoritePanel (advancedPanel, wavelet); addfavoritePanel(locallabPanel, locallab); - + addfavoritePanel (transformPanel, crop); addfavoritePanel (transformPanel, resize); addPanel (resize->getPackBox(), prsharpening, 2); @@ -187,7 +187,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit transformPanelSW = Gtk::manage (new MyScrolledWindow ()); rawPanelSW = Gtk::manage (new MyScrolledWindow ()); advancedPanelSW = Gtk::manage (new MyScrolledWindow ()); - locallabPanelSW = Gtk::manage(new MyScrolledWindow()); + locallabPanelSW = Gtk::manage(new MyScrolledWindow()); // load panel endings for (int i = 0; i < 8; i++) { @@ -585,8 +585,8 @@ void ToolPanelCoordinator::profileChange( // Reset IPTC values when switching procparams from the History if (event == rtengine::EvHistoryBrowsed) { - mergedParams->iptc.clear(); - mergedParams->exif.clear(); + mergedParams->metadata.iptc.clear(); + mergedParams->metadata.exif.clear(); } // And apply the partial profile nparams to mergedParams From 1935f3d76d583d5ca082fc7e1580ed27b918189a Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 10 Apr 2020 06:47:13 -0700 Subject: [PATCH 040/110] exif panel: ensure that keys are not empty in the displayed tag tree (cherry picked from commit da45bf30bddf311b6c7d0d990d078b2a37d4b500) --- rtdata/languages/default | 1 + rtgui/exifpanel.cc | 28 ++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index a5ce4fa54..1b625bdac 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -78,6 +78,7 @@ EXIFPANEL_RESETALL;Reset All EXIFPANEL_RESETALLHINT;Reset all tags to their original values. EXIFPANEL_RESETHINT;Reset the selected tags to their original values. EXIFPANEL_BASIC_GROUP;Basic +EXIFPANEL_VALUE_NOT_SHOWN;Not shown EXPORT_BYPASS;Processing steps to bypass EXPORT_BYPASS_ALL;Select / Unselect All EXPORT_BYPASS_DEFRINGE;Bypass Defringe diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index a130a09b8..4957cc0b6 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -293,9 +293,12 @@ void ExifPanel::refreshTags() pos = s.find('.'); if (pos != std::string::npos) { g = s.substr(0, pos); - // s = s.substr(pos+1); + s = s.substr(pos+1); + } + auto l = tag.tagLabel(); + if (!l.empty()) { + s = l; } - s = tag.tagLabel(); return std::make_pair(g, Glib::ustring(s)); }; @@ -311,7 +314,7 @@ void ExifPanel::refreshTags() (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { return escapeHtmlChars(tag.print(&exif)); } - return "(Not shown)"; + return "(" + M("EXIFPANEL_VALUE_NOT_SHOWN") + ")"; }; if (const rtengine::FramesData *fd = dynamic_cast(idata)) { @@ -338,7 +341,24 @@ void ExifPanel::refreshTags() } addTag(p.first, lbl, value, true, edited); } - std::set keyset; + struct KeyLt { + bool operator()(const std::string &a, const std::string &b) const + { + auto p1 = a.find_last_of('.'); + auto p2 = b.find_last_of('.'); + const char *sa = a.c_str(); + const char *sb = b.c_str(); + if (p1 != std::string::npos && p2 != std::string::npos) { + bool hex_a = strncmp(sa+p1+1, "0x", 2) == 0; + bool hex_b = strncmp(sb+p2+1, "0x", 2) == 0; + if (hex_a != hex_b) { + return !hex_a; + } + } + return strcmp(sa, sb) < 0; + } + }; + std::set keyset; for (const auto& tag : exif) { const bool editable = ed.find(tag.key()) != ed.end(); if (!editable) { From e9705620551aae8edd66d3172273b8f51a61301b Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 11 Apr 2020 00:31:55 +0200 Subject: [PATCH 041/110] metadata: check for "Exif.Photo.ExposureBiasValue" in addition to "Exif.Image.ExposureBiasValue" for exposure compensation Fixes #49 (cherry picked from commit a7cb9add3453c581347e738110461f0af15cb1cb) --- rtengine/imagedata.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 52a9fa297..fac34ba76 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -321,6 +321,8 @@ FramesData::FramesData(const Glib::ustring &fname) : if (find_exif_tag("Exif.Image.ExposureBiasValue")) { expcomp = pos->toFloat(); + } else if (find_exif_tag("Exif.Photo.ExposureBiasValue")) { + expcomp = pos->toFloat(); } if (find_exif_tag("Exif.Image.Rating")) { From a9aa17f153cf8a64c2f89af773098ef255fa9050 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 11 Apr 2020 00:45:49 +0200 Subject: [PATCH 042/110] metadata: small tweaks to expcomp and fnumber default values in "apply changes" mode (cherry picked from commit af20ad37cceb3b4bf0a01e46b5cec023d4170300) --- rtengine/imagedata.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index fac34ba76..d8cec7604 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -721,11 +721,10 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const return; } set_exif(exif, "Exif.Photo.ISOSpeedRatings", getISOSpeed()); - set_exif(exif, "Exif.Photo.FNumber", Exiv2::DoubleValue(getFNumber())); - //set_exif(exif, "Exif.Photo.ExposureTime", Exiv2::DoubleValue(getShutterSpeed())); + set_exif(exif, "Exif.Photo.FNumber", apertureToString(getFNumber())); set_exif(exif, "Exif.Photo.ExposureTime", shutterToString(getShutterSpeed())); set_exif(exif, "Exif.Photo.FocalLength", Exiv2::DoubleValue(getFocalLen())); - set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::DoubleValue(getExpComp())); + set_exif(exif, "Exif.Photo.ExposureBiasValue", expcompToString(getExpComp(), false)); set_exif(exif, "Exif.Image.Make", getMake()); set_exif(exif, "Exif.Image.Model", getModel()); set_exif(exif, "Exif.Photo.LensModel", getLens()); From 1de9516ef0ec43f1c49359bc8f648ba7b34e9a22 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 11 Apr 2020 02:50:49 -0700 Subject: [PATCH 043/110] metadata: better defaults and presentation of the exif tag tree (cherry picked from commit 9edc783c1b6ba3b49c933560a73e2de126e04dc1) --- rtengine/procparams.cc | 8 ++++-- rtgui/exifpanel.cc | 63 ++++++++++++++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 06ea2be6a..d5cc7b45b 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -5335,13 +5335,15 @@ std::vector MetaDataParams::basicExifKeys = { MetaDataParams::MetaDataParams(): - mode(MetaDataParams::TUNNEL), - exifKeys{"*"}, + mode(MetaDataParams::EDIT), + exifKeys{}, exif{}, iptc{} { + exifKeys = basicExifKeys; } + bool MetaDataParams::operator==(const MetaDataParams &other) const { return mode == other.mode @@ -9409,7 +9411,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } if (keyFile.has_group("MetaData")) { - int mode = int(MetaDataParams::TUNNEL); + int mode = int(MetaDataParams::EDIT); assignFromKeyfile(keyFile, "MetaData", "Mode", pedited, mode, pedited->metadata.mode); if (mode >= int(MetaDataParams::TUNNEL) && mode <= int(MetaDataParams::STRIP)) { diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 4957cc0b6..05d69f6e3 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -73,14 +73,6 @@ ExifPanel::ExifPanel() : exifTree->append_column(exif_active_column_); - // { - // Gtk::TreeView::Column *c = Gtk::manage(new Gtk::TreeView::Column("")); - // Gtk::CellRendererPixbuf *pb = Gtk::manage(new Gtk::CellRendererPixbuf()); - // c->pack_start(*pb, false); - // c->add_attribute(*pb, "pixbuf", exifColumns.expander_icon); - // exifTree->append_column(*c); - // } - Gtk::TreeView::Column *viewcol = Gtk::manage (new Gtk::TreeView::Column ("Field Name")); Gtk::CellRendererPixbuf* render_pb = Gtk::manage (new Gtk::CellRendererPixbuf ()); Gtk::CellRendererText *render_txt = Gtk::manage (new Gtk::CellRendererText()); @@ -310,7 +302,7 @@ void ExifPanel::refreshTags() const auto to_value = [&](Exiv2::Exifdatum &tag) -> Glib::ustring { - if (!tag.tagLabel().empty() && tag.typeId() != Exiv2::undefined && + if (!tag.tagLabel().empty() && //tag.typeId() != Exiv2::undefined && (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { return escapeHtmlChars(tag.print(&exif)); } @@ -342,6 +334,13 @@ void ExifPanel::refreshTags() addTag(p.first, lbl, value, true, edited); } struct KeyLt { + KeyLt(): + order_{ + {"Exif.GPSInfo", 0}, + {"Exif.Photo", 1}, + {"Exif.Image", 2} + } + {} bool operator()(const std::string &a, const std::string &b) const { auto p1 = a.find_last_of('.'); @@ -355,8 +354,28 @@ void ExifPanel::refreshTags() return !hex_a; } } + if (p1 != p2 || strncmp(sa, sb, p1) != 0) { + std::string ga(sa, sa+p1); + std::string gb(sb, sb+p2); + int ia = getorder(ga); + int ib = getorder(gb); + if (ia != ib) { + return ia < ib; + } + } return strcmp(sa, sb) < 0; } + + int getorder(const std::string &key) const + { + auto it = order_.find(key); + if (it == order_.end()) { + return 1000; + } + return it->second; + } + + std::unordered_map order_; }; std::set keyset; for (const auto& tag : exif) { @@ -565,11 +584,6 @@ void ExifPanel::onKeyActiveToggled(const Glib::ustring &path) for (auto &c : row.children()) { c[exifColumns.active] = b; } - } else if (!b) { - it = row.parent(); - if (it) { - (*it)[exifColumns.active] = b; - } } notifyListener(); } @@ -579,7 +593,26 @@ void ExifPanel::onKeyActiveToggled(const Glib::ustring &path) void ExifPanel::setKeyActive(Gtk::CellRenderer *renderer, const Gtk::TreeModel::iterator &it) { auto row = *it; - static_cast(renderer)->set_active(row[exifColumns.active]); + Gtk::CellRendererToggle *toggle = static_cast(renderer); + if (row[exifColumns.is_group]) { + bool all_true = true, all_false = true; + for (auto &c : row.children()) { + if (c[exifColumns.active]) { + all_false = false; + } else { + all_true = false; + } + } + if (!all_true && !all_false) { + toggle->property_inconsistent() = true; + } else { + toggle->property_inconsistent() = false; + toggle->set_active(all_true); + } + } else { + toggle->property_inconsistent() = false; + toggle->set_active(row[exifColumns.active]); + } } From 3f0556454893610812b059b291bba5a268ed2173 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 14 Apr 2020 00:05:30 -0700 Subject: [PATCH 044/110] exifpanel: fixed missing markup escaping when adding tag values Fixes #54 (cherry picked from commit 383619d6260fa10b8f112e3dc55e0323f5e99b43) --- rtgui/exifpanel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 05d69f6e3..bcc95bfd0 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -329,7 +329,7 @@ void ExifPanel::refreshTags() p.second = k.tagLabel(); if (pos != exif.end() && pos->size()) { edited = changeList->find(pos->key()) != changeList->end(); - value = pos->print(&exif); + value = escapeHtmlChars(pos->print(&exif)); } addTag(p.first, lbl, value, true, edited); } From 7c9726ddbe1ae91fb07b40c768c84883c2148998 Mon Sep 17 00:00:00 2001 From: David Hunt Date: Tue, 14 Apr 2020 00:11:03 -0700 Subject: [PATCH 045/110] metadata: use std::unique_ptr instead of Exiv2::Image::AutoPtr Fixes #55 (cherry picked from commit 9466fc133f1af465a784a7384cf0369d7c35b901) --- rtengine/metadata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index d04b979fe..884c8a9a1 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -52,7 +52,7 @@ private: constexpr size_t IMAGE_CACHE_SIZE = 200; -Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring& fname) +std::unique_ptr open_exiv2(const Glib::ustring& fname) { #ifdef EXV_UNICODE_PATH glong ws_size = 0; From 38eb9f9f187aad17c37d43e3d6a469b1cd14b487 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 14 Apr 2020 05:36:40 -0700 Subject: [PATCH 046/110] exifpanel: improved ui for editing tags (cherry picked from commit f6f4ddf54c25e6e577bf4960ea51fc23e8434559) --- rtgui/exifpanel.cc | 144 +++++++++++++++------------------------------ rtgui/exifpanel.h | 4 +- 2 files changed, 51 insertions(+), 97 deletions(-) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index bcc95bfd0..c44a4f8d2 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -48,7 +48,7 @@ ExifPanel::ExifPanel() : exifTree->set_rules_hint (false); exifTree->set_reorderable (false); exifTree->set_enable_search (false); - exifTree->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); + exifTree->get_selection()->set_mode(Gtk::SELECTION_SINGLE); scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE); scrolledWindow->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT); @@ -99,7 +99,7 @@ ExifPanel::ExifPanel() : Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText()); render_txtv->property_ellipsize() = Pango::ELLIPSIZE_END; viewcolv->pack_start (*render_txtv, true); - viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value); + // viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value); viewcolv->set_expand (true); viewcolv->set_resizable (true); viewcol->set_fixed_width (35); @@ -107,6 +107,8 @@ ExifPanel::ExifPanel() : viewcolv->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); render_txtv->property_ypad() = 0; + viewcolv->set_cell_data_func(*render_txtv, sigc::mem_fun(this, &ExifPanel::setExifTagValue)); + render_txtv->signal_edited().connect(sigc::mem_fun(this, &ExifPanel::onEditExifTagValue)); exifTree->append_column(*viewcolv); @@ -138,7 +140,6 @@ ExifPanel::ExifPanel() : pack_end (*buttons1, Gtk::PACK_SHRINK); exifTree->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ExifPanel::exifSelectionChanged)); - exifTree->signal_row_activated().connect(sigc::mem_fun(*this, &ExifPanel::onExifRowActivated)); reset->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetPressed) ); resetAll->signal_clicked().connect ( sigc::mem_fun (*this, &ExifPanel::resetAllPressed) ); @@ -401,20 +402,18 @@ void ExifPanel::refreshTags() void ExifPanel::exifSelectionChanged () { - Glib::RefPtr selection = exifTree->get_selection(); std::vector sel = selection->get_selected_rows(); - if (sel.size() > 1) { - reset->set_sensitive (1); - } else if (sel.size() == 1) { + if (sel.size() >= 1) { Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (sel[0]); - - if (iter->get_value(exifColumns.icon) == editicon) { - reset->set_sensitive (1); + if (iter->get_value(exifColumns.editable)) { + reset->set_sensitive(true); + add->set_sensitive(true); } } else { - reset->set_sensitive (0); + reset->set_sensitive(false); + add->set_sensitive(false); } } @@ -432,107 +431,43 @@ void ExifPanel::resetPressed() { cur_active_keys_ = get_active_keys(); - std::vector sel = exifTree->get_selection()->get_selected_rows(); - + auto sel = exifTree->get_selection()->get_selected_rows(); for (size_t i = 0; i < sel.size(); i++) { resetIt(exifTreeModel->get_iter(sel[i])); } refreshTags(); + + if (!sel.empty()) { + exifTree->get_selection()->select(sel[0]); + } + notifyListener(); } -void ExifPanel::resetAllPressed () +void ExifPanel::resetAllPressed() { + auto sel = exifTree->get_selection()->get_selected_rows(); setImageData(idata); *changeList = *defChangeList; cur_active_keys_ = initial_active_keys_; refreshTags(); + if (!sel.empty()) { + exifTree->get_selection()->select(sel[0]); + } notifyListener(); } -void ExifPanel::addPressed () +void ExifPanel::addPressed() { + Gtk::TreeModel::Path path; + Gtk::TreeViewColumn *col; - Gtk::Dialog* dialog = new Gtk::Dialog (M ("EXIFPANEL_ADDTAGDLG_TITLE"), * ((Gtk::Window*)get_toplevel()), true); - dialog->add_button ("_OK", Gtk::RESPONSE_OK); - dialog->add_button ("_Cancel", Gtk::RESPONSE_CANCEL); - - Gtk::Box* hb1 = new Gtk::Box (); - Gtk::Box* hb2 = new Gtk::Box (); - - Gtk::Label* tlabel = new Gtk::Label (M ("EXIFPANEL_ADDTAGDLG_SELECTTAG") + ":"); - MyComboBoxText* tcombo = new MyComboBoxText (); - - for (const auto& p : editableTags) { - tcombo->append(p.second); + exifTree->get_cursor(path, col); + const auto it = exifTreeModel->get_iter(path); + if (it && it->get_value(exifColumns.editable)) { + exifTree->set_cursor(path, *col, true); } - - hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4); - hb1->pack_start (*tcombo); - - Gtk::Label* vlabel = new Gtk::Label (M ("EXIFPANEL_ADDTAGDLG_ENTERVALUE") + ":"); - Gtk::Entry* ventry = new Gtk::Entry (); - hb2->pack_start (*vlabel, Gtk::PACK_SHRINK, 4); - hb2->pack_start (*ventry); - - Glib::ustring sel; - Glib::ustring val; - { - const Glib::RefPtr selection = exifTree->get_selection(); - const std::vector rows = selection->get_selected_rows(); - - if (rows.size() == 1) { - const Gtk::TreeModel::iterator iter = exifTreeModel->get_iter(rows[0]); - if (iter->get_value(exifColumns.editable)) { - sel = iter->get_value(exifColumns.key); - val = iter->get_value(exifColumns.value_nopango); - } - } - } - - if (sel.empty()) { - tcombo->set_active(0); - } else { - for (size_t i = 0; i < editableTags.size(); ++i) { - if (editableTags[i].first == sel) { - tcombo->set_active(i); - break; - } - } - } - - ventry->set_text(val); - ventry->set_activates_default (true); - dialog->set_default_response (Gtk::RESPONSE_OK); - dialog->get_content_area()->pack_start (*hb1, Gtk::PACK_SHRINK); - dialog->get_content_area()->pack_start (*hb2, Gtk::PACK_SHRINK, 4); - tlabel->show (); - tcombo->show (); - vlabel->show (); - ventry->show (); - hb1->show (); - hb2->show (); - - if (dialog->run () == Gtk::RESPONSE_OK) { - cur_active_keys_ = get_active_keys(); - auto key = editableTags[tcombo->get_active_row_number()].first; - const auto value = ventry->get_text(); - (*changeList)[key] = value; - if (!all_keys_active()) { - cur_active_keys_.insert(key); - } - refreshTags(); - notifyListener(); - } - - delete dialog; - delete tlabel; - delete tcombo; - delete vlabel; - delete ventry; - delete hb1; - delete hb2; } void ExifPanel::activateAllPressed() @@ -682,11 +617,28 @@ void ExifPanel::onExifRowCollapsed(const Gtk::TreeModel::iterator &it, const Gtk } -void ExifPanel::onExifRowActivated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) +void ExifPanel::setExifTagValue(Gtk::CellRenderer *renderer, const Gtk::TreeModel::iterator &it) +{ + auto row = *it; + Gtk::CellRendererText *txt = static_cast(renderer); + txt->property_editable() = row[exifColumns.editable]; + txt->property_markup() = row[exifColumns.value]; +} + + +void ExifPanel::onEditExifTagValue(const Glib::ustring &path, const Glib::ustring &value) { auto it = exifTreeModel->get_iter(path); auto row = *it; - if (row[exifColumns.editable]) { - addPressed(); + std::string key = row[exifColumns.key]; + + changeList[key] = value; + if (!all_keys_active()) { + cur_active_keys_.insert(key); } + refreshTags(); + + it = exifTreeModel->get_iter(path); + exifTree->get_selection()->select(it); + notifyListener(); } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index da4cc1e37..261561ea0 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -117,8 +117,10 @@ private: void onExifTreeClick(GdkEventButton *event); void onExifRowExpanded(const Gtk::TreeModel::iterator &it, const Gtk::TreeModel::Path &path); void onExifRowCollapsed(const Gtk::TreeModel::iterator &it, const Gtk::TreeModel::Path &path); - void onExifRowActivated(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column); + void setExifTagValue(Gtk::CellRenderer *renderer, const Gtk::TreeModel::iterator &it); + void onEditExifTagValue(const Glib::ustring &path, const Glib::ustring &value); + public: ExifPanel (); ~ExifPanel() override; From 30e77ee96fa83c0a593568cdcacbdedc2e6746b6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 20 Apr 2020 07:32:55 -0700 Subject: [PATCH 047/110] fixed compilation error with Apple Clang 7.0.0 (cherry picked from commit dd5b10d9dc8eb7447e37ac30ddd7545897c878b0) --- rtengine/metadata.cc | 3 ++- rtgui/exifpanel.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 884c8a9a1..732133785 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -76,7 +76,8 @@ std::unique_ptr open_exiv2(const Glib::ustring& fname) #endif throw Exiv2::Error(error_code, "exiv2: invalid image"); } - return image; + std::unique_ptr ret(image.release()); + return ret; } } // namespace diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index c44a4f8d2..44c70bc12 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -632,7 +632,7 @@ void ExifPanel::onEditExifTagValue(const Glib::ustring &path, const Glib::ustrin auto row = *it; std::string key = row[exifColumns.key]; - changeList[key] = value; + (*changeList)[key] = value; if (!all_keys_active()) { cur_active_keys_.insert(key); } From 41834c7007a2d821e61ada4eef0a2e10eea14565 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 24 Apr 2020 05:00:50 -0700 Subject: [PATCH 048/110] cmake: fix build issue on opensuse (exiv2 library not found) Fixes #64 (cherry picked from commit 33ced3e42605fcc4f69a0be03aa4df3691fa66f9) --- CMakeLists.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3630eecb..aa118e15b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ endif() # Warning for GCC 10, which causes problems #5749: if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "10.1") - message(STATUS "WARNING: gcc ${CMAKE_CXX_COMPILER_VERSION} is known to miscompile RawTherapee when using -ftree-loop-vectorize, forcing the option to be off") + message(STATUS "WARNING: gcc ${CMAKE_CXX_COMPILER_VERSION} is known to miscompile RawTherapee when using -ftree-loop-vectorize, forcing the option to be off") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-tree-loop-vectorize") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-tree-loop-vectorize") endif() @@ -482,10 +482,17 @@ set(EXIV2_LIBRARIES "") foreach(l ${_exiv2_libs}) set(_el "_el-NOTFOUND") if(EXIV2_LIBRARY_DIRS) + message(STATUS "searching for library ${l} in ${EXIV2_LIBRARY_DIRS}") find_library(_el ${l} PATHS ${EXIV2_LIBRARY_DIRS} NO_DEFAULT_PATH) + if(NOT _el) + message(STATUS " NOT FOUND, searching again in default path") + find_library(_el ${l}) + endif() else() - find_library(_el ${l} PATHS ${EXIV2_LIBRARY_DIRS}) + message(STATUS "searching for library ${l}") + find_library(_el ${l})# PATHS ${EXIV2_LIBRARY_DIRS}) endif() + message(STATUS " result: ${_el}") set(EXIV2_LIBRARIES ${EXIV2_LIBRARIES} ${_el}) endforeach() @@ -709,7 +716,7 @@ elseif(APPLE) -DSYSTEM:STRING=Apple -DCXX_FLAGS:STRING=${CXX_FLAGS} -DLFLAGS:STRING=${LFLAGS} - -DCOMPILER_INFO:STRING=${COMPILER_INFO}) + -DCOMPILER_INFO:STRING=${COMPILER_INFO}) else() list(APPEND ABOUT_COMMAND_WITH_ARGS -DSYSTEM:STRING=Linux -DCXX_FLAGS:STRING=${CXX_FLAGS} -DLFLAGS:STRING=${LFLAGS} @@ -771,14 +778,17 @@ foreach(l ${LENSFUN_LIBRARIES}) # want, and not the system's one (e.g. if we have a custom version # installed in a non-standard location) set(_l "_l-NOTFOUND") + message(STATUS "searching for library ${l} in ${LENSFUN_LIBRARY_DIRS}") find_library(_l ${l} PATHS ${LENSFUN_LIBRARY_DIRS} NO_DEFAULT_PATH) else() # LENSFUN_LIBRARY_DIRS can be empty if lensfun is installed in the # default path. In this case, adding NO_DEFAULT_PATH would make # find_library fail... set(_l "_l-NOTFOUND") + message(STATUS "searching for library ${l}") find_library(_l ${l}) endif() + message(STATUS " result: ${_l}") set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${_l}) endforeach() check_cxx_source_compiles( From 62249218435ddea570322ba5353a502770a5c8a8 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 7 May 2020 09:26:13 +0200 Subject: [PATCH 049/110] metadata: workaround for misbehaviour of exiv2 on ubuntu 20.04 (cherry picked from commit 26b8860d4bb803cff0277c7b2353b58b5e02fbc6) --- rtengine/metadata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 732133785..6e2b53ed8 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -68,7 +68,7 @@ std::unique_ptr open_exiv2(const Glib::ustring& fname) auto image = Exiv2::ImageFactory::open(Glib::filename_from_utf8(fname)); #endif image->readMetadata(); - if (!image->good()) { + if (!image->good() || image->exifData().empty()) { #if EXIV2_TEST_VERSION(0,27,0) auto error_code = Exiv2::kerErrorMessage; #else From 700eeccb393cf283076cc0617585f35d93b8bd2d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 8 May 2020 02:11:08 -0700 Subject: [PATCH 050/110] metadata: don't raise error if exif is empty when opening an image for saving Fixes #79 (regression introduced by 26b8860d4bb803cff0277c7b2353b58b5e02fbc6) (cherry picked from commit 62ae8e15b8ca07cbe545ed42c323e986448c3213) --- rtengine/metadata.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 6e2b53ed8..4c347c86c 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -52,7 +52,8 @@ private: constexpr size_t IMAGE_CACHE_SIZE = 200; -std::unique_ptr open_exiv2(const Glib::ustring& fname) +std::unique_ptr open_exiv2(const Glib::ustring& fname, + bool check_exif) { #ifdef EXV_UNICODE_PATH glong ws_size = 0; @@ -68,7 +69,7 @@ std::unique_ptr open_exiv2(const Glib::ustring& fname) auto image = Exiv2::ImageFactory::open(Glib::filename_from_utf8(fname)); #endif image->readMetadata(); - if (!image->good() || image->exifData().empty()) { + if (!image->good() || (check_exif && image->exifData().empty())) { #if EXIV2_TEST_VERSION(0,27,0) auto error_code = Exiv2::kerErrorMessage; #else @@ -121,7 +122,7 @@ void Exiv2Metadata::load() const if (cache_ && cache_->get(src_, val) && val.second >= finfo->modification_time()) { image_ = val.first; } else { - auto img = open_exiv2(src_); + auto img = open_exiv2(src_, true); image_.reset(img.release()); if (cache_) { cache_->set(src_, CacheVal(image_, finfo->modification_time())); @@ -218,7 +219,7 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const void Exiv2Metadata::saveToImage(const Glib::ustring &path) const { - auto dst = open_exiv2(path); + auto dst = open_exiv2(path, false); if (image_.get()) { dst->setIptcData(image_->iptcData()); dst->setXmpData(image_->xmpData()); @@ -432,7 +433,7 @@ Exiv2::XmpData Exiv2Metadata::getXmpSidecar(const Glib::ustring &path) Exiv2::XmpData ret; auto fname = xmpSidecarPath(path); if (Glib::file_test(fname, Glib::FILE_TEST_EXISTS)) { - auto image = open_exiv2(fname); + auto image = open_exiv2(fname, false); ret = image->xmpData(); } return ret; From 6cec8057742a964d069428a2511f8e65819a2e7e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 17 May 2020 18:28:06 +0200 Subject: [PATCH 051/110] metadata: try to be more robust when saving Tentative fix for #89 (cherry picked from commit a8b53fef753c7a1146013feeb66be87c688b8631) --- rtengine/imageio.cc | 2 +- rtengine/metadata.cc | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index af945949f..4d8f93d55 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1399,7 +1399,7 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const // dst->writeMetadata(); } catch (const std::exception& exc) { std::cout << "EXIF ERROR: " << exc.what() << std::endl; - return false; + //return false; } } diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 4c347c86c..0205e3134 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -238,7 +238,35 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const dst->exifData()["Exif.Image.Software"] = "RawTherapee " RTVERSION; import_exif_pairs(dst->exifData()); import_iptc_pairs(dst->iptcData()); - dst->writeMetadata(); + bool xmp_tried = false; + bool iptc_tried = false; + for (int i = 0; i < 3; ++i) { + try { + dst->writeMetadata(); + return; + } catch (Exiv2::Error &exc) { + if (exc.code() == 37) { + std::string msg = exc.what(); + if (msg.find("XMP") != std::string::npos && + !dst->xmpData().empty()) { + dst->xmpData().clear(); + if (!xmp_tried && merge_xmp_) { + do_merge_xmp(dst.get()); + xmp_tried = true; + } + } else if (msg.find("IPTC") != std::string::npos && + !dst->iptcData().empty()) { + dst->iptcData().clear(); + if (!iptc_tried) { + import_iptc_pairs(dst->iptcData()); + iptc_tried = true; + } + } + } else { + throw exc; + } + } + } } From 0415d556fc66e528374b2fa9d194197d8ddc16d0 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 20 May 2020 16:31:33 +0200 Subject: [PATCH 052/110] exifpanel: ignore errors when printing tags in human-readable form (cherry picked from commit 47fa34e7365d618f250826eb412c72fe0ab8cfed) --- rtgui/exifpanel.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 44c70bc12..136e97b6e 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -303,10 +303,12 @@ void ExifPanel::refreshTags() const auto to_value = [&](Exiv2::Exifdatum &tag) -> Glib::ustring { - if (!tag.tagLabel().empty() && //tag.typeId() != Exiv2::undefined && - (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { - return escapeHtmlChars(tag.print(&exif)); - } + try { + if (!tag.tagLabel().empty() && //tag.typeId() != Exiv2::undefined && + (tag.typeId() == Exiv2::asciiString || tag.size() < 256)) { + return escapeHtmlChars(tag.print(&exif)); + } + } catch (std::exception &) {} return "(" + M("EXIFPANEL_VALUE_NOT_SHOWN") + ")"; }; From 1e0cf4544528f224291aa504e47946c27c982e8f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 3 Jun 2020 02:47:17 -0700 Subject: [PATCH 053/110] metadata: use copyXmpTo* instead of moveXmpTo* (cherry picked from commit d3ac9618f8a3e2688f7a084419eeebbe24a76664) --- rtengine/metadata.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 0205e3134..8028e933f 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -196,8 +196,8 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const auto xmp = getXmpSidecar(src_); Exiv2::ExifData exif; Exiv2::IptcData iptc; - Exiv2::moveXmpToIptc(xmp, iptc); - Exiv2::moveXmpToExif(xmp, exif); + Exiv2::copyXmpToIptc(xmp, iptc); + Exiv2::copyXmpToExif(xmp, exif); for (auto &datum : exif) { dst->exifData()[datum.key()] = datum; From 393dbcf9f938a2554d081b8a7d0e71cc351f9901 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 4 Jun 2020 02:48:47 -0700 Subject: [PATCH 054/110] metadata: allow the user to specify XResolution/YResolution see https://discuss.pixls.us/t/note-to-the-dev-guys-about-72-ppi-output (cherry picked from commit ad237944699800368ba50151f6774ee203d61ed5) --- rtdata/languages/default | 3 ++- rtengine/procparams.cc | 8 ++++-- rtgui/editorpanel.cc | 4 ++- rtgui/exifpanel.cc | 55 ++++++++++++++++++++++++++++++++-------- rtgui/exifpanel.h | 3 +++ rtgui/metadatapanel.cc | 6 +++++ rtgui/metadatapanel.h | 2 ++ rtgui/toolpanelcoord.cc | 6 +++++ rtgui/toolpanelcoord.h | 2 ++ 9 files changed, 75 insertions(+), 14 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 1b625bdac..a0b25e0b6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -52,6 +52,7 @@ DYNPROFILEEDITOR_PROFILE;Processing Profile EDITWINDOW_TITLE;Image Edit EDIT_OBJECT_TOOLTIP;Displays a widget on the preview window which lets you adjust this tool. EDIT_PIPETTE_TOOLTIP;To add an adjustment point to the curve, hold the Ctrl key while left-clicking the desired spot in the image preview.\nTo adjust the point, hold the Ctrl key while left-clicking the corresponding area in the preview, then let go of Ctrl (unless you desire fine control) and while still holding the left mouse button move the mouse up or down to move that point up or down in the curve. +ERROR_MSG_METADATA_VALUE;Metadata: error setting %1 to %2 EXIFFILTER_APERTURE;Aperture EXIFFILTER_CAMERA;Camera EXIFFILTER_EXPOSURECOMPENSATION;Exposure compensation (EV) @@ -1556,7 +1557,7 @@ MAIN_TAB_EXPOSURE_TOOLTIP;Shortcut: Alt-e MAIN_TAB_FAVORITES;Favorites MAIN_TAB_FAVORITES_TOOLTIP;Shortcut: Alt-u MAIN_TAB_FILTER; Filter -MAIN_TAB_INSPECT; Inspect +MAIN_TAB_INSPECT; Inspect MAIN_TAB_IPTC;IPTC MAIN_TAB_LOCALLAB;Local MAIN_TAB_LOCALLAB_TOOLTIP;Shortcut: Alt-o diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d5cc7b45b..f0300a011 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -5289,7 +5289,9 @@ const std::map exif_keys = { {"Make", "Exif.Image.Make"}, {"Model", "Exif.Image.Model"}, {"Lens", "Exif.Photo.LensModel"}, - {"DateTime", "Exif.Photo.DateTimeOriginal"} + {"DateTime", "Exif.Photo.DateTimeOriginal"}, + {"XResolution", "Exif.Image.XResolution"}, + {"YResolution", "Exif.Image.YResolution"} }; const std::map iptc_keys = { @@ -5330,7 +5332,9 @@ std::vector MetaDataParams::basicExifKeys = { "Exif.Photo.ISOSpeedRatings", "Exif.Photo.ExposureBiasValue", "Exif.Photo.Flash", - "Exif.Photo.DateTimeOriginal" + "Exif.Photo.DateTimeOriginal", + "Exif.Image.XResolution", + "Exif.Image.YResolution" }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index c2ad9241a..350538626 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -487,7 +487,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) firstProcessingDone = false; // construct toolpanelcoordinator - tpc = new ToolPanelCoordinator (); + tpc = new ToolPanelCoordinator(); + tpc->setProgressListener(this); // build GUI @@ -1227,6 +1228,7 @@ void EditorPanel::setProgressState(bool inProcessing) void EditorPanel::error(const Glib::ustring& descr) { + parent->error(descr); } void EditorPanel::error(const Glib::ustring& title, const Glib::ustring& descr) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 136e97b6e..719674151 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -34,7 +34,8 @@ using namespace rtengine::procparams; ExifPanel::ExifPanel() : idata(nullptr), changeList(new rtengine::procparams::ExifPairs), - defChangeList(new rtengine::procparams::ExifPairs) + defChangeList(new rtengine::procparams::ExifPairs), + pl_(nullptr) { for (auto &k : MetaDataParams::basicExifKeys) { editableTags.push_back(std::make_pair(k, "")); @@ -318,8 +319,16 @@ void ExifPanel::refreshTags() for (const auto& p : *changeList) { try { - exif[p.first] = p.second; + auto &datum = exif[p.first]; + if (datum.setValue(p.second) != 0) { + if (pl_) { + pl_->error(Glib::ustring::compose(M("ERROR_MSG_METADATA_VALUE"), p.first, p.second)); + } + } } catch (const std::exception& exc) { + if (pl_) { + pl_->error(Glib::ustring::compose(M("ERROR_MSG_METADATA_VALUE"), p.first, p.second)); + } } } @@ -628,19 +637,45 @@ void ExifPanel::setExifTagValue(Gtk::CellRenderer *renderer, const Gtk::TreeMode } -void ExifPanel::onEditExifTagValue(const Glib::ustring &path, const Glib::ustring &value) +void ExifPanel::onEditExifTagValue(const Glib::ustring &path, const Glib::ustring &val) { auto it = exifTreeModel->get_iter(path); auto row = *it; std::string key = row[exifColumns.key]; + auto value = val; - (*changeList)[key] = value; - if (!all_keys_active()) { - cur_active_keys_.insert(key); + bool good = true; + try { + Exiv2::ExifData data; + auto &datum = data[key]; + if (datum.setValue(value) != 0) { + if ((datum.typeId() == Exiv2::signedRational || datum.typeId() == Exiv2::unsignedRational) && datum.setValue(value + "/1") == 0) { + value += "/1"; + } else { + good = false; + } + } + } catch (std::exception &exc) { + good = false; } - refreshTags(); - it = exifTreeModel->get_iter(path); - exifTree->get_selection()->select(it); - notifyListener(); + if (good) { + (*changeList)[key] = value; + if (!all_keys_active()) { + cur_active_keys_.insert(key); + } + refreshTags(); + + it = exifTreeModel->get_iter(path); + exifTree->get_selection()->select(it); + notifyListener(); + } else if (pl_) { + pl_->error(Glib::ustring::compose(M("ERROR_MSG_METADATA_VALUE"), key, value)); + } +} + + +void ExifPanel::setProgressListener(rtengine::ProgressListener *pl) +{ + pl_ = pl; } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index 261561ea0..bc8d6229f 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -99,6 +99,8 @@ private: std::unordered_set initial_active_keys_; std::unordered_set cur_active_keys_; + rtengine::ProgressListener *pl_; + void addTag(const std::string &key, const std::pair &label, const Glib::ustring &value, bool editable, bool edited); void refreshTags(); void resetIt(const Gtk::TreeModel::const_iterator& iter); @@ -136,4 +138,5 @@ public: void notifyListener(); + void setProgressListener(rtengine::ProgressListener *pl); }; diff --git a/rtgui/metadatapanel.cc b/rtgui/metadatapanel.cc index e26444ccc..4e6252da4 100644 --- a/rtgui/metadatapanel.cc +++ b/rtgui/metadatapanel.cc @@ -127,3 +127,9 @@ void MetaDataPanel::metaDataModeChanged() listener->panelChanged(EvMetaDataMode, M("HISTORY_CHANGED")); } } + + +void MetaDataPanel::setProgressListener(rtengine::ProgressListener *pl) +{ + exifpanel->setProgressListener(pl); +} diff --git a/rtgui/metadatapanel.h b/rtgui/metadatapanel.h index bc74ac484..aacbb9fe1 100644 --- a/rtgui/metadatapanel.h +++ b/rtgui/metadatapanel.h @@ -45,5 +45,7 @@ public: void setImageData(const rtengine::FramesMetaData* id); void setListener(ToolPanelListener *tpl) override; + + void setProgressListener(rtengine::ProgressListener *pl); }; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index fde949606..defe64065 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -1271,3 +1271,9 @@ bool ToolPanelCoordinator::getFilmNegativeSpot(rtengine::Coord spot, int spotSiz { return ipc && ipc->getFilmNegativeSpot(spot.x, spot.y, spotSize, refInput, refOutput); } + + +void ToolPanelCoordinator::setProgressListener(rtengine::ProgressListener *pl) +{ + metadata->setProgressListener(pl); +} diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 675b77de7..4c46a39ec 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -348,6 +348,8 @@ public: void setEditProvider(EditDataProvider *provider); + void setProgressListener(rtengine::ProgressListener *pl); + private: IdleRegister idle_register; }; From 322e709bcb29cdb49db1b49a42ff3877e9c349d0 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 17 Sep 2020 23:17:45 -0700 Subject: [PATCH 055/110] metadata: do not accidentally remove exif tags when embedding the arp sidecar in XMP Fixes #127 (cherry picked from commit 49cbe9bd19db558a4be36221472cbb5e78aa95a2) --- rtengine/imageio.cc | 2 +- rtengine/metadata.cc | 6 ++++-- rtengine/metadata.h | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 4d8f93d55..b38fc745c 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1370,7 +1370,7 @@ bool ImageIO::saveMetadata(const Glib::ustring &fname) const if (has_meta) { try { - metadataInfo.saveToImage(fname); + metadataInfo.saveToImage(fname, false); // auto src = open_exiv2(metadataInfo.filename()); // auto dst = open_exiv2(fname); // src->readMetadata(); diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 8028e933f..049233cc6 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -217,7 +217,7 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const } -void Exiv2Metadata::saveToImage(const Glib::ustring &path) const +void Exiv2Metadata::saveToImage(const Glib::ustring &path, bool preserve_all_tags) const { auto dst = open_exiv2(path, false); if (image_.get()) { @@ -227,7 +227,9 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path) const do_merge_xmp(dst.get()); } auto srcexif = image_->exifData(); - remove_unwanted(srcexif); + if (!preserve_all_tags) { + remove_unwanted(srcexif); + } dst->setExifData(srcexif); } else { dst->setExifData(exif_data_); diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 57484d234..0f9f7919d 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -53,7 +53,7 @@ public: void setExif(const rtengine::procparams::ExifPairs& exif); void setIptc(const rtengine::procparams::IPTCPairs& iptc); - void saveToImage(const Glib::ustring& path) const; + void saveToImage(const Glib::ustring& path, bool preserve_all_tags) const; void saveToXmp(const Glib::ustring& path) const; void setExifKeys(const std::vector *keys); From fca1b5c5f5bbac9dd11717299740176d92d3785e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 1 Oct 2020 08:46:38 +0200 Subject: [PATCH 056/110] added support for easier editing of some common metadata tags (cherry picked from commit 0e3f760b520a5cbaa4e63d0f8a5ca5574093f411) --- rtgui/exifpanel.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 719674151..0664132f6 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -28,6 +28,8 @@ #include "../rtengine/metadata.h" #include "../rtengine/procparams.h" +#include + using namespace rtengine; using namespace rtengine::procparams; @@ -637,6 +639,74 @@ void ExifPanel::setExifTagValue(Gtk::CellRenderer *renderer, const Gtk::TreeMode } +namespace { + + +Glib::ustring to_fraction(const Glib::ustring &s) +{ + auto i = s.find("."); + if (i != Glib::ustring::npos) { + return s.substr(0, i) + s.substr(i+1) + "/1" + Glib::ustring(s.size() - i - 1, '0'); + } + return s; +} + +typedef Glib::ustring (*validator_func)(const Glib::ustring &); + +Glib::ustring get_fnumber(const Glib::ustring &val) +{ + Glib::MatchInfo m; + auto re = Glib::Regex::create("f? *([0-9.]+) *", Glib::REGEX_CASELESS); + if (re->match(val, m)) { + auto s = m.fetch(1); + return to_fraction(s); + } + return val; +} + +Glib::ustring get_shutterspeed(const Glib::ustring &val) +{ + Glib::MatchInfo m; + auto re = Glib::Regex::create(" *([0-9/]+) *s? *", Glib::REGEX_CASELESS); + if (re->match(val, m)) { + auto s = m.fetch(1); + return s; + } + return val; +} + +Glib::ustring get_focallen(const Glib::ustring &val) +{ + Glib::MatchInfo m; + auto re = Glib::Regex::create(" *([0-9.]+) *(mm)? *", Glib::REGEX_CASELESS); + if (re->match(val, m)) { + auto s = m.fetch(1); + return to_fraction(s); + } + return val; +} + +Glib::ustring get_expcomp(const Glib::ustring &val) +{ + Glib::MatchInfo m; + auto re = Glib::Regex::create(" *(-?[0-9.]+) *(EV)? *", Glib::REGEX_CASELESS); + if (re->match(val, m)) { + auto s = m.fetch(1); + return to_fraction(s); + } + return val; +} + +std::unordered_map validators = { + {"Exif.Photo.FNumber", get_fnumber}, + {"Exif.Photo.ExposureTime", get_shutterspeed}, + {"Exif.Photo.FocalLength", get_focallen}, + {"Exif.Photo.ExposureBiasValue", get_expcomp} +}; + +} // namespace + + void ExifPanel::onEditExifTagValue(const Glib::ustring &path, const Glib::ustring &val) { auto it = exifTreeModel->get_iter(path); @@ -648,6 +718,13 @@ void ExifPanel::onEditExifTagValue(const Glib::ustring &path, const Glib::ustrin try { Exiv2::ExifData data; auto &datum = data[key]; + auto it = validators.find(key); + if (it != validators.end()) { + auto v = it->second(value); + if (datum.setValue(v) == 0) { + value = v; + } + } if (datum.setValue(value) != 0) { if ((datum.typeId() == Exiv2::signedRational || datum.typeId() == Exiv2::unsignedRational) && datum.setValue(value + "/1") == 0) { value += "/1"; From 0102fca563cd4f3121428122b1c46787aabb0691 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 25 Nov 2020 23:32:55 -0800 Subject: [PATCH 057/110] improved metadata extraction from ancient Kodak DCS4xx cameras (cherry picked from commit a2cc73f5f4769ad9ad2daaea9b5adbe7b158ad9e) --- rtengine/imagedata.cc | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index d8cec7604..da0c136fc 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "imagedata.h" #include "imagesource.h" @@ -311,6 +313,8 @@ FramesData::FramesData(const Glib::ustring &fname) : } else if (find_exif_tag("Exif.Photo.DateTimeDigitized")) { datetime_taken = pos->print(&exif); + } else if (find_exif_tag("Exif.Image.DateTime")) { + datetime_taken = validateUft8(pos->print(&exif)); } if (sscanf(datetime_taken.c_str(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { time.tm_year -= 1900; @@ -334,6 +338,42 @@ FramesData::FramesData(const Glib::ustring &fname) : } } + // try getting some metadata from ImageDescription + if (!make.compare(0, 5, "KODAK") && !getISOSpeed() && !getFNumber() && !getFocalLen() && !getShutterSpeed() && + find_exif_tag("Exif.Image.ImageDescription")) { + std::string s = pos->toString(); + std::string line; + std::smatch m; + const auto d = + [&m]() -> double { + std::string s = m[1]; + return atof(s.c_str()); + }; + while (true) { + auto p = s.find('\r'); + if (p == std::string::npos) { + break; + } + auto line = s.substr(0, p); + s = s.substr(p+1); + + if (std::regex_match(line, m, std::regex("ISO: +([0-9]+) *"))) { + iso_speed = d(); + } else if (std::regex_match(line, m, std::regex("Aperture: +F([0-9.]+) *"))) { + aperture = d(); + } else if (std::regex_match(line, m, std::regex("Shutter: +([0-9.]+) *"))) { + shutter = d(); + if (shutter) { + shutter = 1.0/shutter; + } + } else if (std::regex_match(line, m, std::regex("Lens \\(mm\\): +([0-9.]+) *"))) { + focal_len = d(); + } else if (std::regex_match(line, m, std::regex("Exp Comp: +([0-9.]+) *"))) { + expcomp = d(); + } + } + } + // ----------------------- // Special file type detection (HDR, PixelShift) // ------------------------ From 92befa7e810bfec7b2a8cbeb8b7162c3b627b684 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 2 Dec 2020 02:03:00 -0800 Subject: [PATCH 058/110] refactored code for extracting image dimensions from metadata (cherry picked from commit 0ece9c5bfad09bc9052238d83fa696ef39effaaa) --- rtengine/imagedata.cc | 20 ++++++++++++- rtengine/imagedata.h | 5 ++++ rtengine/metadata.cc | 23 +++++++++++++++ rtengine/metadata.h | 2 ++ rtengine/rawimagesource.cc | 58 +++++++++++++++++++++++++++++++------- rtengine/rawimagesource.h | 4 ++- rtengine/rtengine.h | 5 ++-- rtengine/rtthumbnail.cc | 11 ++++++-- rtengine/rtthumbnail.h | 4 ++- rtgui/cacheimagedata.cc | 12 +++++++- rtgui/cacheimagedata.h | 8 ++++++ rtgui/editorpanel.cc | 9 ++++-- rtgui/thumbnail.cc | 6 ++++ 13 files changed, 146 insertions(+), 21 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index da0c136fc..469388b1c 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -81,7 +81,9 @@ FramesData::FramesData(const Glib::ustring &fname) : lens("Unknown"), sampleFormat(IIOSF_UNKNOWN), isPixelShift(false), - isHDR(false) + isHDR(false), + w_(-1), + h_(-1) { make.clear(); model.clear(); @@ -374,6 +376,8 @@ FramesData::FramesData(const Glib::ustring &fname) : } } + meta.getDimensions(w_, h_); + // ----------------------- // Special file type detection (HDR, PixelShift) // ------------------------ @@ -773,3 +777,17 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const strftime(buf, 256, "%Y:%m:%d %H:%M:%S", &t); set_exif(exif, "Exif.Photo.DateTimeOriginal", buf); } + + +void FramesData::getDimensions(int &w, int &h) const +{ + w = w_; + h = h_; +} + + +void FramesData::setDimensions(int w, int h) +{ + w_ = w; + h_ = h; +} diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 3a915c15d..88c0ec48d 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -57,6 +57,8 @@ private: IIOSampleFormat sampleFormat; bool isPixelShift; bool isHDR; + int w_; + int h_; public: explicit FramesData(const Glib::ustring& fname); @@ -84,8 +86,11 @@ public: std::string getOrientation() const override; Glib::ustring getFileName() const override; int getRating() const override; + void getDimensions(int &w, int &h) const override; void fillBasicTags(Exiv2::ExifData &exif) const; + + void setDimensions(int w, int h); }; } diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 049233cc6..85fcf79ff 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -448,6 +448,29 @@ void Exiv2Metadata::setExifKeys(const std::vector *keys) } +void Exiv2Metadata::getDimensions(int &w, int &h) const +{ + if (image_) { + if (dynamic_cast(image_.get())) { + auto &exif = image_->exifData(); + auto itw = exif.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); + auto ith = exif.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); + if (itw != exif.end() && ith != exif.end()) { + w = itw->toLong(); + h = ith->toLong(); + } else { + w = h = -1; + } + } else { + w = image_->pixelWidth(); + h = image_->pixelHeight(); + } + } else { + w = h = -1; + } +} + + Glib::ustring Exiv2Metadata::xmpSidecarPath(const Glib::ustring &path) { Glib::ustring fn = path; diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 0f9f7919d..d9b195ed5 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -58,6 +58,8 @@ public: void setExifKeys(const std::vector *keys); + void getDimensions(int &w, int &h) const; + static Glib::ustring xmpSidecarPath(const Glib::ustring& path); static Exiv2::XmpData getXmpSidecar(const Glib::ustring& path); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 8f8a71553..e583a27a5 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -690,7 +690,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima { MyMutex::MyLock lock(getImageMutex); - tran = defTransform (tran); + tran = defTransform(ri, tran); // compute channel multipliers double r, g, b; @@ -1009,8 +1009,41 @@ void RawImageSource::convertColorSpace(Imagefloat* image, const ColorManagementP void RawImageSource::getFullSize (int& w, int& h, int tr) { + computeFullSize(ri, tr, w, h); - tr = defTransform (tr); + // tr = defTransform(ri, tr); + + // if (fuji) { + // w = ri->get_FujiWidth() * 2 + 1; + // h = (H - ri->get_FujiWidth()) * 2 + 1; + // } else if (d1x) { + // w = W; + // h = 2 * H; + // } else { + // w = W; + // h = H; + // } + + // if ((tr & TR_ROT) == TR_R90 || (tr & TR_ROT) == TR_R270) { + // int tmp = w; + // w = h; + // h = tmp; + // } + + // w -= 2 * border; + // h -= 2 * border; +} + + +void RawImageSource::computeFullSize(const RawImage *ri, int tr, int &w, int &h) +{ + tr = defTransform(ri, tr); + + const int W = ri->get_width(); + const int H = ri->get_height(); + const bool fuji = ri->get_FujiWidth() != 0; + const bool d1x = !ri->get_model().compare("D1X"); + const int border = (ri->getSensorType() == ST_BAYER ? 4 : (ri->getSensorType() == ST_FUJI_XTRANS ? 7 : 0)); if (fuji) { w = ri->get_FujiWidth() * 2 + 1; @@ -1253,6 +1286,11 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) // Load complete Exif information idata = new FramesData(fname); // TODO: std::unique_ptr<> idata->setDCRawFrameCount (numFrames); + { + int ww, hh; + getFullSize(ww, hh); + idata->setDimensions(ww, hh); + } green(W, H); red(W, H); @@ -2718,7 +2756,7 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::defTransform (int tran) +int RawImageSource::defTransform(const RawImage *ri, int tran) { int deg = ri->get_rotateDegree(); @@ -4466,7 +4504,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double Probably (sure) there are improvement to do... I have create a table temperature with temp and white point with 118 values between 2000K and 12000K we can obviously change these values, more...with different steps - I have create a table for tint (green)with 134 values between 0.4 to 4. + I have create a table for tint (green)with 134 values between 0.4 to 4. I have create or recuparate and transformed 201 spectral colors from Colorchecker24, others color and my 468 colors target, or from web flowers, etc. with a step of 5nm, I think it is large enough. I think this value of 201 is now complete: I tested correlation with 60, 90, 100, 120, 155...better student increase with number of color, but now it seems stabilized Of course we can increase this number :) @@ -4519,7 +4557,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double itcwb_precis : 5 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file */ // BENCHFUN - + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB"); const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, @@ -5064,7 +5102,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } estimchrom /= sizcu4; - if (settings->verbose) { + if (settings->verbose) { printf("estimchrom=%f\n", estimchrom); } if (settings->itcwb_sort) { //sort in ascending with chroma values @@ -5366,7 +5404,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int if (settings->itcwb_precis == 5) { precision = 5; } else if (settings->itcwb_precis < 5) { - precision = 3; + precision = 3; } else if (settings->itcwb_precis > 5) { precision = 9; } @@ -5628,11 +5666,11 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (settings->itcwb_precis == 5) { precision = 5; } else if (settings->itcwb_precis < 5) { - precision = 3; + precision = 3; } else if (settings->itcwb_precis > 5) { precision = 9; } - + const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ; const int bfh = H / precision + ((H % precision) > 0 ? 1 : 0); WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw); @@ -6093,7 +6131,7 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vectorinit(); + + RawImageSource::computeFullSize(ri, TR_NONE, tpp->full_width, tpp->full_height); + delete ri; return tpp; } @@ -1025,7 +1028,9 @@ Thumbnail::Thumbnail () : gammaCorrected (false), colorMatrix{}, scaleGain (1.0), - isRaw (true) + isRaw (true), + full_width(-1), + full_height(-1) { } @@ -1236,7 +1241,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.dehaze(baseImg, params.dehaze); ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0, 0); - + // perform transform int origFW; int origFH; @@ -2125,7 +2130,7 @@ bool Thumbnail::readData (const Glib::ustring& fname) colorMatrix[i][j] = cm[ix++]; } } - + if (keyFile.has_key ("LiveThumbData", "ScaleGain")) { scaleGain = keyFile.get_double ("LiveThumbData", "ScaleGain"); } diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 33bfec21c..455f4fadb 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -82,6 +82,8 @@ class Thumbnail public: bool isRaw; + int full_width; + int full_height; ~Thumbnail (); Thumbnail (); @@ -94,7 +96,7 @@ public: void getDimensions (int& w, int& h, double& scaleFac); static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching = false); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching=false); static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false); void getCamWB (double& temp, double& green); diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc index 97007751c..365b8f1b7 100644 --- a/rtgui/cacheimagedata.cc +++ b/rtgui/cacheimagedata.cc @@ -56,7 +56,9 @@ CacheImageData::CacheImageData() : greenAWBMul(-1.0), blueAWBMul(-1.0), rotate(0), - thumbImgType(0) + thumbImgType(0), + width(-1), + height(-1) { } @@ -208,6 +210,12 @@ int CacheImageData::load (const Glib::ustring& fname) if (keyFile.has_key ("FileInfo", "SampleFormat")) { sampleFormat = (rtengine::IIO_Sample_Format)keyFile.get_integer ("FileInfo", "SampleFormat"); } + if (keyFile.has_key("FileInfo", "Width")) { + width = keyFile.get_integer("FileInfo", "Width"); + } + if (keyFile.has_key("FileInfo", "Height")) { + height = keyFile.get_integer("FileInfo", "Height"); + } } if (format == FT_Raw && keyFile.has_group ("ExtraRawInfo")) { @@ -298,6 +306,8 @@ int CacheImageData::save (const Glib::ustring& fname) keyFile.set_string ("FileInfo", "Filetype", filetype); keyFile.set_integer ("FileInfo", "FrameCount", frameCount); keyFile.set_integer ("FileInfo", "SampleFormat", sampleFormat); + keyFile.set_integer("FileInfo", "Width", width); + keyFile.set_integer("FileInfo", "Height", height); if (format == FT_Raw) { keyFile.set_integer ("ExtraRawInfo", "ThumbImageType", thumbImgType); diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index 2b4d5f471..cb02b9169 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -80,6 +80,9 @@ public: QUICK_THUMBNAIL = 1 // was the thumbnail generated from embedded jpeg }; + int width; + int height; + CacheImageData (); int load (const Glib::ustring& fname); @@ -110,4 +113,9 @@ public: bool getHDR() const override { return isHDR; } std::string getImageType() const override { return isPixelShift ? "PS" : isHDR ? "HDR" : "STD"; } rtengine::IIOSampleFormat getSampleFormat() const override { return sampleFormat; } + void getDimensions(int &w, int &h) const override + { + w = width; + h = height; + } }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 350538626..62556fb68 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1357,8 +1357,13 @@ void EditorPanel::info_toggled () escapeHtmlChars (Glib::path_get_dirname (openThm->getFileName())) + G_DIR_SEPARATOR_S, escapeHtmlChars (Glib::path_get_basename (openThm->getFileName())) ); - int ww = ipc->getFullWidth(); - int hh = ipc->getFullHeight(); + int ww = -1, hh = -1; + idata->getDimensions(ww, hh); + if (ww <= 0) { + ww = ipc->getFullWidth(); + hh = ipc->getFullHeight(); + } + //megapixels infoString = Glib::ustring::compose ("%1\n%2 MP (%3x%4)", infoString, diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index dfc1bfeb7..2ee17ba27 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -241,6 +241,10 @@ void Thumbnail::_generateThumbnailImage () cfs.format = FT_Raw; cfs.thumbImgType = quick ? CacheImageData::QUICK_THUMBNAIL : CacheImageData::FULL_THUMBNAIL; infoFromImage (fname); + if (!quick) { + cfs.width = tpp->full_width; + cfs.height = tpp->full_height; + } } } @@ -893,6 +897,8 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname) cfs.filetype = ""; } + idata->getDimensions(cfs.width, cfs.height); + delete idata; return deg; } From d16bc6f6ea84f842473453bb1032a87b13be245c Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 12 Dec 2020 17:10:45 +0100 Subject: [PATCH 059/110] metadata: do not copy Exif tags with 0 count Tentative fix for #147 (cherry picked from commit 12f699df10c1c0854c0e882db151560a1f4f3a26) --- rtengine/metadata.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 85fcf79ff..f5f2d972c 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -230,7 +230,12 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path, bool preserve_all_tag if (!preserve_all_tags) { remove_unwanted(srcexif); } - dst->setExifData(srcexif); + //dst->setExifData(srcexif); + for (auto &tag : srcexif) { + if (tag.count() > 0) { + dst->exifData()[tag.key()] = tag; + } + } } else { dst->setExifData(exif_data_); dst->setIptcData(iptc_data_); From 3d209e687d29e9c88245e90a218f01291df2ab06 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 12 Jan 2021 00:21:58 -0800 Subject: [PATCH 060/110] metadata: filter out unwanted tags when syncing with xmp sidecars (cherry picked from commit 239f3f59b931efb15482134fffd5f6065616e574) --- rtengine/metadata.cc | 14 +++++++++----- rtengine/metadata.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index f5f2d972c..236d402da 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -130,7 +130,7 @@ void Exiv2Metadata::load() const } if (merge_xmp_) { - do_merge_xmp(image_.get()); + do_merge_xmp(image_.get(), false); } } } @@ -190,15 +190,19 @@ void Exiv2Metadata::setIptc(const rtengine::procparams::IPTCPairs &iptc) *iptc_ = iptc; } -void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst) const +void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst, bool keep_all) const { try { auto xmp = getXmpSidecar(src_); Exiv2::ExifData exif; Exiv2::IptcData iptc; Exiv2::copyXmpToIptc(xmp, iptc); - Exiv2::copyXmpToExif(xmp, exif); + Exiv2::moveXmpToExif(xmp, exif); + if (!keep_all) { + remove_unwanted(exif); + } + for (auto &datum : exif) { dst->exifData()[datum.key()] = datum; } @@ -224,7 +228,7 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path, bool preserve_all_tag dst->setIptcData(image_->iptcData()); dst->setXmpData(image_->xmpData()); if (merge_xmp_) { - do_merge_xmp(dst.get()); + do_merge_xmp(dst.get(), preserve_all_tags); } auto srcexif = image_->exifData(); if (!preserve_all_tags) { @@ -258,7 +262,7 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path, bool preserve_all_tag !dst->xmpData().empty()) { dst->xmpData().clear(); if (!xmp_tried && merge_xmp_) { - do_merge_xmp(dst.get()); + do_merge_xmp(dst.get(), preserve_all_tags); xmp_tried = true; } } else if (msg.find("IPTC") != std::string::npos && diff --git a/rtengine/metadata.h b/rtengine/metadata.h index d9b195ed5..9de285111 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -67,7 +67,7 @@ public: static void cleanup(); private: - void do_merge_xmp(Exiv2::Image* dst) const; + void do_merge_xmp(Exiv2::Image* dst, bool keep_all) const; void import_exif_pairs(Exiv2::ExifData& out) const; void import_iptc_pairs(Exiv2::IptcData& out) const; void remove_unwanted(Exiv2::ExifData& dst) const; From 7d5b9e9d65d50fd1e892db9b473a891dd639ce6f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 20 Jan 2021 18:22:43 +0100 Subject: [PATCH 061/110] metadata: fixed bug in transferring basic tags (cherry picked from commit 89afbd90e154ddd5e6071c44990b68aa62227739) --- rtengine/imagedata.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 469388b1c..b4058e56e 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -754,7 +754,8 @@ void set_exif(Exiv2::ExifData &exif, const std::string &key, T val) { try { exif[key] = val; - } catch (std::exception &exc) {} + } catch (std::exception &exc) { + } } } // namespace @@ -765,10 +766,10 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const return; } set_exif(exif, "Exif.Photo.ISOSpeedRatings", getISOSpeed()); - set_exif(exif, "Exif.Photo.FNumber", apertureToString(getFNumber())); - set_exif(exif, "Exif.Photo.ExposureTime", shutterToString(getShutterSpeed())); + set_exif(exif, "Exif.Photo.FNumber", Exiv2::DoubleValue(getFNumber())); + set_exif(exif, "Exif.Photo.ExposureTime", Exiv2::DoubleValue(getShutterSpeed())); set_exif(exif, "Exif.Photo.FocalLength", Exiv2::DoubleValue(getFocalLen())); - set_exif(exif, "Exif.Photo.ExposureBiasValue", expcompToString(getExpComp(), false)); + set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::DoubleValue(getExpComp())); set_exif(exif, "Exif.Image.Make", getMake()); set_exif(exif, "Exif.Image.Model", getModel()); set_exif(exif, "Exif.Photo.LensModel", getLens()); From ba79d8b7f06e85f9b908bb0fa5f9ee3d7ea71f11 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 20 Jan 2021 20:59:08 +0100 Subject: [PATCH 062/110] (hopefully) better metadata formatting (cherry picked from commit 89be8ee8e71b1d56f5c6ce7ce4068ab330e19d68) --- rtengine/imagedata.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index b4058e56e..d6b643bcd 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -766,10 +766,14 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const return; } set_exif(exif, "Exif.Photo.ISOSpeedRatings", getISOSpeed()); - set_exif(exif, "Exif.Photo.FNumber", Exiv2::DoubleValue(getFNumber())); - set_exif(exif, "Exif.Photo.ExposureTime", Exiv2::DoubleValue(getShutterSpeed())); - set_exif(exif, "Exif.Photo.FocalLength", Exiv2::DoubleValue(getFocalLen())); - set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::DoubleValue(getExpComp())); + set_exif(exif, "Exif.Photo.FNumber", Exiv2::URationalValue(Exiv2::URational(round(getFNumber() * 10), 10))); + auto s = shutterToString(getShutterSpeed()); + if (s.find('/') == std::string::npos) { + s += "/1"; + } + set_exif(exif, "Exif.Photo.ExposureTime", s); + set_exif(exif, "Exif.Photo.FocalLength", Exiv2::URationalValue(Exiv2::URational(getFocalLen() * 10, 10))); + set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::DoubleValue(round(getExpComp() * 100) / 100.0)); set_exif(exif, "Exif.Image.Make", getMake()); set_exif(exif, "Exif.Image.Model", getModel()); set_exif(exif, "Exif.Photo.LensModel", getLens()); From 939315f67b83441ba214678fc60f491f22beda22 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 26 Jan 2021 08:15:36 +0100 Subject: [PATCH 063/110] metadata: do not exclude tags that were explicitly selected by the user (cherry picked from commit 60d862fa72046ecf8f44c2a1677f72237e86e838) --- rtengine/metadata.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 236d402da..c0bdcfa29 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -363,9 +363,10 @@ void Exiv2Metadata::remove_unwanted(Exiv2::ExifData &dst) const } for (auto it = dst.begin(); it != dst.end(); ) { - if (badtags.find(it->key()) != badtags.end()) { + int relevant = exif_keys_ ? (exif_keys_->find(it->key()) != exif_keys_->end() ? 1 : 0) : -1; + if (badtags.find(it->key()) != badtags.end() && relevant != 1) { it = dst.erase(it); - } else if (exif_keys_ && exif_keys_->find(it->key()) == exif_keys_->end()) { + } else if (relevant == 0) { it = dst.erase(it); } else { bool found = false; From 522f6f44730606ce19e7f5b9d886cab18f767fb3 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 27 Jan 2021 10:06:25 -0800 Subject: [PATCH 064/110] metadata: make sure to include XResolution and YResolution when writing TIFFs This is mandatory (according to http://dpfmanager.org), and in fact needed for Photoshop compatibility (cherry picked from commit 5d281810cc7a7f7dc563dde030cf90c78dbf55d0) --- rtengine/imageio.cc | 26 ++++++++++++++++++++++++++ rtengine/metadata.cc | 40 ++++++++++++++++++++++++++++++++++++++-- rtengine/metadata.h | 2 ++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index b38fc745c..67b856092 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1098,6 +1098,7 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con return IMIO_SUCCESS; } + int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool uncompressed) const { if (getWidth() < 1 || getHeight() < 1) { @@ -1168,6 +1169,31 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u } }();*/ + // somehow Exiv2 (tested with 0.27.3) doesn't seem to be able to update + // XResolution and YResolution, so we do it ourselves here.... + constexpr float default_resolution = 300.f; + float x_res = default_resolution; + float y_res = default_resolution; + int res_unit = RESUNIT_INCH; + if (!metadataInfo.filename().empty()) { + auto exif = metadataInfo.getOutputExifData(); + auto it = exif.findKey(Exiv2::ExifKey("Exif.Image.XResolution")); + if (it != exif.end()) { + x_res = it->toFloat(); + } + it = exif.findKey(Exiv2::ExifKey("Exif.Image.YResolution")); + if (it != exif.end()) { + y_res = it->toFloat(); + } + it = exif.findKey(Exiv2::ExifKey("Exif.Image.ResolutionUnit")); + if (it != exif.end()) { + res_unit = it->toLong(); + } + } + TIFFSetField(out, TIFFTAG_XRESOLUTION, x_res); + TIFFSetField(out, TIFFTAG_YRESOLUTION, y_res); + TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, res_unit); + if (!uncompressed) { TIFFSetField (out, TIFFTAG_PREDICTOR, (bps == 16 || bps == 32) && isFloat ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL); } diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index c0bdcfa29..b6476f92a 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -390,7 +390,12 @@ void Exiv2Metadata::import_exif_pairs(Exiv2::ExifData &out) const for (auto &p : *exif_) { try { out[p.first] = p.second; - } catch (std::exception &exc) {} + } catch (std::exception &exc) { + if (settings->verbose) { + std::cout << "Error setting " << p.first << " to " << p.second + << ": " << exc.what() << std::endl; + } + } } } @@ -408,7 +413,12 @@ void Exiv2Metadata::import_iptc_pairs(Exiv2::IptcData &out) const out.add(d); } } - } catch (std::exception &exc) {} + } catch (std::exception &exc) { + if (settings->verbose) { + std::cout << "Error setting " << p.first + << ": " << exc.what() << std::endl; + } + } } } @@ -515,4 +525,30 @@ void Exiv2Metadata::cleanup() Exiv2::XmpParser::terminate(); } + +Exiv2::ExifData Exiv2Metadata::getOutputExifData() const +{ + Exiv2::ExifData exif = exifData(); + try { + auto xmp = getXmpSidecar(src_); + Exiv2::moveXmpToExif(xmp, exif); + } catch (std::exception &exc) { + if (settings->verbose) { + std::cerr << "Error loading metadata from XMP sidecar: " + << exc.what() << std::endl; + } + } + remove_unwanted(exif); + import_exif_pairs(exif); + for (auto it = exif.begin(); it != exif.end(); ) { + if (it->count() > 0) { + ++it; + } else { + it = exif.erase(it); + } + } + return exif; +} + + } // namespace rtengine diff --git a/rtengine/metadata.h b/rtengine/metadata.h index 9de285111..cd27aada5 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -60,6 +60,8 @@ public: void getDimensions(int &w, int &h) const; + Exiv2::ExifData getOutputExifData() const; + static Glib::ustring xmpSidecarPath(const Glib::ustring& path); static Exiv2::XmpData getXmpSidecar(const Glib::ustring& path); From c75296b910a264dc9f224b10b03cc526ac5f26d7 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 4 Apr 2021 21:15:09 +0200 Subject: [PATCH 065/110] metadata: properly set the value of Exif.Photo.ExposureBiasValue (cherry picked from commit b0bdd1fda6759b8041a0cbf5ce977e947ea10cff) --- rtengine/imagedata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index d6b643bcd..b61bb8cfd 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -773,7 +773,7 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const } set_exif(exif, "Exif.Photo.ExposureTime", s); set_exif(exif, "Exif.Photo.FocalLength", Exiv2::URationalValue(Exiv2::URational(getFocalLen() * 10, 10))); - set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::DoubleValue(round(getExpComp() * 100) / 100.0)); + set_exif(exif, "Exif.Photo.ExposureBiasValue", Exiv2::RationalValue(Exiv2::Rational(round(getExpComp() * 100), 100))); set_exif(exif, "Exif.Image.Make", getMake()); set_exif(exif, "Exif.Image.Model", getModel()); set_exif(exif, "Exif.Photo.LensModel", getLens()); From 77d1bc2cb1137e392f8422b3600976a7750f1352 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 7 Apr 2021 02:18:33 -0700 Subject: [PATCH 066/110] metadata: use exiv2 to handle BMFF files (e.g. CR3) if supported (cherry picked from commit 1469a0a8225cb44fe7f130f375879aef23496a8b) --- rtengine/metadata.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index b6476f92a..555f9e7b2 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -517,6 +517,9 @@ void Exiv2Metadata::init() { cache_.reset(new ImageCache(IMAGE_CACHE_SIZE)); Exiv2::XmpParser::initialize(); +#ifdef EXV_ENABLE_BMFF + Exiv2::enableBMFF(true); +#endif } From a73e74f9cc31bb09100201756879ff0b415b62a8 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 22 Jun 2021 23:59:47 -0700 Subject: [PATCH 067/110] metadata: fixed bug in setting shutter speed in output jpgs (cherry picked from commit b6a1a15a76c2091f6f940ae7d16d45caa93dbb99) --- rtengine/imagedata.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index b61bb8cfd..4772b2230 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -695,11 +695,12 @@ std::string FramesMetaData::apertureToString(double aperture) std::string FramesMetaData::shutterToString(double shutter) { - char buffer[256]; if (shutter > 0.0 && shutter <= 0.5) { snprintf(buffer, sizeof(buffer), "1/%0.0f", 1.0 / shutter); + } else if (int(shutter) == shutter) { + snprintf(buffer, sizeof(buffer), "%d", int(shutter)); } else { snprintf(buffer, sizeof(buffer), "%0.1f", shutter); } @@ -755,6 +756,9 @@ void set_exif(Exiv2::ExifData &exif, const std::string &key, T val) try { exif[key] = val; } catch (std::exception &exc) { + if (settings->verbose) { + std::cout << "Exif -- error setting " << key << " to " << val << ": " << exc.what() << std::endl; + } } } @@ -768,7 +772,11 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const set_exif(exif, "Exif.Photo.ISOSpeedRatings", getISOSpeed()); set_exif(exif, "Exif.Photo.FNumber", Exiv2::URationalValue(Exiv2::URational(round(getFNumber() * 10), 10))); auto s = shutterToString(getShutterSpeed()); - if (s.find('/') == std::string::npos) { + auto p = s.find('.'); + if (p != std::string::npos) { + assert(p == s.length()-2); + s = s.substr(0, p) + s.substr(p+1) + "/10"; + } else if (s.find('/') == std::string::npos) { s += "/1"; } set_exif(exif, "Exif.Photo.ExposureTime", s); From f2248dce9dd71e03c379fd59bbb96a43f0e3329e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 2 Nov 2021 22:05:47 +0100 Subject: [PATCH 068/110] metadata: detect pixelshift files from sony and fujifilm (cherry picked from commit 6554778f7bc6ce50c3bb8a98ca1907cb945c2e34) --- rtengine/imagedata.cc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 4772b2230..a1db3c8d3 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -424,6 +424,30 @@ FramesData::FramesData(const Glib::ustring &fname) : } } + if (make == "SONY") { + if (find_exif_tag("Exif.SubImage1.BitsPerSample") && pos->toLong() == 14) { + if (find_exif_tag("Exif.SubImage1.SamplesPerPixel") && pos->toLong() == 4 && + find_exif_tag("Exif.SubImage1.PhotometricInterpretation") && pos->toLong() == 32892 && + find_exif_tag("Exif.SubImage1.Compression") && pos->toLong() == 1) { + isPixelShift = true; + } + } else if (bps != exif.end() && bps->toLong() == 14 && + spp != exif.end() && spp->toLong() == 4 && + c != exif.end() && c->toLong() == 1 && + find_exif_tag("Exif.Image.Software") && + pos->toString() == "make_arq") { + isPixelShift = true; + } + } else if (make == "FUJIFILM") { + if (bps != exif.end() && bps->toLong() == 16 && + spp != exif.end() && spp->toLong() == 4 && + c != exif.end() && c->toLong() == 1 && + find_exif_tag("Exif.Image.Software") && + pos->toString() == "make_arq") { + isPixelShift = true; + } + } + sampleFormat = IIOSF_UNKNOWN; if (sf == exif.end()) From 2ce81cccc56f40677697ff00ac91decf6d28f3c3 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 16 Nov 2021 23:21:40 -0800 Subject: [PATCH 069/110] metadata: fixed glitches in importing IPTC tags (cherry picked from commit 3d03f654e22ca01f058492eab2c8fcbc564dc1b9) --- rtengine/metadata.cc | 13 +- rtgui/iptcpanel.cc | 706 ++++++++++++++++++++++--------------------- 2 files changed, 373 insertions(+), 346 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 555f9e7b2..d372119d9 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -198,6 +198,7 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst, bool keep_all) const Exiv2::IptcData iptc; Exiv2::copyXmpToIptc(xmp, iptc); Exiv2::moveXmpToExif(xmp, exif); + std::unordered_set seen; if (!keep_all) { remove_unwanted(exif); @@ -207,10 +208,18 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst, bool keep_all) const dst->exifData()[datum.key()] = datum; } for (auto &datum : iptc) { - dst->iptcData()[datum.key()] = datum; + if (seen.insert(datum.key()).second) { + dst->iptcData()[datum.key()] = datum; + } else { + dst->iptcData().add(datum); + } } for (auto &datum : xmp) { - dst->xmpData()[datum.key()] = datum; + if (seen.insert(datum.key()).second) { + dst->xmpData()[datum.key()] = datum; + } else { + dst->xmpData().add(datum); + } } } catch (std::exception &exc) { if (settings->verbose) { diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index bee7ec74a..f103433c3 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -81,390 +81,390 @@ IPTCPanel::IPTCPanel(): { set_orientation(Gtk::ORIENTATION_VERTICAL); - set_spacing (4); + set_spacing(4); - Gtk::Grid* iptc = Gtk::manage( new Gtk::Grid () ); + Gtk::Grid* iptc = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(iptc, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); iptc->set_row_spacing(3); int row = 0; - Gtk::Label* capl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_DESCRIPTION") + ":") ); + Gtk::Label* capl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_DESCRIPTION") + ":")); setExpandAlignProperties(capl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - captionText = Gtk::TextBuffer::create (); - captionView = Gtk::manage( new Gtk::TextView (captionText) ); + captionText = Gtk::TextBuffer::create(); + captionView = Gtk::manage(new Gtk::TextView(captionText)); setExpandAlignProperties(captionView, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::ScrolledWindow* scrolledWindowc = Gtk::manage( new Gtk::ScrolledWindow() ); + Gtk::ScrolledWindow* scrolledWindowc = Gtk::manage(new Gtk::ScrolledWindow()); setExpandAlignProperties(scrolledWindowc, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - scrolledWindowc->set_min_content_height (100); + scrolledWindowc->set_min_content_height(100); scrolledWindowc->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); scrolledWindowc->add(*captionView); - capl->set_tooltip_text (M("IPTCPANEL_DESCRIPTIONHINT")); - captionView->set_tooltip_text (M("IPTCPANEL_DESCRIPTIONHINT")); + capl->set_tooltip_text(M("IPTCPANEL_DESCRIPTIONHINT")); + captionView->set_tooltip_text(M("IPTCPANEL_DESCRIPTIONHINT")); captionView->set_size_request(35, 95); - iptc->attach (*capl, 0, row++, 1, 1); - iptc->attach (*scrolledWindowc, 0, row++, 1, 1); + iptc->attach(*capl, 0, row++, 1, 1); + iptc->attach(*scrolledWindowc, 0, row++, 1, 1); // -------------------------- - Gtk::Label* capwl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_DESCRIPTIONWRITER") + ":") ); + Gtk::Label* capwl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_DESCRIPTIONWRITER") + ":")); setExpandAlignProperties(capwl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - captionWriter = Gtk::manage( new Gtk::Entry () ); + captionWriter = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(captionWriter, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - capwl->set_tooltip_text (M("IPTCPANEL_DESCRIPTIONWRITERHINT")); - captionWriter->set_tooltip_text (M("IPTCPANEL_DESCRIPTIONWRITERHINT")); - iptc->attach (*capwl, 0, row++, 1, 1); - iptc->attach (*captionWriter, 0, row++, 1, 1); + capwl->set_tooltip_text(M("IPTCPANEL_DESCRIPTIONWRITERHINT")); + captionWriter->set_tooltip_text(M("IPTCPANEL_DESCRIPTIONWRITERHINT")); + iptc->attach(*capwl, 0, row++, 1, 1); + iptc->attach(*captionWriter, 0, row++, 1, 1); // -------------------------- - Gtk::Label* headl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_HEADLINE") + ":") ); + Gtk::Label* headl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_HEADLINE") + ":")); setExpandAlignProperties(headl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - headline = Gtk::manage( new Gtk::Entry () ); + headline = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(headline, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - headl->set_tooltip_text (M("IPTCPANEL_HEADLINEHINT")); - headline->set_tooltip_text (M("IPTCPANEL_HEADLINEHINT")); - iptc->attach (*headl, 0, row++, 1, 1); - iptc->attach (*headline, 0, row++, 1, 1); + headl->set_tooltip_text(M("IPTCPANEL_HEADLINEHINT")); + headline->set_tooltip_text(M("IPTCPANEL_HEADLINEHINT")); + iptc->attach(*headl, 0, row++, 1, 1); + iptc->attach(*headline, 0, row++, 1, 1); // -------------------------- - Gtk::Label* instl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_INSTRUCTIONS") + ":") ); + Gtk::Label* instl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_INSTRUCTIONS") + ":")); setExpandAlignProperties(instl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - instructions = Gtk::manage( new Gtk::Entry () ); + instructions = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(instructions, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - instl->set_tooltip_text (M("IPTCPANEL_INSTRUCTIONSHINT")); - instructions->set_tooltip_text (M("IPTCPANEL_INSTRUCTIONSHINT")); - iptc->attach (*instl, 0, row++, 1, 1); - iptc->attach (*instructions, 0, row++, 1, 1); + instl->set_tooltip_text(M("IPTCPANEL_INSTRUCTIONSHINT")); + instructions->set_tooltip_text(M("IPTCPANEL_INSTRUCTIONSHINT")); + iptc->attach(*instl, 0, row++, 1, 1); + iptc->attach(*instructions, 0, row++, 1, 1); // -------------------------- - Gtk::Separator* hsep1 = Gtk::manage( new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL) ); + Gtk::Separator* hsep1 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); setExpandAlignProperties(hsep1, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - iptc->attach (*hsep1, 0, row++, 2, 1); + iptc->attach(*hsep1, 0, row++, 2, 1); // -------------------------- - Gtk::Label* keyl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_KEYWORDS") + ":")); + Gtk::Label* keyl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_KEYWORDS") + ":")); setExpandAlignProperties(keyl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - keyl->set_tooltip_text (M("IPTCPANEL_KEYWORDSHINT")); - keywords = Gtk::manage( new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE) ); + keyl->set_tooltip_text(M("IPTCPANEL_KEYWORDSHINT")); + keywords = Gtk::manage(new Gtk::ListViewText(1, false, Gtk::SELECTION_MULTIPLE)); setExpandAlignProperties(keywords, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - keywords->set_headers_visible (false); - keywords->set_size_request (50, 95); - Gtk::ScrolledWindow* scrolledWindowkw = Gtk::manage( new Gtk::ScrolledWindow() ); + keywords->set_headers_visible(false); + keywords->set_size_request(50, 95); + Gtk::ScrolledWindow* scrolledWindowkw = Gtk::manage(new Gtk::ScrolledWindow()); setExpandAlignProperties(scrolledWindowkw, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - scrolledWindowkw->set_min_content_height (100); + scrolledWindowkw->set_min_content_height(100); scrolledWindowkw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); scrolledWindowkw->add(*keywords); - keyword = Gtk::manage(new MyComboBoxText (true)); + keyword = Gtk::manage(new MyComboBoxText(true)); setExpandAlignProperties(keyword, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); keyword->set_size_request(75); - keywords->set_tooltip_text (M("IPTCPANEL_KEYWORDSHINT")); - keyword->set_tooltip_text (M("IPTCPANEL_KEYWORDSHINT")); - addKW = Gtk::manage( new Gtk::Button () ); + keywords->set_tooltip_text(M("IPTCPANEL_KEYWORDSHINT")); + keyword->set_tooltip_text(M("IPTCPANEL_KEYWORDSHINT")); + addKW = Gtk::manage(new Gtk::Button()); setExpandAlignProperties(addKW, false, true, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - delKW = Gtk::manage( new Gtk::Button () ); + delKW = Gtk::manage(new Gtk::Button()); setExpandAlignProperties(delKW, false, true, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - Gtk::Image* addKWImg = Gtk::manage( new RTImage ("add-small.png") ); + Gtk::Image* addKWImg = Gtk::manage(new RTImage("add-small.png")); setExpandAlignProperties(addKWImg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - Gtk::Image* delKWImg = Gtk::manage( new RTImage ("remove-small.png") ); + Gtk::Image* delKWImg = Gtk::manage(new RTImage("remove-small.png")); setExpandAlignProperties(delKWImg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - addKW->add (*addKWImg); - delKW->add (*delKWImg); - Gtk::Grid* kwgrid = Gtk::manage( new Gtk::Grid () ); + addKW->add(*addKWImg); + delKW->add(*delKWImg); + Gtk::Grid* kwgrid = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(kwgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - kwgrid->attach (*keyword, 0, 0, 1, 1); - kwgrid->attach (*addKW, 1, 0, 1, 1); - kwgrid->attach (*delKW, 2, 0, 1, 1); - iptc->attach (*keyl, 0, row++, 1, 1); - iptc->attach (*kwgrid, 0, row++, 1, 1); + kwgrid->attach(*keyword, 0, 0, 1, 1); + kwgrid->attach(*addKW, 1, 0, 1, 1); + kwgrid->attach(*delKW, 2, 0, 1, 1); + iptc->attach(*keyl, 0, row++, 1, 1); + iptc->attach(*kwgrid, 0, row++, 1, 1); // -------------------------- - iptc->attach (*scrolledWindowkw, 0, row++, 2, 1); + iptc->attach(*scrolledWindowkw, 0, row++, 2, 1); // -------------------------- - Gtk::Separator* hsep2 = Gtk::manage( new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL) ); + Gtk::Separator* hsep2 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); setExpandAlignProperties(hsep2, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - iptc->attach (*hsep2, 0, row++, 2, 1); + iptc->attach(*hsep2, 0, row++, 2, 1); // -------------------------- - Gtk::Label* catl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_CATEGORY") + ":") ); + Gtk::Label* catl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_CATEGORY") + ":")); setExpandAlignProperties(catl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - category = Gtk::manage(new MyComboBoxText (true)); + category = Gtk::manage(new MyComboBoxText(true)); category->set_size_request(75); setExpandAlignProperties(category, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - catl->set_tooltip_text (M("IPTCPANEL_CATEGORYHINT")); - category->set_tooltip_text (M("IPTCPANEL_CATEGORYHINT")); - Gtk::Label* scl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_SUPPCATEGORIES") + ":") ); + catl->set_tooltip_text(M("IPTCPANEL_CATEGORYHINT")); + category->set_tooltip_text(M("IPTCPANEL_CATEGORYHINT")); + Gtk::Label* scl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_SUPPCATEGORIES") + ":")); setExpandAlignProperties(scl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - suppCategories = Gtk::manage( new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE) ); + suppCategories = Gtk::manage(new Gtk::ListViewText(1, false, Gtk::SELECTION_MULTIPLE)); setExpandAlignProperties(suppCategories, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - suppCategories->set_headers_visible (false); + suppCategories->set_headers_visible(false); suppCategories->set_size_request(50, 95); - Gtk::ScrolledWindow* scrolledWindowsc = Gtk::manage( new Gtk::ScrolledWindow() ); + Gtk::ScrolledWindow* scrolledWindowsc = Gtk::manage(new Gtk::ScrolledWindow()); setExpandAlignProperties(scrolledWindowsc, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - scrolledWindowsc->set_min_content_height (100); + scrolledWindowsc->set_min_content_height(100); scrolledWindowsc->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); scrolledWindowsc->add(*suppCategories); - suppCategory = Gtk::manage(new MyComboBoxText (true)); + suppCategory = Gtk::manage(new MyComboBoxText(true)); suppCategory->set_size_request(75); setExpandAlignProperties(suppCategory, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - scl->set_tooltip_text (M("IPTCPANEL_SUPPCATEGORIESHINT")); - suppCategories->set_tooltip_text (M("IPTCPANEL_SUPPCATEGORIESHINT")); - suppCategory->set_tooltip_text (M("IPTCPANEL_SUPPCATEGORIESHINT")); - addSC = Gtk::manage( new Gtk::Button () ); + scl->set_tooltip_text(M("IPTCPANEL_SUPPCATEGORIESHINT")); + suppCategories->set_tooltip_text(M("IPTCPANEL_SUPPCATEGORIESHINT")); + suppCategory->set_tooltip_text(M("IPTCPANEL_SUPPCATEGORIESHINT")); + addSC = Gtk::manage(new Gtk::Button()); setExpandAlignProperties(addSC, false, true, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - delSC = Gtk::manage( new Gtk::Button () ); + delSC = Gtk::manage(new Gtk::Button()); setExpandAlignProperties(delSC, false, true, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - Gtk::Image* addSCImg = Gtk::manage( new RTImage ("add-small.png") ); + Gtk::Image* addSCImg = Gtk::manage(new RTImage("add-small.png")); setExpandAlignProperties(addSCImg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - Gtk::Image* delSCImg = Gtk::manage( new RTImage ("remove-small.png") ); + Gtk::Image* delSCImg = Gtk::manage(new RTImage("remove-small.png")); setExpandAlignProperties(delSCImg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - addSC->add (*addSCImg); - delSC->add (*delSCImg); - Gtk::Grid* scgrid = Gtk::manage( new Gtk::Grid () ); + addSC->add(*addSCImg); + delSC->add(*delSCImg); + Gtk::Grid* scgrid = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(scgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - scgrid->attach (*suppCategory, 0, 0, 1, 1); - scgrid->attach (*addSC, 1, 0, 1, 1); - scgrid->attach (*delSC, 2, 0, 1, 1); - iptc->attach (*catl, 0, row++, 1, 1); - iptc->attach (*category, 0, row++, 1, 1); + scgrid->attach(*suppCategory, 0, 0, 1, 1); + scgrid->attach(*addSC, 1, 0, 1, 1); + scgrid->attach(*delSC, 2, 0, 1, 1); + iptc->attach(*catl, 0, row++, 1, 1); + iptc->attach(*category, 0, row++, 1, 1); // -------------------------- - iptc->attach (*scl, 0, row++, 1, 1); - iptc->attach (*scgrid, 0, row++, 1, 1); + iptc->attach(*scl, 0, row++, 1, 1); + iptc->attach(*scgrid, 0, row++, 1, 1); // -------------------------- - iptc->attach (*scrolledWindowsc, 0, row++, 2, 1); + iptc->attach(*scrolledWindowsc, 0, row++, 2, 1); // -------------------------- - Gtk::Separator* hsep3 = Gtk::manage( new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL) ); + Gtk::Separator* hsep3 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); setExpandAlignProperties(hsep3, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - iptc->attach (*hsep3, 0, row++, 2, 1); + iptc->attach(*hsep3, 0, row++, 2, 1); // -------------------------- - Gtk::Label* creatorLbl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_CREATOR") + ":") ); + Gtk::Label* creatorLbl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_CREATOR") + ":")); setExpandAlignProperties(creatorLbl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - creator = Gtk::manage( new Gtk::Entry () ); + creator = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(creator, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - creatorLbl->set_tooltip_text (M("IPTCPANEL_CREATORHINT")); - creator->set_tooltip_text (M("IPTCPANEL_CREATORHINT")); - iptc->attach (*creatorLbl, 0, row++, 1, 1); - iptc->attach (*creator, 0, row++, 1, 1); + creatorLbl->set_tooltip_text(M("IPTCPANEL_CREATORHINT")); + creator->set_tooltip_text(M("IPTCPANEL_CREATORHINT")); + iptc->attach(*creatorLbl, 0, row++, 1, 1); + iptc->attach(*creator, 0, row++, 1, 1); // -------------------------- - Gtk::Label* creatorJobTitleLbl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_CREATORJOBTITLE") + ":") ); + Gtk::Label* creatorJobTitleLbl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_CREATORJOBTITLE") + ":")); setExpandAlignProperties(creatorJobTitleLbl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - creatorJobTitle = Gtk::manage( new Gtk::Entry () ); + creatorJobTitle = Gtk::manage( new Gtk::Entry()); setExpandAlignProperties(creatorJobTitle, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - creatorJobTitleLbl->set_tooltip_text (M("IPTCPANEL_CREATORJOBTITLEHINT")); - creatorJobTitle->set_tooltip_text (M("IPTCPANEL_CREATORJOBTITLEHINT")); - iptc->attach (*creatorJobTitleLbl, 0, row++, 1, 1); - iptc->attach (*creatorJobTitle, 0, row++, 1, 1); + creatorJobTitleLbl->set_tooltip_text(M("IPTCPANEL_CREATORJOBTITLEHINT")); + creatorJobTitle->set_tooltip_text(M("IPTCPANEL_CREATORJOBTITLEHINT")); + iptc->attach(*creatorJobTitleLbl, 0, row++, 1, 1); + iptc->attach(*creatorJobTitle, 0, row++, 1, 1); // -------------------------- - Gtk::Label* credl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_CREDIT") + ":") ); + Gtk::Label* credl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_CREDIT") + ":")); setExpandAlignProperties(credl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - credit = Gtk::manage( new Gtk::Entry () ); + credit = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(credit, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - credl->set_tooltip_text (M("IPTCPANEL_CREDITHINT")); - credit->set_tooltip_text (M("IPTCPANEL_CREDITHINT")); - iptc->attach (*credl, 0, row++, 1, 1); - iptc->attach (*credit, 0, row++, 1, 1); + credl->set_tooltip_text(M("IPTCPANEL_CREDITHINT")); + credit->set_tooltip_text(M("IPTCPANEL_CREDITHINT")); + iptc->attach(*credl, 0, row++, 1, 1); + iptc->attach(*credit, 0, row++, 1, 1); // -------------------------- - Gtk::Label* sourl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_SOURCE") + ":") ); + Gtk::Label* sourl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_SOURCE") + ":")); setExpandAlignProperties(sourl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - source = Gtk::manage( new Gtk::Entry () ); + source = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(source, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - sourl->set_tooltip_text (M("IPTCPANEL_SOURCEHINT")); - source->set_tooltip_text (M("IPTCPANEL_SOURCEHINT")); - iptc->attach (*sourl, 0, row++, 1, 1); - iptc->attach (*source, 0, row++, 1, 1); + sourl->set_tooltip_text(M("IPTCPANEL_SOURCEHINT")); + source->set_tooltip_text(M("IPTCPANEL_SOURCEHINT")); + iptc->attach(*sourl, 0, row++, 1, 1); + iptc->attach(*source, 0, row++, 1, 1); // -------------------------- - Gtk::Label* cprl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_COPYRIGHT") + ":") ); + Gtk::Label* cprl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_COPYRIGHT") + ":")); setExpandAlignProperties(cprl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - copyright = Gtk::manage( new Gtk::Entry () ); + copyright = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(copyright, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - cprl->set_tooltip_text (M("IPTCPANEL_COPYRIGHTHINT")); - copyright->set_tooltip_text (M("IPTCPANEL_COPYRIGHTHINT")); - iptc->attach (*cprl, 0, row++, 1, 1); - iptc->attach (*copyright, 0, row++, 1, 1); + cprl->set_tooltip_text(M("IPTCPANEL_COPYRIGHTHINT")); + copyright->set_tooltip_text(M("IPTCPANEL_COPYRIGHTHINT")); + iptc->attach(*cprl, 0, row++, 1, 1); + iptc->attach(*copyright, 0, row++, 1, 1); // -------------------------- - Gtk::Separator* hsep4 = Gtk::manage( new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL) ); + Gtk::Separator* hsep4 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); setExpandAlignProperties(hsep4, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - iptc->attach (*hsep4, 0, row++, 2, 1); + iptc->attach(*hsep4, 0, row++, 2, 1); // -------------------------- - Gtk::Label* cityl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_CITY") + ":") ); + Gtk::Label* cityl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_CITY") + ":")); setExpandAlignProperties(cityl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - city = Gtk::manage( new Gtk::Entry () ); + city = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(city, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - cityl->set_tooltip_text (M("IPTCPANEL_CITYHINT")); - city->set_tooltip_text (M("IPTCPANEL_CITYHINT")); - iptc->attach (*cityl, 0, row++, 1, 1); - iptc->attach (*city, 0, row++, 1, 1); + cityl->set_tooltip_text(M("IPTCPANEL_CITYHINT")); + city->set_tooltip_text(M("IPTCPANEL_CITYHINT")); + iptc->attach(*cityl, 0, row++, 1, 1); + iptc->attach(*city, 0, row++, 1, 1); // -------------------------- - Gtk::Label* provl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_PROVINCE") + ":") ); + Gtk::Label* provl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_PROVINCE") + ":")); setExpandAlignProperties(provl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - province = Gtk::manage( new Gtk::Entry () ); + province = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(province, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - provl->set_tooltip_text (M("IPTCPANEL_PROVINCEHINT")); - province->set_tooltip_text (M("IPTCPANEL_PROVINCEHINT")); - iptc->attach (*provl, 0, row++, 1, 1); - iptc->attach (*province, 0, row++, 1, 1); + provl->set_tooltip_text(M("IPTCPANEL_PROVINCEHINT")); + province->set_tooltip_text(M("IPTCPANEL_PROVINCEHINT")); + iptc->attach(*provl, 0, row++, 1, 1); + iptc->attach(*province, 0, row++, 1, 1); // -------------------------- - Gtk::Label* ctrl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_COUNTRY") + ":") ); + Gtk::Label* ctrl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_COUNTRY") + ":")); setExpandAlignProperties(ctrl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - country = Gtk::manage( new Gtk::Entry () ); + country = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(country, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - ctrl->set_tooltip_text (M("IPTCPANEL_COUNTRYHINT")); - country->set_tooltip_text (M("IPTCPANEL_COUNTRYHINT")); - iptc->attach (*ctrl, 0, row++, 1, 1); - iptc->attach (*country, 0, row++, 1, 1); + ctrl->set_tooltip_text(M("IPTCPANEL_COUNTRYHINT")); + country->set_tooltip_text(M("IPTCPANEL_COUNTRYHINT")); + iptc->attach(*ctrl, 0, row++, 1, 1); + iptc->attach(*country, 0, row++, 1, 1); // -------------------------- - Gtk::Label* titll = Gtk::manage( new Gtk::Label (M("IPTCPANEL_TITLE") + ":") ); + Gtk::Label* titll = Gtk::manage(new Gtk::Label(M("IPTCPANEL_TITLE") + ":")); setExpandAlignProperties(titll, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - title = Gtk::manage( new Gtk::Entry () ); + title = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(title, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - titll->set_tooltip_text (M("IPTCPANEL_TITLEHINT")); - title->set_tooltip_text (M("IPTCPANEL_TITLEHINT")); - iptc->attach (*titll, 0, row++, 1, 1); - iptc->attach (*title, 0, row++, 1, 1); + titll->set_tooltip_text(M("IPTCPANEL_TITLEHINT")); + title->set_tooltip_text(M("IPTCPANEL_TITLEHINT")); + iptc->attach(*titll, 0, row++, 1, 1); + iptc->attach(*title, 0, row++, 1, 1); // -------------------------- - Gtk::Label* dcl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_DATECREATED") + ":") ); + Gtk::Label* dcl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_DATECREATED") + ":")); setExpandAlignProperties(dcl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - dateCreated = Gtk::manage( new Gtk::Entry () ); + dateCreated = Gtk::manage( new Gtk::Entry()); setExpandAlignProperties(dateCreated, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - dcl->set_tooltip_text (M("IPTCPANEL_DATECREATEDHINT")); - dateCreated->set_tooltip_text (M("IPTCPANEL_DATECREATEDHINT")); - iptc->attach (*dcl, 0, row++, 1, 1); - iptc->attach (*dateCreated, 0, row++, 1, 1); + dcl->set_tooltip_text(M("IPTCPANEL_DATECREATEDHINT")); + dateCreated->set_tooltip_text(M("IPTCPANEL_DATECREATEDHINT")); + iptc->attach(*dcl, 0, row++, 1, 1); + iptc->attach(*dateCreated, 0, row++, 1, 1); // -------------------------- - Gtk::Label* trl = Gtk::manage( new Gtk::Label (M("IPTCPANEL_TRANSREFERENCE") + ":") ); + Gtk::Label* trl = Gtk::manage(new Gtk::Label(M("IPTCPANEL_TRANSREFERENCE") + ":")); setExpandAlignProperties(trl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - transReference = Gtk::manage( new Gtk::Entry () ); + transReference = Gtk::manage(new Gtk::Entry()); setExpandAlignProperties(transReference, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - trl->set_tooltip_text (M("IPTCPANEL_TRANSREFERENCEHINT")); - transReference->set_tooltip_text (M("IPTCPANEL_TRANSREFERENCEHINT")); - iptc->attach (*trl, 0, row++, 1, 1); - iptc->attach (*transReference, 0, row++, 1, 1); + trl->set_tooltip_text(M("IPTCPANEL_TRANSREFERENCEHINT")); + transReference->set_tooltip_text(M("IPTCPANEL_TRANSREFERENCEHINT")); + iptc->attach(*trl, 0, row++, 1, 1); + iptc->attach(*transReference, 0, row++, 1, 1); // -------------------------- - Gtk::ScrolledWindow* scrolledWindow = Gtk::manage( new Gtk::ScrolledWindow() ); + Gtk::ScrolledWindow* scrolledWindow = Gtk::manage(new Gtk::ScrolledWindow()); setExpandAlignProperties(scrolledWindow, false, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE); scrolledWindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_RIGHT); scrolledWindow->add(*iptc); - pack_start (*scrolledWindow); + pack_start(*scrolledWindow); - Gtk::Grid* bbox = Gtk::manage( new Gtk::Grid () ); + Gtk::Grid* bbox = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(bbox, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - reset = Gtk::manage( new Gtk::Button () ); // M("IPTCPANEL_RESET") + reset = Gtk::manage(new Gtk::Button()); // M("IPTCPANEL_RESET") reset->get_style_context()->add_class("Left"); - reset->set_image (*Gtk::manage(new RTImage ("undo.png", "redo.png"))); + reset->set_image(*Gtk::manage(new RTImage("undo.png", "redo.png"))); setExpandAlignProperties(reset, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - bbox->attach_next_to (*reset, Gtk::POS_LEFT, 1, 1); + bbox->attach_next_to(*reset, Gtk::POS_LEFT, 1, 1); - file = Gtk::manage( new Gtk::Button () ); // M("IPTCPANEL_EMBEDDED") + file = Gtk::manage(new Gtk::Button()); // M("IPTCPANEL_EMBEDDED") file->get_style_context()->add_class("MiddleH"); - file->set_image (*Gtk::manage(new RTImage ("folder-open.png"))); + file->set_image(*Gtk::manage(new RTImage("folder-open.png"))); setExpandAlignProperties(file, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - bbox->attach_next_to (*file, Gtk::POS_RIGHT, 1, 1); + bbox->attach_next_to(*file, Gtk::POS_RIGHT, 1, 1); - copy = Gtk::manage( new Gtk::Button () ); + copy = Gtk::manage(new Gtk::Button()); copy->get_style_context()->add_class("MiddleH"); - copy->set_image (*Gtk::manage(new RTImage ("copy.png"))); + copy->set_image(*Gtk::manage(new RTImage("copy.png"))); setExpandAlignProperties(copy, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - bbox->attach_next_to (*copy, Gtk::POS_RIGHT, 1, 1); + bbox->attach_next_to(*copy, Gtk::POS_RIGHT, 1, 1); - paste = Gtk::manage( new Gtk::Button () ); + paste = Gtk::manage(new Gtk::Button()); paste->get_style_context()->add_class("Right"); - paste->set_image (*Gtk::manage(new RTImage ("paste.png"))); + paste->set_image(*Gtk::manage(new RTImage("paste.png"))); setExpandAlignProperties(paste, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - bbox->attach_next_to (*paste, Gtk::POS_RIGHT, 1, 1); + bbox->attach_next_to(*paste, Gtk::POS_RIGHT, 1, 1); - pack_end (*bbox, Gtk::PACK_SHRINK, 2); + pack_end(*bbox, Gtk::PACK_SHRINK, 2); reset->set_tooltip_text(M("IPTCPANEL_RESETHINT")); file->set_tooltip_text(M("IPTCPANEL_EMBEDDEDHINT")); copy->set_tooltip_text(M("IPTCPANEL_COPYHINT")); paste->set_tooltip_text(M("IPTCPANEL_PASTEHINT")); - reset->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::resetClicked) ); - file->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::fileClicked) ); - copy->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::copyClicked) ); - paste->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::pasteClicked) ); + reset->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::resetClicked)); + file->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::fileClicked)); + copy->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::copyClicked)); + paste->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::pasteClicked)); - addKW->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::addKeyWord) ); - delKW->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::delKeyWord) ); - addSC->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::addSuppCategory) ); - delSC->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::delSuppCategory) ); - keyword->get_entry()->signal_activate().connect( sigc::mem_fun(*this, &IPTCPanel::addKeyWord) ); - suppCategory->get_entry()->signal_activate().connect( sigc::mem_fun(*this, &IPTCPanel::addSuppCategory) ); + addKW->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::addKeyWord)); + delKW->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::delKeyWord)); + addSC->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::addSuppCategory)); + delSC->signal_clicked().connect(sigc::mem_fun(*this, &IPTCPanel::delSuppCategory)); + keyword->get_entry()->signal_activate().connect(sigc::mem_fun(*this, &IPTCPanel::addKeyWord)); + suppCategory->get_entry()->signal_activate().connect(sigc::mem_fun(*this, &IPTCPanel::addSuppCategory)); - conns[0] = captionText->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[1] = captionWriter->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[2] = headline->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[3] = instructions->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[4] = category->get_entry()->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[5] = creator->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[6] = creatorJobTitle->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[7] = credit->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[8] = source->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[9] = copyright->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[10] = city->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[11] = province->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[12] = country->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[13] = title->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[14] = dateCreated->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); - conns[15] = transReference->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[0] = captionText->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[1] = captionWriter->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[2] = headline->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[3] = instructions->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[4] = category->get_entry()->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[5] = creator->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[6] = creatorJobTitle->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[7] = credit->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[8] = source->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[9] = copyright->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[10] = city->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[11] = province->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[12] = country->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[13] = title->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[14] = dateCreated->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); + conns[15] = transReference->signal_changed().connect(sigc::mem_fun(*this, &IPTCPanel::updateChangeList)); - category->get_entry()->set_max_length (3); - keyword->get_entry()->set_max_length (64); - captionWriter->set_max_length (32); - instructions->set_max_length (256); - creator->set_max_length (32); - creatorJobTitle->set_max_length (32); - credit->set_max_length (32); - source->set_max_length (32); - copyright->set_max_length (128); - city->set_max_length (32); - province->set_max_length (32); - country->set_max_length (64); - title->set_max_length (64); - dateCreated->set_max_length (8); - transReference->set_max_length (32); + category->get_entry()->set_max_length(3); + keyword->get_entry()->set_max_length(64); + captionWriter->set_max_length(32); + instructions->set_max_length(256); + creator->set_max_length(32); + creatorJobTitle->set_max_length(32); + credit->set_max_length(32); + source->set_max_length(32); + copyright->set_max_length(128); + city->set_max_length(32); + province->set_max_length(32); + country->set_max_length(64); + title->set_max_length(64); + dateCreated->set_max_length(10); + transReference->set_max_length(32); - show_all (); + show_all(); } void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); + disableListener(); changeList->clear(); if (!pp->metadata.iptc.empty()) { @@ -473,8 +473,8 @@ void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) *changeList = *embeddedData; } - applyChangeList (); - enableListener (); + applyChangeList(); + enableListener(); } void IPTCPanel::write (ProcParams* pp, ParamsEdited* pedited) @@ -489,7 +489,7 @@ void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pe *defChangeList = defParams->metadata.iptc; } -void IPTCPanel::setImageData (const FramesMetaData* id) +void IPTCPanel::setImageData(const FramesMetaData* id) { embeddedData->clear(); if (id) { @@ -507,267 +507,285 @@ void IPTCPanel::setImageData (const FramesMetaData* id) } } - file->set_sensitive (!embeddedData->empty()); + file->set_sensitive(!embeddedData->empty()); } -void IPTCPanel::notifyListener () +void IPTCPanel::notifyListener() { if (listener) { - listener->panelChanged (EvIPTC, M("HISTORY_CHANGED")); + listener->panelChanged(EvIPTC, M("HISTORY_CHANGED")); } } -void IPTCPanel::addKeyWord () + +void IPTCPanel::addKeyWord() { + keyword->get_entry()->select_region(0, keyword->get_entry()->get_text().size()); - keyword->get_entry()->select_region (0, keyword->get_entry()->get_text().size()); - - for (unsigned int i = 0; i < keywords->size(); i++) - if (keywords->get_text (i) == keyword->get_entry()->get_text()) { + for (unsigned int i = 0; i < keywords->size(); i++) { + if (keywords->get_text(i) == keyword->get_entry()->get_text()) { return; } + } - keywords->append (keyword->get_entry()->get_text()); - keyword->prepend (keyword->get_entry()->get_text()); + keywords->append(keyword->get_entry()->get_text()); + keyword->prepend(keyword->get_entry()->get_text()); std::vector items; for (Gtk::TreeModel::iterator i = keyword->get_model()->children().begin(); i != keyword->get_model()->children().end(); ++i) { Glib::ustring s; - i->get_value (0, s); - items.push_back (s); + i->get_value(0, s); + items.push_back(s); } - keyword->remove_all (); + keyword->remove_all(); for (unsigned int i = 0; i < 10 && i < items.size(); i++) { - keyword->append (items[i]); + keyword->append(items[i]); } - keywords->scroll_to_row (keywords->get_model()->get_path(--keywords->get_model()->children().end())); + keywords->scroll_to_row(keywords->get_model()->get_path(--keywords->get_model()->children().end())); - updateChangeList (); + updateChangeList(); } -void IPTCPanel::delKeyWord () -{ - std::vector selection = keywords->get_selected (); +void IPTCPanel::delKeyWord() +{ + std::vector selection = keywords->get_selected(); if (!selection.empty()) { std::vector keep; for (unsigned int i = 0; i < keywords->size(); i++) - if (std::find (selection.begin(), selection.end(), i) == selection.end()) { - keep.push_back (keywords->get_text (i)); + if (std::find(selection.begin(), selection.end(), i) == selection.end()) { + keep.push_back(keywords->get_text(i)); } - keywords->clear_items (); + keywords->clear_items(); - for (unsigned int i = 0; i < keep.size(); i++) { - keywords->append (keep[i]); + for(unsigned int i = 0; i < keep.size(); i++) { + keywords->append(keep[i]); } } - updateChangeList (); + updateChangeList(); } -void IPTCPanel::addSuppCategory () +void IPTCPanel::addSuppCategory() { for (unsigned int i = 0; i < suppCategories->size(); i++) - if (suppCategories->get_text (i) == suppCategory->get_entry()->get_text()) { + if (suppCategories->get_text(i) == suppCategory->get_entry()->get_text()) { return; } - suppCategories->append (suppCategory->get_entry()->get_text()); - suppCategory->prepend (suppCategory->get_entry()->get_text()); + suppCategories->append(suppCategory->get_entry()->get_text()); + suppCategory->prepend(suppCategory->get_entry()->get_text()); std::vector items; for (Gtk::TreeModel::iterator i = suppCategory->get_model()->children().begin(); i != suppCategory->get_model()->children().end(); ++i) { Glib::ustring s; - i->get_value (0, s); - items.push_back (s); + i->get_value(0, s); + items.push_back(s); } - suppCategory->remove_all (); + suppCategory->remove_all(); for (unsigned int i = 0; i < 10 && i < items.size(); i++) { - suppCategory->append (items[i]); + suppCategory->append(items[i]); } - suppCategories->scroll_to_row (suppCategories->get_model()->get_path(--suppCategories->get_model()->children().end())); - suppCategory->get_entry()->select_region (0, suppCategory->get_entry()->get_text().size()); + suppCategories->scroll_to_row(suppCategories->get_model()->get_path(--suppCategories->get_model()->children().end())); + suppCategory->get_entry()->select_region(0, suppCategory->get_entry()->get_text().size()); - updateChangeList (); + updateChangeList(); } -void IPTCPanel::delSuppCategory () +void IPTCPanel::delSuppCategory() { - std::vector selection = suppCategories->get_selected (); + std::vector selection = suppCategories->get_selected(); if (!selection.empty()) { std::vector keep; for (unsigned int i = 0; i < suppCategories->size(); i++) - if (std::find (selection.begin(), selection.end(), i) == selection.end()) { - keep.push_back (suppCategories->get_text (i)); + if (std::find(selection.begin(), selection.end(), i) == selection.end()) { + keep.push_back(suppCategories->get_text(i)); } - suppCategories->clear_items (); + suppCategories->clear_items(); for (unsigned int i = 0; i < keep.size(); i++) { - suppCategories->append (keep[i]); + suppCategories->append(keep[i]); } } - updateChangeList (); + updateChangeList(); } -void IPTCPanel::updateChangeList () +void IPTCPanel::updateChangeList() { - changeList->clear (); - (*changeList)[CAPTION].push_back (captionText->get_text ()); - (*changeList)[CAPTION_WRITER].push_back (captionWriter->get_text ()); - (*changeList)[HEADLINE].push_back (headline->get_text ()); - (*changeList)[INSTRUCTIONS].push_back (instructions->get_text ()); + changeList->clear(); + (*changeList)[CAPTION].push_back(captionText->get_text()); + (*changeList)[CAPTION_WRITER].push_back(captionWriter->get_text()); + (*changeList)[HEADLINE].push_back(headline->get_text()); + (*changeList)[INSTRUCTIONS].push_back(instructions->get_text()); + std::set sset; + sset.clear(); for (unsigned int i = 0; i < keywords->size(); i++) { - (*changeList)[KEYWORDS].push_back (keywords->get_text (i)); + sset.insert(keywords->get_text(i)); + } + for (auto &s : sset) { + (*changeList)[KEYWORDS].push_back(s); } - (*changeList)[CATEGORY].push_back (category->get_entry()->get_text ()); + (*changeList)[CATEGORY].push_back(category->get_entry()->get_text()); + sset.clear(); for (unsigned int i = 0; i < suppCategories->size(); i++) { - (*changeList)[SUPPLEMENTAL_CATEGORIES].push_back (suppCategories->get_text (i)); + sset.insert(suppCategories->get_text(i)); + } + for (auto &s : sset) { + (*changeList)[SUPPLEMENTAL_CATEGORIES].push_back(s); } - (*changeList)[CREATOR].push_back (creator->get_text ()); - (*changeList)[CREATOR_JOB_TITLE].push_back (creatorJobTitle->get_text ()); - (*changeList)[CREDIT].push_back (credit->get_text ()); - (*changeList)[SOURCE].push_back (source->get_text ()); - (*changeList)[COPYRIGHT].push_back (copyright->get_text ()); - (*changeList)[CITY].push_back (city->get_text ()); - (*changeList)[PROVINCE].push_back (province->get_text ()); - (*changeList)[COUNTRY].push_back (country->get_text ()); - (*changeList)[TITLE].push_back (title->get_text ()); - (*changeList)[DATE_CREATED].push_back (dateCreated->get_text ()); - (*changeList)[TRANS_REFERENCE].push_back (transReference->get_text ()); + (*changeList)[CREATOR].push_back(creator->get_text()); + (*changeList)[CREATOR_JOB_TITLE].push_back(creatorJobTitle->get_text()); + (*changeList)[CREDIT].push_back(credit->get_text()); + (*changeList)[SOURCE].push_back(source->get_text()); + (*changeList)[COPYRIGHT].push_back(copyright->get_text()); + (*changeList)[CITY].push_back(city->get_text()); + (*changeList)[PROVINCE].push_back(province->get_text()); + (*changeList)[COUNTRY].push_back(country->get_text()); + (*changeList)[TITLE].push_back(title->get_text()); + (*changeList)[DATE_CREATED].push_back(dateCreated->get_text()); + (*changeList)[TRANS_REFERENCE].push_back(transReference->get_text()); - notifyListener (); + notifyListener(); } -void IPTCPanel::applyChangeList () -{ +void IPTCPanel::applyChangeList() +{ for (int i = 0; i < 16; i++) { - conns[i].block (true); + conns[i].block(true); } - captionText->set_text (""); - captionWriter->set_text (""); - headline->set_text (""); - instructions->set_text (""); - keywords->clear_items (); - category->get_entry()->set_text (""); - suppCategories->clear_items (); - creator->set_text (""); - creatorJobTitle->set_text (""); - credit->set_text (""); - source->set_text (""); - copyright->set_text (""); - city->set_text (""); - province->set_text (""); - country->set_text (""); - title->set_text (""); - dateCreated->set_text (""); - transReference->set_text (""); - keyword->get_entry()->set_text (""); - suppCategory->get_entry()->set_text (""); + captionText->set_text(""); + captionWriter->set_text(""); + headline->set_text(""); + instructions->set_text(""); + keywords->clear_items(); + category->get_entry()->set_text(""); + suppCategories->clear_items(); + creator->set_text(""); + creatorJobTitle->set_text(""); + credit->set_text(""); + source->set_text(""); + copyright->set_text(""); + city->set_text(""); + province->set_text(""); + country->set_text(""); + title->set_text(""); + dateCreated->set_text(""); + transReference->set_text(""); + keyword->get_entry()->set_text(""); + suppCategory->get_entry()->set_text(""); for (rtengine::procparams::IPTCPairs::const_iterator i = changeList->begin(); i != changeList->end(); ++i) { if (i->first == CAPTION && !i->second.empty()) { - captionText->set_text (i->second.at(0)); + captionText->set_text(i->second.at(0)); } else if (i->first == CAPTION_WRITER && !i->second.empty()) { - captionWriter->set_text (i->second.at(0)); + captionWriter->set_text(i->second.at(0)); } else if (i->first == HEADLINE && !i->second.empty()) { - headline->set_text (i->second.at(0)); + headline->set_text(i->second.at(0)); } else if (i->first == INSTRUCTIONS && !i->second.empty()) { - instructions->set_text (i->second.at(0)); - } else if (i->first == KEYWORDS) + instructions->set_text(i->second.at(0)); + } else if (i->first == KEYWORDS) { + std::set sset; for (unsigned int j = 0; j < i->second.size(); j++) { - keywords->append (i->second.at(j)); + sset.insert(i->second[j]); } - else if (i->first == CATEGORY && !i->second.empty()) { - category->get_entry()->set_text (i->second.at(0)); - } else if (i->first == SUPPLEMENTAL_CATEGORIES) + for (auto &s : sset) { + keywords->append(s); + } + } else if (i->first == CATEGORY && !i->second.empty()) { + category->get_entry()->set_text(i->second.at(0)); + } else if (i->first == SUPPLEMENTAL_CATEGORIES) { + std::set sset; for (unsigned int j = 0; j < i->second.size(); j++) { - suppCategories->append (i->second.at(j)); + sset.insert(i->second[j]); } - else if (i->first == CREATOR && !i->second.empty()) { - creator->set_text (i->second.at(0)); + for (auto &s : sset) { + suppCategories->append(s); + } + } else if (i->first == CREATOR && !i->second.empty()) { + creator->set_text(i->second.at(0)); } else if (i->first == CREATOR_JOB_TITLE && !i->second.empty()) { - creatorJobTitle->set_text (i->second.at(0)); + creatorJobTitle->set_text(i->second.at(0)); } else if (i->first == CREDIT && !i->second.empty()) { - credit->set_text (i->second.at(0)); + credit->set_text(i->second.at(0)); } else if (i->first == SOURCE && !i->second.empty()) { - source->set_text (i->second.at(0)); + source->set_text(i->second.at(0)); } else if (i->first == COPYRIGHT && !i->second.empty()) { - copyright->set_text (i->second.at(0)); + copyright->set_text(i->second.at(0)); } else if (i->first == CITY && !i->second.empty()) { - city->set_text (i->second.at(0)); + city->set_text(i->second.at(0)); } else if (i->first == PROVINCE && !i->second.empty()) { - province->set_text (i->second.at(0)); + province->set_text(i->second.at(0)); } else if (i->first == COUNTRY && !i->second.empty()) { - country->set_text (i->second.at(0)); + country->set_text(i->second.at(0)); } else if (i->first == TITLE && !i->second.empty()) { - title->set_text (i->second.at(0)); + title->set_text(i->second.at(0)); } else if (i->first == DATE_CREATED && !i->second.empty()) { - dateCreated->set_text (i->second.at(0)); + dateCreated->set_text(i->second.at(0)); } else if (i->first == TRANS_REFERENCE && !i->second.empty()) { - transReference->set_text (i->second.at(0)); + transReference->set_text(i->second.at(0)); } } for (int i = 0; i < 16; i++) { - conns[i].block (false); + conns[i].block(false); } } -void IPTCPanel::resetClicked () +void IPTCPanel::resetClicked() { - disableListener (); + disableListener(); *changeList = *defChangeList; - applyChangeList (); - enableListener (); - notifyListener (); + applyChangeList(); + enableListener(); + notifyListener(); } -void IPTCPanel::fileClicked () +void IPTCPanel::fileClicked() { - disableListener (); + disableListener(); *changeList = *embeddedData; - applyChangeList (); - enableListener (); - notifyListener (); + applyChangeList(); + enableListener(); + notifyListener(); } -void IPTCPanel::copyClicked () +void IPTCPanel::copyClicked() { - clipboard.setIPTC (*changeList); + clipboard.setIPTC(*changeList); } -void IPTCPanel::pasteClicked () +void IPTCPanel::pasteClicked() { - disableListener (); - *changeList = clipboard.getIPTC (); - applyChangeList (); - enableListener (); - notifyListener (); + disableListener(); + *changeList = clipboard.getIPTC(); + applyChangeList(); + enableListener(); + notifyListener(); } From a0e9a5960688df8432afddd6b73b0a45b8ed0de6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Nov 2021 05:22:00 -0800 Subject: [PATCH 070/110] do not save IPTC tags in the arp if they are unchanged (cherry picked from commit c4c642794868c2b03fd824acc0a7db962162c16f) --- rtgui/iptcpanel.cc | 21 ++++++++++++++------- rtgui/iptcpanel.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index f103433c3..a7aa38f88 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -461,34 +461,41 @@ IPTCPanel::IPTCPanel(): show_all(); } + void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { - disableListener(); changeList->clear(); if (!pp->metadata.iptc.empty()) { *changeList = pp->metadata.iptc; + changelist_valid_ = true; } else { *changeList = *embeddedData; + changelist_valid_ = false; } applyChangeList(); enableListener(); } + void IPTCPanel::write (ProcParams* pp, ParamsEdited* pedited) { - - pp->metadata.iptc = *changeList; + if (changelist_valid_) { + pp->metadata.iptc = *changeList; + } else { + pp->metadata.iptc.clear(); + } } + void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - *defChangeList = defParams->metadata.iptc; } + void IPTCPanel::setImageData(const FramesMetaData* id) { embeddedData->clear(); @@ -510,9 +517,9 @@ void IPTCPanel::setImageData(const FramesMetaData* id) file->set_sensitive(!embeddedData->empty()); } + void IPTCPanel::notifyListener() { - if (listener) { listener->panelChanged(EvIPTC, M("HISTORY_CHANGED")); } @@ -628,7 +635,7 @@ void IPTCPanel::delSuppCategory() void IPTCPanel::updateChangeList() { - + changelist_valid_ = true; changeList->clear(); (*changeList)[CAPTION].push_back(captionText->get_text()); (*changeList)[CAPTION_WRITER].push_back(captionWriter->get_text()); @@ -756,9 +763,9 @@ void IPTCPanel::applyChangeList() void IPTCPanel::resetClicked() { - disableListener(); *changeList = *defChangeList; + changelist_valid_ = false; applyChangeList(); enableListener(); notifyListener(); diff --git a/rtgui/iptcpanel.h b/rtgui/iptcpanel.h index da52fa7d2..66564a151 100644 --- a/rtgui/iptcpanel.h +++ b/rtgui/iptcpanel.h @@ -34,6 +34,7 @@ private: const std::unique_ptr changeList; const std::unique_ptr defChangeList; const std::unique_ptr embeddedData; + bool changelist_valid_; Gtk::TextView* captionView; Glib::RefPtr captionText; From b409e0bab2a63d718823df78862b8b70d1b739ff Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 25 Nov 2021 14:32:36 -0800 Subject: [PATCH 071/110] fixed handling IPTC metadata that admit multiple values (cherry picked from commit 8becb08ec1417215bf8f02c54000d37c2e6920f0) --- rtengine/metadata.cc | 66 ++++++++++++++++++++++++++++++++----------- rtengine/metadata.h | 9 +++++- rtengine/procparams.h | 5 ++++ rtgui/iptcpanel.cc | 7 +++++ 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index d372119d9..28a9c1742 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -81,6 +81,20 @@ std::unique_ptr open_exiv2(const Glib::ustring& fname, return ret; } + +template +void clear_metadata_key(Data &data, const Key &key) +{ + while (true) { + auto it = data.findKey(key); + if (it == data.end()) { + break; + } else { + data.erase(it); + } + } +} + } // namespace @@ -119,18 +133,29 @@ void Exiv2Metadata::load() const if (!src_.empty() && !image_.get() && Glib::file_test(src_.c_str(), Glib::FILE_TEST_EXISTS)) { CacheVal val; auto finfo = Gio::File::create_for_path(src_)->query_info(G_FILE_ATTRIBUTE_TIME_MODIFIED); - if (cache_ && cache_->get(src_, val) && val.second >= finfo->modification_time()) { - image_ = val.first; - } else { - auto img = open_exiv2(src_, true); - image_.reset(img.release()); - if (cache_) { - cache_->set(src_, CacheVal(image_, finfo->modification_time())); + Glib::TimeVal xmp_mtime(0, 0); + if (merge_xmp_) { + auto xmpname = xmpSidecarPath(src_); + if (Glib::file_test(xmpname.c_str(), Glib::FILE_TEST_EXISTS)) { + xmp_mtime = Gio::File::create_for_path(xmpname)->query_info(G_FILE_ATTRIBUTE_TIME_MODIFIED)->modification_time(); } } - if (merge_xmp_) { - do_merge_xmp(image_.get(), false); + if (cache_ && cache_->get(src_, val) && val.image_mtime >= finfo->modification_time() && val.use_xmp == merge_xmp_ && val.xmp_mtime >= xmp_mtime) { + image_ = val.image; + } else { + auto img = open_exiv2(src_, true); + image_.reset(img.release()); + if (merge_xmp_) { + do_merge_xmp(image_.get(), false); + } + if (cache_) { + val.image = image_; + val.image_mtime = finfo->modification_time(); + val.xmp_mtime = xmp_mtime; + val.use_xmp = merge_xmp_; + cache_->set(src_, val); + } } } } @@ -198,7 +223,7 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst, bool keep_all) const Exiv2::IptcData iptc; Exiv2::copyXmpToIptc(xmp, iptc); Exiv2::moveXmpToExif(xmp, exif); - std::unordered_set seen; + std::unordered_map> seen; if (!keep_all) { remove_unwanted(exif); @@ -208,16 +233,23 @@ void Exiv2Metadata::do_merge_xmp(Exiv2::Image *dst, bool keep_all) const dst->exifData()[datum.key()] = datum; } for (auto &datum : iptc) { - if (seen.insert(datum.key()).second) { + auto &s = seen[datum.key()]; + if (s.empty()) { + clear_metadata_key(dst->iptcData(), Exiv2::IptcKey(datum.key())); dst->iptcData()[datum.key()] = datum; - } else { + s.insert(datum.toString()); + } else if (s.insert(datum.toString()).second) { dst->iptcData().add(datum); } } + seen.clear(); for (auto &datum : xmp) { - if (seen.insert(datum.key()).second) { + auto &s = seen[datum.key()]; + if (s.empty()) { + clear_metadata_key(dst->xmpData(), Exiv2::XmpKey(datum.key())); dst->xmpData()[datum.key()] = datum; - } else { + s.insert(datum.toString()); + } else if (s.insert(datum.toString()).second) { dst->xmpData().add(datum); } } @@ -415,9 +447,11 @@ void Exiv2Metadata::import_iptc_pairs(Exiv2::IptcData &out) const try { auto &v = p.second; if (v.size() >= 1) { - out[p.first] = v[0]; + clear_metadata_key(out, Exiv2::IptcKey(p.first)); + Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); + d.setValue(v[0]); + out[p.first] = d; for (size_t j = 1; j < v.size(); ++j) { - Exiv2::Iptcdatum d(Exiv2::IptcKey(p.first)); d.setValue(v[j]); out.add(d); } diff --git a/rtengine/metadata.h b/rtengine/metadata.h index cd27aada5..ff62e0848 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -85,7 +85,14 @@ private: std::shared_ptr> exif_keys_; - typedef std::pair, Glib::TimeVal> CacheVal; + struct CacheVal { + std::shared_ptr image; + Glib::TimeVal image_mtime; + Glib::TimeVal xmp_mtime; + bool use_xmp; + CacheVal() = default; + }; + //typedef std::pair, Glib::TimeVal> CacheVal; typedef Cache ImageCache; static std::unique_ptr cache_; }; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d874a9b13..8133a433a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1803,6 +1803,11 @@ public: return pairs.empty(); } + iterator erase(const const_iterator& key) + { + return pairs.erase(key); + } + void clear() { pairs.clear(); diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index a7aa38f88..eb6366fac 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -673,6 +673,13 @@ void IPTCPanel::updateChangeList() (*changeList)[DATE_CREATED].push_back(dateCreated->get_text()); (*changeList)[TRANS_REFERENCE].push_back(transReference->get_text()); + for (auto &p : *embeddedData) { + auto it = changeList->find(p.first); + if (it != changeList->end() && p.second == it->second) { + changeList->erase(it); + } + } + notifyListener(); } From 09d72259e3a43f1ab0b8370d4086c99973c3b6f9 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 5 Dec 2021 20:42:28 +0100 Subject: [PATCH 072/110] take care of some warnings Fixes #223 (cherry picked from commit f5bc793aa1efcba183602de3eec4746f4da3db8e) --- rtengine/metadata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/metadata.h b/rtengine/metadata.h index ff62e0848..7424b2720 100644 --- a/rtengine/metadata.h +++ b/rtengine/metadata.h @@ -90,7 +90,7 @@ private: Glib::TimeVal image_mtime; Glib::TimeVal xmp_mtime; bool use_xmp; - CacheVal() = default; + CacheVal(): image(nullptr), image_mtime(), xmp_mtime(), use_xmp(false) {} }; //typedef std::pair, Glib::TimeVal> CacheVal; typedef Cache ImageCache; From c7d5b5076dcb41d69248b6873b26eee331307b67 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 21 Mar 2022 01:09:50 -0700 Subject: [PATCH 073/110] metadata: fallback to Exif.Photo.LensModel for lenses unknown to exiv2 (cherry picked from commit 64e25471b003e302414d0cf48f64ccd1a988b454) --- rtengine/imagedata.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index a1db3c8d3..2caba4553 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -281,6 +281,10 @@ FramesData::FramesData(const Glib::ustring &fname) : if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + if (pos->count() == 1 && lens == std::to_string(pos->toLong()) && + find_exif_tag("Exif.Photo.LensModel")) { + lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + } } else if (find_exif_tag("Exif.Photo.LensSpecification") && pos->count() == 4) { const auto round = [](float f) -> float From 9fd136c2f3ab7dea5b13863ead0ff3243d868271 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 11 Apr 2022 23:11:27 -0700 Subject: [PATCH 074/110] metadata: work around misidentification of some Canon RF lenses with teleconverter (cherry picked from commit 3aae273f862f0c1611a134c6e84f460bba83bcf4) --- rtengine/imagedata.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 2caba4553..c8fb56a63 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -281,9 +281,15 @@ FramesData::FramesData(const Glib::ustring &fname) : if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? - if (pos->count() == 1 && lens == std::to_string(pos->toLong()) && - find_exif_tag("Exif.Photo.LensModel")) { + auto p = pos; + if (find_exif_tag("Exif.CanonFi.RFLensType") && find_exif_tag("Exif.Canon.LensModel")) { lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + if (Glib::ustring(lens).lowercase().find("canon") == Glib::ustring::npos) { + lens = std::string("Canon ") + lens; + } + } else if (p->count() == 1 && lens == std::to_string(p->toLong()) && + find_exif_tag("Exif.Photo.LensModel")) { + lens = validateUft8(p->print(&exif)); // validateUft8 (#5923) still needed? } } else if (find_exif_tag("Exif.Photo.LensSpecification") && pos->count() == 4) { const auto round = From 00c13bf2af65fb749d6d6ea4b6a6954c5080691f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 13 Apr 2022 05:54:30 -0700 Subject: [PATCH 075/110] tweaked lens identification for Canon RF cameras (cherry picked from commit a7e4ef71f9b400ffd53532c91d2ecb4e17e5ce2a) --- rtengine/imagedata.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index c8fb56a63..40a2baba4 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -284,9 +284,6 @@ FramesData::FramesData(const Glib::ustring &fname) : auto p = pos; if (find_exif_tag("Exif.CanonFi.RFLensType") && find_exif_tag("Exif.Canon.LensModel")) { lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? - if (Glib::ustring(lens).lowercase().find("canon") == Glib::ustring::npos) { - lens = std::string("Canon ") + lens; - } } else if (p->count() == 1 && lens == std::to_string(p->toLong()) && find_exif_tag("Exif.Photo.LensModel")) { lens = validateUft8(p->print(&exif)); // validateUft8 (#5923) still needed? From 2ac459e927db8abb9f1f6c8a00a5cec2aa5c91df Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 15 Apr 2022 04:53:49 -0700 Subject: [PATCH 076/110] further tweaks to lens identification (cherry picked from commit 4fd18fed00eb799b8d82f472a98f270617bc3fb4) --- rtengine/imagedata.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 40a2baba4..8697aea09 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -284,9 +284,12 @@ FramesData::FramesData(const Glib::ustring &fname) : auto p = pos; if (find_exif_tag("Exif.CanonFi.RFLensType") && find_exif_tag("Exif.Canon.LensModel")) { lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? - } else if (p->count() == 1 && lens == std::to_string(p->toLong()) && - find_exif_tag("Exif.Photo.LensModel")) { - lens = validateUft8(p->print(&exif)); // validateUft8 (#5923) still needed? + } else if (p->count() == 1 && lens == std::to_string(p->toLong())) { + if (find_exif_tag("Exif.Canon.LensModel")) { + lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + } else if (find_exif_tag("Exif.Photo.LensModel")) { + lens = validateUft8(p->print(&exif)); // validateUft8 (#5923) still needed? + } } } else if (find_exif_tag("Exif.Photo.LensSpecification") && pos->count() == 4) { const auto round = From eb7c15126055961668b7f17a631655618dcbeaa6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 18 Apr 2022 23:47:58 -0700 Subject: [PATCH 077/110] metadata: fixed regression with older exiv2 versions Fixes #246 (cherry picked from commit ac3e78c25ed5b14019661d5c6c58af15032e968d) --- rtengine/imagedata.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 8697aea09..d035760db 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -123,8 +123,15 @@ FramesData::FramesData(const Glib::ustring &fname) : const auto find_exif_tag = [&exif, &pos](const std::string &name) -> bool { - pos = exif.findKey(Exiv2::ExifKey(name)); - return pos != exif.end() && pos->size(); + try { + pos = exif.findKey(Exiv2::ExifKey(name)); + return pos != exif.end() && pos->size(); + } catch (std::exception &e) { + if (settings->verbose) { + std::cerr << "Exiv2 WARNING -- error finding tag " << name << ": " << e.what() << std::endl; + } + return false; + } }; const auto find_tag = From 7324ea723041ee2c20e1f66e174888566f32522d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 6 Jul 2022 07:04:24 -0700 Subject: [PATCH 078/110] replace Glib::filename_to_utf8 with custom fname_to_utf8 (cherry picked from commit 30b4daf9077e3c6780cefbf6c4223da4698b8612) --- rtgui/main-cli.cc | 19 ------------------- rtgui/main.cc | 23 ++--------------------- rtgui/pathutils.cc | 21 +++++++++++++++++++++ rtgui/pathutils.h | 5 ++++- 4 files changed, 27 insertions(+), 41 deletions(-) diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index feef93564..00272357e 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -67,25 +67,6 @@ Glib::ustring argv1; namespace { -// For an unknown reason, Glib::filename_to_utf8 doesn't work on reliably Windows, -// so we're using Glib::filename_to_utf8 for Linux/Apple and Glib::locale_to_utf8 for Windows. -Glib::ustring fname_to_utf8 (const char* fname) -{ -#ifdef WIN32 - - try { - return Glib::locale_to_utf8 (fname); - } catch (Glib::Error&) { - return Glib::convert_with_fallback (fname, "UTF-8", "ISO-8859-1", "?"); - } - -#else - - return Glib::filename_to_utf8 (fname); - -#endif -} - bool fast_export = false; } diff --git a/rtgui/main.cc b/rtgui/main.cc index 9f623a6df..08891ef46 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -44,6 +44,7 @@ #include "extprog.h" #include "../rtengine/dynamicprofile.h" #include "../rtengine/procparams.h" +#include "pathutils.h" #ifndef WIN32 #include @@ -71,27 +72,7 @@ bool remote = false; unsigned char initialGdkScale = 1; //Glib::Threads::Thread* mainThread; -namespace -{ - -// For an unknown reason, Glib::filename_to_utf8 doesn't work on reliably Windows, -// so we're using Glib::filename_to_utf8 for Linux/Apple and Glib::locale_to_utf8 for Windows. -Glib::ustring fname_to_utf8 (const char* fname) -{ -#ifdef WIN32 - - try { - return Glib::locale_to_utf8 (fname); - } catch (Glib::Error&) { - return Glib::convert_with_fallback (fname, "UTF-8", "ISO-8859-1", "?"); - } - -#else - - return Glib::filename_to_utf8 (fname); - -#endif -} +namespace { // This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex static Glib::Threads::RecMutex myGdkRecMutex; diff --git a/rtgui/pathutils.cc b/rtgui/pathutils.cc index fc47a0e25..ef67564b2 100644 --- a/rtgui/pathutils.cc +++ b/rtgui/pathutils.cc @@ -16,6 +16,7 @@ * along with RawTherapee. If not, see . */ +#include #include #include "pathutils.h" @@ -48,3 +49,23 @@ Glib::ustring getExtension (const Glib::ustring& filename) return ""; } } + + +// For an unknown reason, Glib::filename_to_utf8 doesn't work on reliably Windows, +// so we're using Glib::filename_to_utf8 for Linux/Apple and Glib::locale_to_utf8 for Windows. +Glib::ustring fname_to_utf8(const std::string &fname) +{ +#ifdef WIN32 + + try { + return Glib::locale_to_utf8(fname); + } catch (Glib::Error&) { + return Glib::convert_with_fallback(fname, "UTF-8", "ISO-8859-1", "?"); + } + +#else + + return Glib::filename_to_utf8(fname); + +#endif +} diff --git a/rtgui/pathutils.h b/rtgui/pathutils.h index 482dfb82f..8ac1533b7 100644 --- a/rtgui/pathutils.h +++ b/rtgui/pathutils.h @@ -1,4 +1,5 @@ -/* +/* -*- C++ -*- + * * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath @@ -18,7 +19,9 @@ */ #pragma once #include +#include // Removed from guiutils because used by rawtherapee-cli Glib::ustring removeExtension (const Glib::ustring& filename); Glib::ustring getExtension (const Glib::ustring& filename); +Glib::ustring fname_to_utf8(const std::string& fname); From 0421a0acfab8e0c2dc83ae72df3719a981509bd6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 29 Jun 2021 14:36:53 +0200 Subject: [PATCH 079/110] fixed bug in handling raw border Fixes 189 (cherry picked from commit 10df3c06c37a4eb6f38aae2f4a711798af0c4884) --- rtengine/rawimagesource.cc | 37 +++++++++---------------------------- rtengine/rawimagesource.h | 2 +- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 728d71b3a..77a07183a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1010,35 +1010,13 @@ void RawImageSource::convertColorSpace(Imagefloat* image, const ColorManagementP colorSpaceConversion (image, cmp, wb, pre_mul, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); } -void RawImageSource::getFullSize (int& w, int& h, int tr) +void RawImageSource::getFullSize(int& w, int& h, int tr) { - computeFullSize(ri, tr, w, h); - - // tr = defTransform(ri, tr); - - // if (fuji) { - // w = ri->get_FujiWidth() * 2 + 1; - // h = (H - ri->get_FujiWidth()) * 2 + 1; - // } else if (d1x) { - // w = W; - // h = 2 * H; - // } else { - // w = W; - // h = H; - // } - - // if ((tr & TR_ROT) == TR_R90 || (tr & TR_ROT) == TR_R270) { - // int tmp = w; - // w = h; - // h = tmp; - // } - - // w -= 2 * border; - // h -= 2 * border; + computeFullSize(ri, tr, w, h, border); } -void RawImageSource::computeFullSize(const RawImage *ri, int tr, int &w, int &h) +void RawImageSource::computeFullSize(const RawImage *ri, int tr, int &w, int &h, int border) { tr = defTransform(ri, tr); @@ -1046,7 +1024,10 @@ void RawImageSource::computeFullSize(const RawImage *ri, int tr, int &w, int &h) const int H = ri->get_height(); const bool fuji = ri->get_FujiWidth() != 0; const bool d1x = !ri->get_model().compare("D1X"); - const int border = (ri->getSensorType() == ST_BAYER ? 4 : (ri->getSensorType() == ST_FUJI_XTRANS ? 7 : 0)); + const int b = + border >= 0 ? border : + (ri->getSensorType() == ST_BAYER ? 4 : + (ri->getSensorType() == ST_FUJI_XTRANS ? 7 : 0)); if (fuji) { w = ri->get_FujiWidth() * 2 + 1; @@ -1065,8 +1046,8 @@ void RawImageSource::computeFullSize(const RawImage *ri, int tr, int &w, int &h) h = tmp; } - w -= 2 * border; - h -= 2 * border; + w -= 2 * b; + h -= 2 * b; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 9ef0086da..50b59e9dd 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -231,7 +231,7 @@ public: virtual float operator()(int row) const { return 1.f; } }; - static void computeFullSize(const RawImage *ri, int tr, int &w, int &h); + static void computeFullSize(const RawImage *ri, int tr, int &w, int &h, int border=-1); protected: typedef unsigned short ushort; From b8d25d542a4dae532001ed6e0f6342d2b865e670 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 5 Feb 2023 17:46:13 -0800 Subject: [PATCH 080/110] Fix crash reading Pentax metadata --- rtengine/imagedata.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 4dbc3f0a0..bf80f8c51 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -430,7 +430,6 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : ) { if (find_exif_tag("Exif.Pentax.DriveMode")) { std::string buf = pos->toString(3); - buf[3] = 0; if (buf == "HDR") { isHDR = true; #if PRINT_HDR_PS_DETECTION From e5904297864b95a02d93e955a6b3d14d87cccd94 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 11 Feb 2023 17:51:43 -0800 Subject: [PATCH 081/110] Remove outdated comment Issue #5787 in the Exiv2 branch is handled by commit 522f6f4. --- rtengine/imageio.cc | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 67b856092..9aa8a0702 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1152,23 +1152,6 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_ADOBE_DEFLATE); TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, (bps == 16 || bps == 32) && isFloat ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT); - /* - - TODO: Re-apply fix from #5787 - - [out]() - { - const std::vector default_tags = rtexif::ExifManager::getDefaultTIFFTags(nullptr); - - TIFFSetField (out, TIFFTAG_XRESOLUTION, default_tags[2]->toDouble()); - TIFFSetField (out, TIFFTAG_YRESOLUTION, default_tags[3]->toDouble()); - TIFFSetField (out, TIFFTAG_RESOLUTIONUNIT, default_tags[4]->toInt()); - - for (auto default_tag : default_tags) { - delete default_tag; - } - }();*/ - // somehow Exiv2 (tested with 0.27.3) doesn't seem to be able to update // XResolution and YResolution, so we do it ourselves here.... constexpr float default_resolution = 300.f; From 9c6dac5f25be4473610b2d30d5f5ab4f76605f31 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 11 Feb 2023 18:06:20 -0800 Subject: [PATCH 082/110] Remove outdated comments Validation of metadata is still needed for #5923. --- rtengine/imagedata.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index bf80f8c51..0ed5ab253 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -160,11 +160,11 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : // List of tag names taken from exiv2's printSummary() in actions.cpp if (find_tag(Exiv2::make)) { - make = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + make = validateUft8(pos->print(&exif)); } if (find_tag(Exiv2::model)) { - model = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + model = validateUft8(pos->print(&exif)); } if (make.size() > 0) { @@ -303,15 +303,15 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : } if (find_tag(Exiv2::lensName)) { - lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + lens = validateUft8(pos->print(&exif)); auto p = pos; if (find_exif_tag("Exif.CanonFi.RFLensType") && find_exif_tag("Exif.Canon.LensModel")) { - lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + lens = validateUft8(pos->print(&exif)); } else if (p->count() == 1 && lens == std::to_string(p->toLong())) { if (find_exif_tag("Exif.Canon.LensModel")) { - lens = validateUft8(pos->print(&exif)); // validateUft8 (#5923) still needed? + lens = validateUft8(pos->print(&exif)); } else if (find_exif_tag("Exif.Photo.LensModel")) { - lens = validateUft8(p->print(&exif)); // validateUft8 (#5923) still needed? + lens = validateUft8(p->print(&exif)); } } } else if (find_exif_tag("Exif.Photo.LensSpecification") && pos->count() == 4) { @@ -333,7 +333,7 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : if (fn_lo < fn_hi) { buf << "-" << fn_hi; } - lens = buf.str(); + lens = validateUft8(buf.str()); } if (lens.empty() || lens.find_first_not_of('-') == std::string::npos) { lens = "Unknown"; From cf545abc874c98e3578495b7e423ff850fac0553 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Feb 2023 17:10:00 -0800 Subject: [PATCH 083/110] Read serial number with Exiv2 --- rtengine/imagedata.cc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 0ed5ab253..4c4d4112b 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -264,6 +264,44 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : } } + if (find_tag(Exiv2::serialNumber)) { + serial = validateUft8(pos->toString()); + } else { + const std::vector serial_number_tags{ + "Exif.Photo.BodySerialNumber", + "Exif.Canon.SerialNumber", + "Exif.Fujifilm.SerialNumber", + "Exif.Nikon3.SerialNumber", + "Exif.Nikon3.SerialNO", + "Exif.Olympus.SerialNumber2", + "Exif.OlympusEq.SerialNumber", + "Exif.Pentax.SerialNumber", + "Exif.PentaxDng.SerialNumber", + "Exif.Sigma.SerialNumber", + "Exif.Canon.InternalSerialNumber", + "Exif.OlympusEq.InternalSerialNumber", + "Exif.Panasonic.InternalSerialNumber", + }; + if (serial_number_tags.cend() != std::find_if(serial_number_tags.cbegin(), serial_number_tags.cend(), find_exif_tag)) { + serial = validateUft8(pos->toString()); + } else if (find_exif_tag("Exif.Minolta.WBInfoA100") || find_exif_tag("Exif.SonyMinolta.WBInfoA100")) { + const long index = 18908; + const int length = 12; + if (pos->count() >= index + length) { + for (int i = 0; i < length; ++i) { + serial += static_cast(pos->toLong(index + i)); + } + serial = validateUft8(serial); + } + } else if (find_exif_tag("Exif.Pentax.CameraInfo") || find_exif_tag("Exif.PentaxDng.CameraInfo")) { + const long index = 4; + if (pos->count() >= index) { + serial = validateUft8(pos->toString(index)); + } + } + // TODO: Serial number from tags not supported by Exiv2. + } + if (find_tag(Exiv2::focalLength)) { // This works around a bug in exiv2 the developers refuse to fix // For details see http://dev.exiv2.org/issues/1083 From cac76c18c0672166e8e6ab76e5bf1562d428ada8 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Feb 2023 17:47:07 -0800 Subject: [PATCH 084/110] Re-introduce UTF-8 validation for EXIF panel --- rtgui/exifpanel.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 0664132f6..487635f5b 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -194,13 +194,10 @@ void ExifPanel::setImageData (const FramesMetaData* id) idata = id; } -void ExifPanel::addTag(const std::string &key, const std::pair &label, const Glib::ustring &value, bool editable, bool edited) +void ExifPanel::addTag(const std::string &key, const std::pair &label, const Glib::ustring &exifValue, bool editable, bool edited) { - // TODO Re-fix #5923 if necessary - //if (!value.validate()) { - // value = "???"; - //} + const Glib::ustring& value = exifValue.validate() ? exifValue : "???"; // auto root = exifTreeModel->children(); From a329e423ec6086b84b3a6d3b2c0ec25fbb51d066 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Feb 2023 18:19:28 -0800 Subject: [PATCH 085/110] Remove outdated comments about ratings --- rtengine/imagedata.cc | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 4c4d4112b..4e5022973 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -88,7 +88,7 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : make("Unknown"), model("Unknown"), orientation("Unknown"), - rating(0), // FIXME: Implement + rating(0), lens("Unknown"), sampleFormat(IIOSF_UNKNOWN), isPixelShift(false), @@ -196,27 +196,6 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : } } - /* - TODO: Implement ratings in exiv2 situations. See PR #5325 - - // Look for Rating metadata in the following order: - // 1. EXIF - // 2. XMP - // 3. pp3 sidecar file - tag = newFrameRootDir->findTagUpward("Rating"); - if (tag && tag->toInt() != 0) { - rating = tag->toInt(); - } - char sXMPRating[64]; - if (newFrameRootDir->getXMPTagValue("xmp:Rating", sXMPRating)) { - // Guard against out-of-range values (<0, >5) - rating = rtengine::max(0, rtengine::min(5, atoi(sXMPRating))); - // Currently, Rating=-1 is not supported. A value of -1 should mean - // "Rejected" according to the specification. Maybe in the future, Rating=-1 - // sets InTrash=true? - } - */ - std::string::size_type nonspace_pos = make.find_last_not_of(' '); if (nonspace_pos != std::string::npos && nonspace_pos + 1 < make.size()) { make.erase(nonspace_pos + 1); From 8704c1dd8655e43abfd0631e5bcd66e7fb1c1314 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Wed, 15 Feb 2023 21:34:03 -0800 Subject: [PATCH 086/110] Add bound check Thanks to Floessie (https://github.com/Beep6581/RawTherapee/pull/5889#discussion_r622755925) --- rtengine/dcp.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 1f9de0158..29d3625a2 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -650,13 +650,16 @@ public: } case FLOAT: { - union IntFloat { - std::uint32_t i; - float f; - } conv; + if (offset + 3 < tag->second.value.size()) { + union IntFloat { + std::uint32_t i; + float f; + } conv; - conv.i = sget4(tag->second.value.data() + offset); - return conv.f; // IEEE FLOATs are already C format, they just need a recast + conv.i = sget4(tag->second.value.data() + offset); + return conv.f; // IEEE FLOATs are already C format, they just need a recast + } + return 0.0; } default: { From 1bacb8b5b0b43e01b8c9e950915c5ba3fe379f83 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 18 Feb 2023 12:10:41 -0800 Subject: [PATCH 087/110] Add Exiv2 to GitHub Actions workflows --- .github/workflows/appimage.yml | 19 ++++++++++++++++++- .github/workflows/codeql.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/windows.yml | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index cc0d16b8f..ec724c379 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -28,7 +28,21 @@ jobs: echo "Running apt update." sudo apt update echo "Installing dependencies with apt." - DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin + DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin libexpat1-dev libbrotli-dev zlib1g-dev + + - name: Install Exiv2 + run: | + EXIV2_VERSION='v0.27.6' + echo "Cloning Exiv2 $EXIV2_VERSION." + git clone --depth 1 --branch "$EXIV2_VERSION" https://github.com/Exiv2/exiv2.git ext/exiv2 + + echo "Configuring build." + mkdir ext/exiv2/build + cd ext/exiv2/build + cmake -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_BMFF=ON .. + + echo "Building and installing." + sudo make -j$(nproc) install - name: Configure build run: | @@ -111,6 +125,9 @@ jobs: - name: Package AppImage working-directory: ./build run: | + echo "LD_LIBRARY_PATH is '$LD_LIBRARY_PATH'. Adding /usr/local/lib." + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" + echo "Creating artifact name." if [ '${{github.ref_type}}' == 'tag' ]; then ARTIFACT_NAME="RawTherapee_${REF_NAME_FILTERED}_${{matrix.build_type}}" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b90d30e27..d3b3244b4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -35,7 +35,7 @@ jobs: echo "Running apt update." sudo apt update echo "Installing dependencies with apt." - DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin + DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin libexiv2-dev - name: Configure build run: | diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 11ae28aa4..7b0df3ac3 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -21,7 +21,7 @@ jobs: mkdir build date +%s > build/stamp brew uninstall --ignore-dependencies libtiff - brew install libtiff gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++@2 little-cms2 libiptcdata fftw lensfun expat pkgconfig llvm shared-mime-info | tee -a depslog + brew install libtiff gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++@2 little-cms2 libiptcdata fftw lensfun expat pkgconfig llvm shared-mime-info exiv2 | tee -a depslog date -u echo "----====Pourage====----" cat depslog | grep Pouring diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ab81edec6..3b9791865 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -45,6 +45,7 @@ jobs: mingw-w64-x86_64-fftw mingw-w64-x86_64-lensfun mingw-w64-x86_64-libiptcdata + mingw-w64-x86_64-exiv2 - name: Configure build run: | From 006a7d9975daea025eb809b1ed5b33aceebc083d Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 18 Feb 2023 18:16:12 -0800 Subject: [PATCH 088/110] Fix CodeQL alert --- rtengine/dcp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 29d3625a2..76dfeff5c 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -773,7 +773,7 @@ private: const std::size_t saved_position = std::ftell(file_) + 4; // Load value field (possibly seek before) - const std::size_t value_size = tag.count * getTypeSize(tag.type); + const std::size_t value_size = static_cast(tag.count) * getTypeSize(tag.type); if (value_size > 4) { if (std::fseek(file_, get4(), SEEK_SET) == -1) { From 1e6cc85fe2bfd2c765d143e63a5a7cdf0ba151d0 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 18 Mar 2023 18:15:38 -0700 Subject: [PATCH 089/110] Add missing includes Thanks to Benitoite (https://github.com/Beep6581/RawTherapee/pull/5889#issuecomment-1475033091) --- rtengine/imagedata.cc | 7 ++++--- rtengine/imageio.cc | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 4e5022973..73c51b103 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -17,19 +17,20 @@ * along with RawTherapee. If not, see . */ #include +#include +#include +#include #include #include #include #include #include -#include -#include #include "imagedata.h" #include "imagesource.h" -#include "rt_math.h" #include "metadata.h" +#include "rt_math.h" #include "utils.h" #pragma GCC diagnostic warning "-Wextra" diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 5748ef085..0388467be 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include From da1c258057bbd4fe440b183ba1792a63f676e627 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:03:46 -0700 Subject: [PATCH 090/110] Enable publishing of metadata-exiv2 builds --- .github/workflows/appimage.yml | 2 +- .github/workflows/windows.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 2f0e0b3e5..bbeb09e0d 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -11,7 +11,7 @@ on: - dev workflow_dispatch: env: - publish_pre_dev_labels: '[]' + publish_pre_dev_labels: '["Beep6581:metadata-exiv2"]' jobs: build: runs-on: ubuntu-18.04 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index dcdec99d7..d50dca59d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -11,7 +11,7 @@ on: - dev workflow_dispatch: env: - publish_pre_dev_labels: '[]' + publish_pre_dev_labels: '["Beep6581:metadata-exiv2"]' jobs: build: runs-on: windows-2022 From 294c6167ae5d7bc3b899a96c10b7bc46087be913 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 26 Mar 2023 16:08:13 -0700 Subject: [PATCH 091/110] Add missing DLL to Windows build Exiv2 and dependent libraries were missing. --- .github/workflows/windows.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d50dca59d..b9a4a0b35 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -119,9 +119,12 @@ jobs: "libcairo-2.dll" \ "libcairo-gobject-2.dll" \ "libcairomm-1.0-1.dll" \ + "libcrypto-3-x64.dll" \ + "libcurl-4.dll" \ "libdatrie-1.dll" \ "libdeflate.dll" \ "libepoxy-0.dll" \ + "libexiv2.dll" \ "libexpat-1.dll" \ libffi-*.dll \ "libfftw3f-3.dll" \ @@ -145,6 +148,7 @@ jobs: "libgtkmm-3.0-1.dll" \ "libharfbuzz-0.dll" \ "libiconv-2.dll" \ + "libidn2-0.dll" \ "libintl-8.dll" \ "libjbig-0.dll" \ "libjpeg-8.dll" \ @@ -152,6 +156,7 @@ jobs: "liblensfun.dll" \ "libLerc.dll" \ "liblzma-5.dll" \ + "libnghttp2-14.dll" \ "libpango-1.0-0.dll" \ "libpangocairo-1.0-0.dll" \ "libpangoft2-1.0-0.dll" \ @@ -160,14 +165,18 @@ jobs: "libpcre2-8-0.dll" \ "libpixman-1-0.dll" \ "libpng16-16.dll" \ + "libpsl-5.dll" \ "librsvg-2-2.dll" \ "libsharpyuv-0.dll" \ "libsigc-2.0-0.dll" \ + "libssh2-1.dll" \ + "libssl-3-x64.dll" \ "libstdc++-6.dll" \ "libsystre-0.dll" \ "libthai-0.dll" \ "libtiff-6.dll" \ "libtre-5.dll" \ + "libunistring-5.dll" \ "libwebp-7.dll" \ "libwinpthread-1.dll" \ "libxml2-2.dll" \ From 533a05cd9d3d17a818fac10d71dbea76fa3ccf2f Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 Apr 2023 16:59:24 -0700 Subject: [PATCH 092/110] Get lens name from Nikon Z series images --- rtengine/imagedata.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 73c51b103..636838548 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -320,7 +320,9 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : //orientation = pos->print(&exif); } - if (find_tag(Exiv2::lensName)) { + if (find_exif_tag("Exif.NikonLd4.LensIDNumber")) { + lens = validateUft8(pos->print(&exif)); + } else if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); auto p = pos; if (find_exif_tag("Exif.CanonFi.RFLensType") && find_exif_tag("Exif.Canon.LensModel")) { From 30025d2ac2e0e30cf4a38fab1485d35e31483056 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 Apr 2023 17:22:10 -0700 Subject: [PATCH 093/110] Get Sony image lens from Sony lens ID tag --- rtengine/imagedata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 636838548..c3b177734 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -320,7 +320,7 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : //orientation = pos->print(&exif); } - if (find_exif_tag("Exif.NikonLd4.LensIDNumber")) { + if (find_exif_tag("Exif.NikonLd4.LensIDNumber") || find_exif_tag("Exif.Sony2.LensID")) { lens = validateUft8(pos->print(&exif)); } else if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); From 0bbcea8806e0f0e97d8b19953e8f070a595c026d Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 Apr 2023 23:43:10 -0700 Subject: [PATCH 094/110] Fix Nikon Z series lens identification --- rtengine/imagedata.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index c3b177734..9bf1b1210 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -320,7 +320,9 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : //orientation = pos->print(&exif); } - if (find_exif_tag("Exif.NikonLd4.LensIDNumber") || find_exif_tag("Exif.Sony2.LensID")) { + if ((find_exif_tag("Exif.NikonLd4.LensID") && pos->toLong()) || + (find_exif_tag("Exif.NikonLd4.LensIDNumber") && pos->toLong()) || + (find_exif_tag("Exif.Sony2.LensID") && pos->toLong())) { lens = validateUft8(pos->print(&exif)); } else if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); From ab79a4fc3e2d5d94fa70f79a9b135a27d90c6a4c Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:08:54 -0700 Subject: [PATCH 095/110] Refine lens name reading for Nikon Z and Sony Fall back to other EXIF tags in case Exiv2 cannot interpret the lens ID. --- rtengine/imagedata.cc | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 9bf1b1210..168177876 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -320,10 +320,33 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : //orientation = pos->print(&exif); } - if ((find_exif_tag("Exif.NikonLd4.LensID") && pos->toLong()) || - (find_exif_tag("Exif.NikonLd4.LensIDNumber") && pos->toLong()) || - (find_exif_tag("Exif.Sony2.LensID") && pos->toLong())) { - lens = validateUft8(pos->print(&exif)); + if (!make.compare(0, 5, "NIKON")) { + if (find_exif_tag("Exif.NikonLd4.LensID")) { + if (!pos->toLong()) { // No data, look in LensIDNumber. + const auto p = pos; + if (!find_exif_tag("Exif.NikonLd4.LensIDNumber")) { + pos = p; // Tag not found, so reset pos. + } + } + lens = pos->print(&exif); + if (lens == std::to_string(pos->toLong())) { // Not known to Exiv2. + lens.clear(); + } else { + lens = validateUft8(lens); + } + } + } else if (!make.compare(0, 4, "SONY")) { + if (find_exif_tag("Exif.Sony2.LensID") && pos->toLong()) { + lens = pos->print(&exif); + if (lens == std::to_string(pos->toLong())) { // Not know to Exiv2. + lens.clear(); + } else { + lens = validateUft8(lens); + } + } + } + if (!lens.empty()) { + // Already found the lens name. } else if (find_tag(Exiv2::lensName)) { lens = validateUft8(pos->print(&exif)); auto p = pos; From f5dba61243611dfa580a5cf42164653d8d147d52 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 29 Apr 2023 18:43:38 -0700 Subject: [PATCH 096/110] Allow Lensfun DB dir editing from preferences Also refactor the file chooser button widget to share code with the file chooser entry. Use our own folder icon instead of the system one. --- rtdata/languages/default | 1 + rtgui/guiutils.cc | 387 +++++++++++++++++++++++---------------- rtgui/guiutils.h | 80 +++++--- rtgui/preferences.cc | 58 +++--- rtgui/preferences.h | 7 +- 5 files changed, 314 insertions(+), 219 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 45471bb5c..8fa85f144 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1913,6 +1913,7 @@ PREFERENCES_INTENT_SATURATION;Saturation PREFERENCES_INTERNALTHUMBIFUNTOUCHED;Show embedded JPEG thumbnail if raw is unedited PREFERENCES_LANG;Language PREFERENCES_LANGAUTODETECT;Use system language +PREFERENCES_LENSFUNDBDIR;Lensfun database directory PREFERENCES_LENSPROFILESDIR;Lens profiles directory PREFERENCES_MAXRECENTFOLDERS;Maximum number of recent folders PREFERENCES_MENUGROUPEXTPROGS;Group 'Open with' diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 18b82fe36..3581097ed 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1299,23 +1299,201 @@ bool MyHScale::on_key_press_event (GdkEventKey* event) } } -MyFileChooserButton::MyFileChooserButton(const Glib::ustring &title, Gtk::FileChooserAction action): - title_(title), - action_(action), - lbl_("", Gtk::ALIGN_START), - show_hidden_(false) +class MyFileChooserWidget::Impl { - lbl_.set_ellipsize(Pango::ELLIPSIZE_MIDDLE); - lbl_.set_justify(Gtk::JUSTIFY_LEFT); - set_none(); - box_.pack_start(lbl_, true, true); - Gtk::Image *img = Gtk::manage(new Gtk::Image()); - img->set_from_icon_name("folder-open", Gtk::ICON_SIZE_BUTTON); - box_.pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), false, false, 5); - box_.pack_start(*img, false, false); - box_.show_all_children(); - add(box_); - signal_clicked().connect(sigc::mem_fun(*this, &MyFileChooserButton::show_chooser)); +public: + Impl(const Glib::ustring &title, Gtk::FileChooserAction action) : + title_(title), + action_(action) + { + } + + Glib::ustring title_; + Gtk::FileChooserAction action_; + std::string filename_; + std::string current_folder_; + std::vector> file_filters_; + Glib::RefPtr cur_filter_; + std::vector shortcut_folders_; + bool show_hidden_{false}; + sigc::signal selection_changed_; +}; + + +MyFileChooserWidget::MyFileChooserWidget(const Glib::ustring &title, Gtk::FileChooserAction action) : + pimpl(new Impl(title, action)) +{ +} + + +std::unique_ptr MyFileChooserWidget::make_folder_image() +{ + return std::unique_ptr(new RTImage("folder-open-small.png")); +} + +void MyFileChooserWidget::show_chooser(Gtk::Widget *parent) +{ + Gtk::FileChooserDialog dlg(getToplevelWindow(parent), pimpl->title_, pimpl->action_); + dlg.add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); + dlg.add_button(M(pimpl->action_ == Gtk::FILE_CHOOSER_ACTION_SAVE ? "GENERAL_SAVE" : "GENERAL_OPEN"), Gtk::RESPONSE_OK); + dlg.set_filename(pimpl->filename_); + for (auto &f : pimpl->file_filters_) { + dlg.add_filter(f); + } + if (pimpl->cur_filter_) { + dlg.set_filter(pimpl->cur_filter_); + } + for (auto &f : pimpl->shortcut_folders_) { + dlg.add_shortcut_folder(f); + } + if (!pimpl->current_folder_.empty()) { + dlg.set_current_folder(pimpl->current_folder_); + } + dlg.set_show_hidden(pimpl->show_hidden_); + int res = dlg.run(); + if (res == Gtk::RESPONSE_OK) { + pimpl->filename_ = dlg.get_filename(); + pimpl->current_folder_ = dlg.get_current_folder(); + on_filename_set(); + pimpl->selection_changed_.emit(); + } +} + + +void MyFileChooserWidget::on_filename_set() +{ + // Sub-classes decide if anything needs to be done. +} + + +sigc::signal &MyFileChooserWidget::signal_selection_changed() +{ + return pimpl->selection_changed_; +} + + +sigc::signal &MyFileChooserWidget::signal_file_set() +{ + return pimpl->selection_changed_; +} + + +std::string MyFileChooserWidget::get_filename() const +{ + return pimpl->filename_; +} + + +bool MyFileChooserWidget::set_filename(const std::string &filename) +{ + pimpl->filename_ = filename; + on_filename_set(); + return true; +} + + +void MyFileChooserWidget::add_filter(const Glib::RefPtr &filter) +{ + pimpl->file_filters_.push_back(filter); +} + + +void MyFileChooserWidget::remove_filter(const Glib::RefPtr &filter) +{ + auto it = std::find(pimpl->file_filters_.begin(), pimpl->file_filters_.end(), filter); + if (it != pimpl->file_filters_.end()) { + pimpl->file_filters_.erase(it); + } +} + + +void MyFileChooserWidget::set_filter(const Glib::RefPtr &filter) +{ + pimpl->cur_filter_ = filter; +} + + +std::vector> MyFileChooserWidget::list_filters() const +{ + return pimpl->file_filters_; +} + + +bool MyFileChooserWidget::set_current_folder(const std::string &filename) +{ + pimpl->current_folder_ = filename; + if (pimpl->action_ == Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) { + set_filename(filename); + } + return true; +} + +std::string MyFileChooserWidget::get_current_folder() const +{ + return pimpl->current_folder_; +} + + +bool MyFileChooserWidget::add_shortcut_folder(const std::string &folder) +{ + pimpl->shortcut_folders_.push_back(folder); + return true; +} + + +bool MyFileChooserWidget::remove_shortcut_folder(const std::string &folder) +{ + auto it = std::find(pimpl->shortcut_folders_.begin(), pimpl->shortcut_folders_.end(), folder); + if (it != pimpl->shortcut_folders_.end()) { + pimpl->shortcut_folders_.erase(it); + } + return true; +} + + +void MyFileChooserWidget::unselect_all() +{ + pimpl->filename_ = ""; + on_filename_set(); +} + + +void MyFileChooserWidget::unselect_filename(const std::string &filename) +{ + if (pimpl->filename_ == filename) { + unselect_all(); + } +} + + +void MyFileChooserWidget::set_show_hidden(bool yes) +{ + pimpl->show_hidden_ = yes; +} + + +class MyFileChooserButton::Impl +{ +public: + Gtk::Box box_; + Gtk::Label lbl_{"", Gtk::ALIGN_START}; +}; + +MyFileChooserButton::MyFileChooserButton(const Glib::ustring &title, Gtk::FileChooserAction action): + MyFileChooserWidget(title, action), + pimpl(new Impl()) +{ + pimpl->lbl_.set_ellipsize(Pango::ELLIPSIZE_MIDDLE); + pimpl->lbl_.set_justify(Gtk::JUSTIFY_LEFT); + on_filename_set(); + pimpl->box_.pack_start(pimpl->lbl_, true, true); + pimpl->box_.pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), false, false, 5); + pimpl->box_.pack_start(*Gtk::manage(make_folder_image().release()), false, false); + pimpl->box_.show_all_children(); + add(pimpl->box_); + signal_clicked().connect([this]() { + show_chooser(this); + }); if (GTK_MINOR_VERSION < 20) { set_border_width(2); // margin doesn't work on GTK < 3.20 @@ -1324,151 +1502,16 @@ MyFileChooserButton::MyFileChooserButton(const Glib::ustring &title, Gtk::FileCh set_name("MyFileChooserButton"); } - -void MyFileChooserButton::show_chooser() +void MyFileChooserButton::on_filename_set() { - Gtk::FileChooserDialog dlg(getToplevelWindow(this), title_, action_); - dlg.add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); - dlg.add_button(M(action_ == Gtk::FILE_CHOOSER_ACTION_SAVE ? "GENERAL_SAVE" : "GENERAL_OPEN"), Gtk::RESPONSE_OK); - dlg.set_filename(filename_); - for (auto &f : file_filters_) { - dlg.add_filter(f); - } - if (cur_filter_) { - dlg.set_filter(cur_filter_); - } - for (auto &f : shortcut_folders_) { - dlg.add_shortcut_folder(f); - } - if (!current_folder_.empty()) { - dlg.set_current_folder(current_folder_); - } - dlg.set_show_hidden(show_hidden_); - int res = dlg.run(); - if (res == Gtk::RESPONSE_OK) { - filename_ = dlg.get_filename(); - current_folder_ = dlg.get_current_folder(); - lbl_.set_label(Glib::path_get_basename(filename_)); - selection_changed_.emit(); - } -} - - -sigc::signal &MyFileChooserButton::signal_selection_changed() -{ - return selection_changed_; -} - - -sigc::signal &MyFileChooserButton::signal_file_set() -{ - return selection_changed_; -} - - -std::string MyFileChooserButton::get_filename() const -{ - return filename_; -} - - -bool MyFileChooserButton::set_filename(const std::string &filename) -{ - filename_ = filename; - if (Glib::file_test(filename_, Glib::FILE_TEST_EXISTS)) { - lbl_.set_label(Glib::path_get_basename(filename_)); + if (Glib::file_test(get_filename(), Glib::FILE_TEST_EXISTS)) { + pimpl->lbl_.set_label(Glib::path_get_basename(get_filename())); } else { - set_none(); - } - return true; -} - - -void MyFileChooserButton::add_filter(const Glib::RefPtr &filter) -{ - file_filters_.push_back(filter); -} - - -void MyFileChooserButton::remove_filter(const Glib::RefPtr &filter) -{ - auto it = std::find(file_filters_.begin(), file_filters_.end(), filter); - if (it != file_filters_.end()) { - file_filters_.erase(it); + pimpl->lbl_.set_label(Glib::ustring("(") + M("GENERAL_NONE") + ")"); } } -void MyFileChooserButton::set_filter(const Glib::RefPtr &filter) -{ - cur_filter_ = filter; -} - - -std::vector> MyFileChooserButton::list_filters() -{ - return file_filters_; -} - - -bool MyFileChooserButton::set_current_folder(const std::string &filename) -{ - current_folder_ = filename; - if (action_ == Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) { - set_filename(filename); - } - return true; -} - -std::string MyFileChooserButton::get_current_folder() const -{ - return current_folder_; -} - - -bool MyFileChooserButton::add_shortcut_folder(const std::string &folder) -{ - shortcut_folders_.push_back(folder); - return true; -} - - -bool MyFileChooserButton::remove_shortcut_folder(const std::string &folder) -{ - auto it = std::find(shortcut_folders_.begin(), shortcut_folders_.end(), folder); - if (it != shortcut_folders_.end()) { - shortcut_folders_.erase(it); - } - return true; -} - - -void MyFileChooserButton::unselect_all() -{ - filename_ = ""; - set_none(); -} - - -void MyFileChooserButton::unselect_filename(const std::string &filename) -{ - if (filename_ == filename) { - unselect_all(); - } -} - - -void MyFileChooserButton::set_show_hidden(bool yes) -{ - show_hidden_ = yes; -} - - -void MyFileChooserButton::set_none() -{ - lbl_.set_label(Glib::ustring("(") + M("GENERAL_NONE") + ")"); -} - // For an unknown reason (a bug ?), it doesn't work when action = FILE_CHOOSER_ACTION_SELECT_FOLDER ! bool MyFileChooserButton::on_scroll_event (GdkEventScroll* event) { @@ -1493,6 +1536,40 @@ void MyFileChooserButton::get_preferred_width_for_height_vfunc (int height, int } +class MyFileChooserEntry::Impl +{ +public: + Gtk::Entry entry; + Gtk::Button file_chooser_button; +}; + + +MyFileChooserEntry::MyFileChooserEntry(const Glib::ustring &title, Gtk::FileChooserAction action) : + MyFileChooserWidget(title, action), + pimpl(new Impl()) +{ + pimpl->file_chooser_button.set_image(*Gtk::manage(make_folder_image().release())); + pimpl->file_chooser_button.signal_clicked().connect([this]() { + const auto &filename = pimpl->entry.get_text(); + if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { + set_current_folder(filename); + } + set_filename(filename); + show_chooser(this); + }); + + pack_start(pimpl->entry, true, true); + pack_start(pimpl->file_chooser_button, false, false); +} + + +void MyFileChooserEntry::on_filename_set() +{ + if (pimpl->entry.get_text() != get_filename()) { + pimpl->entry.set_text(get_filename()); + } +} + TextOrIcon::TextOrIcon (const Glib::ustring &fname, const Glib::ustring &labelTx, const Glib::ustring &tooltipTx) { diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 152b626de..58877aed4 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -396,34 +396,10 @@ protected: }; -/** - * @brief subclass of Gtk::FileChooserButton in order to handle the scrollwheel - */ -class MyFileChooserButton final : public Gtk::Button { -private: - void show_chooser(); - - Glib::ustring title_; - Gtk::FileChooserAction action_; - Gtk::Box box_; - Gtk::Label lbl_; - std::string filename_; - std::string current_folder_; - std::vector> file_filters_; - Glib::RefPtr cur_filter_; - std::vector shortcut_folders_; - bool show_hidden_; - sigc::signal selection_changed_; - -protected: - bool on_scroll_event (GdkEventScroll* event) override; - void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; - void get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const override; - - void set_none(); - +class MyFileChooserWidget +{ public: - explicit MyFileChooserButton(const Glib::ustring &title, Gtk::FileChooserAction action=Gtk::FILE_CHOOSER_ACTION_OPEN); + virtual ~MyFileChooserWidget() = default; sigc::signal &signal_selection_changed(); sigc::signal &signal_file_set(); @@ -434,7 +410,7 @@ public: void add_filter(const Glib::RefPtr &filter); void remove_filter(const Glib::RefPtr &filter); void set_filter(const Glib::RefPtr &filter); - std::vector> list_filters(); + std::vector> list_filters() const; bool set_current_folder(const std::string &filename); std::string get_current_folder() const; @@ -446,6 +422,54 @@ public: void unselect_filename(const std::string &filename); void set_show_hidden(bool yes); + +protected: + explicit MyFileChooserWidget(const Glib::ustring &title, Gtk::FileChooserAction action=Gtk::FILE_CHOOSER_ACTION_OPEN); + + static std::unique_ptr make_folder_image(); + + void show_chooser(Gtk::Widget *parent); + virtual void on_filename_set(); + +private: + class Impl; + + std::unique_ptr pimpl; +}; + +/** + * @brief subclass of Gtk::FileChooserButton in order to handle the scrollwheel + */ +class MyFileChooserButton final : public Gtk::Button, public MyFileChooserWidget +{ +private: + class Impl; + + std::unique_ptr pimpl; + +protected: + bool on_scroll_event (GdkEventScroll* event) override; + void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; + void get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const override; + + void on_filename_set() override; + +public: + explicit MyFileChooserButton(const Glib::ustring &title, Gtk::FileChooserAction action=Gtk::FILE_CHOOSER_ACTION_OPEN); +}; + +class MyFileChooserEntry : public Gtk::Box, public MyFileChooserWidget +{ +public: + explicit MyFileChooserEntry(const Glib::ustring &title, Gtk::FileChooserAction action = Gtk::FILE_CHOOSER_ACTION_OPEN); + +protected: + void on_filename_set() override; + +private: + class Impl; + + std::unique_ptr pimpl; }; /** diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 1ae01da2d..1e652faf4 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -667,7 +667,19 @@ Gtk::Widget* Preferences::getImageProcessingPanel () dirgrid->attach_next_to(*lensProfilesDirLabel, *cameraProfilesDirLabel, Gtk::POS_BOTTOM, 1, 1); dirgrid->attach_next_to(*lensProfilesDir, *lensProfilesDirLabel, Gtk::POS_RIGHT, 1, 1); - //Pack directories to Image Processing panel + // Lensfun DB dir + Gtk::Label *lensfunDbDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LENSFUNDBDIR") + ":")); + setExpandAlignProperties(lensfunDbDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + lensfunDbDir = Gtk::manage(new MyFileChooserEntry(M("PREFERENCES_LENSFUNDBDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(lensfunDbDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + Gtk::Label* lensfunDbDirRestartNeededLabel = Gtk::manage(new Gtk::Label(Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); + setExpandAlignProperties(lensfunDbDirRestartNeededLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + + dirgrid->attach_next_to(*lensfunDbDirLabel, *lensProfilesDirLabel, Gtk::POS_BOTTOM, 1, 1); + dirgrid->attach_next_to(*lensfunDbDir, *lensfunDbDirLabel, Gtk::POS_RIGHT, 1, 1); + dirgrid->attach_next_to(*lensfunDbDirRestartNeededLabel, *lensfunDbDir, Gtk::POS_RIGHT, 1, 1); + + //Pack directories to Image Processing panel cdf->add(*dirgrid); vbImageProcessing->pack_start (*cdf, Gtk::PACK_SHRINK, 4 ); @@ -1315,10 +1327,7 @@ Gtk::Widget* Preferences::getFileBrowserPanel() sdlast = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRLAST"))); sdhome = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRHOME"))); sdother = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIROTHER") + ": ")); - startupdir = Gtk::manage(new Gtk::Entry()); - - Gtk::Button* sdselect = Gtk::manage(new Gtk::Button()); - sdselect->set_image (*Gtk::manage (new RTImage ("folder-open-small.png"))); + startupdir = Gtk::manage(new MyFileChooserEntry(M("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); Gtk::RadioButton::Group opts = sdcurrent->get_group(); sdlast->set_group(opts); @@ -1332,14 +1341,11 @@ Gtk::Widget* Preferences::getFileBrowserPanel() Gtk::Box* otherbox = Gtk::manage(new Gtk::Box()); otherbox->pack_start(*sdother, Gtk::PACK_SHRINK); otherbox->pack_start(*startupdir); - otherbox->pack_end(*sdselect, Gtk::PACK_SHRINK, 4); vbsd->pack_start(*otherbox, Gtk::PACK_SHRINK, 0); fsd->add(*vbsd); vbFileBrowser->pack_start (*fsd, Gtk::PACK_SHRINK, 4); - sdselect->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::selectStartupDir)); - //--- @@ -1839,7 +1845,7 @@ void Preferences::storePreferences() moptions.startupDir = STARTUPDIR_LAST; } else if (sdother->get_active()) { moptions.startupDir = STARTUPDIR_CUSTOM; - moptions.startupPath = startupdir->get_text(); + moptions.startupPath = startupdir->get_filename(); } moptions.parseExtensions.clear(); @@ -1868,8 +1874,9 @@ void Preferences::storePreferences() moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename(); moptions.clutsDir = clutsDir->get_filename(); - moptions.rtSettings.cameraProfilesPath = cameraProfilesDir->get_filename(); - moptions.rtSettings.lensProfilesPath = lensProfilesDir->get_filename(); + moptions.rtSettings.cameraProfilesPath = cameraProfilesDir->get_filename(); + moptions.rtSettings.lensProfilesPath = lensProfilesDir->get_filename(); + moptions.rtSettings.lensfunDbDirectory = lensfunDbDir->get_filename(); moptions.baBehav.resize(ADDSET_PARAM_NUM); @@ -2065,7 +2072,7 @@ void Preferences::fillPreferences() sdhome->set_active(); } else if (moptions.startupDir == STARTUPDIR_CUSTOM) { sdother->set_active(); - startupdir->set_text(moptions.startupPath); + startupdir->set_current_folder(moptions.startupPath); } extensionModel->clear(); @@ -2125,10 +2132,12 @@ void Preferences::fillPreferences() flatFieldChanged(); clutsDir->set_current_folder(moptions.clutsDir); - - cameraProfilesDir->set_current_folder(moptions.rtSettings.cameraProfilesPath); - - lensProfilesDir->set_current_folder(moptions.rtSettings.lensProfilesPath); + + cameraProfilesDir->set_current_folder(moptions.rtSettings.cameraProfilesPath); + + lensProfilesDir->set_current_folder(moptions.rtSettings.lensProfilesPath); + + lensfunDbDir->set_current_folder(moptions.rtSettings.lensfunDbDirectory); addc.block(true); setc.block(true); @@ -2257,23 +2266,6 @@ void Preferences::cancelPressed() hide(); } -void Preferences::selectStartupDir() -{ - - Gtk::FileChooserDialog dialog(getToplevelWindow(this), M("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); - //dialog.set_transient_for(*this); - - //Add response buttons to the dialog: - dialog.add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); - dialog.add_button(M("GENERAL_OPEN"), Gtk::RESPONSE_OK); - - int result = dialog.run(); - - if (result == Gtk::RESPONSE_OK) { - startupdir->set_text(dialog.get_filename()); - } -} - void Preferences::aboutPressed() { diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 6e31761a4..821842773 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -92,7 +92,7 @@ class Preferences final : Gtk::ComboBoxText* languages; Gtk::CheckButton* ckbLangAutoDetect; Gtk::Entry* dateformat; - Gtk::Entry* startupdir; + MyFileChooserEntry* startupdir; Gtk::RadioButton* sdcurrent; Gtk::RadioButton* sdlast; Gtk::RadioButton* sdhome; @@ -115,8 +115,9 @@ class Preferences final : MyFileChooserButton* darkFrameDir; MyFileChooserButton* flatFieldDir; MyFileChooserButton* clutsDir; - MyFileChooserButton* cameraProfilesDir; - MyFileChooserButton* lensProfilesDir; + MyFileChooserButton* cameraProfilesDir; + MyFileChooserButton* lensProfilesDir; + MyFileChooserEntry* lensfunDbDir; Gtk::Label *dfLabel; Gtk::Label *ffLabel; From 45a3b36b3aadbaa3adbbedbc47738467c5bd6501 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 Apr 2023 12:30:46 -0700 Subject: [PATCH 097/110] Fix file chooser entry not updating Save file name while it is typed in the text entry. Add placeholder text for Lensfun database directory to indicate automatic detection if left blank. --- rtgui/guiutils.cc | 21 +++++++++++++++++++-- rtgui/guiutils.h | 3 +++ rtgui/preferences.cc | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 3581097ed..a0317d226 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1548,13 +1548,18 @@ MyFileChooserEntry::MyFileChooserEntry(const Glib::ustring &title, Gtk::FileChoo MyFileChooserWidget(title, action), pimpl(new Impl()) { + const auto on_text_changed = [this]() { + set_filename(pimpl->entry.get_text()); + }; + pimpl->entry.get_buffer()->signal_deleted_text().connect([on_text_changed](guint, guint) { on_text_changed(); }); + pimpl->entry.get_buffer()->signal_inserted_text().connect([on_text_changed](guint, const gchar *, guint) { on_text_changed(); }); + pimpl->file_chooser_button.set_image(*Gtk::manage(make_folder_image().release())); pimpl->file_chooser_button.signal_clicked().connect([this]() { - const auto &filename = pimpl->entry.get_text(); + const auto &filename = get_filename(); if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { set_current_folder(filename); } - set_filename(filename); show_chooser(this); }); @@ -1563,6 +1568,18 @@ MyFileChooserEntry::MyFileChooserEntry(const Glib::ustring &title, Gtk::FileChoo } +Glib::ustring MyFileChooserEntry::get_placeholder_text() const +{ + return pimpl->entry.get_placeholder_text(); +} + + +void MyFileChooserEntry::set_placeholder_text(const Glib::ustring &text) +{ + pimpl->entry.set_placeholder_text(text); +} + + void MyFileChooserEntry::on_filename_set() { if (pimpl->entry.get_text() != get_filename()) { diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 58877aed4..8bc047bf7 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -463,6 +463,9 @@ class MyFileChooserEntry : public Gtk::Box, public MyFileChooserWidget public: explicit MyFileChooserEntry(const Glib::ustring &title, Gtk::FileChooserAction action = Gtk::FILE_CHOOSER_ACTION_OPEN); + Glib::ustring get_placeholder_text() const; + void set_placeholder_text(const Glib::ustring &text); + protected: void on_filename_set() override; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 1e652faf4..da8272442 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -671,6 +671,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () Gtk::Label *lensfunDbDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LENSFUNDBDIR") + ":")); setExpandAlignProperties(lensfunDbDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); lensfunDbDir = Gtk::manage(new MyFileChooserEntry(M("PREFERENCES_LENSFUNDBDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + lensfunDbDir->set_placeholder_text(Glib::ustring::compose("(%1)", M("GENERAL_AUTO"))); setExpandAlignProperties(lensfunDbDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); Gtk::Label* lensfunDbDirRestartNeededLabel = Gtk::manage(new Gtk::Label(Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); setExpandAlignProperties(lensfunDbDirRestartNeededLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); From 8c98925f3d744d9cd9b4b044d9b7b2824e958994 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 12 May 2023 22:44:04 -0700 Subject: [PATCH 098/110] Get lens name from EXIF group for ILCE/NEX cameras Fix incorrect lens name read in certain cases from Sony cameras (see https://discuss.pixls.us/t/call-for-testing-rawtherapee-metadata-handling-with-exiv2-includes-cr3-support/36240/87). --- rtengine/imagedata.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 168177876..71d5c5693 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -336,9 +336,20 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : } } } else if (!make.compare(0, 4, "SONY")) { - if (find_exif_tag("Exif.Sony2.LensID") && pos->toLong()) { + // ExifTool prefers LensType2 over LensType (called + // Exif.Sony2.LensID by Exiv2). Exiv2 doesn't support LensType2 yet, + // so we let Exiv2 try it's best. For non ILCE/NEX cameras which + // likely don't have LensType2, we use Exif.Sony2.LensID because + // Exif.Photo.LensModel may be incorrect (see + // https://discuss.pixls.us/t/call-for-testing-rawtherapee-metadata-handling-with-exiv2-includes-cr3-support/36240/36). + if ( + // Camera model is neither a ILCE nor NEX. + (!find_exif_tag("Exif.Image.Model") || + (pos->toString().compare(0, 4, "ILCE") && pos->toString().compare(0, 3, "NEX"))) && + // LensID exists. + find_exif_tag("Exif.Sony2.LensID") && pos->toLong()) { lens = pos->print(&exif); - if (lens == std::to_string(pos->toLong())) { // Not know to Exiv2. + if (lens == std::to_string(pos->toLong())) { // Not known to Exiv2. lens.clear(); } else { lens = validateUft8(lens); From 81a3ba558e65e0464edd49d67fcc771814db2fd5 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 12 May 2023 22:50:53 -0700 Subject: [PATCH 099/110] Update Exiv2 to v0.28.0 for AppImage --- .github/workflows/appimage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 292ce862f..d50628902 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -34,7 +34,7 @@ jobs: - name: Install Exiv2 run: | - EXIV2_VERSION='v0.27.6' + EXIV2_VERSION='v0.28.0' echo "Cloning Exiv2 $EXIV2_VERSION." git clone --depth 1 --branch "$EXIV2_VERSION" https://github.com/Exiv2/exiv2.git ext/exiv2 From e4690e73a33a069a72da2619189a16f44c1174ba Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 12 May 2023 23:14:58 -0700 Subject: [PATCH 100/110] Add missing build dependency for AppImage --- .github/workflows/appimage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index d50628902..fae43ed25 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -30,7 +30,7 @@ jobs: echo "Running apt update." sudo apt update echo "Installing dependencies with apt." - DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin libexpat1-dev libbrotli-dev zlib1g-dev + DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin libexpat1-dev libbrotli-dev zlib1g-dev libinih-dev - name: Install Exiv2 run: | From 0ac49e4d9a111ac03b275ef0718a0ed44162ca43 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 13 May 2023 15:31:14 -0700 Subject: [PATCH 101/110] Support Exiv2 >= v0.28.0 The various Datum classes no longer have the toLong method and must be replaced with toInt64. ErrorCode is an enum class instead of an enum. Error classes are reduced to Exiv2::Error. --- rtengine/imagedata.cc | 65 ++++++++++++++++++++++++++----------------- rtengine/imageio.cc | 15 +++++++++- rtengine/metadata.cc | 36 ++++++++++++++++++++---- 3 files changed, 83 insertions(+), 33 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 71d5c5693..4ff918c21 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -50,6 +50,19 @@ const std::string& validateUft8(const std::string& str, const std::string& on_er return on_error; } +template +auto to_long(const Iterator &iter, Integer n = Integer{0}) -> decltype( +#if EXIV2_TEST_VERSION(0,28,0) + iter->toInt64() +) { + return iter->toInt64(n); +#else + iter->toLong() +) { + return iter->toLong(n); +#endif +} + } namespace rtengine { @@ -269,7 +282,7 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : const int length = 12; if (pos->count() >= index + length) { for (int i = 0; i < length; ++i) { - serial += static_cast(pos->toLong(index + i)); + serial += static_cast(to_long(pos, index + i)); } serial = validateUft8(serial); } @@ -313,7 +326,7 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : "Rotate 270 CW", "Unknown" }; - auto idx = pos->toLong(); + auto idx = to_long(pos); if (idx >= 0 && idx < long(ormap.size())) { orientation = ormap[idx]; } @@ -322,14 +335,14 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : if (!make.compare(0, 5, "NIKON")) { if (find_exif_tag("Exif.NikonLd4.LensID")) { - if (!pos->toLong()) { // No data, look in LensIDNumber. + if (!to_long(pos)) { // No data, look in LensIDNumber. const auto p = pos; if (!find_exif_tag("Exif.NikonLd4.LensIDNumber")) { pos = p; // Tag not found, so reset pos. } } lens = pos->print(&exif); - if (lens == std::to_string(pos->toLong())) { // Not known to Exiv2. + if (lens == std::to_string(to_long(pos))) { // Not known to Exiv2. lens.clear(); } else { lens = validateUft8(lens); @@ -347,9 +360,9 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : (!find_exif_tag("Exif.Image.Model") || (pos->toString().compare(0, 4, "ILCE") && pos->toString().compare(0, 3, "NEX"))) && // LensID exists. - find_exif_tag("Exif.Sony2.LensID") && pos->toLong()) { + find_exif_tag("Exif.Sony2.LensID") && to_long(pos)) { lens = pos->print(&exif); - if (lens == std::to_string(pos->toLong())) { // Not known to Exiv2. + if (lens == std::to_string(to_long(pos))) { // Not known to Exiv2. lens.clear(); } else { lens = validateUft8(lens); @@ -363,7 +376,7 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : auto p = pos; if (find_exif_tag("Exif.CanonFi.RFLensType") && find_exif_tag("Exif.Canon.LensModel")) { lens = validateUft8(pos->print(&exif)); - } else if (p->count() == 1 && lens == std::to_string(p->toLong())) { + } else if (p->count() == 1 && lens == std::to_string(to_long(p))) { if (find_exif_tag("Exif.Canon.LensModel")) { lens = validateUft8(pos->print(&exif)); } else if (find_exif_tag("Exif.Photo.LensModel")) { @@ -421,11 +434,11 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : } if (find_exif_tag("Exif.Image.Rating")) { - rating = pos->toLong(); + rating = to_long(pos); } else { auto it = meta.xmpData().findKey(Exiv2::XmpKey("Xmp.xmp.Rating")); if (it != meta.xmpData().end() && it->size()) { - rating = it->toLong(); + rating = to_long(it); } } @@ -501,8 +514,8 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : || find_exif_tag("Exif.PentaxDng.Quality") ) && ( - pos->toLong() == 7 - || pos->toLong() == 8 + to_long(pos) == 7 + || to_long(pos) == 8 ) ) { isPixelShift = true; @@ -513,23 +526,23 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : } if (make == "SONY") { - if (find_exif_tag("Exif.SubImage1.BitsPerSample") && pos->toLong() == 14) { - if (find_exif_tag("Exif.SubImage1.SamplesPerPixel") && pos->toLong() == 4 && - find_exif_tag("Exif.SubImage1.PhotometricInterpretation") && pos->toLong() == 32892 && - find_exif_tag("Exif.SubImage1.Compression") && pos->toLong() == 1) { + if (find_exif_tag("Exif.SubImage1.BitsPerSample") && to_long(pos) == 14) { + if (find_exif_tag("Exif.SubImage1.SamplesPerPixel") && to_long(pos) == 4 && + find_exif_tag("Exif.SubImage1.PhotometricInterpretation") && to_long(pos) == 32892 && + find_exif_tag("Exif.SubImage1.Compression") && to_long(pos) == 1) { isPixelShift = true; } - } else if (bps != exif.end() && bps->toLong() == 14 && - spp != exif.end() && spp->toLong() == 4 && - c != exif.end() && c->toLong() == 1 && + } else if (bps != exif.end() && to_long(bps) == 14 && + spp != exif.end() && to_long(spp) == 4 && + c != exif.end() && to_long(c) == 1 && find_exif_tag("Exif.Image.Software") && pos->toString() == "make_arq") { isPixelShift = true; } } else if (make == "FUJIFILM") { - if (bps != exif.end() && bps->toLong() == 16 && - spp != exif.end() && spp->toLong() == 4 && - c != exif.end() && c->toLong() == 1 && + if (bps != exif.end() && to_long(bps) == 16 && + spp != exif.end() && to_long(spp) == 4 && + c != exif.end() && to_long(c) == 1 && find_exif_tag("Exif.Image.Software") && pos->toString() == "make_arq") { isPixelShift = true; @@ -548,22 +561,22 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : { sampleformat = SAMPLEFORMAT_UINT; } else { - sampleformat = sf->toLong(); + sampleformat = to_long(sf); } if (bps == exif.end() || spp == exif.end() || pi == exif.end()) { return; } - bitspersample = bps->toLong(); - samplesperpixel = spp->toLong(); + bitspersample = to_long(bps); + samplesperpixel = to_long(spp); - photometric = pi->toLong(); + photometric = to_long(pi); if (photometric == PHOTOMETRIC_LOGLUV) { if (c == exif.end()) { compression = COMPRESSION_NONE; } else { - compression = c->toLong(); + compression = to_long(c); } } diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 0388467be..1c8e9016d 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -86,6 +86,19 @@ FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname) return f; } +template +auto to_long(const Iterator &iter, Integer n = Integer{0}) -> decltype( +#if EXIV2_TEST_VERSION(0,28,0) + iter->toInt64() +) { + return iter->toInt64(n); +#else + iter->toLong() +) { + return iter->toLong(n); +#endif +} + } void ImageIO::setMetadata(Exiv2Metadata info) @@ -1185,7 +1198,7 @@ int ImageIO::saveTIFF ( } it = exif.findKey(Exiv2::ExifKey("Exif.Image.ResolutionUnit")); if (it != exif.end()) { - res_unit = it->toLong(); + res_unit = to_long(it); } } TIFFSetField(out, TIFFTAG_XRESOLUTION, x_res); diff --git a/rtengine/metadata.cc b/rtengine/metadata.cc index 28a9c1742..0a55c1424 100644 --- a/rtengine/metadata.cc +++ b/rtengine/metadata.cc @@ -31,6 +31,13 @@ #include "../rtgui/pathutils.h" +#if EXIV2_TEST_VERSION(0,28,0) +using Exiv2Error = Exiv2::Error; +#else +using Exiv2Error = Exiv2::AnyError; +#endif + + namespace rtengine { extern const Settings *settings; @@ -39,9 +46,13 @@ std::unique_ptr Exiv2Metadata::cache_(nullptr); namespace { -class Error: public Exiv2::AnyError { +class Error: public Exiv2Error { public: - Error(const std::string &msg): msg_(msg) {} + Error(const std::string &msg): +#if EXIV2_TEST_VERSION(0,28,0) + Exiv2Error(Exiv2::ErrorCode::kerGeneralError), +#endif + msg_(msg) {} const char *what() const throw() { return msg_.c_str(); } int code() const throw() { return 0; } @@ -71,7 +82,7 @@ std::unique_ptr open_exiv2(const Glib::ustring& fname, image->readMetadata(); if (!image->good() || (check_exif && image->exifData().empty())) { #if EXIV2_TEST_VERSION(0,27,0) - auto error_code = Exiv2::kerErrorMessage; + auto error_code = Exiv2::ErrorCode::kerErrorMessage; #else auto error_code = 1; #endif @@ -95,6 +106,19 @@ void clear_metadata_key(Data &data, const Key &key) } } +template +auto to_long(const Iterator &iter, Integer n = Integer{0}) -> decltype( +#if EXIV2_TEST_VERSION(0,28,0) + iter->toInt64() +) { + return iter->toInt64(n); +#else + iter->toLong() +) { + return iter->toLong(n); +#endif +} + } // namespace @@ -297,7 +321,7 @@ void Exiv2Metadata::saveToImage(const Glib::ustring &path, bool preserve_all_tag dst->writeMetadata(); return; } catch (Exiv2::Error &exc) { - if (exc.code() == 37) { + if (exc.code() == Exiv2::ErrorCode::kerTooLargeJpegSegment) { std::string msg = exc.what(); if (msg.find("XMP") != std::string::npos && !dst->xmpData().empty()) { @@ -519,8 +543,8 @@ void Exiv2Metadata::getDimensions(int &w, int &h) const auto itw = exif.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); auto ith = exif.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); if (itw != exif.end() && ith != exif.end()) { - w = itw->toLong(); - h = ith->toLong(); + w = to_long(itw); + h = to_long(ith); } else { w = h = -1; } From 572a75f02a25111fbc1b2163c4ae3c801ef9a879 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 14 May 2023 11:06:23 -0700 Subject: [PATCH 102/110] Fix lens model reading for Sony ILMEs and ZV-E10 Use lens model from the EXIF group for these cameras. --- rtengine/imagedata.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 4ff918c21..430559f3d 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -356,11 +356,11 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) : // Exif.Photo.LensModel may be incorrect (see // https://discuss.pixls.us/t/call-for-testing-rawtherapee-metadata-handling-with-exiv2-includes-cr3-support/36240/36). if ( - // Camera model is neither a ILCE nor NEX. + // Camera model is neither a ILCE, ILME, nor NEX. (!find_exif_tag("Exif.Image.Model") || - (pos->toString().compare(0, 4, "ILCE") && pos->toString().compare(0, 3, "NEX"))) && - // LensID exists. - find_exif_tag("Exif.Sony2.LensID") && to_long(pos)) { + (pos->toString().compare(0, 4, "ILCE") && pos->toString().compare(0, 4, "ILME") && pos->toString().compare(0, 3, "NEX"))) && + // LensID exists. 0xFFFF could be one of many lenses. + find_exif_tag("Exif.Sony2.LensID") && to_long(pos) && to_long(pos) != 0xFFFF) { lens = pos->print(&exif); if (lens == std::to_string(to_long(pos))) { // Not known to Exiv2. lens.clear(); From c557b320c24adc83f3934d0c81acd82a87f7c221 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 14 May 2023 18:18:27 -0700 Subject: [PATCH 103/110] Refresh cached image data if sidecar is changed --- rtgui/cacheimagedata.cc | 17 +++++++++++++++++ rtgui/cacheimagedata.h | 3 +++ rtgui/cachemanager.cc | 17 ++++++++++++++++- rtgui/cachemanager.h | 2 ++ rtgui/thumbnail.cc | 16 +++++++++++++--- rtgui/thumbnail.h | 5 ++++- 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc index 365b8f1b7..bfc4e920a 100644 --- a/rtgui/cacheimagedata.cc +++ b/rtgui/cacheimagedata.cc @@ -26,6 +26,15 @@ #include "../rtengine/procparams.h" #include "../rtengine/settings.h" + +namespace +{ + +const Glib::ustring INI_GROUP_XMP_SIDECAR = "XmpSidecar"; +const Glib::ustring INI_XMP_SIDECAR_MD5 = "MD5"; + +} + CacheImageData::CacheImageData() : supported(false), format(FT_Invalid), @@ -108,6 +117,12 @@ int CacheImageData::load (const Glib::ustring& fname) } } + if (keyFile.has_group(INI_GROUP_XMP_SIDECAR)) { + if (keyFile.has_key(INI_GROUP_XMP_SIDECAR, INI_XMP_SIDECAR_MD5)) { + xmpSidecarMd5 = keyFile.get_string(INI_GROUP_XMP_SIDECAR, INI_XMP_SIDECAR_MD5); + } + } + timeValid = keyFile.has_group ("DateTime"); if (timeValid) { @@ -268,6 +283,8 @@ int CacheImageData::save (const Glib::ustring& fname) keyFile.set_boolean ("General", "RecentlySaved", recentlySaved); keyFile.set_integer ("General", "Rating", rating); + keyFile.set_string(INI_GROUP_XMP_SIDECAR, INI_XMP_SIDECAR_MD5, xmpSidecarMd5); + // remove the old implementation of Rank and InTrash from cache if (keyFile.has_key ("General", "Rank")) { keyFile.remove_key("General", "Rank"); diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index cb02b9169..8c0fa6513 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -39,6 +39,9 @@ public: bool inTrashOld; // old implementation of inTrash bool recentlySaved; + // XMP sidecar info. + Glib::ustring xmpSidecarMd5; + // time/date info bool timeValid; short year; diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 5e540b604..4d865ce76 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -97,6 +97,10 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) } const auto cacheName = getCacheFileName ("data", fname, ".txt", md5); + const auto xmpSidecarMd5 = + rtengine::settings->metadata_xmp_sync != rtengine::Settings::MetadataXmpSync::NONE + ? getMD5(Thumbnail::xmpSidecarPath(fname)) + : ""; // let's see if we have it in the cache { @@ -106,6 +110,11 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) if (error == 0 && imageData.supported) { + if (xmpSidecarMd5 != imageData.xmpSidecarMd5) { + updateImageInfo(fname, imageData, xmpSidecarMd5); + imageData.save(cacheName); + } + thumbnail.reset (new Thumbnail (this, fname, &imageData)); if (!thumbnail->isSupported ()) { @@ -117,7 +126,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) // if not, create a new one if (!thumbnail) { - thumbnail.reset (new Thumbnail (this, fname, md5)); + thumbnail.reset (new Thumbnail (this, fname, md5, xmpSidecarMd5)); if (!thumbnail->isSupported ()) { thumbnail.reset (); @@ -413,3 +422,9 @@ void CacheManager::applyCacheSizeLimitation () const } } +void CacheManager::updateImageInfo(const Glib::ustring &fname, CacheImageData &imageData, const Glib::ustring &xmpSidecarMd5) const +{ + Thumbnail::infoFromImage(fname, imageData); + imageData.xmpSidecarMd5 = xmpSidecarMd5; +} + diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h index 61602aeba..a7ab14f0a 100644 --- a/rtgui/cachemanager.h +++ b/rtgui/cachemanager.h @@ -27,6 +27,7 @@ #include "../rtengine/noncopyable.h" +class CacheImageData; class Thumbnail; class CacheManager : @@ -42,6 +43,7 @@ private: void deleteFiles (const Glib::ustring& fname, const std::string& md5, bool purgeData, bool purgeProfile) const; void applyCacheSizeLimitation () const; + void updateImageInfo(const Glib::ustring &fname, CacheImageData &imageData, const Glib::ustring &xmpSidecarMd5) const; public: static CacheManager* getInstance (); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index ce262206f..a2941aaa5 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -148,7 +148,7 @@ Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, CacheImageDat tpp = nullptr; } -Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, const std::string& md5) : +Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, const std::string& md5, const std::string &xmpSidecarMd5) : fname(fname), cachemgr(cm), ref(1), @@ -166,6 +166,7 @@ Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, const std::st cfs.md5 = md5; + cfs.xmpSidecarMd5 = xmpSidecarMd5; loadProcParams (); _generateThumbnailImage (); cfs.recentlySaved = false; @@ -176,6 +177,11 @@ Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, const std::st tpp = nullptr; } +Glib::ustring Thumbnail::xmpSidecarPath(const Glib::ustring &imagePath) +{ + return rtengine::Exiv2Metadata::xmpSidecarPath(imagePath); +} + void Thumbnail::_generateThumbnailImage () { @@ -852,7 +858,12 @@ ThFileType Thumbnail::getType () const int Thumbnail::infoFromImage (const Glib::ustring& fname) { - rtengine::FramesMetaData* idata = rtengine::FramesMetaData::fromFile (fname); + return infoFromImage(fname, cfs); +} + +int Thumbnail::infoFromImage(const Glib::ustring &fname, CacheImageData &cfs) +{ + std::unique_ptr idata(rtengine::FramesMetaData::fromFile (fname)); if (!idata) { return 0; @@ -915,7 +926,6 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname) idata->getDimensions(cfs.width, cfs.height); - delete idata; return deg; } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index e071fdd9f..9ead1e5e8 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -93,9 +93,12 @@ class Thumbnail public: Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf); - Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5); + Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5, const std::string &xmpSidecarMd5); ~Thumbnail (); + static int infoFromImage(const Glib::ustring &fname, CacheImageData &cfs); + static Glib::ustring xmpSidecarPath(const Glib::ustring &imagePath); + bool hasProcParams () const; const rtengine::procparams::ProcParams& getProcParams (); const rtengine::procparams::ProcParams& getProcParamsU (); // Unprotected version From a592b2dfc3c39f663d98f4757acd78ff8bfedf97 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 Jul 2023 17:54:52 -0700 Subject: [PATCH 104/110] Fix invisible separator in file browser Places Set minimum height and color for the TreeView separator for the RawTherapee and legacy RawTherapee themes. --- rtdata/themes/RawTherapee - Legacy-GTK3-20_.css | 2 ++ rtdata/themes/RawTherapee-GTK3-20_.css | 2 ++ 2 files changed, 4 insertions(+) diff --git a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css index 07a0bd65d..ba62fd366 100644 --- a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css +++ b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css @@ -227,6 +227,8 @@ menu separator { } #PlacesPaned .view.separator { + min-height: 0.16666666666666666em; + color: #363636; } #MetaPanelNotebook separator { diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index 2e314510a..e909eb33f 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -207,6 +207,8 @@ menu separator { } #PlacesPaned .view.separator { + min-height: 0.16666666666666666em; + color: #363636; } #MetaPanelNotebook separator { From 3e13e77b6f657d76533a676f3bfbe60e885dba94 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 Jul 2023 18:09:19 -0700 Subject: [PATCH 105/110] Move favorited places to the top of the list --- rtgui/placesbrowser.cc | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/rtgui/placesbrowser.cc b/rtgui/placesbrowser.cc index 3440080f8..f1209a3a0 100644 --- a/rtgui/placesbrowser.cc +++ b/rtgui/placesbrowser.cc @@ -106,9 +106,32 @@ void PlacesBrowser::refreshPlacesList () { placesModel->clear (); + // append favorites + for (size_t i = 0; i < options.favoriteDirs.size(); i++) { + Glib::RefPtr fav = Gio::File::create_for_path (options.favoriteDirs[i]); + + if (fav && fav->query_exists()) { + try { + if (auto info = fav->query_info ()) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = info->get_display_name (); + newrow[placesColumns.icon] = info->get_icon (); + newrow[placesColumns.root] = fav->get_parse_name (); + newrow[placesColumns.type] = 5; + newrow[placesColumns.rowSeparator] = false; + } + } catch(Gio::Error&) {} + } + } + // append home directory Glib::RefPtr hfile = Gio::File::create_for_path (userHomeDir()); // Will send back "My documents" on Windows now, which has no restricted access + if (!placesModel->children().empty()) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.rowSeparator] = true; + } + if (hfile && hfile->query_exists()) { try { if (auto info = hfile->query_info ()) { @@ -223,29 +246,6 @@ void PlacesBrowser::refreshPlacesList () newrow[placesColumns.rowSeparator] = false; } } - - // append favorites - if (!placesModel->children().empty()) { - Gtk::TreeModel::Row newrow = *(placesModel->append()); - newrow[placesColumns.rowSeparator] = true; - } - - for (size_t i = 0; i < options.favoriteDirs.size(); i++) { - Glib::RefPtr fav = Gio::File::create_for_path (options.favoriteDirs[i]); - - if (fav && fav->query_exists()) { - try { - if (auto info = fav->query_info ()) { - Gtk::TreeModel::Row newrow = *(placesModel->append()); - newrow[placesColumns.label] = info->get_display_name (); - newrow[placesColumns.icon] = info->get_icon (); - newrow[placesColumns.root] = fav->get_parse_name (); - newrow[placesColumns.type] = 5; - newrow[placesColumns.rowSeparator] = false; - } - } catch(Gio::Error&) {} - } - } } bool PlacesBrowser::rowSeparatorFunc (const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter) From 548907da3422bff719d4c6142815cb3bb11d8c2d Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 6 Aug 2023 16:44:54 -0700 Subject: [PATCH 106/110] Fix external editor button updates Make sure the pop-up button is updated in both multiple editors modes. --- rtgui/editwindow.cc | 7 +++++++ rtgui/editwindow.h | 2 ++ rtgui/popupcommon.cc | 16 ++++++++++++++-- rtgui/popupcommon.h | 6 ++++-- rtgui/rtwindow.cc | 11 +++++++++++ rtgui/rtwindow.h | 3 +++ 6 files changed, 41 insertions(+), 4 deletions(-) diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index 0364b0afa..3184c21c4 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -488,6 +488,13 @@ void EditWindow::set_title_decorated(Glib::ustring fname) set_title("RawTherapee " + M("EDITWINDOW_TITLE") + subtitle); } +void EditWindow::updateExternalEditorWidget(int selectedIndex, const std::vector &editors) +{ + for (const auto& panel : epanels) { + panel.second->updateExternalEditorWidget(selectedIndex, editors); + } +} + void EditWindow::updateToolPanelToolLocations( const std::vector &favorites, bool cloneFavoriteTools) { diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h index 0b10cb67e..a5932c081 100644 --- a/rtgui/editwindow.h +++ b/rtgui/editwindow.h @@ -24,6 +24,7 @@ #include "guiutils.h" class EditorPanel; +class ExternalEditor; class RTWindow; class EditWindow : @@ -66,6 +67,7 @@ public: bool selectEditorPanel(const std::string &name); bool closeOpenEditors(); bool isProcessing(); + void updateExternalEditorWidget(int selectedIndex, const std::vector &editors); void updateToolPanelToolLocations( const std::vector &favorites, bool cloneFavoriteTools); diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 2517a0a76..741d4da0f 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -20,10 +20,12 @@ */ #include + +#include "guiutils.h" #include "multilangmgr.h" #include "popupcommon.h" #include "rtimage.h" -#include "guiutils.h" +#include "threadutils.h" PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) : buttonImage (nullptr) @@ -203,6 +205,15 @@ void PopUpCommon::changeImage(const Glib::ustring& fileName, const Glib::RefPtr< void PopUpCommon::entrySelected(Gtk::Widget* widget) { + if (widget != menu->get_active()) { // Not actually selected. + return; + } + + if (!entrySelectionMutex.trylock()) { // Already being updated. + return; + } + entrySelectionMutex.unlock(); + int i = 0; for (const auto & child : menu->get_children()) { if (widget == child) { @@ -249,7 +260,8 @@ bool PopUpCommon::setSelected (int entryNum) setButtonHint(); auto radioMenuItem = dynamic_cast(menu->get_children()[entryNum]); - if (radioMenuItem && menu->get_active() != radioMenuItem) { + if (radioMenuItem && !radioMenuItem->get_active()) { + MyMutex::MyLock updateLock(entrySelectionMutex); radioMenuItem->set_active(); } diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index 228e0fba0..91bfdabea 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -20,12 +20,13 @@ */ #pragma once -#include "glibmm/refptr.h" +#include "threadutils.h" + #include #include +#include #include - #include namespace Gio @@ -91,6 +92,7 @@ private: Gtk::Button* arrowButton; int selected; bool hasMenu; + MyMutex entrySelectionMutex; void changeImage(int position); void changeImage(const Glib::ustring& fileName, const Glib::RefPtr& gIcon); diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index dcfc2f05c..5513f356b 100755 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -589,6 +589,7 @@ void RTWindow::addEditorPanel (EditorPanel* ep, const std::string &name) } else { ep->setParent (this); ep->setParentWindow (this); + ep->setExternalEditorChangedSignal(&externalEditorChangedSignal); // construct closeable tab for the image Gtk::Grid* titleGrid = Gtk::manage (new Gtk::Grid ()); @@ -637,6 +638,7 @@ void RTWindow::remEditorPanel (EditorPanel* ep) wndEdit->remEditorPanel (ep); } else { bool queueHadFocus = (mainNB->get_current_page() == mainNB->page_num (*bpanel)); + ep->setExternalEditorChangedSignal(nullptr); epanels.erase (ep->getFileName()); filesEdited.erase (ep->getFileName ()); fpanel->refreshEditedState (filesEdited); @@ -1060,6 +1062,15 @@ void RTWindow::updateExternalEditorWidget(int selectedIndex, const std::vectorupdateExternalEditorWidget(selectedIndex, editors); } + + for (auto panel : epanels) { + panel.second->updateExternalEditorWidget(selectedIndex, editors); + } + + if (options.multiDisplayMode > 0) { + EditWindow::getInstance(this) + ->updateExternalEditorWidget(selectedIndex, editors); + } } void RTWindow::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC) diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index 922588a19..4c3aa75ea 100755 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -20,6 +20,7 @@ #include #include +#include #if defined(__APPLE__) #include @@ -48,6 +49,8 @@ private: std::set filesEdited; std::map epanels; + sigc::signal externalEditorChangedSignal; + Splash* splash; Gtk::ProgressBar prProgBar; PLDBridge* pldBridge; From 1f7d2d4ebcb78a2754b9f5e4e4d9230bc1ec28ef Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:10:44 -0700 Subject: [PATCH 107/110] Remove metadata-exiv2 from pre-dev publishing --- .github/workflows/appimage.yml | 2 +- .github/workflows/windows.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index fae43ed25..760f3f25b 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -11,7 +11,7 @@ on: - dev workflow_dispatch: env: - publish_pre_dev_labels: '["Beep6581:metadata-exiv2"]' + publish_pre_dev_labels: '[]' jobs: build: runs-on: ubuntu-20.04 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index efe2295cc..b368ad0c0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -11,7 +11,7 @@ on: - dev workflow_dispatch: env: - publish_pre_dev_labels: '["Beep6581:metadata-exiv2"]' + publish_pre_dev_labels: '[]' jobs: build: runs-on: windows-2022 From db4bfd8695578b06c24dd0eaea36e589a8c74120 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:39:59 -0700 Subject: [PATCH 108/110] Add tooltips for LCP & Lensfun dir in preferences --- rtdata/languages/default | 2 ++ rtgui/preferences.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index 8fa85f144..835831547 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1914,7 +1914,9 @@ PREFERENCES_INTERNALTHUMBIFUNTOUCHED;Show embedded JPEG thumbnail if raw is uned PREFERENCES_LANG;Language PREFERENCES_LANGAUTODETECT;Use system language PREFERENCES_LENSFUNDBDIR;Lensfun database directory +PREFERENCES_LENSFUNDBDIR_TOOLTIP;Directory containing the Lensfun database. Leave empty to use the default directories. PREFERENCES_LENSPROFILESDIR;Lens profiles directory +PREFERENCES_LENSPROFILESDIR_TOOLTIP;Directory containing Adobe Lens Correction Profiles (LCPs) PREFERENCES_MAXRECENTFOLDERS;Maximum number of recent folders PREFERENCES_MENUGROUPEXTPROGS;Group 'Open with' PREFERENCES_MENUGROUPFILEOPERATIONS;Group 'File operations' diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index da8272442..82ef67d2f 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -660,6 +660,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () //Lens Profiles Dir Gtk::Label *lensProfilesDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LENSPROFILESDIR") + ":")); + lensProfilesDirLabel->set_tooltip_text(M("PREFERENCES_LENSPROFILESDIR_TOOLTIP")); setExpandAlignProperties(lensProfilesDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); lensProfilesDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_LENSPROFILESDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); setExpandAlignProperties(lensProfilesDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); @@ -669,6 +670,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () // Lensfun DB dir Gtk::Label *lensfunDbDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LENSFUNDBDIR") + ":")); + lensfunDbDirLabel->set_tooltip_text(M("PREFERENCES_LENSFUNDBDIR_TOOLTIP")); setExpandAlignProperties(lensfunDbDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); lensfunDbDir = Gtk::manage(new MyFileChooserEntry(M("PREFERENCES_LENSFUNDBDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); lensfunDbDir->set_placeholder_text(Glib::ustring::compose("(%1)", M("GENERAL_AUTO"))); From 83263a3504165db900685878370427804d748696 Mon Sep 17 00:00:00 2001 From: Hombre57 Date: Sun, 13 Aug 2023 01:01:18 +0200 Subject: [PATCH 109/110] Fix for Treeview's editable entries incorrectly displayed --- rtdata/themes/RawTherapee-GTK3-20_.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index e909eb33f..b69e543d1 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -44,7 +44,7 @@ textview.view, treeview.view { padding: 0; margin: 0; } -.view, .textview, textview, textview.view { +.view, .textview, textview, textview.view, treeview > entry { background-color: #262626; } /* The headers of these panels */ From ac48cc55d8556403b92d3183c69080b60faabe58 Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Tue, 15 Aug 2023 07:52:38 -0700 Subject: [PATCH 110/110] Better use of cache with inpaint opposed highight reconstruction (#6822) * Speed up preview when inpaint opposed enabled Only reprocess from raw if the white balance is changed. Otherwise, a cache from later in the pipeline can be used. * Remove unused code * Fix refresh map bit positions * Make WB & inpaint opposed refresh less brittle Co-authored-by: Hombre57 --------- Co-authored-by: Hombre57 --- rtengine/clutstore.cc | 2 +- rtengine/dcrop.cc | 12 ++++++------ rtengine/filmnegativeproc.cc | 2 +- rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 13 ++++++++----- rtengine/iplocallab.cc | 2 +- rtengine/perspectivecorrection.cc | 2 +- rtengine/previewimage.cc | 2 +- rtengine/rawimagesource.cc | 7 +------ rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 12 ++++++------ rtengine/refreshmap.h | 12 +++++++----- rtengine/rtthumbnail.cc | 2 +- rtengine/simpleprocess.cc | 6 +++--- rtengine/spot.cc | 4 ++-- rtengine/stdimagesource.cc | 2 +- rtengine/stdimagesource.h | 2 +- rtgui/whitebalance.cc | 8 ++++---- 18 files changed, 47 insertions(+), 47 deletions(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 4c70ad951..e3bd9c988 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -57,7 +57,7 @@ bool loadFile( rtengine::procparams::ColorManagementParams icm; icm.workingProfile = working_color_space; - img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams(), 0); + img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams()); if (!working_color_space.empty()) { img_src.convertColorSpace(img_float.get(), icm, curr_wb); diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index dda8489df..6abfc7aba 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -231,18 +231,18 @@ void Crop::update(int todo) if (settings->leveldnautsimpl == 1) { if (params.dirpyrDenoise.Cmethod == "MAN" || params.dirpyrDenoise.Cmethod == "PON") { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); } } else { if (params.dirpyrDenoise.C2method == "MANU") { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); } } if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PRE") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "PREV")) { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); if ((!isDetailWindow) && parent->adnListener && skip == 1 && params.dirpyrDenoise.enabled) { float lowdenoise = 1.f; @@ -454,7 +454,7 @@ void Crop::update(int todo) for (int wcr = 0; wcr <= 2; wcr++) { for (int hcr = 0; hcr <= 2; hcr++) { PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1); - parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); + parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); // we only need image reduced to 1/4 here for (int ii = 0; ii < crH; ii += 2) { @@ -615,7 +615,7 @@ void Crop::update(int todo) // if (params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); } if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) { @@ -751,7 +751,7 @@ void Crop::update(int todo) fattalCrop.reset(f); PreviewProps pp(0, 0, parent->fw, parent->fh, skip); int tr = getCoarseBitMask(params.coarse); - parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw, 0); + parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw); parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB); if (params.dirpyrDenoise.enabled || params.filmNegative.enabled || params.spot.enabled) { diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index eb029d77a..416f495c5 100644 --- a/rtengine/filmnegativeproc.cc +++ b/rtengine/filmnegativeproc.cc @@ -84,7 +84,7 @@ void getSpotAvgMax(ImageSource *imgsrc, ColorTemp currWB, const std::unique_ptr< } rtengine::Imagefloat spotImg(spotSize, spotSize); - imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw, 0); + imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw); auto avgMax = [spotSize, &spotImg](RGB & avg, RGB & max) -> void { avg = {}; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index bda1ceb74..2319ddada 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -109,7 +109,7 @@ public: virtual void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const = 0; // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* - virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw, int opposed) = 0; + virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw) = 0; virtual eSensorType getSensorType () const = 0; virtual bool isMono () const = 0; // true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f939535c2..e214bbfc7 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -407,6 +407,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) Color HLR alters rgb output of demosaic, so re-demosaic is needed when Color HLR is being turned off; if HLR is enabled and changing method *from* Color to any other method OR HLR gets disabled when Color method was selected + If white balance changed with inpaint opposed, because inpaint opposed depends on the white balance */ // If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST @@ -414,7 +415,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono(), imgsrc->isGainMapSupported()); } - bool iscolor = (params->toneCurve.method == "Color");// || params->toneCurve.method == "Coloropp"); + bool iscolor = (params->toneCurve.method == "Color" || params->toneCurve.method == "Coloropp"); + if ((todo & M_WB) && params->toneCurve.hrenabled && params->toneCurve.method == "Coloropp") { + todo |= DEMOSAIC; + } if ((todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) @@ -872,8 +876,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) PreviewProps pp(0, 0, fw, fh, scale); // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications ipf.setScale(scale); - int inpaintopposed = 1;//force getimage to use inpaint-opposed if enable, only once - imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw, inpaintopposed); + imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw); if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty()) { spotsDone = true; @@ -2967,7 +2970,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a currWB = ColorTemp(); // = no white balance } - imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw, 0); + imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw); ImProcFunctions ipf(&ppar, true); if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) { @@ -3144,7 +3147,7 @@ void ImProcCoordinator::process() paramsUpdateMutex.unlock(); // M_VOID means no update, and is a bit higher that the rest - if (change & (M_VOID - 1)) { + if (change & (~M_VOID)) { updatePreviewImage(change, panningRelatedChange); } diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 91c8b5dc4..75bb03267 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2130,7 +2130,7 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, Imagefloat img(int(fw / SCALE + 0.5), int(fh / SCALE + 0.5)); const ProcParams neutral; - imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw, 0); + imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw); imgsrc->convertColorSpace(&img, params->icm, imgsrc->getWB()); float minVal = RT_INFINITY; float maxVal = -RT_INFINITY; diff --git a/rtengine/perspectivecorrection.cc b/rtengine/perspectivecorrection.cc index f4428faf2..7a56ef5a8 100644 --- a/rtengine/perspectivecorrection.cc +++ b/rtengine/perspectivecorrection.cc @@ -297,7 +297,7 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); neutral.icm.outputProfile = ColorManagementParams::NoICMString; - src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw, 0); + src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw); src->convertColorSpace(img.get(), pparams->icm, src->getWB()); neutral.commonTrans.autofill = false; // Ensures crop factor is correct. diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index e131211ce..b7e6ad9f8 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -120,7 +120,7 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext double contrastThresholdDummy = 0.0; rawImage.demosaic(params.raw, false, contrastThresholdDummy); Imagefloat image(fw, fh); - rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw, 0); + rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw); rtengine::Image8 output(fw, fh); rawImage.convertColorSpace(&image, params.icm, wb); #ifdef _OPENMP diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d12fa7f02..eabeb2fc9 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -741,9 +741,8 @@ void RawImageSource::getWBMults(const ColorTemp &ctemp, const RAWParams &raw, st autoGainComp = camInitialGain / initialGain; } -void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed) +void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) { - // added int opposed to force getimage to use inpaint-opposed if enable, only once MyMutex::MyLock lock(getImageMutex); tran = defTransform(ri, tran); @@ -850,10 +849,6 @@ void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* imag bool doHr = (hrp.hrenabled && !iscolor); if (hrp.hrenabled && iscolor) { - if(hrp.method == "Coloropp" && opposed == 1) {//force Inpaint opposed if WB change, and opposed limited the number to 1 - rgbSourceModified = false; - } - if (!rgbSourceModified) { if (hrp.method == "Color") { if (settings->verbose) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 4bcbc7a7c..e6f9da9d5 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -146,7 +146,7 @@ public: void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const procparams::WBParams & wbpar) override; void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override; - void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override; + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override; eSensorType getSensorType () const override; bool isMono () const override; ColorTemp getWB () const override diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index eb4a3f888..c589e8ba4 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -64,9 +64,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DARKFRAME, // EvLCPUseVign, HDR, // EvLCPUseCA, M_VOID, // EvFixedExp - ALLNORAW, // EvWBMethod, - ALLNORAW, // EvWBTemp, - ALLNORAW, // EvWBGreen, + WB, // EvWBMethod, + WB, // EvWBTemp, + WB, // EvWBGreen, AUTOEXP, // EvToneCurveMode1, AUTOEXP, // EvToneCurve2, AUTOEXP, // EvToneCurveMode2, @@ -234,7 +234,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvCATbadpix LUMINANCECURVE, // EvCATAutoadap DEFRINGE, // EvPFCurve - ALLNORAW, // EvWBequal + WB, // EvWBequal 0, // EvWBequalbo : obsolete HDR, // EvGradientDegree HDR, // EvGradientEnabled @@ -470,7 +470,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvRetinexgaintransmission RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens - ALLNORAW, // EvWBtempBias + WB, // EvWBtempBias DARKFRAME, // EvRawImageNum 0, // unused 0, // unused @@ -517,7 +517,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvTMFattalEnabled HDR, // EvTMFattalThreshold HDR, // EvTMFattalAmount - ALLNORAW, // EvWBEnabled + WB, // EvWBEnabled AUTOEXP, // EvRGBEnabled LUMINANCECURVE, // EvLEnabled DEMOSAIC, // EvPdShrEnabled diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index b53252796..7113ba6a5 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -23,17 +23,18 @@ #include "procevents.h" // Use M_VOID if you wish to update the proc params without updating the preview at all ! -#define M_VOID (1<<17) +#define M_VOID (1<<20) // Use M_MINUPDATE if you wish to update the preview without modifying the image (think about it like a "refreshPreview") // Must NOT be used with other event (i.e. will be used for MINUPDATE only) -#define M_MINUPDATE (1<<16) +#define M_MINUPDATE (1<<19) // Force high quality -#define M_HIGHQUAL (1<<15) +#define M_HIGHQUAL (1<<18) // Elementary functions that can be done to // the preview image when an event occurs -#define M_SPOT (1<<19) -#define M_CSHARP (1<<18) +#define M_WB (1<<17) +#define M_SPOT (1<<16) +#define M_CSHARP (1<<15) #define M_MONITOR (1<<14) #define M_RETINEX (1<<13) #define M_CROP (1<<12) @@ -57,6 +58,7 @@ #define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define DEMOSAIC (M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define WB (M_WB|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define ALLNORAW (M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define CAPTURESHARPEN (M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR|M_CSHARP) #define HDR (M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 5894bfa75..59dc14f86 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -350,7 +350,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, eSensorType &sensorType, PreviewProps pp(0, 0, w, h, 1); Imagefloat tmp(w, h); - src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw, 0); + src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw); src.convertColorSpace(&tmp, neutral.icm, src.getWB()); Image8 *img = new Image8(w, h); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index cc9756919..229aee2a8 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -373,7 +373,7 @@ private: int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f; int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f; PreviewProps ppP(beg_tileW, beg_tileH, crW, crH, skipP); - imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); + imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); // we only need image reduced to 1/4 here @@ -597,7 +597,7 @@ private: for (int wcr = 0; wcr <= 2; wcr++) { for (int hcr = 0; hcr <= 2; hcr++) { PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1); - imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); + imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); @@ -757,7 +757,7 @@ private: } baseImg = new Imagefloat(fw, fh); - imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw, 1); + imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw); if (pl) { pl->setProgress(0.50); diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 09186a399..5ed090712 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -459,7 +459,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s } } - imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw, 0); + imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw); if (cmp) { imgsrc->convertColorSpace(srcImage, *cmp, currWB); } @@ -479,7 +479,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s dstImage->b(y, x) = 60000.f; } } - imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw, 0); + imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw); if (cmp) { imgsrc->convertColorSpace(dstImage, *cmp, currWB); } diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 2375d7cfd..9363c84cb 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -193,7 +193,7 @@ int StdImageSource::load (const Glib::ustring &fname) return 0; } -void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed) +void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) { // the code will use OpenMP as of now. diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 866e90b99..8c2a54a3b 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -58,7 +58,7 @@ public: int load (const Glib::ustring &fname) override; void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override {}; - void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override; + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override; void getrgbloc (int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const procparams::WBParams & wbpar) override {}; ColorTemp getWB () const override { diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc index f5ed63b37..f72f3bc51 100644 --- a/rtgui/whitebalance.cc +++ b/rtgui/whitebalance.cc @@ -246,10 +246,10 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC } auto m = ProcEventMapper::getInstance(); - EvWBObserver10 = m->newEvent(ALLNORAW, "HISTORY_MSG_WBALANCE_OBSERVER10"); - EvWBitcwbprim = m->newEvent(ALLNORAW, "HISTORY_MSG_WBITC_PRIM"); - EvWBitcwbalg = m->newEvent(ALLNORAW, "HISTORY_MSG_WBITC_OBS"); - EvWBitcwgreen = m->newEvent(ALLNORAW, "HISTORY_MSG_WBITC_GREEN"); + EvWBObserver10 = m->newEvent(WB, "HISTORY_MSG_WBALANCE_OBSERVER10"); + EvWBitcwbprim = m->newEvent(WB, "HISTORY_MSG_WBITC_PRIM"); + EvWBitcwbalg = m->newEvent(WB, "HISTORY_MSG_WBITC_OBS"); + EvWBitcwgreen = m->newEvent(WB, "HISTORY_MSG_WBITC_GREEN"); //Add the model columns to the Combo (which is a kind of view),