Resolve exiv2 merge conflicts and merge with

This commit is contained in:
Thanatomanic 2020-10-16 11:45:26 +02:00
commit 8b4389ade9
49 changed files with 1531 additions and 17588 deletions

1
.gitignore vendored
View File

@ -23,7 +23,6 @@ Release
rtdata/rawtherapee.desktop
rtengine/librtengine.a
rtexif/librtexif.a
rtgui/config.h
rtgui/version.h
rtgui/rawtherapee

View File

@ -467,6 +467,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)
@ -482,7 +500,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)
@ -570,6 +587,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()
@ -747,11 +765,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})
@ -788,7 +808,6 @@ else()
CACHE INTERNAL "" FORCE)
endif()
add_subdirectory(rtexif)
add_subdirectory(rtengine)
add_subdirectory(rtgui)
add_subdirectory(rtdata)

View File

@ -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

View File

@ -1,3 +1,4 @@
<<<<<<< HEAD
if(EXTRA_INCDIR)
include_directories("${EXTRA_INCDIR}")
endif()
@ -42,8 +43,11 @@ if(NOT WITH_SYSTEM_KLT)
else()
include_directories("${KLT_INCLUDE_DIRS}")
endif()
if(EXIV2_INCLUDE_DIRS)
include_directories("${EXIV2_INCLUDE_DIRS}")
endif()
link_directories("${PROJECT_SOURCE_DIR}/rtexif"
link_directories(
"${EXPAT_LIBRARY_DIRS}"
"${EXTRA_LIBDIR}"
"${FFTW3F_LIBRARY_DIRS}"
@ -205,7 +209,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}
@ -222,6 +226,7 @@ target_link_libraries(rtengine rtexif
${LENSFUN_LIBRARIES}
${RSVG_LIBRARIES}
${KLT_LIBRARIES}
)
${EXIV2_LIBRARIES}
)
install(FILES ${CAMCONSTSFILE} DESTINATION "${DATADIR}" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)

View File

