Skip to content

Commit

Permalink
Merge branch 'Exiv2:main' into WebAssembly
Browse files Browse the repository at this point in the history
  • Loading branch information
1div0 authored Sep 28, 2023
2 parents c1286b7 + fe44c8c commit 8bb5636
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 34 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/on_PR_meson.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,17 @@ jobs:
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
Emscripten:
runs-on: ubuntu-latest
name: Emscripten
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
python3 -m pip install meson ninja
- name: Emscripten
uses: mymindstorm/setup-emsdk@v11
- name: Compile
run: |
meson setup "${{github.workspace}}/build" --cross-file="${{github.workspace}}/em.txt" --wrap-mode=forcefallback -Ddefault_library=static -Dwarning_level=3 -Dcpp_std=c++20 -DunitTests=disabled
meson compile -C "${{github.workspace}}/build" --verbose
6 changes: 6 additions & 0 deletions app/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1826,7 +1826,13 @@ int renameFile(std::string& newPath, const tm* tm) {
std::string path = newPath;
auto oldFsPath = fs::path(path);
std::string format = Params::instance().format_;
std::string filename = p.stem().string();
std::string basesuffix = "";
int pos = filename.find('.');
if (pos > 0)
basesuffix = filename.substr(filename.find('.'));
replace(format, ":basename:", p.stem().string());
replace(format, ":basesuffix:", basesuffix);
replace(format, ":dirname:", p.parent_path().filename().string());
replace(format, ":parentname:", p.parent_path().parent_path().filename().string());

Expand Down
1 change: 1 addition & 0 deletions app/exiv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ void Params::help(std::ostream& os) const {
<< _(" -r fmt Filename format for the 'rename' action. The format string\n")
<< _(" follows strftime(3). The following keywords are also supported:\n")
<< _(" :basename: - original filename without extension\n")
<< _(" :basesuffix: - suffix in original filename, starts with first dot and ends before extension\n")
<< _(" :dirname: - name of the directory holding the original file\n")
<< _(" :parentname: - name of parent directory\n") << _(" Default 'fmt' is %Y%m%d_%H%M%S\n")
<< _(" -c txt JPEG comment string to set in the image.\n")
Expand Down
11 changes: 11 additions & 0 deletions em.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
nm = 'emnm'

[host_machine]
system = 'emscripten'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
17 changes: 12 additions & 5 deletions exiv2.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,11 +455,12 @@ environment variable). The *fmt* string follows the definitions in
date and time. In addition, the following special character sequences are
also provided:

| Variable | Description |
|:------ |:---- |
| :basename: | Original filename without extension |
| :dirname: | Name of the directory holding the original file |
| :parentname: | Name of parent directory |
| Variable | Description |
|:------ |:---- |
| :basename: | Original filename without extension |
| :basesuffix: | Suffix in original filename, starts with first dot and ends before extension, e.g. PANO, MP, NIGHT added by Google Camera app |
| :dirname: | Name of the directory holding the original file |
| :parentname: | Name of parent directory |

The default *fmt* is %Y%m%d_%H%M%S

Expand Down Expand Up @@ -491,6 +492,12 @@ exiv2.exe: File `./Stonehenge_16_Jul_2015.jpg' exists. [O]verwrite, [r]ename or
Renaming file to ./Stonehenge_16_Jul_2015_1.jpg
```

If the filename contains a suffix, which shall be included in new filename:
```
$ exiv2 --verbose --rename '%d_%b_%Y:basesuffix:' Stonehenge.PANO.jpg
File 1/1: Stonehenge.PANO.jpg
Renaming file to '16_Jul_2015.PANO'.jpg```
<div id="adjust_time">
### **-a** *time*, **--adjust** *time*
Expand Down
18 changes: 16 additions & 2 deletions src/canonmn_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ constexpr TagDetails canonModelId[] = {
{0x80000480, "EOS R50"},
{0x80000481, "EOS R6 Mark II"},
{0x80000487, "EOS R8"},
{0x80000491, "PowerShot V10"},
{0x80000498, "EOS R100"},
{0x80000520, "EOS D2000C"},
{0x80000560, "EOS D6000C"},
};
Expand Down Expand Up @@ -2062,6 +2064,8 @@ constexpr TagDetails canonCsLensType[] = {
{61182, "Canon RF 400mm F2.8L IS USM + RF1.4x"},
{61182, "Canon RF 400mm F2.8L IS USM + RF2x"},
{61182, "Canon RF 600mm F4L IS USM"},
{61182, "Canon RF 600mm F4L IS USM + RF1.4x"},
{61182, "Canon RF 600mm F4L IS USM + RF2x"},
{61182, "Canon RF 800mm F5.6L IS USM"},
{61182, "Canon RF 800mm F5.6L IS USM + RF1.4x"},
{61182, "Canon RF 800mm F5.6L IS USM + RF2x"},
Expand All @@ -2072,7 +2076,11 @@ constexpr TagDetails canonCsLensType[] = {
{61182, "Canon RF 135mm F1.8 L IS USM"},
{61182, "Canon RF 24-50mm F4.5-6.3 IS STM"},
{61182, "Canon RF-S 55-210mm F5-7.1 IS STM"},
{65535, "n/a"},
{61182, "Canon RF 100-300mm F2.8L IS USM"},
{61182, "Canon RF 100-300mm F2.8L IS USM + RF1.4x"},
{61182, "Canon RF 100-300mm F2.8L IS USM + RF2x"},
{61182, "Canon RF 28mm F2.8 STM"},
{65535, N_("n/a")},
};

//! FlashActivity, tag 0x001c
Expand Down Expand Up @@ -2490,7 +2498,7 @@ constexpr TagDetails canonToningEffect[] = {
};

//! RFLensType, tag 0x003D
// from https://github.com/exiftool/exiftool/blob/12.49/lib/Image/ExifTool/Canon.pm#L6791
// from https://github.com/exiftool/exiftool/blob/12.67/lib/Image/ExifTool/Canon.pm#L6833
constexpr TagDetails canonRFLensType[] = {
{0, N_("n/a")},
{257, "Canon RF 50mm F1.2L USM"},
Expand Down Expand Up @@ -2529,6 +2537,8 @@ constexpr TagDetails canonRFLensType[] = {
{290, "Canon RF 400mm F2.8L IS USM + RF1.4x"},
{291, "Canon RF 400mm F2.8L IS USM + RF2x"},
{292, "Canon RF 600mm F4L IS USM"},
{293, "Canon RF 600mm F4L IS USM + RF1.4x"},
{294, "Canon RF 600mm F4L IS USM + RF2x"},
{295, "Canon RF 800mm F5.6L IS USM"},
{296, "Canon RF 800mm F5.6L IS USM + RF1.4x"},
{297, "Canon RF 800mm F5.6L IS USM + RF2x"},
Expand All @@ -2539,6 +2549,10 @@ constexpr TagDetails canonRFLensType[] = {
{303, "Canon RF 135mm F1.8 L IS USM"},
{304, "Canon RF 24-50mm F4.5-6.3 IS STM"},
{305, "Canon RF-S 55-210mm F5-7.1 IS STM"},
{306, "Canon RF 100-300mm F2.8L IS USM"},
{307, "Canon RF 100-300mm F2.8L IS USM + RF1.4x"},
{308, "Canon RF 100-300mm F2.8L IS USM + RF2x"},
{313, "Canon RF 28mm F2.8 STM"},
};

// Canon File Info Tag
Expand Down
60 changes: 38 additions & 22 deletions src/easyaccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,29 @@ ExifData::const_iterator findMetadatum(const ExifData& ed, const char* const key
return ed.end();
} // findMetadatum

/*!
@brief Search \em ed for a Metadatum specified by the \em keys.
The \em keys are searched in the order of their appearance, the
first available Metadatum is returned, except it is in NikonLd4
and its value 0.
Example: Exif.NikonLd4.LensID and Exif.NikonLd4.LensIDNumber are
usually together included, one of them has value 0 (which means
undefined), so skip tag with value 0.
@param ed The %Exif metadata container to search
@param keys Array of keys to look for
@param count Number of elements in the array
*/
ExifData::const_iterator findMetadatumSkip0inNikonLd4(const ExifData& ed, const char* const keys[], size_t count) {
for (size_t i = 0; i < count; ++i) {
auto pos = ed.findKey(ExifKey(keys[i]));
if (pos != ed.end()) {
if (strncmp(keys[i], "Exif.NikonLd4", 13) != 0 || pos->getValue()->toInt64(0) > 0)
return pos;
}
}
return ed.end();
} // findMetadatumSkip0inNikonLd4
} // anonymous namespace

// *****************************************************************************
Expand Down Expand Up @@ -201,7 +224,6 @@ ExifData::const_iterator sceneMode(const ExifData& ed) {
"Exif.Panasonic.SceneMode",
"Exif.Pentax.PictureMode",
"Exif.PentaxDng.PictureMode",
"Exif.Photo.SceneCaptureType",
};
return findMetadatum(ed, keys, std::size(keys));
}
Expand Down Expand Up @@ -263,26 +285,18 @@ ExifData::const_iterator lensName(const ExifData& ed) {
"Exif.Nikon3.Lens",
};

for (const auto& key : keys) {
auto pos = ed.findKey(ExifKey(key));
if (pos != ed.end()) {
// Exif.NikonLd4.LensID and Exif.NikonLd4.LensIDNumber are usually together included,
// one of them has value 0 (which means undefined), so skip tag with value 0
if (strncmp(key, "Exif.NikonLd4", 13) != 0 || pos->getValue()->toInt64(0) > 0)
return pos;
}
}
return ed.end();
return findMetadatumSkip0inNikonLd4(ed, keys, std::size(keys));
}

ExifData::const_iterator saturation(const ExifData& ed) {
static constexpr const char* keys[] = {
"Exif.Photo.Saturation", "Exif.CanonCs.Saturation", "Exif.MinoltaCsNew.Saturation",
"Exif.MinoltaCsOld.Saturation", "Exif.MinoltaCs7D.Saturation", "Exif.MinoltaCs5D.Saturation",
"Exif.Fujifilm.Color", "Exif.Nikon3.Saturation", "Exif.NikonPc.Saturation",
"Exif.Panasonic.Saturation", "Exif.Pentax.Saturation", "Exif.PentaxDng.Saturation",
"Exif.Sigma.Saturation", "Exif.Sony1.Saturation", "Exif.Sony2.Saturation",
"Exif.Casio.Saturation", "Exif.Casio2.Saturation", "Exif.Casio2.Saturation2",
"Exif.Fujifilm.Color", "Exif.Nikon3.Saturation", "Exif.Nikon3.Saturation2",
"Exif.NikonPc.Saturation", "Exif.Panasonic.Saturation", "Exif.Pentax.Saturation",
"Exif.PentaxDng.Saturation", "Exif.Sigma.Saturation", "Exif.Sony1.Saturation",
"Exif.Sony2.Saturation", "Exif.Casio.Saturation", "Exif.Casio2.Saturation",
"Exif.Casio2.Saturation2",
};
return findMetadatum(ed, keys, std::size(keys));
}
Expand Down Expand Up @@ -418,10 +432,11 @@ ExifData::const_iterator subjectDistance(const ExifData& ed) {
"Exif.Photo.SubjectDistance", "Exif.Image.SubjectDistance", "Exif.CanonSi.SubjectDistance",
"Exif.CanonFi.FocusDistanceUpper", "Exif.CanonFi.FocusDistanceLower", "Exif.MinoltaCsNew.FocusDistance",
"Exif.Nikon1.FocusDistance", "Exif.Nikon3.FocusDistance", "Exif.NikonLd2.FocusDistance",
"Exif.NikonLd3.FocusDistance", "Exif.NikonLd4.FocusDistance", "Exif.Olympus.FocusDistance",
"Exif.OlympusFi.FocusDistance", "Exif.Casio.ObjectDistance", "Exif.Casio2.ObjectDistance",
"Exif.NikonLd3.FocusDistance", "Exif.NikonLd4.FocusDistance", "Exif.NikonLd4.FocusDistance2",
"Exif.Olympus.FocusDistance", "Exif.OlympusFi.FocusDistance", "Exif.Casio.ObjectDistance",
"Exif.Casio2.ObjectDistance",
};
return findMetadatum(ed, keys, std::size(keys));
return findMetadatumSkip0inNikonLd4(ed, keys, std::size(keys));
}

