Skip to content

Commit 4d247d3

Browse files
committed
feat: Support display color space interop IDs in I/O
* Display referred interop IDs are now chosen over scene referred ones by default on file read. This more closely matches the standards for CICP, ICC and other color metadata. Most images will now have oiio:ColorSpace set to srgb_rec709_display rather than srgb_rec709_scene on file read. There is groundwork to add control to prefer either display or scene referred, but I'm not sure yet what the best way to expose it is. * Both srgb_rec709_scene and srgb_rec709_display are now (distinct) built-in color spaces. The built-in "sRGB" color space name was changed to be an alias of srgb_rec709_display rather than srgb_rec709_scene. * Previously only srgb_rec709_scene was recognized as sRGB for file metadata and display, now srgb_rec709_display and g22_rec709_display are treated as sRGB as well. The reason for g22_rec709_display behavior is that this type of display is often used to correct for the discrepancy where images are encoded as sRGB but usually decoded as gamma 2.2 by the physical display. By encoding it as gamma 2.2 and claiming it's sRGB the transfer functions cancel out exactly. * g24_rec709_display is now recognized as having gamma 2.4, and the name g24_rec709_scene was replaced with ocio:g24_rec709_scene since the former is not an official interop ID. * cio:itu709_rec709_scene and ocio:lin_ciexyzd65_display were added to complete the list of interop IDs in OCIO configs that match a CICP. Signed-off-by: Brecht Van Lommel <[email protected]>
1 parent 6e5712b commit 4d247d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+528
-379
lines changed

src/bmp.imageio/bmpinput.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <OpenImageIO/fmath.h>
99
#include <OpenImageIO/imageio.h>
1010

11+
#include "imageio_pvt.h"
12+
1113
#include "bmp_pvt.h"
1214