@ -39,7 +39,6 @@
#include "../rtgui/options.h"
using namespace rtengine;
using namespace rtexif;
namespace
{
@ -430,7 +429,378 @@ std::map<std::string, std::string> getAliases(const Glib::ustring& profile_dir)
return res;
}
}
class DCPMetadata
{
private:
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) :
file_(file),
order_(UNKNOWN)
{
}
bool parse()
{
if (!file_) {
#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
std::fseek(file_, 0, SEEK_SET);
std::uint16_t bo;
std::fread(&bo, 1, 2, file_);
order_ = ByteOrder(bo);
get2(); // Skip
// Seek to IFD
const std::size_t offset = get4();
std::fseek(file_, offset, SEEK_SET);
// First read the IFD directory
const std::uint16_t numtags = get2();
if (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);
}
}
return true;
}
bool find(int id) const
{
return tags_.find(id) != tags_.end();
}
std::string toString(int id) const
{
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 {};
}
std::int32_t toInt(int id, std::size_t offset = 0, TagType as_type = INVALID) const
{
const Tags::const_iterator tag = tags_.find(id);
if (tag == tags_.end()) {
return 0;
}
if (as_type == INVALID) {
as_type = tag->second.type;
}
switch (as_type) {
case SBYTE: {
if (offset < tag->second.value.size()) {
return static_cast<signed char>(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<std::int16_t>(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<std::int32_t>(sget4(tag->second.value.data() + offset)) / denominator;
}
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()) {
return static_cast<signed char>(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<std::int16_t>(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<double>(numerator) / static_cast<double>(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) const
{
const Tags::const_iterator tag = tags_.find(id);
if (tag != tags_.end()) {
return tag->second.count;
}
return 0;
}
private:
struct Tag {
int id;
std::vector<unsigned char> value;
TagType type;
unsigned int count;
};
using Tags = std::unordered_map<int, Tag>;
std::uint16_t sget2(const std::uint8_t* s) const
{
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
{
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<std::uint16_t>::max();
std::fread(&res, 1, 2, file_);
return sget2(reinterpret_cast<const std::uint8_t*>(&res));
}
std::uint32_t get4()
{
std::uint32_t res = std::numeric_limits<std::uint32_t>::max();
std::fread(&res, 1, 4, file_);
return sget4(reinterpret_cast<const std::uint8_t*>(&res));
}
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;
}
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 (
tag.type == INVALID
|| tag.type > DOUBLE
|| tag.count > 10 * 1024 * 1024
) {
tag.type = INVALID;
return false;
}
// Store next Tag's position in file
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);
if (value_size > 4) {
if (std::fseek(file_, get4(), SEEK_SET) == -1) {
tag.type = INVALID;
return false;
}
}
// 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);
return true;
}
FILE* const file_;
Tags tags_;
ByteOrder order_;
};
} // namespace
struct DCPProfileApplyState::Data {
float pro_photo[3][3];
@ -462,23 +832,23 @@ 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 {
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
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
};
static const float adobe_camera_raw_default_curve[] = {
@ -748,54 +1118,48 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
return;
}
ExifManager exifManager(file, nullptr, true);
exifManager.parseTIFF(false);
std::unique_ptr<TagDirectory> 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(TAG_KEY_CALIBRATION_ILLUMINANT_1)
? md.toShort(TAG_KEY_CALIBRATION_ILLUMINANT_1)
: -1;
light_source_2 =
tag
? tag->toInt(0, rtexif::SHORT)
: -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 = 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(TAG_KEY_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(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] = tag->toDouble((col + row * 3) * 8);
forward_matrix_1[row][col] = md.toDouble(TAG_KEY_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(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] = tag->toDouble((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)
tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_1));
if (!tag) {
if (!md.find(TAG_KEY_COLOR_MATRIX_1)) {
std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl;
fclose(file);
return;
@ -805,29 +1169,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(TAG_KEY_COLOR_MATRIX_1, (col + row * 3) * 8);
}
}
tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DIMS));
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 (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(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING) && md.toInt(TAG_KEY_PROFILE_LOOK_TABLE_ENCODING);
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 = 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(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
@ -844,25 +1203,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(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 (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(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING) && md.toInt(TAG_KEY_PROFILE_HUE_SAT_MAP_ENCODING);
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 = 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(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 =
@ -882,14 +1236,14 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
// Second matrix
has_color_matrix_2 = true;
tag = tagDir->getTag(toUnderlying(TagKey::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] =
tag
? tag->toDouble((col + row * 3) * 8)
: color_matrix_1[row][col];
cm2
? md.toDouble(TAG_KEY_COLOR_MATRIX_2, (col + row * 3) * 8)
: color_matrix_1[row][col];
}
}
@ -898,27 +1252,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(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);
}
}
}
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(TAG_KEY_BASELINE_EXPOSURE_OFFSET);
if (has_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
tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_TONE_CURVE));
if (tag) {
if (md.find(TAG_KEY_PROFILE_TONE_CURVE)) {
std::vector<double> curve_points = {
static_cast<double>(DCT_Spline) // The first value is the curve type
};
@ -926,9 +1274,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(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;
@ -944,9 +1292,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(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<double> curve_points = {
static_cast<double>(DCT_Spline)
@ -1799,7 +2145,7 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll)
std::deque<Glib::ustring> dirs = {
rt_profile_dir,
Glib::build_filename(options.rtdir, "dcpprofiles")
Glib::build_filename(options.rtdir, "dcpprofiles")
};
while (!dirs.empty()) {

View File

@ -390,7 +390,7 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool)
return &(iter->second);
}
FramesData idata(filename, std::unique_ptr<RawMetaDataLocation>(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);

View File

@ -86,7 +86,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

View File

@ -342,7 +342,7 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool)
return &(iter->second);
}
FramesData idata(filename, std::unique_ptr<RawMetaDataLocation>(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);

View File

@ -277,10 +277,9 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st
std::unique_ptr<IImage8> source;
{
RawMetaDataLocation rml;
eSensorType sensor_type;
int w, h;
std::unique_ptr<Thumbnail> thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true, true));
const std::unique_ptr<Thumbnail> 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;
@ -309,11 +308,10 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st
std::unique_ptr<IImage8> target;
{
RawMetaDataLocation rml;
eSensorType sensor_type;
double scale;
int w = fw / skip, h = fh / skip;
std::unique_ptr<Thumbnail> thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, false, true));
const std::unique_ptr<Thumbnail> 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;

File diff suppressed because it is too large Load Diff

View File

@ -21,36 +21,24 @@
#include <cstdio>
#include <memory>
#include <string>
#include <vector>
#include <glibmm.h>
#include <exiv2/exiv2.hpp>
#include <libiptcdata/iptc-data.h>
#include "imageio.h"
namespace Glib
{
class ustring;
}
namespace rtexif
{
class TagDirectory;
}
#include "rawimage.h"
#include "rtengine.h"
namespace rtengine
{
class FrameData final
Exiv2::Image::AutoPtr open_exiv2(const Glib::ustring &fname); // TODO: Global function?
class FramesData :
public FramesMetaData
{
protected:
rtexif::TagDirectory* frameRootDir;
IptcData* iptc;
private:
bool ok_;
Glib::ustring fname_;
unsigned int dcrawFrameCount;
struct tm time;
time_t timeStamp;
int iso_speed;
@ -64,85 +52,35 @@ protected:
int rating;
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;
int getRating () const;
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;
int getRating() const override;
Glib::ustring getFileName() const override;
};
class FramesData final : public FramesMetaData {
private:
// frame's root IFD, can be a file root IFD or a SUB-IFD
std::vector<std::unique_ptr<FrameData>> frames;
// root IFD in the file
std::vector<rtexif::TagDirectory*> roots;
IptcData* iptc;
unsigned int dcrawFrameCount;
public:
explicit FramesData (const Glib::ustring& fname, std::unique_ptr<RawMetaDataLocation> 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;
int getRating (unsigned int frame = 0) const override;
};
}

View File

@ -24,7 +24,6 @@
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <libiptcdata/iptc-jpeg.h>
#include "rt_math.h"
#include "procparams.h"
#include "utils.h"
@ -39,9 +38,9 @@
#endif
#include "imageio.h"
#include "iptcpairs.h"
#include "iccjpeg.h"
#include "color.h"
#include "imagedata.h"
#include "jpeg.h"
@ -80,125 +79,55 @@ 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)
MetadataInfo::MetadataInfo(const Glib::ustring& src) :
src_(src),
exif_(new rtengine::procparams::ExifPairs),
iptc_(new rtengine::procparams::IPTCPairs)
{
if (exifRoot != nullptr) {
delete exifRoot;
exifRoot = nullptr;
}
if (eroot) {
rtexif::TagDirectory* td = 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)
const Glib::ustring& MetadataInfo::filename() const
{
// store exif info
exifChange->clear();
*exifChange = exif;
if (exifRoot != nullptr) {
delete exifRoot;
exifRoot = nullptr;
}
if (eroot) {
exifRoot = 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, (const unsigned char*)i->second.at(j).c_str(), min(static_cast<size_t>(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, (const unsigned char*)i->second.at(j).c_str(), min(static_cast<size_t>(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, (const 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);
return src_;
}
void ImageIO::setOutputProfile (const char* pdata, int plen)
const rtengine::procparams::ExifPairs& MetadataInfo::exif() const
{
return *exif_;
}
delete [] profileData;
const rtengine::procparams::IPTCPairs& MetadataInfo::iptc() const
{
return *iptc_;
}
if (pdata) {
profileData = new char [plen];
memcpy (profileData, pdata, plen);
} else {
profileData = nullptr;
}
void MetadataInfo::setExif(const rtengine::procparams::ExifPairs &exif)
{
*exif_ = exif;
}
profileLength = plen;
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),
loadedProfileLength(0),
exifChange(new procparams::ExifPairs),
iptc(nullptr),
exifRoot(nullptr),
sampleFormat(IIOSF_UNKNOWN),
sampleArrangement(IIOSA_UNKNOWN)
{
@ -212,8 +141,6 @@ ImageIO::~ImageIO ()
}
deleteLoadedProfileData();
delete exifRoot;
delete [] profileData;
}
void png_read_data(png_struct_def *png_ptr, unsigned char *data, size_t length);
@ -925,76 +852,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_textp>(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_charp>(png_malloc(ping, allocated_length));
text[0].key = static_cast<png_charp>(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<unsigned long int>(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) {
@ -1023,7 +880,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) {
@ -1057,39 +914,15 @@ 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<png_charp>(profileData);
png_const_charp profdata = reinterpret_cast<png_const_charp>(profileData.data());
#else
png_bytep profdata = reinterpret_cast<png_bytep>(profileData);
png_const_bytep profdata = reinterpret_cast<png_const_bytep>(profileData.data());
#endif
png_set_iCCP(png, info, const_cast<png_charp>("icc"), 0, profdata, profileLength);
png_set_iCCP(png, info, "icc", 0, profdata, profileData.size());
}
{
// 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];
@ -1123,6 +956,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);
@ -1222,52 +1060,9 @@ 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);
if (!profileData.empty()) {
write_icc_profile (&cinfo, reinterpret_cast<const JOCTET*>(profileData.data()), profileData.size());
}
// write image data
@ -1316,6 +1111,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);
@ -1342,7 +1142,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* const mode = "w";
#ifdef WIN32
FILE *file = g_fopen_withBinaryAndLock (fname);
int fileno = _fileno(file);
@ -1350,7 +1150,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) {
@ -1363,113 +1163,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<rtexif::TagDirectory*> (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);
@ -1499,8 +1193,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++) {
@ -1542,38 +1236,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);
@ -1581,6 +1243,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);
@ -1711,3 +1377,43 @@ 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 (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;
return false;
}
}

View File

@ -19,11 +19,8 @@
#pragma once
#include <memory>
#include <glibmm/ustring.h>
#include <libiptcdata/iptc-data.h>
#include "iimage.h"
#include "imagedimensions.h"
#include "imageformat.h"
@ -40,51 +37,60 @@ enum {
IMIO_CANNOTWRITEFILE
};
namespace rtexif
{
class TagDirectory;
}
namespace rtengine
{
class ColorTemp;
class ProgressListener;
class Imagefloat;
namespace procparams
{
class ExifPairs;
class IPTCPairs;
}
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<rtengine::procparams::ExifPairs> exif_;
std::unique_ptr<rtengine::procparams::IPTCPairs> iptc_;
};
class ImageIO : virtual public ImageDatas
{
protected:
ProgressListener* pl;
cmsHPROFILE embProfile;
char* profileData;
std::string profileData;
int profileLength;
char* loadedProfileData;
bool loadedProfileDataJpg;
int loadedProfileLength;
const std::unique_ptr<procparams::ExifPairs> exifChange;
IptcData* iptc;
const rtexif::TagDirectory* exifRoot;
MyMutex imutex;
IIOSampleFormat sampleFormat;
IIOSampleArrangement sampleArrangement;
MetadataInfo metadataInfo;
private:
void deleteLoadedProfileData( );
public:
static Glib::ustring errorMsg[6];
ImageIO();
~ImageIO() override;
@ -119,9 +125,10 @@ 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 setOutputProfile (const char* pdata, int plen);
void setMetadata(MetadataInfo info);
void setOutputProfile(const std::string& pdata);
bool saveMetadata(const Glib::ustring &fname) const;
MyMutex& mutex ();
};

View File

@ -173,7 +173,7 @@ public:
{
outCurve = { 0.0 };
}
double getDirPyrDenoiseExpComp ( )
{
return dirpyrdenoiseExpComp;

View File

@ -1510,20 +1510,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<unsigned int>(params->raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1);
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) {
//imgNum = rtengine::LIM<unsigned int>(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
@ -2075,7 +2065,7 @@ 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);
delete im;

View File

@ -5622,18 +5622,18 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl
double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size)
{
if (!fname.empty()) {
rtengine::RawMetaDataLocation ri;
// TODO: std::unique_ptr<> to the rescue
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;

View File

@ -1,44 +0,0 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
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"}
};

View File

@ -61,9 +61,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();

View File

@ -310,7 +310,35 @@ bool saveToKeyfile(
return false;
}
}
const std::map<std::string, std::string> exif_keys = {
{"Copyright", "Exif.Image.Copyright"},
{"Artist", "Exif.Image.Artist"},
{"ImageDescription", "Exif.Image.ImageDescription"},
{"Exif.UserComment", "Exif.Photo.UserComment"}
};
const std::map<std::string, std::string> 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
{
@ -5348,9 +5376,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", "Luminance", dehaze.luminance, keyFile);
// Directional pyramid denoising
@ -6388,16 +6416,30 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
// EXIF change list
if (!pedited || pedited->exif) {
std::map<Glib::ustring, Glib::ustring> 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<std::string, std::string> m;
for (auto &p : iptc_keys) {
m[p.second] = p.first;
}
for (IPTCPairs::const_iterator i = iptc.begin(); i != iptc.end(); ++i) {
Glib::ArrayHandle<Glib::ustring> values = i->second;
keyFile.set_string_list("IPTC", i->first, values);
auto it = m.find(i->first);
if (it != m.end()) {
Glib::ArrayHandle<Glib::ustring> values = i->second;
keyFile.set_string_list("IPTC", it->second, values);
}
}
}
@ -8322,7 +8364,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "Dehaze", "Depth", pedited, dehaze.depth, pedited->dehaze.depth);
assignFromKeyfile(keyFile, "Dehaze", "Luminance", pedited, dehaze.luminance, pedited->dehaze.luminance);
}
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);
@ -8724,10 +8766,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;
}
}
}
}
@ -8747,7 +8792,13 @@ 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
@ -8756,7 +8807,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) {

View File

@ -1651,8 +1651,17 @@ struct MetaDataParams {
*/
class ExifPairs final
{
private:
using Pairs = std::map<Glib::ustring, Glib::ustring>;
public:
using const_iterator = std::map<Glib::ustring, Glib::ustring>::const_iterator;
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
{
@ -1669,6 +1678,11 @@ public:
pairs.clear();
}
size_type erase(const Glib::ustring& key)
{
return pairs.erase(key);
}
Glib::ustring& operator[](const Glib::ustring& key)
{
return pairs[key];
@ -1680,7 +1694,7 @@ public:
}
private:
std::map<Glib::ustring, Glib::ustring> pairs;
Pairs pairs;
};
/**

View File

@ -1201,8 +1201,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly)
// Load complete Exif information
std::unique_ptr<RawMetaDataLocation> rml(new RawMetaDataLocation (ri->get_exifBase(), ri->get_ciffBase(), ri->get_ciffLen()));
idata = new FramesData (fname, std::move(rml));
idata = new FramesData(fname); // TODO: std::unique_ptr<>
idata->setDCRawFrameCount (numFrames);
green(W, H);

View File

@ -1,37 +0,0 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
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) {}
};
}

View File

@ -30,7 +30,6 @@
#include "iimage.h"
#include "imageformat.h"
#include "procevents.h"
#include "rawmetadatalocation.h"
#include "settings.h"
#include "../rtgui/threadutils.h"
@ -87,78 +86,56 @@ 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 the rating of the image */
virtual int getRating (unsigned int frame = 0) 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;
/** @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);
@ -179,7 +156,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<RawMetaDataLocation> 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 */

View File

@ -209,7 +209,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;
@ -314,10 +314,10 @@ 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
RawImageSource src;
int err = src.load(fname, true);
if (err) {
@ -326,7 +326,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml
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);
@ -370,7 +370,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;
@ -380,7 +380,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;
@ -391,7 +391,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL
return tpp;
}
RawImage *ri = new RawImage (fname);
unsigned int imageNum = 0;
int r = ri->loadRaw (false, imageNum, false);
@ -405,10 +405,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
@ -448,8 +444,8 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL
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, rml, sensorType, w, h);
img = load_inspector_mode(fname, sensorType, w, h);
if (!img) {
delete tpp;
return nullptr;
@ -457,7 +453,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL
tpp->scale = 1.;
tpp->thumbImg = img;
return tpp;
}
} else {
@ -513,28 +509,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL
#define FISGREEN(filter,row,col) \
((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1 || !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;
@ -583,10 +558,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);
@ -1098,20 +1069,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)
{
unsigned int imgNum = 0;
if (isRaw) {
if (sensorType == ST_BAYER) {
imgNum = rtengine::LIM<unsigned int>(params.raw.bayersensor.imageNum, 0, metadata->getFrameCount() - 1);
} else if (sensorType == ST_FUJI_XTRANS) {
//imgNum = rtengine::LIM<unsigned int>(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);
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;
@ -1210,7 +1173,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);
@ -1398,7 +1361,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
}
}
// luminance processing
// ipf.EPDToneMap(labView,0,6);
@ -1471,7 +1434,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
ipf.ciecam_02float (cieView, adap, 1, 2, labView, &params, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, sk, execsharp, d, dj, yb, rtt);
delete cieView;
}
// color processing
//ipf.colorCurve (labView, labView);

