Skip to content

Commit b9ea1c9

Browse files
committed
Change API functions to getCICP and getColorInteropID, keep more logic in file formats
Signed-off-by: Brecht Van Lommel <[email protected]>
1 parent ec29653 commit b9ea1c9

File tree

11 files changed

+186
-156
lines changed

11 files changed

+186
-156
lines changed

src/ffmpeg.imageio/ffmpeginput.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,11 @@ FFmpegInput::open(const std::string& name, ImageSpec& spec)
549549
= { m_codec_context->color_primaries, m_codec_context->color_trc,
550550
m_codec_context->colorspace,
551551
m_codec_context->color_range == AVCOL_RANGE_MPEG ? 0 : 1 };
552-
ColorConfig::default_colorconfig().set_colorspace_cicp(m_spec, cicp);
552+
m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp);
553+
const ColorConfig& colorconfig(ColorConfig::default_colorconfig());
554+
string_view interop_id = colorconfig.getColorInteropID(cicp);
555+
if (!interop_id.empty())
556+
m_spec.attribute("oiio:ColorSpace", interop_id);
553557

554558
m_nsubimages = m_frames;
555559
spec = m_spec;

src/heif.imageio/heifinput.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,12 @@ HeifInput::seek_subimage(int subimage, int miplevel)
292292
int(nclx->transfer_characteristics),
293293
int(nclx->matrix_coefficients),
294294
int(nclx->full_range_flag ? 1 : 0) };
295+
m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp);
295296
const ColorConfig& colorconfig(
296297
ColorConfig::default_colorconfig());
297-
colorconfig.set_colorspace_cicp(m_spec, cicp);
298+
string_view interop_id = colorconfig.getColorInteropID(cicp);
299+
if (!interop_id.empty())
300+
m_spec.attribute("oiio:ColorSpace", interop_id);
298301
}
299302
heif_nclx_color_profile_free(nclx);
300303
}

