diff --git a/source/blender/imbuf/IMB_colormanagement.hh b/source/blender/imbuf/IMB_colormanagement.hh index 5451d3cd88e..b0e6fefb660 100644 --- a/source/blender/imbuf/IMB_colormanagement.hh +++ b/source/blender/imbuf/IMB_colormanagement.hh @@ -78,6 +78,7 @@ blender::Vector IMB_colormanagement_space_to_icc_profile(const ColorSpace * For describing the colorspace of videos and high dynamic range image files. */ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool video, + const bool rgb_matrix, int cicp[4]); const ColorSpace *IMB_colormanagement_space_from_cicp(const int cicp[4], const bool video); diff --git a/source/blender/imbuf/intern/colormanagement.cc b/source/blender/imbuf/intern/colormanagement.cc index d1b1a5cf964..b3544ddce76 100644 --- a/source/blender/imbuf/intern/colormanagement.cc +++ b/source/blender/imbuf/intern/colormanagement.cc @@ -1410,7 +1410,10 @@ static const int CICP_MATRIX_REC2020_NCL = 9; /* Range */ static const int CICP_RANGE_FULL = 1; -bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool video, int cicp[4]) +bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, + const bool video, + const bool rgb_matrix, + int cicp[4]) { const StringRefNull interop_id = colorspace->interop_id(); if (interop_id.is_empty()) { @@ -1421,22 +1424,18 @@ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool * ASWF Color Interop Forum defined display spaces. * https://en.wikipedia.org/wiki/Coding-independent_code_points * https://www.w3.org/TR/png-3/#cICP-chunk - * - * For images we always use RGB matrix as that is the only thing supported for PNG. - * For video we specify an appropriate matrix to YUV or similar. This should also - * be used for HEIF and AVIF which are based on video codecs. */ - + */ if (interop_id == "pq_rec2020_display") { cicp[0] = CICP_PRI_REC2020; cicp[1] = CICP_TRC_PQ; - cicp[2] = (video) ? CICP_MATRIX_REC2020_NCL : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_REC2020_NCL; cicp[3] = CICP_RANGE_FULL; return true; } if (interop_id == "hlg_rec2020_display") { cicp[0] = CICP_PRI_REC2020; cicp[1] = CICP_TRC_HLG; - cicp[2] = (video) ? CICP_MATRIX_REC2020_NCL : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_REC2020_NCL; cicp[3] = CICP_RANGE_FULL; return true; } @@ -1444,7 +1443,7 @@ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool /* Rec.2020 matrix may seem odd, but follows Color Interop Forum recommendation. */ cicp[0] = CICP_PRI_P3D65; cicp[1] = CICP_TRC_PQ; - cicp[2] = (video) ? CICP_MATRIX_REC2020_NCL : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_REC2020_NCL; cicp[3] = CICP_RANGE_FULL; return true; } @@ -1452,14 +1451,14 @@ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool /* BT.709 matrix may seem odd, but follows Color Interop Forum recommendation. */ cicp[0] = CICP_PRI_P3D65; cicp[1] = CICP_TRC_G26; - cicp[2] = (video) ? CICP_MATRIX_BT709 : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_BT709; cicp[3] = CICP_RANGE_FULL; return true; } if (interop_id == "g22_rec709_display") { cicp[0] = CICP_PRI_REC709; cicp[1] = CICP_TRC_G22; - cicp[2] = (video) ? CICP_MATRIX_BT709 : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_BT709; cicp[3] = CICP_RANGE_FULL; return true; } @@ -1467,7 +1466,7 @@ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool /* There is no gamma 2.4 trc, but BT.709 is close. */ cicp[0] = CICP_PRI_REC2020; cicp[1] = CICP_TRC_BT709; - cicp[2] = (video) ? CICP_MATRIX_REC2020_NCL : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_REC2020_NCL; cicp[3] = CICP_RANGE_FULL; return true; } @@ -1475,7 +1474,7 @@ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool /* There is no gamma 2.4 trc, but BT.709 is close. */ cicp[0] = CICP_PRI_REC709; cicp[1] = CICP_TRC_BT709; - cicp[2] = (video) ? CICP_MATRIX_BT709 : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_BT709; cicp[3] = CICP_RANGE_FULL; return true; } @@ -1485,7 +1484,7 @@ bool IMB_colormanagement_space_to_cicp(const ColorSpace *colorspace, const bool * "Quicktime gamma shift bug" that complicates things. */ cicp[0] = CICP_PRI_P3D65; cicp[1] = (video) ? CICP_TRC_BT709 : CICP_TRC_SRGB; - cicp[2] = (video) ? CICP_MATRIX_BT709 : CICP_MATRIX_RGB; + cicp[2] = (rgb_matrix) ? CICP_MATRIX_RGB : CICP_MATRIX_BT709; cicp[3] = CICP_RANGE_FULL; return true; } diff --git a/source/blender/imbuf/intern/oiio/openimageio_support.cc b/source/blender/imbuf/intern/oiio/openimageio_support.cc index 611329e987e..14c7200a684 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_support.cc +++ b/source/blender/imbuf/intern/oiio/openimageio_support.cc @@ -159,6 +159,17 @@ static void set_file_colorspace(ImFileColorSpace &r_colorspace, string ics = spec.get_string_attribute("oiio:ColorSpace"); STRNCPY_UTF8(r_colorspace.metadata_colorspace, ics.c_str()); } + + /* Get colorspace from CICP. */ + int cicp[4] = {}; + if (spec.getattribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp, true)) { + const bool for_video = false; + const ColorSpace *colorspace = IMB_colormanagement_space_from_cicp(cicp, for_video); + if (colorspace) { + STRNCPY_UTF8(r_colorspace.metadata_colorspace, + IMB_colormanagement_colorspace_get_name(colorspace)); + } + } } /** @@ -459,7 +470,7 @@ ImageSpec imb_create_write_spec(const WriteContext &ctx, int file_channels, Type } } - /* Write ICC profile if there is one associated with the colorspace. */ + /* Write ICC profile and/or CICP if there is one associated with the colorspace. */ const ColorSpace *colorspace = (ctx.mem_spec.format == TypeDesc::FLOAT) ? ctx.ibuf->float_buffer.colorspace : ctx.ibuf->byte_buffer.colorspace; @@ -470,6 +481,15 @@ ImageSpec imb_create_write_spec(const WriteContext &ctx, int file_channels, Type OIIO::TypeDesc(OIIO::TypeDesc::UINT8, icc_profile.size()), icc_profile.data()); } + + /* PNG only supports RGB matrix. For AVIF and HEIF we want to use a YUV matrix + * as these are based on video codecs designed to use them. */ + const bool for_video = false; + const bool rgb_matrix = STREQ(ctx.file_format, "png"); + int cicp[4]; + if (IMB_colormanagement_space_to_cicp(colorspace, for_video, rgb_matrix, cicp)) { + file_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp); + } } return file_spec; diff --git a/source/blender/imbuf/movie/intern/movie_write.cc b/source/blender/imbuf/movie/intern/movie_write.cc index 59df5d2bdff..5ba54e8a0b4 100644 --- a/source/blender/imbuf/movie/intern/movie_write.cc +++ b/source/blender/imbuf/movie/intern/movie_write.cc @@ -795,9 +795,10 @@ static void set_colorspace_options(AVCodecContext *c, const ColorSpace *colorspa const AVPixFmtDescriptor *pix_fmt_desc = av_pix_fmt_desc_get(c->pix_fmt); const bool is_rgb_format = (pix_fmt_desc->flags & AV_PIX_FMT_FLAG_RGB); const bool for_video = true; + const bool rgb_matrix = false; int cicp[4]; - if (colorspace && IMB_colormanagement_space_to_cicp(colorspace, for_video, cicp)) { + if (colorspace && IMB_colormanagement_space_to_cicp(colorspace, for_video, rgb_matrix, cicp)) { /* Note ffmpeg enums are documented to match CICP. */ c->color_primaries = AVColorPrimaries(cicp[0]); c->color_trc = AVColorTransferCharacteristic(cicp[1]);