1315
OIIO_PLUGIN_NAMESPACE_BEGIN
@@ -262,7 +264,8 @@ BmpInput::open(const std::string& name, ImageSpec& newspec,
262264
// Default presumption is that a BMP file is meant to look reasonable on a
263265
// display, so assume it's sRGB. This is not really correct -- see the
264266
// comments below.
265-
m_spec.attribute("oiio:ColorSpace", "srgb_rec709_scene");
267+
const bool erase_other_attributes = false;
268+
pvt::set_colorspace_srgb(m_spec, erase_other_attributes);
266269
#if 0
267270
if (m_dib_header.size >= WINDOWS_V4
268271
&& m_dib_header.cs_type == CSType::CalibratedRGB) {

src/dds.imageio/ddsinput.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <OpenImageIO/parallel.h>
1616
#include <OpenImageIO/typedesc.h>
1717

18+
#include "imageio_pvt.h"
19+
1820
#include "dds_pvt.h"
1921
#define BCDEC_IMPLEMENTATION
2022
#include "bcdec.h"
@@ -828,7 +830,7 @@ DDSInput::seek_subimage(int subimage, int miplevel)
828830
if (bpp != 0)
829831
m_spec.attribute("oiio:BitsPerSample", bpp);
830832

831-
const char* colorspace = nullptr;
833+
bool is_srgb = false;
832834

833835
if (m_dds.fmt.fourCC == DDS_4CC_DX10) {
834836
switch (m_dx10.dxgiFormat) {
@@ -838,18 +840,17 @@ DDSInput::seek_subimage(int subimage, int miplevel)
838840
case DDS_FORMAT_BC7_UNORM_SRGB:
839841
case DDS_FORMAT_R8G8B8A8_UNORM_SRGB:
840842
case DDS_FORMAT_B8G8R8A8_UNORM_SRGB:
841-
case DDS_FORMAT_B8G8R8X8_UNORM_SRGB:
842-
colorspace = "srgb_rec709_scene";
843-
break;
843+
case DDS_FORMAT_B8G8R8X8_UNORM_SRGB: is_srgb = true; break;
844844
}
845845
}
846846

847-
// linear color space for HDR-ish images
848-
if (colorspace == nullptr
849-
&& (basetype == TypeDesc::HALF || basetype == TypeDesc::FLOAT))
850-
colorspace = "lin_rec709_scene";
851-
852-
m_spec.set_colorspace(colorspace);
847+
if (is_srgb) {
848+
pvt::set_colorspace_srgb(m_spec);
849+
} else if (!is_srgb
850+
&& (basetype == TypeDesc::HALF || basetype == TypeDesc::FLOAT)) {
851+
// linear color space for HDR-ish images
852+
m_spec.set_colorspace("lin_rec709_scene");
853+
}
853854

854855
m_spec.default_channel_names();
855856
// Special case: if a 2-channel DDS RG or YA?

src/doc/stdmetadata.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,11 @@ Color information
149149
- `"lin_ap1_scene"`, `"ACEScg"` : ACEScg color space encoding.
150150
- `"lin_ap0_scene"` : ACES2065-1, the recommended ACES space for
151151
interchange and archiving.
152-
- `"srgb_rec709_scene"` : Using standard (piecewise) sRGB response and
152+
- `"srgb_rec709_display"` : Using standard (piecewise) sRGB response and
153153
primaries. The token `"sRGB"` is treated as a synonym.
154-
- `"g22_rec709_scene"` : Rec709/sRGB primaries, but using a response curve
154+
- `"srgb_rec709_scene"` : Same response and primaries as
155+
`"srgb_rec709_display"` but for scene referred images.
156+
- `"g22_rec709_display"` : Rec709/sRGB primaries, but using a response curve
155157
corresponding to gamma 2.2.
156158

157159
Additionally, `"scene_linear"` is a role that is appropriate for color

src/dpx.imageio/dpxinput.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
// ago and are probably the sole maintainers of this code, and just allow
2222
// ourselves to diverge from the original.
2323

24+
#include "imageio_pvt.h"
2425
#include "libdpx/DPX.h"
2526
#include "libdpx/DPXColorConverter.h"
2627
#include "libdpx/DPXHeader.h"
@@ -314,7 +315,7 @@ DPXInput::seek_subimage(int subimage, int miplevel)
314315
switch (m_dpx.header.Transfer(subimage)) {
315316
case dpx::kLinear: m_spec.set_colorspace("lin_rec709_scene"); break;
316317
case dpx::kLogarithmic: m_spec.set_colorspace("KodakLog"); break;
317-
case dpx::kITUR709: m_spec.set_colorspace("srgb_rec709_scene"); break;
318+
case dpx::kITUR709: pvt::set_colorspace_srgb(m_spec); break;
318319
case dpx::kUserDefined:
319320
if (!std::isnan(m_dpx.header.Gamma()) && m_dpx.header.Gamma() != 0) {
320321
set_colorspace_rec709_gamma(m_spec, float(m_dpx.header.Gamma()));

src/ffmpeg.imageio/ffmpeginput.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ receive_frame(AVCodecContext* avctx, AVFrame* picture, AVPacket* avpkt)
7171

7272

7373

74+
#include "imageio_pvt.h"
7475
#include <OpenImageIO/color.h>
7576
#include <OpenImageIO/imageio.h>
7677
#include <iostream>
@@ -549,11 +550,7 @@ FFmpegInput::open(const std::string& name, ImageSpec& spec)
549550
= { m_codec_context->color_primaries, m_codec_context->color_trc,
550551
m_codec_context->colorspace,
551552
m_codec_context->color_range == AVCOL_RANGE_MPEG ? 0 : 1 };
552-
m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp);
553-
const ColorConfig& colorconfig(ColorConfig::default_colorconfig());
554-
string_view interop_id = colorconfig.get_color_interop_id(cicp);
555-
if (!interop_id.empty())
556-
m_spec.attribute("oiio:ColorSpace", interop_id);
553+
pvt::set_colorspace_cicp(spec, cicp);
557554

558555
m_nsubimages = m_frames;
559556
spec = m_spec;

src/gif.imageio/gifinput.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <OpenImageIO/imageio.h>
1313
#include <OpenImageIO/thread.h>
1414

15+
#include "imageio_pvt.h"
16+
1517
// GIFLIB:
1618
// http://giflib.sourceforge.net/
1719
// Format description:
@@ -259,7 +261,7 @@ GIFInput::read_subimage_metadata(ImageSpec& newspec)
259261
newspec.nchannels = 4;
260262
newspec.default_channel_names();
261263
newspec.alpha_channel = 4;
262-
newspec.set_colorspace("srgb_rec709_scene");
264+
pvt::set_colorspace_srgb(newspec);
263265

264266
m_previous_disposal_method = m_disposal_method;
265267
m_disposal_method = DISPOSAL_UNSPECIFIED;

src/heif.imageio/heifinput.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <OpenImageIO/platform.h>
1010
#include <OpenImageIO/tiffutils.h>
1111

12+
#include "imageio_pvt.h"
13+
1214
#include <libheif/heif_cxx.h>
1315

1416
#define MAKE_LIBHEIF_VERSION(a, b, c, d) \
@@ -273,7 +275,7 @@ HeifInput::seek_subimage(int subimage, int miplevel)
273275
if (m_bitdepth > 8) {
274276
m_spec.attribute("oiio:BitsPerSample", m_bitdepth);
275277
}
276-
m_spec.set_colorspace("srgb_rec709_scene");
278+
pvt::set_colorspace_srgb(m_spec);
277279

278280
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
279281
// Read CICP. Have to use the C API to get it from the image handle,
@@ -292,12 +294,7 @@ HeifInput::seek_subimage(int subimage, int miplevel)
292294
int(nclx->transfer_characteristics),
293295
int(nclx->matrix_coefficients),
294296
int(nclx->full_range_flag ? 1 : 0) };
295-
m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp);
296-
const ColorConfig& colorconfig(
297-
ColorConfig::default_colorconfig());
298-
string_view interop_id = colorconfig.get_color_interop_id(cicp);
299-
if (!interop_id.empty())
300-
m_spec.attribute("oiio:ColorSpace", interop_id);
297+
pvt::set_colorspace_cicp(m_spec, cicp);
301298
}
302299
heif_nclx_color_profile_free(nclx);
303300
}