src/heif.imageio/heifoutput.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,12 @@ HeifOutput::close()
251251
void (*)(heif_color_profile_nclx*)>
252252
nclx(heif_nclx_color_profile_alloc(), heif_nclx_color_profile_free);
253253
const ColorConfig& colorconfig(ColorConfig::default_colorconfig());
254-
const bool auto_cicp = true;
255-
int cicp[4];
256-
if (colorconfig.get_colorspace_cicp(m_spec, auto_cicp, cicp)) {
254+
const ParamValue* p = m_spec.find_attribute("CICP",
255+
TypeDesc(TypeDesc::INT, 4));
256+
string_view colorspace = m_spec.get_string_attribute("oiio:ColorSpace");
257+
const int* cicp = (p) ? static_cast<const int*>(p->data())
258+
: colorconfig.getCICP(colorspace);
259+
if (cicp) {
257260
nclx->color_primaries = heif_color_primaries(cicp[0]);
258261
nclx->transfer_characteristics = heif_transfer_characteristics(
259262
cicp[1]);

src/include/OpenImageIO/color.h

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,18 @@ class OIIO_API ColorConfig {
402402
bool equivalent(string_view color_space,
403403
string_view other_color_space) const;
404404

405+
/// Find CICP code corresponding to the colorspace.
406+
/// Returns pointer to int[4], and nullptr if not found.
407+
///
408+
/// @version 3.1
409+
const int* getCICP(string_view colorspace) const;
410+
411+
/// Find color interop ID corresponding to the CICP code.
412+
/// Returns empty string if not found.
413+
///
414+
/// @version 3.1
415+
string_view getColorInteropID(const int cicp[4]) const;
416+
405417
/// Return a filename or other identifier for the config we're using.
406418
std::string configname() const;
407419

@@ -422,23 +434,6 @@ class OIIO_API ColorConfig {
422434
/// @version 3.0
423435
void set_colorspace_rec709_gamma(ImageSpec& spec, float gamma) const;
424436

425-
/// Set the "CICP" attribute in the spec. If a corresponding colorspace
426-
/// is found, automatically set "oiio:ColorSpace" as well. It also removes
427-
/// or alters several other attributes that may hint color space in ways
428-
/// that might be contradictory or no longer true.
429-
///
430-
/// @version 3.1
431-
void set_colorspace_cicp(ImageSpec& spec, const int cicp[4]) const;
432-
433-
/// Get the CICP code corresponding from the "CICP" attribute. If there
434-
/// is no such attribute and auto_cicp is true, attempt to determine a CICP
435-
/// code from the "oiio:ColorSpace" attribute.
436-
/// Returns false if no CICP code could be determined.
437-
///
438-
/// @version 3.1
439-
bool get_colorspace_cicp(ImageSpec& spec, bool auto_cicp,
440-
int cicp[4]) const;
441-
442437
/// Return if OpenImageIO was built with OCIO support
443438
static bool supportsOpenColorIO();
444439

src/libOpenImageIO/color_ocio.cpp

Lines changed: 121 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,127 @@ ColorConfig::parseColorSpaceFromString(string_view str) const
19971997
}
19981998

19991999

2000+
//////////////////////////////////////////////////////////////////////////
2001+
//
2002+
// Color Interop ID
2003+
2004+
namespace {
2005+
enum class CICPPrimaries : int {
2006+
Rec709 = 1,
2007+
Rec2020 = 9,
2008+
XYZD65 = 10,
2009+
P3D65 = 12,
2010+
};
2011+
2012+
enum class CICPTransfer : int {
2013+
BT709 = 1,
2014+
Gamma22 = 4,
2015+
Linear = 8,
2016+
sRGB = 13,
2017+
PQ = 16,
2018+
Gamma26 = 17,
2019+
HLG = 18,
2020+
};
2021+
2022+
enum class CICPMatrix : int {
2023+
RGB = 0,
2024+
BT709 = 1,
2025+
Unspecified = 2,
2026+
Rec2020_NCL = 9,
2027+
Rec2020_CL = 10,
2028+
};
2029+
2030+
enum class CICPRange : int {
2031+
Narrow = 0,
2032+
Full = 1,
2033+
};
2034+
2035+
struct ColorInteropID {
2036+
constexpr ColorInteropID(const char* interop_id, CICPPrimaries primaries,
2037+
CICPTransfer transfer, CICPMatrix matrix)
2038+
: interop_id(interop_id)
2039+
, cicp({ int(primaries), int(transfer), int(matrix),
2040+
int(CICPRange::Full) })
2041+
{
2042+
}
2043+
2044+
const char* interop_id;
2045+
std::array<int, 4> cicp;
2046+
};
2047+
2048+
// Mapping between color interop ID and CICP, based on Color Interop Forum
2049+
// recommendations.
2050+
constexpr ColorInteropID color_interop_ids[] = {
2051+
// Scene referred interop IDs first so they are the default in automatic
2052+
// conversion from CICP to interop ID.
2053+
{ "srgb_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::sRGB,
2054+
CICPMatrix::BT709 },
2055+
{ "srgb_p3d65_scene", CICPPrimaries::P3D65, CICPTransfer::sRGB,
2056+
CICPMatrix::BT709 },
2057+
{ "g22_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::Gamma22,
2058+
CICPMatrix::BT709 },
2059+
// These are not display color spaces at all, but can be represented by CICP.
2060+
{ "lin_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::Linear,
2061+
CICPMatrix::BT709 },
2062+
{ "lin_p3d65_scene", CICPPrimaries::P3D65, CICPTransfer::Linear,
2063+
CICPMatrix::BT709 },
2064+
{ "lin_rec2020_scene", CICPPrimaries::Rec2020, CICPTransfer::Linear,
2065+
CICPMatrix::Rec2020_CL },
2066+
{ "lin_ciexyzd65_scene", CICPPrimaries::XYZD65, CICPTransfer::Linear,
2067+
CICPMatrix::Unspecified },
2068+
2069+
// Display referred interop IDs.
2070+
{ "srgb_rec709_display", CICPPrimaries::Rec709, CICPTransfer::sRGB,
2071+
CICPMatrix::BT709 },
2072+
{ "g24_rec709_display", CICPPrimaries::Rec709, CICPTransfer::BT709,
2073+
CICPMatrix::BT709 },
2074+
{ "srgb_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::sRGB,
2075+
CICPMatrix::BT709 },
2076+
{ "srgbe_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::sRGB,
2077+
CICPMatrix::BT709 },
2078+
{ "pq_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::PQ,
2079+
CICPMatrix::Rec2020_NCL },
2080+
{ "pq_rec2020_display", CICPPrimaries::Rec2020, CICPTransfer::PQ,
2081+
CICPMatrix::Rec2020_NCL },
2082+
{ "hlg_rec2020_display", CICPPrimaries::Rec2020, CICPTransfer::HLG,
2083+
CICPMatrix::Rec2020_NCL },
2084+
{ "g22_rec709_display", CICPPrimaries::Rec709, CICPTransfer::Gamma22,
2085+
CICPMatrix::BT709 },
2086+
// No CICP code for Adobe RGB primaries.
2087+
// { "g22_adobergb_display" }
2088+
{ "g26_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::Gamma26,
2089+
CICPMatrix::BT709 },
2090+
{ "g26_xyzd65_display", CICPPrimaries::XYZD65, CICPTransfer::Gamma26,
2091+
CICPMatrix::Unspecified },
2092+
{ "pq_xyzd65_display", CICPPrimaries::XYZD65, CICPTransfer::PQ,
2093+
CICPMatrix::Unspecified },
2094+
};
2095+
} // namespace
2096+
2097+
string_view
2098+
ColorConfig::getColorInteropID(const int cicp[4]) const
2099+
{
2100+
for (const ColorInteropID& interop : color_interop_ids) {
2101+
if (interop.cicp[0] == cicp[0] && interop.cicp[1] == cicp[1]) {
2102+
return interop.interop_id;
2103+
}
2104+
}
2105+
return "";
2106+
}
2107+
2108+
const int*
2109+
ColorConfig::getCICP(string_view colorspace) const
2110+
{
2111+
if (!colorspace.empty()) {
2112+
for (const ColorInteropID& interop : color_interop_ids) {
2113+
if (equivalent(colorspace, interop.interop_id)) {
2114+
return interop.cicp.data();
2115+
}
2116+
}
2117+
}
2118+
return nullptr;
2119+
}
2120+
20002121

20012122
//////////////////////////////////////////////////////////////////////////
20022123
//
@@ -2655,134 +2776,6 @@ ColorConfig::set_colorspace_rec709_gamma(ImageSpec& spec, float gamma) const
26552776
}
26562777
}
26572778

2658-
namespace {
2659-
enum class CICPPrimaries {
2660-
Rec709 = 1,
2661-
Rec2020 = 9,
2662-
XYZD65 = 10,
2663-
P3D65 = 12,
2664-
};
2665-
enum class CICPTransfer {
2666-
BT709 = 1,
2667-
Gamma22 = 4,
2668-
Linear = 8,
2669-
sRGB = 13,
2670-
PQ = 16,
2671-
Gamma26 = 17,
2672-
HLG = 18,
2673-
};
2674-
enum class CICPMatrix {
2675-
RGB = 0,
2676-
BT709 = 1,
2677-
Unspecified = 2,
2678-
Rec2020_NCL = 9,
2679-
Rec2020_CL = 10,
2680-
};
2681-
enum class CICPRange {
2682-
Narrow = 0,
2683-
Full = 1,
2684-
};
2685-
2686-
// Mapping between color interop ID and CICP, based on Color Interop Forum
2687-
// recommendations.
2688-
struct ColorSpaceCICP {
2689-
const char* interop_id;
2690-
CICPPrimaries primaries;
2691-
CICPTransfer transfer;
2692-
CICPMatrix matrix;
2693-
};
2694-
2695-
constexpr ColorSpaceCICP color_space_cicp[] = {
2696-
// Scene referred interop IDs first so they are the default in automatic
2697-
// conversion from CICP to interop ID.
2698-
{ "srgb_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::sRGB,
2699-
CICPMatrix::BT709 },
2700-
{ "srgb_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::sRGB,
2701-
CICPMatrix::BT709 },
2702-
{ "srgb_p3d65_scene", CICPPrimaries::P3D65, CICPTransfer::sRGB,
2703-
CICPMatrix::BT709 },
2704-
// These are not display color spaces at all, but can be represented by CICP.
2705-
{ "lin_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::Linear,
2706-
CICPMatrix::BT709 },
2707-
{ "lin_p3d65_scene", CICPPrimaries::P3D65, CICPTransfer::Linear,
2708-
CICPMatrix::BT709 },
2709-
{ "lin_rec2020_scene", CICPPrimaries::Rec2020, CICPTransfer::Linear,
2710-
CICPMatrix::Rec2020_CL },
2711-
{ "lin_ciexyzd65_scene", CICPPrimaries::XYZD65, CICPTransfer::Linear,
2712-
CICPMatrix::Unspecified },
2713-
2714-
// Display referred interop IDs.
2715-
{ "srgb_rec709_display", CICPPrimaries::Rec709, CICPTransfer::sRGB,
2716-
CICPMatrix::BT709 },
2717-
{ "g24_rec709_display", CICPPrimaries::Rec709, CICPTransfer::BT709,
2718-
CICPMatrix::BT709 },
2719-
{ "srgb_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::sRGB,
2720-
CICPMatrix::BT709 },
2721-
{ "srgbe_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::sRGB,
2722-
CICPMatrix::BT709 },
2723-
{ "pq_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::PQ,
2724-
CICPMatrix::Rec2020_NCL },
2725-
{ "pq_rec2020_display", CICPPrimaries::Rec2020, CICPTransfer::PQ,
2726-
CICPMatrix::Rec2020_NCL },
2727-
{ "hlg_rec2020_display", CICPPrimaries::Rec2020, CICPTransfer::HLG,
2728-
CICPMatrix::Rec2020_NCL },
2729-
{ "g22_rec709_display", CICPPrimaries::Rec709, CICPTransfer::Gamma22,
2730-
CICPMatrix::BT709 },
2731-
// No CICP code for Adobe RGB primaries.
2732-
// { "g22_adobergb_display" }
2733-
{ "g26_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::Gamma26,
2734-
CICPMatrix::BT709 },
2735-
{ "g26_xyzd65_display", CICPPrimaries::XYZD65, CICPTransfer::Gamma26,
2736-
CICPMatrix::Unspecified },
2737-
{ "pq_xyzd65_display", CICPPrimaries::XYZD65, CICPTransfer::PQ,
2738-
CICPMatrix::Unspecified },
2739-
};
2740-
} // namespace
2741-
2742-
void
2743-
ColorConfig::set_colorspace_cicp(ImageSpec& spec, const int cicp[4]) const
2744-
{
2745-
spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp);
2746-
2747-
for (const ColorSpaceCICP& space : color_space_cicp) {
2748-
if (int(space.primaries) == cicp[0] && int(space.transfer) == cicp[1]) {
2749-
set_colorspace(spec, space.interop_id);
2750-
return;
2751-
}
2752-
}
2753-
}
2754-
2755-
bool
2756-
ColorConfig::get_colorspace_cicp(ImageSpec& spec, bool auto_cicp,
2757-
int cicp[4]) const
2758-
{
2759-
const ParamValue* p = spec.find_attribute("CICP",
2760-
TypeDesc(TypeDesc::INT, 4));
2761-
if (p) {
2762-
std::copy_n(static_cast<const int*>(p->data()), 4, cicp);
2763-
return true;
2764-
}
2765-
2766-
if (!auto_cicp) {
2767-
return false;
2768-
}
2769-
2770-
string_view colorspace = spec.get_string_attribute("oiio:ColorSpace");
2771-
if (!colorspace.empty()) {
2772-
for (const ColorSpaceCICP& space : color_space_cicp) {
2773-
if (equivalent(colorspace, space.interop_id)) {
2774-
cicp[0] = int(space.primaries);
2775-
cicp[1] = int(space.transfer);
2776-
cicp[2] = int(space.matrix);
2777-
cicp[3] = int(CICPRange::Full);
2778-
return true;
2779-
}
2780-
}
2781-
}
2782-
2783-
return false;
2784-
}
2785-
27862779
void
27872780
set_colorspace(ImageSpec& spec, string_view colorspace)
27882781
{

src/png.imageio/png_pvt.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ For further information see the following mailing list threads:
4040
OIIO_PLUGIN_NAMESPACE_BEGIN
4141

4242
#define ICC_PROFILE_ATTR "ICCProfile"
43+
#define CICP_ATTR "CICP"
4344

4445
namespace PNG_pvt {
4546

@@ -330,8 +331,11 @@ read_info(png_structp& sp, png_infop& ip, int& bit_depth, int& color_type,
330331
png_byte pri = 0, trc = 0, mtx = 0, vfr = 0;
331332
if (png_get_cICP(sp, ip, &pri, &trc, &mtx, &vfr)) {
332333
const int cicp[4] = { pri, trc, mtx, vfr };
334+
spec.attribute(CICP_ATTR, TypeDesc(TypeDesc::INT, 4), cicp);
333335
const ColorConfig& colorconfig(ColorConfig::default_colorconfig());
334-
colorconfig.set_colorspace_cicp(spec, cicp);
336+
string_view interop_id = colorconfig.getColorInteropID(cicp);
337+
if (!interop_id.empty())
338+
spec.attribute("oiio:ColorSpace", interop_id);
335339
}
336340
}
337341
#endif
@@ -734,11 +738,12 @@ write_info(png_structp& sp, png_infop& ip, int& color_type, ImageSpec& spec,
734738
#ifdef PNG_cICP_SUPPORTED
735739
// Only automatically determine CICP from oiio::ColorSpace if we didn't
736740
// write colorspace metadata yet.
737-
const bool auto_cicp = !wrote_colorspace;
738-
int cicp[4];
739-
if (colorconfig.get_colorspace_cicp(spec, auto_cicp, cicp)) {
740-
// Matrix must be RGB according to PNG spec v3
741-
cicp[2] = 0;
741+
const ParamValue* p = spec.find_attribute(CICP_ATTR,
742+
TypeDesc(TypeDesc::INT, 4));
743+
const int* cicp = (p) ? static_cast<const int*>(p->data())
744+
: (!wrote_colorspace) ? colorconfig.getCICP(colorspace)
745+
: nullptr;
746+
if (cicp) {
742747
png_byte vals[4];
743748
for (int i = 0; i < 4; ++i)
744749
vals[i] = static_cast<png_byte>(cicp[i]);

0 commit comments

Comments
 (0)