Skip to content

Commit

Permalink
MMVII: Gdal: Extract all (gdal known) metadata from image file as str…
Browse files Browse the repository at this point in the history
…ings
  • Loading branch information
meynardc committed Dec 18, 2024
1 parent b7de624 commit 8a8a692
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 47 deletions.
19 changes: 12 additions & 7 deletions MMVII/include/MMVII_ExifData.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <optional>
#include <cstdint>
#include <map>

namespace MMVII {

Expand Down Expand Up @@ -59,26 +60,30 @@ class cExifData {
std::optional<double> mDateTimeDigitizedNumber_s;
std::optional<double> mDateTimeOriginalNumber_s;

// Fill this structure from file aName (SVP: true: return false on error, false: halt program with error message)
bool FromFile(const std::string &aName, bool SVP=true);
// Fill this structure from file aFileName (SVP: true: return false on error, false: halt program with error message)
bool FromFile(const std::string &aFileName, bool SVP=true);
// Fill only main tags
bool FromFileMainOnly(const std::string &aName, bool SVP=true);
bool FromFileMainOnly(const std::string &aFileName, bool SVP=true);

/*
* static methods
*/

// Fill argument anExif
static bool FromFile(const std::string &aName, cExifData &anExif, bool SVP=true);
static bool FromFile(const std::string &aFileName, cExifData &anExif, bool SVP=true);
// Return a struct
static cExifData CreateFromFile(const std::string &aName, bool SVP=true);
static cExifData CreateFromFile(const std::string &aFileName, bool SVP=true);

// Idem for main tags only
static bool FromFileMainOnly(const std::string &aName, cExifData &anExif, bool SVP=true);
static cExifData CreateFromFileMainOnly(const std::string &aName, bool SVP=true);
static bool FromFileMainOnly(const std::string &aFileName, cExifData &anExif, bool SVP=true);
static cExifData CreateFromFileMainOnly(const std::string &aFileName, bool SVP=true);

// Return a list of ALL exif tags found from file
static std::vector<std::string> StringListFromFile(const std::string &aName, bool SVP=true);

// Return a dict of all metadata strings stored by domain (contains exif if present but other metadata too)
static std::map<std::string, std::vector<std::string>> AllMetadataFromFile(const std::string &aFileName, bool SVP=true);

};


Expand Down
1 change: 1 addition & 0 deletions MMVII/include/MMVII_Image2D.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class cDataFileIm2D : public cRect2
const cExifData& ExifDataAll(bool SVP=true) const;
const cExifData& ExifDataMain(bool SVP=true) const;
std::vector<std::string> ExifStrings(bool SVP=true) const;
std::map<std::string, std::vector<std::string>> AllMetadata(bool SVP=true) const;

/// Create a descriptor on existing file
static cDataFileIm2D Create(const std::string & aName,eForceGray);
Expand Down
12 changes: 10 additions & 2 deletions MMVII/src/ImagesBase/AppliExifData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ cCollecSpecArg2007 & cAppli_ExifData::ArgOpt(cCollecSpecArg2007 & anArgOpt)
{
return
anArgOpt
<< AOpt2007(mDisp,"Disp","0->All known tags , 1->Main tags, 2->Raw strings",{eTA2007::HDV,{eTA2007::Range,"[0,2]"}})
<< AOpt2007(mDisp,"Disp","0:All known tags, 1:Main tags, 2:exif strings, 3:all metadata",{eTA2007::HDV,{eTA2007::Range,"[0,3]"}})
;
}

Expand All @@ -52,7 +52,15 @@ int cAppli_ExifData::Exe()
{
auto aDataFileIm=cDataFileIm2D::Create(aName,eForceGray::No);
std::cout << "####### " << aDataFileIm.Name() <<":" << std::endl;
if (mDisp == 2) {
if (mDisp == 3) {
auto allMetadata = aDataFileIm.AllMetadata();
for (const auto& aDomain : allMetadata ) {
std::cout << "- Domain : " << (aDomain.first.empty() ? "<NULL>" : "\"" + aDomain.first + "\"") << "\n";
for (const auto& aMetadata : aDomain.second) {
std::cout << " . \"" << aMetadata << "\"\n";
}
}
} else if (mDisp == 2) {
auto anExifList = aDataFileIm.ExifStrings();
for (const auto &s : anExifList)
std::cout << s << std::endl;
Expand Down
5 changes: 5 additions & 0 deletions MMVII/src/ImagesBase/FileImages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ std::vector<std::string> cDataFileIm2D::ExifStrings(bool SVP) const
return cExifData::StringListFromFile(mName,SVP);
}

std::map<std::string, std::vector<std::string>> cDataFileIm2D::AllMetadata(bool SVP) const
{
return cExifData::AllMetadataFromFile(mName,SVP);
}



bool cDataFileIm2D::IsPostFixNameImage(const std::string & aPost)
Expand Down
58 changes: 20 additions & 38 deletions MMVII/src/ImagesBase/cExifData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,31 +254,7 @@ void FillExif(const CPLStringList& aStrings, cExifData& aExif, eExtracType aType
}


CPLStringList GetExifMetadataRaw(const std::string &aName, bool SVP)
{

auto onError = SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError;
auto aDataSet = cGdalApi::OpenDataset(aName,GA_ReadOnly,onError);
if (aDataSet == nullptr)
{
return CPLStringList();
}
auto aMetadataDomainList = CPLStringList(aDataSet->GetMetadataDomainList(),TRUE);

if (aMetadataDomainList.FindString("") < 0) // Add empty domain if not already present
aMetadataDomainList.AddString("");
for (int i=0; i<aMetadataDomainList.Count(); i++)
{
auto aMetadataList = CPLStringList((CSLConstList)aDataSet->GetMetadata(aMetadataDomainList[i]));
if (aMetadataList.FindName("EXIF_ExifVersion") >= 0) {
aMetadataList.Sort();
cGdalApi::CloseDataset(aDataSet);
return aMetadataList;
}
}
cGdalApi::CloseDataset(aDataSet);
return CPLStringList();
}


} // private namespace

Expand All @@ -291,16 +267,16 @@ void cExifData::reset()
}


bool cExifData::FromFile(const std::string &aName, bool SVP)
bool cExifData::FromFile(const std::string &aFileName, bool SVP)
{
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
FillExif(aMetadataList, *this, eExtracType::All);
return ! aMetadataList.empty();
}

bool cExifData::FromFileMainOnly(const std::string &aName, bool SVP)
bool cExifData::FromFileMainOnly(const std::string &aFileName, bool SVP)
{
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
FillExif(aMetadataList, *this, eExtracType::Main);
return ! aMetadataList.empty();
}
Expand All @@ -310,7 +286,7 @@ bool cExifData::FromFileMainOnly(const std::string &aName, bool SVP)
// cExifData static methods
std::vector<std::string> cExifData::StringListFromFile(const std::string &aName, bool SVP)
{
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);

std::vector<std::string> anExifList;
for (int i=0; i<aMetadataList.Count(); i++)
Expand All @@ -324,35 +300,41 @@ std::vector<std::string> cExifData::StringListFromFile(const std::string &aName,
return anExifList;
}

bool cExifData::FromFile(const std::string &aName, cExifData &anExif, bool SVP)
bool cExifData::FromFile(const std::string &aFileName, cExifData &anExif, bool SVP)
{
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
FillExif(aMetadataList, anExif,eExtracType::All);
return ! aMetadataList.empty();
}

bool cExifData::FromFileMainOnly(const std::string &aName, cExifData &anExif, bool SVP)
bool cExifData::FromFileMainOnly(const std::string &aFileName, cExifData &anExif, bool SVP)
{
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
FillExif(aMetadataList, anExif,eExtracType::Main);
return ! aMetadataList.empty();
}


cExifData cExifData::CreateFromFile(const std::string &aName, bool SVP)
cExifData cExifData::CreateFromFile(const std::string &aFileName, bool SVP)
{
cExifData anExif;
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
FillExif(aMetadataList, anExif, eExtracType::All);
return anExif;
}

cExifData cExifData::CreateFromFileMainOnly(const std::string &aName, bool SVP)
cExifData cExifData::CreateFromFileMainOnly(const std::string &aFileName, bool SVP)
{
cExifData anExif;
auto aMetadataList = GetExifMetadataRaw(aName,SVP);
auto aMetadataList = cGdalApi::GetExifMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
FillExif(aMetadataList, anExif, eExtracType::Main);
return anExif;
}


std::map<std::string, std::vector<std::string>> cExifData::AllMetadataFromFile(const std::string &aFileName, bool SVP)
{
return cGdalApi::GetMetadata(aFileName,SVP ? cGdalApi::eOnError::ReturnNullptr : cGdalApi::eOnError::RaiseError);
}

} // namespace MMVII
51 changes: 51 additions & 0 deletions MMVII/src/ImagesBase/cGdalApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,57 @@ void cGdalApi::CloseDataset(GDALDataset *aGdalDataset)
GDALClose(GDALDataset::ToHandle(aGdalDataset));
}