View File

@ -93,10 +93,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);

View File

@ -1544,18 +1544,11 @@ 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 + -
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.;
@ -1687,21 +1680,24 @@ 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(initialImage->getMetaData()->getRootExifData());
break;
case MetaDataParams::EDIT:
// ask for the correct frame number, but may contain subframe depending on initial raw's hierarchy
readyImg->setMetadata(initialImage->getMetaData()->getBestExifData(imgsrc, &params.raw), params.exif, params.iptc);
break;
default: // case MetaDataParams::STRIP
// nothing to do
break;
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, &params.raw), params.exif, params.iptc);
break;
default: // case MetaDataParams::STRIP
// nothing to do
break;
}

View File

@ -1,29 +0,0 @@
add_library(rtexif STATIC
canonattribs.cc
fujiattribs.cc
kodakattribs.cc
nikonattribs.cc
olympusattribs.cc
panasonicattribs.cc
pentaxattribs.cc
rtexif.cc
sonyminoltaattribs.cc
stdattribs.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()

File diff suppressed because it is too large Load Diff

View File

@ -1,313 +0,0 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#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}
};
}

View File

@ -1,162 +0,0 @@
/*
* This file is part of RawTherapee.
*/
#include <string.h>
#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.f) {
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.f) {
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.f) {
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 }
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,855 +0,0 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <string>
#include <cmath>
#include <iomanip>
#include <sstream>
#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<std::string, std::string> 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 32 10"] = "Olympus M.Zuiko Digital ED 12-200mm f/3.5-6.3";
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 34 10"] = "Olympus M.Zuiko Digital ED 12-45mm f/4.0 Pro";
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["02 29 10"] = "Leica DG Summilux 12mm f/1.4 Asph.";
lenses["02 30 10"] = "Leica DG Vario-Elmarit 12-60mm f/2.8-4 Asph. Power OIS";
lenses["02 31 10"] = "Lumix G Vario 45-200mm f/4.0-5.6 II";
lenses["02 32 10"] = "Lumix G Vario 100-300mm f/4.0-5.6 II";
lenses["02 33 10"] = "Lumix G X Vario 12-35mm f/2.8 II Asph. Power OIS";
lenses["02 34 10"] = "Lumix G Vario 35-100mm f/2.8 II";
lenses["02 35 10"] = "Leica DG Vario-Elmarit 8-18mm f/2.8-4 Asph.";
lenses["02 36 10"] = "Leica DG Elmarit 200mm f/2.8 Power OIS";
lenses["02 37 10"] = "Leica DG Vario-Elmarit 50-200mm f/2.8-4 Asph. Power OIS";
lenses["02 38 10"] = "Leica DG Vario-Summilux 10-25mm f/1.7 Asph.";
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";
lenses["024 01 10"] = "Venus Optics Laowa 50mm f/2.8 2x Macro";
}
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<std::string, std::string>::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}
};
}

