Color Management: Support for HDR PNG read and write
### Color Management: Support image CICP read/write The CICP support will enable reading and writing HDR PNGs, following the recently released PNG spec: https://www.w3.org/TR/png-3/#cICP-chunk More useful for exporting to the web with reasonable file size would be AVIF support, but that will have to wait for the next library update in Blender 5.1 to add libheif. Note this will only starting working once the 5.0 libraries have landed, which should happen somewhere in the next week. Pull Request: https://projects.blender.org/blender/blender/pulls/145612
This commit is contained in:
committed by
Brecht Van Lommel
parent
488ff26d35
commit
fd9edf5b89
@@ -78,6 +78,7 @@ blender::Vector<char> 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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
Reference in New Issue
Block a user