src/iconvert/iconvert.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <OpenImageIO/strutil.h>
1919
#include <OpenImageIO/sysutil.h>
2020

21+
#include "imageio_pvt.h"
22+
2123

2224
using namespace OIIO;
2325

@@ -224,7 +226,7 @@ adjust_spec(ImageInput* in, ImageOutput* out, const ImageSpec& inspec,
224226
if (gammaval != 1.0f)
225227
outspec.attribute("oiio:Gamma", gammaval);
226228
if (sRGB) {
227-
outspec.set_colorspace("srgb_rec709_scene");
229+
pvt::set_colorspace_srgb(outspec);
228230
if (!strcmp(in->format_name(), "jpeg")
229231
|| outspec.find_attribute("Exif:ColorSpace"))
230232
outspec.attribute("Exif:ColorSpace", 1);

src/include/OpenImageIO/color.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,13 @@ class OIIO_API ColorConfig {
415415
string_view get_color_interop_id(string_view colorspace) const;
416416

417417
/// Find color interop ID corresponding to the CICP code.
418+
/// If prefer_scene_referred is true, prefer returning a scene referred
419+
/// interop ID over a display referred interop ID if both exist.
418420
/// Returns empty string if not found.
419421
///
420422
/// @version 3.1
421-
string_view get_color_interop_id(const int cicp[4]) const;
423+
string_view get_color_interop_id(const int cicp[4],
424+
bool prefer_scene_referred) const;
422425

423426
/// Return a filename or other identifier for the config we're using.
424427
std::string configname() const;

src/include/imageio_pvt.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ parallel_convert_from_float(const float* src, void* dst, size_t nvals,
127127
OIIO_API bool
128128
check_texture_metadata_sanity(ImageSpec& spec);
129129

130+
/// Set oiio:ColorSpace to the default sRGB colorspace, which may be display
131+
/// or scene referred depending on configuration.
132+
///
133+
/// If erase_other_attributes is true, other potentially conflicting attributes
134+
/// are erased.
135+
OIIO_API void
136+
set_colorspace_srgb(ImageSpec& spec, bool erase_other_attributes = true);
137+
130138
/// Returns true if for the purpose of interop, the spec's metadata
131139
/// specifies a color space that should be encoded as sRGB.
132140
///
@@ -143,13 +151,18 @@ get_colorspace_rec709_gamma(const ImageSpec& spec);
143151
// Returns ICC profile from the spec's metadata, either from an ICCProfile
144152
// attribute or from the colorspace if from_colorspace is true.
145153
// Returns an empty vector if not found.
146-
std::vector<uint8_t>
154+
OIIO_API std::vector<uint8_t>
147155
get_colorspace_icc_profile(const ImageSpec& spec, bool from_colorspace = true);
148156

149-
// Returns ICC profile from the spec's metadata, either from a CICP attribute
157+
// Set CICP attribute in the spec's metadata, and set oiio:ColorSpace
158+
// along with it if there is a corresponding known colorspace.
159+
OIIO_API void
160+
set_colorspace_cicp(ImageSpec& spec, const int cicp[4]);
161+
162+
// Returns CICP from the spec's metadata, either from a CICP attribute
150163
// or from the colorspace if from_colorspace is true.
151164
// Returns an empty span if not found.
152-
cspan<int>
165+
OIIO_API cspan<int>
153166
get_colorspace_cicp(const ImageSpec& spec, bool from_colorspace = true);
154167

155168
/// Get the timing report from log_time entries.

0 commit comments

Comments
 (0)