View File

@ -1,138 +0,0 @@
/*
* This file is part of RawTherapee.
*/
#include <string.h>
#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 }
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,706 +0,0 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include <glibmm/ustring.h>
#include "../rtengine/noncopyable.h"
#include "../rtengine/rawmetadatalocation.h"
namespace Glib
{
class KeyFile;
}
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<Tag*> 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)
bool parseJPEG;
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, bool parseJpeg = true);
TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border);
virtual ~TagDirectory ();
inline ByteOrder getOrder () const
{
return order;
}
TagDirectory* getParent ()
{
return parent;
}
inline bool getParseJpeg() const
{
return parseJPEG;
}
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
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<const Tag*> findTags (const char* name);
// Find a all Tags with the given ID by scanning the whole tag tree
std::vector<const Tag*> findTags (int ID);
// Try to get the Tag in the current directory and in parent directories
// (won't look into subdirs)
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) const;
void applyChange (const std::string &field, const Glib::ustring &value);
void printAll (unsigned int level = 0) const; // reentrant debug function, keep level=0 on first call !
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;
void sort ();
};
// a table of tags: id are offset from beginning and not identifiers
class TagDirectoryTable: public TagDirectory, public rtengine::NonCopyable
{
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) const 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<signed char*> (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, std::size_t size, 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) const;
// 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, bool parseJpeg = true);
public:
FILE* f;
std::unique_ptr<rtengine::RawMetaDataLocation> rml;
ByteOrder order;
bool onlyFirst; // Only first IFD
unsigned int IFDOffset;
std::vector<TagDirectory*> roots;
std::vector<TagDirectory*> frames;
ExifManager (FILE* fHandle, std::unique_ptr<rtengine::RawMetaDataLocation> _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<Tag*> 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, sizeof(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)
{
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: {
const double dividend = (int)sget4 (t->getValue() + ofs, t->getOrder());
const double divisor = (int)sget4 (t->getValue() + ofs + 4, t->getOrder());
return divisor == 0. ? 0. : dividend / divisor;
}
case RATIONAL: {
const double dividend = (uint32_t)sget4 (t->getValue() + ofs, t->getOrder());
const double divisor = (uint32_t)sget4 (t->getValue() + ofs + 4, t->getOrder());
return divisor == 0. ? 0. : dividend / divisor;
}
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)
{
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: {
int a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder());
return a == 0 ? 0 : (int)sget4 (t->getValue() + ofs, t->getOrder()) / a;
}
case RATIONAL: {
uint32_t a = (uint32_t)sget4 (t->getValue() + ofs + 4, t->getOrder());
return a == 0 ? 0 : (uint32_t)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<typename T = std::uint32_t>
class ChoiceInterpreter : public Interpreter
{
protected:
using Choices = std::map<T, std::string>;
using ChoicesIterator = typename Choices::const_iterator;
Choices choices;
public:
ChoiceInterpreter () {};
std::string toString (const Tag* t) const override
{
const typename std::map<T, std::string>::const_iterator r = choices.find(t->toInt());
if (r != choices.end()) {
return r->second;
} else {
char buffer[1024];
t->toString(buffer, sizeof(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[];
}

File diff suppressed because it is too large Load Diff

View File

@ -1,927 +0,0 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
* Copyright (c) 2010 Oliver Duis <www.oliverduis.de>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <cstdio>
#include <cstring>
#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";
}
snprintf(buffer, sizeof(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";
}
snprintf(buffer, sizeof(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";
}
snprintf(buffer, sizeof(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) {
snprintf(buffer, sizeof(buffer), "1/%.0f", 1.0 / d);
} else {
snprintf(buffer, sizeof(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) {
snprintf(buffer, sizeof(buffer), "1/%.0f", 1.0 / d);
} else {
snprintf(buffer, sizeof(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";
}
snprintf(buffer, sizeof(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];
snprintf(buffer, sizeof(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}
};
}

View File

@ -193,7 +193,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}

View File

@ -335,7 +335,3 @@ int CacheImageData::save (const Glib::ustring& fname)
}
}
rtengine::procparams::IPTCPairs CacheImageData::getIPTCData(unsigned int frame) const
{
return {};
}

View File

@ -89,30 +89,25 @@ public:
// FramesMetaData interface
//-------------------------------------------------------------------------
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
int getRating (unsigned int frame = 0) const override { return rating; } // FIXME-piotr : missing rating
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 ""; }
int getRating () const override { return rating; } // FIXME-piotr : missing rating
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; }
};

View File

@ -1323,16 +1323,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\n<span size=\"small\">f/</span><span size=\"large\">%3</span> <span size=\"large\">%4</span><span size=\"small\">s</span> <span size=\"small\">%5</span><span size=\"large\">%6</span> <span size=\"large\">%7</span><span size=\"small\">mm</span>",
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 <span size=\"large\">%2</span><span size=\"small\">EV</span>",
@ -1360,7 +1360,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) {

View File

@ -16,24 +16,31 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
*/
#include <unordered_set>
#include "exifpanel.h"
#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)
defChangeList(new rtengine::procparams::ExifPairs),
editableTags{
{"Exif.Photo.UserComment", "User Comment"},
{"Exif.Image.Artist", "Artist"},
{"Exif.Image.Copyright", "Copyright"},
{"Exif.Image.ImageDescription", "Image Description"}
}
{
recursiveOp = true;
exifTree = Gtk::manage (new Gtk::TreeView());
scrolledWindow = Gtk::manage (new Gtk::ScrolledWindow());
@ -51,11 +58,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));
exifTree->set_show_expanders(false);
delicon = RTImage::createPixbufFromFile ("cancel-small.png");
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 +70,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 +105,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,39 +113,28 @@ 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 ();
}
@ -168,21 +145,18 @@ 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;
}
@ -196,107 +170,97 @@ 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)
{
if (!value.validate()) {
value = "???";
}
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 ("<b>") + escapeHtmlChars (field) + "</b>";
row[exifColumns.value] = Glib::ustring ("<b>") + escapeHtmlChars (value) + "</b>";
} else if (action == AC_SYSTEM) {
row[exifColumns.field] = Glib::ustring ("<i>") + escapeHtmlChars (field) + "</i>";
row[exifColumns.value] = Glib::ustring ("<i>") + escapeHtmlChars (value) + "</i>";
} else {
row[exifColumns.field] = escapeHtmlChars (field);
row[exifColumns.value] = escapeHtmlChars (value);
}
return row.children();
}
Gtk::TreeModel::Children ExifPanel::addSeparator ()
void ExifPanel::refreshTags()
{
Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
std::vector<Gtk::TreeModel::Path> sel = selection->get_selected_rows();
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;
exifTreeModel->clear();
return row.children();
}
if (!idata) {
return;
}
void ExifPanel::addDirectory (const TagDirectory* dir, Gtk::TreeModel::Children root, bool checkForSeparator)
{
const Glib::ustring fn = idata->getFileName();
if (fn.empty()) {
return;
}
for (int i = 0; i < dir->getCount(); ++i) {
Tag* t = (const_cast<TagDirectory*> (dir))->getTagByIndex (i);
std::unordered_set<std::string> ed;
for (const auto &p : editableTags) {
ed.insert(p.first);
}
bool hasContent = false;
try {
auto img = open_exiv2(fn);
img->readMetadata();
auto& exif = img->exifData();
if (checkForSeparator && i == 0) {
for (int j = 0; j < dir->getCount(); ++j) {
Tag* t2 = (const_cast<TagDirectory*> (dir))->getTagByIndex (j);
const TagAttrib* currAttrib = t2->getAttrib();
if (currAttrib && (options.lastShowAllExif || currAttrib->action != AC_SYSTEM)) {
addSeparator();
hasContent = true;
break;
}
for (const auto& p : *changeList) {
try {
exif[p.first] = p.second;
} catch (const 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 (const auto& p : editableTags) {
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);
}
} else {
addTag (root, t->nameToString (), t->valueToString (), currAttrib ? (t->getOwnMemory() ? currAttrib->action : AC_SYSTEM) : AC_DONTWRITE, currAttrib && currAttrib->editable);
}
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 (const Exiv2::AnyError& exc) {
return;
}
for (const auto& p : sel) {
exifTree->get_selection()->select(p);
}
}
@ -307,167 +271,46 @@ void ExifPanel::exifSelectionChanged ()
std::vector<Gtk::TreeModel::Path> 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(const Gtk::TreeModel::const_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);
}
const auto key = iter->get_value(exifColumns.key);
changeList->erase(key);
}
void ExifPanel::removePressed ()
{
std::vector<Gtk::TreeModel::Path> 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<Gtk::TreeModel::Path> 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("<b>") + iter->get_value(exifColumns.orig_value) + "</b>");
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 ("<b>") + iter->get_value (exifColumns.orig_value) + "</b>");
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<Gtk::TreeModel::Path> 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 ();
}
@ -484,10 +327,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 (const auto& p : editableTags) {
tcombo->append(p.second);
}
hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4);
hb1->pack_start (*tcombo);
@ -497,21 +339,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;
{
const Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
const std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
if (sel.empty()) {
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) {
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);
}
}
ventry->set_text (getSelectedValue ());
}
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);
@ -524,8 +378,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 = editableTags[tcombo->get_active_row_number()].first;
const auto value = ventry->get_text();
(*changeList)[key] = value;
refreshTags();
notifyListener ();
}
@ -538,186 +394,8 @@ void ExifPanel::addPressed ()
delete hb2;
}
void ExifPanel::showAlltoggled ()
{
options.lastShowAllExif = showAll->get_active();
setImageData (idata);
}
bool ExifPanel::rowSeperatorFunc(const Glib::RefPtr<Gtk::TreeModel>& 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 ("<b>") + value + "</b>");
iter->set_value (exifColumns.value_nopango, value);
iter->set_value (exifColumns.orig_value, value);
iter->set_value (exifColumns.field, Glib::ustring ("<b>") + fseg + "</b>");
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 ("<b>") + value + "</b>");
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<Gtk::TreeSelection> selection = exifTree->get_selection();
std::vector<Gtk::TreeModel::Path> 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<Gtk::TreeSelection> selection = exifTree->get_selection();
std::vector<Gtk::TreeModel::Path> 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.empty()) {
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"));
}

