Files
OpenVulkano/openVulkanoCpp/Image/XmpBuilder.cpp
2025-06-24 00:01:02 +02:00

123 lines
4.7 KiB
C++

/*
* Copyright (c) 2025. MadVoxel AG
* All rights reserved.
*/
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "XmpBuilder.hpp"
#include "Extensions/FmtFormatter.hpp"
namespace OpenVulkano::Image
{
XmpBuilder::XmpBuilder()
{
xmpData << "<?xpacket begin=\"\xEF\xBB\xBF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"; // XMP Wrapper
xmpData << "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF"
" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""
" xmlns:crs=\"http://ns.adobe.com/camera-raw-settings/1.0/\""
" xmlns:camera=\"http://ns.adobe.com/camera/1.0/\""
" xmlns:cineGeo=\"http://ns.adobe.com/cineGeo/1.0/\"" // Cinema/Geometric namespace
" xmlns:exif=\"http://ns.adobe.com/exif/1.0/\"" // EXIF namespace
" xmlns:aux=\"http://ns.adobe.com/exif/1.0/aux/\"" // Auxiliary EXIF namespace
" xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"" // Base XMP namespace
" xmlns:photoshop=\"http://ns.adobe.com/photoshop/1.0/\""
" xmlns:tiff=\"http://ns.adobe.com/tiff/1.0/\""
"><rdf:Description rdf:about=\"\">";
}
std::string XmpBuilder::Finalize()
{
if (!complete)
{ // Finalize
xmpData << "</rdf:Description></rdf:RDF></x:xmpmeta>";
xmpData << "<?xpacket end=\"w\"?>"; // XMP Wrapper
complete = true;
}
return xmpData.str();
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetCameraIntrinsic(const Math::CameraIntrinsicWithResolution& intrinsic)
{
// Calibration matrix in row-major format
const auto& mat = intrinsic.GetMatrix();
xmpData << fmt::format("<camera:CalibrationMatrix>{} {} {} {} {} {} {} {} {}</camera:CalibrationMatrix>",
mat[0][0], mat[1][0], mat[2][0], mat[0][1], mat[1][1], mat[2][1], mat[0][2], mat[1][2], mat[2][2]);
xmpData << fmt::format("<camera:IntrinsicMatrix><rdf:Description>"
"<camera:FocalLengthX>{}</camera:FocalLengthX><camera:FocalLengthY>{}</camera:FocalLengthY>"
"<camera:PrincipalPointX>{}</camera:PrincipalPointX><camera:PrincipalPointY>{}</camera:PrincipalPointY>"
"</rdf:Description></camera:IntrinsicMatrix>",
intrinsic.Fx(), intrinsic.Fy(), intrinsic.Cx(), intrinsic.Cy() );
// Field of View
xmpData << fmt::format("<camera:FieldOfView><rdf:Description>"
"<camera:Horizontal>{}</camera:Horizontal><camera:Vertical>{}</camera:Vertical>"
"</rdf:Description></camera:FieldOfView>",
Math::Utils::degrees(intrinsic.GetFovX()), Math::Utils::degrees(intrinsic.GetFovY()));
return *this;
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetPosition(const Math::Vector3f& position)
{
xmpData << fmt::format("<cineGeo:Position><rdf:Description>"
"<cineGeo:X>{}</cineGeo:X><cineGeo:Y>{}</cineGeo:Y><cineGeo:Z>{}</cineGeo:Z>"
"</rdf:Description></cineGeo:Position>",
position.x, position.y, position.z);
return *this;
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetOrientation(const Math::Vector3f& orientation)
{
Math::Vector3f ori = Math::Utils::degrees(orientation);
xmpData << fmt::format("<cineGeo:Rotation><rdf:Description>"
"<cineGeo:X>{}</cineGeo:X><cineGeo:Y>{}</cineGeo:Y><cineGeo:Z>{}</cineGeo:Z>"
"</rdf:Description></cineGeo:Rotation>",
ori.x, ori.y, ori.z);
return *this;
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetSensorSize(const Math::Vector2f& sensorSize)
{
xmpData << fmt::format("<camera:SensorSize><rdf:Description>"
"<camera:Width>{}</camera:Width><camera:Height>{}</camera:Height>"
"</rdf:Description></camera:SensorSize>",
sensorSize.x, sensorSize.y);
return *this;
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetFocalLength(const float focalLengthMM)
{
xmpData << "<camera:FocalLength>" << focalLengthMM << "</camera:FocalLength>";
return *this;
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetExposureTime(double exposureTime)
{
xmpData << fmt::format("<exif:ExposureTime>{0}</exif:ExposureTime><aux:ExposureTime>{0}</aux:ExposureTime>", exposureTime);
return *this;
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetCreateDateNow()
{
return SetCreateDate(fmt::format("{:%FT%T%Ez}", std::chrono::system_clock::now()));
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetCreateDate(const std::time_t time)
{
#ifdef WIN32
return SetCreateDate(fmt::format("{:%FT%T%Ez}", std::chrono::system_clock::from_time_t(time)));
#else
return SetCreateDate(fmt::format("{:%FT%T%Ez}", fmt::localtime(time)));
#endif
}
[[maybe_unused]] XmpBuilder& XmpBuilder::SetCreateDate(const std::string& createDate)
{
xmpData << "<xmp:CreateDate>" << createDate << "</xmp:CreateDate>";
return *this;
}
}