std::map<std::string, std::vector<std::string>> cGdalApi::GetMetadata(const std::string &aName, eOnError onError)
{
std::map<std::string, std::vector<std::string>> aMetadataMap;

auto aDataSet = cGdalApi::OpenDataset(aName,GA_ReadOnly,onError);
if (aDataSet == nullptr)
{
return aMetadataMap;
}
auto aMetadataDomainList = CPLStringList(aDataSet->GetMetadataDomainList(),TRUE);

if (aMetadataDomainList.FindString("") < 0) // Add empty domain if not already present
aMetadataDomainList.AddString("");
for (int i=0; i<aMetadataDomainList.Count(); i++)
{
auto [it,ok] = aMetadataMap.emplace(aMetadataDomainList[i],std::vector<std::string>());
auto aMetadataList = CPLStringList((CSLConstList)aDataSet->GetMetadata(aMetadataDomainList[i]));
for (int i=0; i<aMetadataList.Count(); i++)
{
it->second.push_back(aMetadataList[i]);
}
}
cGdalApi::CloseDataset(aDataSet);
return aMetadataMap;
}


CPLStringList cGdalApi::GetExifMetadata(const std::string &aName, eOnError onError)
{
auto aDataSet = cGdalApi::OpenDataset(aName,GA_ReadOnly,onError);
if (aDataSet == nullptr)
{
return CPLStringList();
}
auto aMetadataDomainList = CPLStringList(aDataSet->GetMetadataDomainList(),TRUE);

if (aMetadataDomainList.FindString("") < 0) // Add empty domain if not already present
aMetadataDomainList.AddString("");
for (int i=0; i<aMetadataDomainList.Count(); i++)
{
auto aMetadataList = CPLStringList((CSLConstList)aDataSet->GetMetadata(aMetadataDomainList[i]));
if (aMetadataList.FindName("EXIF_ExifVersion") >= 0) {
aMetadataList.Sort();
cGdalApi::CloseDataset(aDataSet);
return aMetadataList;
}
}
cGdalApi::CloseDataset(aDataSet);
return CPLStringList();
}


const std::map<std::string, std::string> &cGdalApi::SupportedDrivers()
{
Expand Down
3 changes: 3 additions & 0 deletions MMVII/src/ImagesBase/cGdalApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class cGdalApi {
static GDALDataset * OpenDataset(const std::string &aName, GDALAccess aAccess, eOnError onError); // return nnullptr on error
static void CloseDataset(GDALDataset *aGdalDataset);

static std::map<std::string, std::vector<std::string>> GetMetadata(const std::string &aName, eOnError onError);
static CPLStringList GetExifMetadata(const std::string &aName, eOnError onError);

template <class TypeIm>
static void ReadWrite(IoMode aMode,
const cDataIm2D<TypeIm>& aImV2,
Expand Down

0 comments on commit 8a8a692

Please sign in to comment.