View File

@ -25,6 +25,18 @@
#include "toolpanel.h"
#include "../rtexif/rtexif.h"
namespace rtengine
{
namespace procparams
{
class ExifPairs;
}
}
class ExifPanel final :
public Gtk::VBox,
public ToolPanel
@ -34,37 +46,29 @@ private:
const rtengine::FramesMetaData* idata;
const std::unique_ptr<rtengine::procparams::ExifPairs> changeList;
const std::unique_ptr<rtengine::procparams::ExifPairs> defChangeList;
bool recursiveOp;
class ExifColumns : public Gtk::TreeModelColumnRecord
{
public:
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon;
Gtk::TreeModelColumn<Glib::ustring> field;
Gtk::TreeModelColumn<Glib::ustring> field_nopango;
Gtk::TreeModelColumn<Glib::ustring> key;
Gtk::TreeModelColumn<Glib::ustring> label;
Gtk::TreeModelColumn<Glib::ustring> value;
Gtk::TreeModelColumn<Glib::ustring> value_nopango;
Gtk::TreeModelColumn<Glib::ustring> orig_value;
Gtk::TreeModelColumn<rtexif::ActionCode> action;
Gtk::TreeModelColumn<bool> editable;
Gtk::TreeModelColumn<bool> edited;
Gtk::TreeModelColumn<bool> 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<Gdk::Pixbuf> delicon;
Glib::RefPtr<Gdk::Pixbuf> keepicon;
Glib::RefPtr<Gdk::Pixbuf> editicon;
@ -73,32 +77,18 @@ private:
Gtk::ScrolledWindow* scrolledWindow;
Glib::RefPtr<Gtk::TreeStore> 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();
const std::vector<std::pair<std::string, Glib::ustring>> 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(const Gtk::TreeModel::const_iterator& iter);
void resetPressed();
void resetAllPressed();
void addPressed();
void showAlltoggled();
bool rowSeperatorFunc(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::iterator& iter);
public:
ExifPanel ();
@ -111,7 +101,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();

View File

@ -16,16 +16,64 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
*/
#include <set>
#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<std::string> 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)
@ -441,11 +489,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 (const auto& tag : iptc) {
if (iptc_keys.find(tag.key()) != iptc_keys.end()) {
(*embeddedData)[tag.key()].push_back(tag.toString());
}
}
} catch (const Exiv2::AnyError& exc) {
embeddedData->clear();
}
}
file->set_sensitive (!embeddedData->empty());
@ -570,32 +627,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 +686,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));
}
}