ExifData::const_iterator lightSource(const ExifData& ed) {
Expand Down Expand Up @@ -453,11 +468,12 @@ ExifData::const_iterator serialNumber(const ExifData& ed) {

ExifData::const_iterator focalLength(const ExifData& ed) {
static constexpr const char* keys[] = {
"Exif.Photo.FocalLength", "Exif.Image.FocalLength", "Exif.Canon.FocalLength",
"Exif.NikonLd2.FocalLength", "Exif.NikonLd3.FocalLength", "Exif.MinoltaCsNew.FocalLength",
"Exif.Pentax.FocalLength", "Exif.PentaxDng.FocalLength", "Exif.Casio2.FocalLength",
"Exif.Photo.FocalLength", "Exif.Image.FocalLength", "Exif.Canon.FocalLength",
"Exif.NikonLd2.FocalLength", "Exif.NikonLd3.FocalLength", "Exif.NikonLd4.FocalLength2",
"Exif.MinoltaCsNew.FocalLength", "Exif.Pentax.FocalLength", "Exif.PentaxDng.FocalLength",
"Exif.Casio2.FocalLength",
};
return findMetadatum(ed, keys, std::size(keys));
return findMetadatumSkip0inNikonLd4(ed, keys, std::size(keys));
}

ExifData::const_iterator subjectArea(const ExifData& ed) {
Expand Down
4 changes: 4 additions & 0 deletions src/nikonmn_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3943,6 +3943,10 @@ std::ostream& Nikon3MakerNote::printLensId4ZMount(std::ostream& os, const Value&
{38, "Nikon", "Nikkor Z 85mm f/1.2 S"}, // 28
{39, "Nikon", "Nikkor Z 17-28mm f/2.8"}, // IB
{40, "Nikon", "Nikkor Z 26mm f/2.8"},
{41, "Nikon", "Nikkor Z DX 12-28mm f/3.5-5.6 PZ VR"},
{42, "Nikon", "Nikkor Z 180-600mm f/5.6-6.3 VR"},
{43, "Nikon", "Nikkor Z DX 24mm f/1.7"},
{44, "Nikon", "Nikkor Z 70-180mm f/2.8"},
};

auto lid = static_cast<uint16_t>(value.toInt64());
Expand Down
3 changes: 3 additions & 0 deletions src/pentaxmn_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ constexpr TagDetails pentaxModel[] = {
{0x13240, "K-1 Mark II"},
{0x13254, "K-3 Mark III"},
{0x13290, "WG-70"},
{0x1329a, "GR IIIx"},
{0x132d6, "K-3 Mark III Monochrome"},
};

//! Quality, tag 0x0008
Expand Down Expand Up @@ -664,6 +666,7 @@ constexpr TagDetails pentaxLensType[] = {
{0x0402, "smc PENTAX-FA 80-320mm F4.5-5.6"},
{0x0403, "smc PENTAX-FA 43mm F1.9 Limited"},
{0x0406, "smc PENTAX-FA 35-80mm F4-5.6"},
{0x0407, "Irix 45mm F/1.4"},
{0x0408, "Irix 150mm F/2.8 Macro"},
{0x0409, "Irix 11mm F/4"},
{0x040a, "Irix 15mm F/2.4"},
Expand Down
39 changes: 37 additions & 2 deletions src/tags_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ constexpr TagDetails exifCompression[] = {
{34712, N_("Leadtools JPEG 2000")},
{34713, N_("Nikon NEF Compressed")},
{34892, N_("JPEG (lossy)")}, // DNG 1.4
{52546, N_("JPEG XL")}, // DNG 1.7
{65000, N_("Kodak DCR Compressed")},
{65535, N_("Pentax PEF Compressed")},
};
Expand All @@ -283,8 +284,8 @@ constexpr TagDetails exifPhotometricInterpretation[] = {
{32844, N_("Pixar LogL")},
{32845, N_("Pixar LogLuv")},
{34892, N_("Linear Raw")},
{51177, N_("Depth Map")}, // DNG 1.5
{52527, N_("Semantic Mask")}, // DNG 1.6
{51177, N_("Depth Map")}, // DNG 1.5
{52527, N_("Photometric Mask")}, // DNG 1.6
};

//! Thresholding, tag 0x0107
Expand Down Expand Up @@ -404,6 +405,7 @@ constexpr TagDetails dngMakerNoteSafety[] = {
constexpr TagDetails dngColorimetricReference[] = {
{0, N_("XYZ values are scene-referred")},
{1, N_("XYZ values are output-referred")},
{2, N_("XYZ values are output-referred and may be HDR")}, // DNG 1.7
};

//! ProfileEmbedPolicy, DNG 1.2 tag 0xc6fd
Expand Down Expand Up @@ -451,6 +453,7 @@ constexpr TagDetails dngDepthMeasureType[] = {
{2, N_("Optical ray")},
};

// clang-format off
//! Base IFD Tags (IFD0 and IFD1)
constexpr TagInfo ifdTagInfo[] = {
{0x000b, "ProcessingSoftware", N_("Processing Software"),
Expand Down Expand Up @@ -1707,12 +1710,44 @@ constexpr TagInfo ifdTagInfo[] = {
"combination of the color tables, weighted by their corresponding Semantic "
"Masks."),
IfdId::ifd0Id, SectionId::dngTags, undefined, -1, printValue}, // DNG 1.6 tag
{0xcd40, "ProfileGainTableMap2", N_("Profile Gain Table Map 2"),
N_("This tag is an extended version of ProfileGainTableMap."),
IfdId::ifd0Id, SectionId::dngTags, undefined, -1, printValue}, // DNG 1.7 tag
{0xcd43, "ColumnInterleaveFactor", N_("Column Interleave Factor"),
N_("This tag specifies that columns of the image are stored in interleaved "
"order. The value of the tag specifies the number of interleaved fields. "
"The use of a non-default value for this tag requires setting the "
"DNGBackwardVersion tag to at least 1.7.0.0."),
IfdId::ifd0Id, SectionId::dngTags, unsignedLong, 1, printValue}, // DNG 1.7 tag
{0xcd44, "ImageSequenceInfo", N_("Image Sequence Info"),
N_("This is an informative tag that describes how the image file relates "
"to other image files captured in a sequence. Applications include focus "
"stacking, merging multiple frames to reduce noise, time lapses, exposure "
"brackets, stitched images for super resolution, and so on."),
IfdId::ifd0Id, SectionId::dngTags, undefined, -1, printValue}, // DNG 1.7 tag
{0xcd46, "ImageStats", N_("Image Stats"),
N_("This is an informative tag that provides basic statistical information "
"about the pixel values of the image in this IFD. Possible applications "
"include normalizing brightness of images when multiple images are displayed "
"together (especially when mixing Standard Dynamic Range and High Dynamic "
"Range images), identifying underexposed or overexposed images, and so on."),
IfdId::ifd0Id, SectionId::dngTags, undefined, -1, printValue}, // DNG 1.7 tag
{0xcd47, "ProfileDynamicRange", N_("Profile Dynamic Range"),
N_("This tag describes the intended rendering output dynamic range for a given "
"camera profile."),
IfdId::ifd0Id, SectionId::dngTags, undefined, 8, printValue}, // DNG 1.7 tag
{0xcd48, "ProfileGroupName", N_("Profile Group Name"),
N_("A UTF-8 encoded string containing the 'group name' of the camera profile. "
"The purpose of this tag is to associate two or more related camera profiles "
"into a common group."),
IfdId::ifd0Id, SectionId::dngTags, asciiString, -1, printValue}, // DNG 1.7 tag

////////////////////////////////////////
// End of list marker
{0xffff, "(UnknownIfdTag)", N_("Unknown IFD tag"), N_("Unknown IFD tag"), IfdId::ifd0Id, SectionId::sectionIdNotSet,
asciiString, -1, printValue},
};
// clang-format on

const TagInfo* ifdTagList() {
return ifdTagInfo;
Expand Down
2 changes: 1 addition & 1 deletion test/data/test_reference_files/IMG_1361.dng.out
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Exif.SubImage2.ImageWidth Long 1 2016 2016
Exif.SubImage2.ImageLength Long 1 1512 1512
Exif.SubImage2.BitsPerSample Short 1 8 8
Exif.SubImage2.Compression Short 1 34892 JPEG (lossy)
Exif.SubImage2.PhotometricInterpretation Short 1 52527 Semantic Mask
Exif.SubImage2.PhotometricInterpretation Short 1 52527 Photometric Mask
Exif.SubImage2.StripOffsets Long 1 5428540 5428540
Exif.SubImage2.SamplesPerPixel Short 1 1 1
Exif.SubImage2.RowsPerStrip Long 1 1512 1512
Expand Down
1 change: 1 addition & 0 deletions test/data/test_reference_files/exiv2-test.out
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Options:
-r fmt Filename format for the 'rename' action. The format string
follows strftime(3). The following keywords are also supported:
:basename: - original filename without extension
:basesuffix: - suffix in original filename, starts with first dot and ends before extension
:dirname: - name of the directory holding the original file
:parentname: - name of parent directory
Default 'fmt' is %Y%m%d_%H%M%S
Expand Down
Loading

0 comments on commit 8bb5636

Please sign in to comment.