Skip to content

Commit 469f404

Browse files
authored
Merge pull request #171 from Blackhart/feature/implement-oiio-reader
#98: Open Image IO Library / Reader
2 parents 6c1c12c + bf1829e commit 469f404

File tree

12 files changed

+1262
-0
lines changed

12 files changed

+1262
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_src_and_test(ffprobe)
22
add_src_and_test(openexr)
3+
add_src_and_test(openimageio)
34

45
build_studio_plugins("${STUDIO_PLUGINS}")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
find_package(OpenImageIO)
2+
3+
SET(LINK_DEPS
4+
xstudio::media_metadata
5+
OpenImageIO::OpenImageIO
6+
)
7+
8+
create_plugin_with_alias(media_metadata_openimageio xstudio::media_metadata::openimageio ${XSTUDIO_GLOBAL_VERSION} "${LINK_DEPS}")
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#include "openimageio_metadata.hpp"
2+
3+
#include <filesystem>
4+
#include <unordered_set>
5+
6+
#include <OpenImageIO/imageio.h>
7+
#include <OpenImageIO/typedesc.h>
8+
9+
#include "xstudio/utility/helpers.hpp"
10+
11+
namespace fs = std::filesystem;
12+
13+
using namespace xstudio::media_metadata;
14+
using namespace xstudio::utility;
15+
using namespace xstudio;
16+
17+
OpenImageIOMediaMetadata::OpenImageIOMediaMetadata() : MediaMetadata("OpenImageIO") {}
18+
19+
MMCertainty OpenImageIOMediaMetadata::supported(
20+
const caf::uri &uri, const std::array<uint8_t, 16> &signature) {
21+
// Step 1: List of supported extensions by OIIO
22+
static const std::unordered_set<std::string> supported_extensions = {
23+
"JPG",
24+
"JPEG",
25+
"PNG",
26+
"TIF",
27+
"TIFF",
28+
"TGA",
29+
"BMP",
30+
"PSD",
31+
"HDR",
32+
"DPX",
33+
"ACES",
34+
"JP2",
35+
"J2K",
36+
"WEBP",
37+
"EXR",
38+
};
39+
40+
// Step 2: Convert the URI to a POSIX path string and fs::path
41+
std::string path = uri_to_posix_path(uri);
42+
fs::path p(path);
43+
44+
// Step 3: Check if the file exists and is a regular file
45+
// Return not supported if the file does not exist or is not a regular file
46+
if (!fs::exists(p) || !fs::is_regular_file(p)) {
47+
return MMC_NO;
48+
}
49+
50+
// Step 4: Get the upper-case extension (handling platform differences)
51+
#ifdef _WIN32
52+
std::string ext = ltrim_char(to_upper_path(p.extension()), '.');
53+
#else
54+
std::string ext = ltrim_char(to_upper(p.extension().string()), '.');
55+
#endif
56+
57+
// Step 5: Check if the extension is in the supported list
58+
// Return fully supported if the extension is in the supported list
59+
if (supported_extensions.count(ext)) {
60+
return MMC_FULLY;
61+
}
62+
63+
// Step 6: Try to detect via OIIO if the extension is supported
64+
// Return maybe supported if the extension is supported by OIIO
65+
auto in = OIIO::ImageInput::open(path);
66+
if (in) {
67+
in->close();
68+
return MMC_MAYBE;
69+
}
70+
71+
// Step 7: Return not supported if all checks fail
72+
return MMC_NO;
73+
}
74+
75+
nlohmann::json OpenImageIOMediaMetadata::read_metadata(const caf::uri &uri) {
76+
std::string path = uri_to_posix_path(uri);
77+
78+
try {
79+
// Step 1: Open the image using OpenImageIO
80+
auto in = OIIO::ImageInput::open(path);
81+
if (!in) {
82+
throw std::runtime_error("Cannot open: " + OIIO::geterror());
83+
}
84+
85+
// Step 2: Get the image specification
86+
const OIIO::ImageSpec &spec = in->spec();
87+
88+
// Step 3: Initialize a JSON object for metadata
89+
nlohmann::json metadata;
90+
91+
// Step 4: Populate basic image properties (width, height, resolution)
92+
metadata["width"] = spec.width;
93+
metadata["height"] = spec.height;
94+
metadata["resolution"] = fmt::format("{} x {}", spec.width, spec.height);
95+
96+
// Step 5: Extract and format the file extension (format)
97+
fs::path p(path);
98+
#ifdef _WIN32
99+
std::string ext = ltrim_char(to_upper_path(p.extension()), '.');
100+
#else
101+
std::string ext = ltrim_char(to_upper(p.extension().string()), '.');
102+
#endif
103+
metadata["format"] = ext;
104+
105+
// Step 6: Determine bit depth and add to metadata
106+
if (spec.format == OIIO::TypeDesc::UINT8) {
107+
metadata["bit_depth"] = "8 bits";
108+
} else if (spec.format == OIIO::TypeDesc::UINT16) {
109+
metadata["bit_depth"] = "16 bits";
110+
} else if (spec.format == OIIO::TypeDesc::HALF) {
111+
metadata["bit_depth"] = "16 bits float";
112+
} else if (spec.format == OIIO::TypeDesc::FLOAT) {
113+
metadata["bit_depth"] = "32 bits float";
114+
} else {
115+
metadata["bit_depth"] = "unknown";
116+
}
117+
118+
// Step 7: Read pixel aspect ratio and aspect ratio
119+
metadata["pixel_aspect"] = spec.get_float_attribute("PixelAspectRatio", 1.0f);
120+
metadata["aspect_ratio"] = spec.get_float_attribute("XResolution", spec.width)
121+
/ spec.get_float_attribute("YResolution", spec.height);
122+
123+
// Step 8: Add extra attributes to metadata
124+
for (const auto &param : spec.extra_attribs) {
125+
metadata[param.name().string()] = param.get_string();
126+
}
127+
128+
// Step 9: Return metadata
129+
return metadata;
130+
} catch (const std::exception &e) {
131+
spdlog::error("Failed to read metadata from {}: {}", path, e.what());
132+
return nlohmann::json::object();
133+
}
134+
}
135+
136+
std::optional<MediaMetadata::StandardFields>
137+
OpenImageIOMediaMetadata::fill_standard_fields(const nlohmann::json &metadata) {
138+
// Step 1: Initialize StandardFields and set default format
139+
StandardFields fields;
140+
fields.format_ = "OpenImageIO";
141+
142+
// Step 2: Fill in the resolution if present in metadata
143+
if (metadata.contains("resolution")) {
144+
fields.resolution_ = metadata["resolution"].get<std::string>();
145+
}
146+
147+
// Step 3: Fill in the image extension (format) if present in metadata
148+
if (metadata.contains("format")) {
149+
fields.format_ = metadata["format"].get<std::string>();
150+
}
151+
152+
// Step 4: Fill in the bit depth if present in metadata
153+
if (metadata.contains("bit_depth")) {
154+
fields.bit_depth_ = metadata["bit_depth"].get<std::string>();
155+
}
156+
157+
// Step 5: Fill in the pixel aspect ratio if present in metadata
158+
if (metadata.contains("pixel_aspect")) {
159+
fields.pixel_aspect_ = metadata["pixel_aspect"].get<float>();
160+
}
161+
162+
return std::make_optional(fields);
163+
}
164+
165+
// Point d'entrée du plugin
166+
extern "C" {
167+
plugin_manager::PluginFactoryCollection *plugin_factory_collection_ptr() {
168+
return new plugin_manager::PluginFactoryCollection(
169+
std::vector<std::shared_ptr<plugin_manager::PluginFactory>>({std::make_shared<
170+
MediaMetadataPlugin<MediaMetadataActor<OpenImageIOMediaMetadata>>>(
171+
Uuid("8f3c4a7e-9b2d-4e1f-a5c8-3d6f7e8a9b1c"),
172+
"OpenImageIO",
173+
"xStudio",
174+
"OpenImageIO Media Metadata Reader",
175+
semver::version("1.0.0"))}));
176+
}
177+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include <array>
4+
5+
#include <nlohmann/json.hpp>
6+
7+
#include "xstudio/media_metadata/media_metadata.hpp"
8+
9+
namespace xstudio {
10+
namespace media_metadata {
11+
12+
class OpenImageIOMediaMetadata : public MediaMetadata {
13+
public:
14+
OpenImageIOMediaMetadata();
15+
~OpenImageIOMediaMetadata() override = default;
16+
17+
MMCertainty
18+
supported(const caf::uri &uri, const std::array<uint8_t, 16> &signature) override;
19+
20+
protected:
21+
nlohmann::json read_metadata(const caf::uri &uri) override;
22+
std::optional<StandardFields>
23+
fill_standard_fields(const nlohmann::json &metadata) override;
24+
};
25+
26+
} // namespace media_metadata
27+
} // namespace xstudio
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
include(CTest)
2+
3+
SET(LINK_DEPS
4+
CAF::core
5+
)
6+
7+
create_tests("${LINK_DEPS}")

src/plugin/media_reader/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ add_src_and_test(ffmpeg)
22
add_src_and_test(openexr)
33
add_src_and_test(ppm)
44
add_src_and_test(blank)
5+
add_src_and_test(openimageio)
56

67
build_studio_plugins("${STUDIO_PLUGINS}")
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
find_package(OpenImageIO REQUIRED)
2+
3+
SET(LINK_DEPS
4+
xstudio::media_reader
5+
OpenImageIO::OpenImageIO
6+
)
7+
8+
create_plugin_with_alias(
9+
media_reader_oiio
10+
xstudio::media_reader::oiio
11+
${XSTUDIO_GLOBAL_VERSION}
12+
"${LINK_DEPS}"
13+
)
14+
15+
target_include_directories(media_reader_oiio PRIVATE ${OPENIMAGEIO_INCLUDE_DIR})
16+

0 commit comments

Comments
 (0)