View File

@ -20,6 +20,7 @@
#include <iomanip>
#include "shcselector.h"
#include "multilangmgr.h"
#include "mycurve.h"
#include "rtscalable.h"

View File

@ -35,14 +35,80 @@
#include "../rtengine/dynamicprofile.h"
#include "../rtengine/profilestore.h"
#include "../rtengine/settings.h"
#include "../rtexif/rtexif.h"
#include "guiutils.h"
#include "batchqueue.h"
#include "extprog.h"
#include "md5helper.h"
#include "pathutils.h"
#include "paramsedited.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<Glib::KeyFile> kf(new Glib::KeyFile);
if (!kf) {
return false;
}
// open the file in write mode
const std::unique_ptr<FILE, decltype(&std::fclose)> 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;
@ -162,24 +228,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<rtengine::RawMetaDataLocation>(new rtengine::RawMetaDataLocation(ri)));
infoFromImage (fname);
}
}
@ -240,7 +305,6 @@ const ProcParams& Thumbnail::getProcParamsU ()
*/
rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool returnParams, bool force, bool flaggingMode)
{
// try to load the last saved parameters from the cache or from the paramfile file
ProcParams* ldprof = nullptr;
@ -258,52 +322,35 @@ 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<rtengine::RawMetaDataLocation>(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;
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<const rtengine::FramesMetaData> imageMetaData(rtengine::FramesMetaData::fromFile(fname));
const std::unique_ptr<PartialProfile, decltype(pp_deleter)> 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();
}
}
} 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<rtengine::RawMetaDataLocation>(new rtengine::RawMetaDataLocation(rtengine::Thumbnail::loadMetaDataFromRaw(fname))), true);
} else {
// Should we ask all frame's MetaData ?
imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true);
}
static int index = 0; // Will act as unique identifier during the session
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("\"");
@ -781,9 +828,9 @@ ThFileType Thumbnail::getType ()
return (ThFileType) cfs.format;
}
int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptr<rtengine::RawMetaDataLocation> 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;

View File

@ -82,7 +82,7 @@ class Thumbnail
void _loadThumbnail (bool firstTrial = true);
void _saveThumbnail ();
void _generateThumbnailImage ();
int infoFromImage (const Glib::ustring& fname, std::unique_ptr<rtengine::RawMetaDataLocation> rml = nullptr);
int infoFromImage (const Glib::ustring& fname);
void loadThumbnail (bool firstTrial = true);
void generateExifDateTimeStrings ();

View File

@ -1,155 +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 '-1<tab>n/a'
# replace '10.1<tab>Sigma' 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 <tab> 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"