avif: color profiles improvements

With Qt 6.8.x, PQ and HLG transfer functions are supported.
Better support for GRAY profiles
This commit is contained in:
Daniel Novomeský 2025-01-02 14:11:55 +01:00
parent a7cf1a87f9
commit 43f3fd05f7

View File

@ -249,11 +249,15 @@ bool QAVIFHandler::decode_one_frame()
}
bool loadalpha;
bool loadgray = false;
if (m_decoder->image->alphaPlane) {
loadalpha = true;
} else {
loadalpha = false;
if (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
loadgray = true;
}
}
QImage::Format resultformat;
@ -285,6 +289,38 @@ bool QAVIFHandler::decode_one_frame()
if (!colorspace.isValid()) {
qWarning("AVIF image has Qt-unsupported or invalid ICC profile!");
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
else {
if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
qWarning("CMYK ICC profile is not extected for AVIF, discarding the ICCprofile!");
colorspace = QColorSpace();
} else if (colorspace.colorModel() == QColorSpace::ColorModel::Rgb && loadgray) {
// Input is GRAY but ICC is RGB, we will return RGB image
loadgray = false;
} else if (colorspace.colorModel() == QColorSpace::ColorModel::Gray && !loadgray) {
// ICC is GRAY but we must return RGB (image has alpha channel for example)
// we create similar RGB profile (same whitepoint and TRC)
QPointF gray_whitePoint = colorspace.whitePoint();
if (gray_whitePoint.isNull()) {
gray_whitePoint = QPointF(0.3127f, 0.329f);
}
const QPointF redP(0.64f, 0.33f);
const QPointF greenP(0.3f, 0.6f);
const QPointF blueP(0.15f, 0.06f);
QColorSpace::TransferFunction trc_new = colorspace.transferFunction();
float gamma_new = colorspace.gamma();
if (trc_new == QColorSpace::TransferFunction::Custom) {
trc_new = QColorSpace::TransferFunction::SRgb;
}
colorspace = QColorSpace(gray_whitePoint, redP, greenP, blueP, trc_new, gamma_new);
if (!colorspace.isValid()) {
qWarning("AVIF plugin created invalid QColorSpace!");
}
}
}
#endif
} else {
float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f};
// outPrimaries: rX, rY, gX, gY, bX, bY, wX, wY
@ -319,6 +355,14 @@ bool QAVIFHandler::decode_one_frame()
case 13:
q_trc = QColorSpace::TransferFunction::SRgb;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16: /* AVIF_TRANSFER_CHARACTERISTICS_PQ */
q_trc = QColorSpace::TransferFunction::St2084;
break;
case 18: /* AVIF_TRANSFER_CHARACTERISTICS_HLG */
q_trc = QColorSpace::TransferFunction::Hlg;
break;
#endif
default:
qWarning("CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
m_decoder->image->colorPrimaries,
@ -328,21 +372,29 @@ bool QAVIFHandler::decode_one_frame()
}
if (q_trc != QColorSpace::TransferFunction::Custom) { // we create new colorspace using Qt
switch (m_decoder->image->colorPrimaries) {
/* AVIF_COLOR_PRIMARIES_BT709 */
case 0:
case 1:
case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */
colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
break;
/* AVIF_COLOR_PRIMARIES_SMPTE432 */
case 12:
colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
break;
default:
colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
if (loadgray) {
colorspace = QColorSpace(whitePoint, q_trc, q_trc_gamma);
} else {
#endif
switch (m_decoder->image->colorPrimaries) {
/* AVIF_COLOR_PRIMARIES_BT709 */
case 0:
case 1:
case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */
colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
break;
/* AVIF_COLOR_PRIMARIES_SMPTE432 */
case 12:
colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
break;
default:
colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
break;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
}
#endif
}
if (!colorspace.isValid()) {
@ -350,8 +402,6 @@ bool QAVIFHandler::decode_one_frame()
}
}
result.setColorSpace(colorspace);
avifRGBImage rgb;
avifRGBImageSetDefaults(&rgb, m_decoder->image);
@ -363,7 +413,7 @@ bool QAVIFHandler::decode_one_frame()
rgb.depth = 16;
rgb.format = AVIF_RGB_FORMAT_RGBA;
if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) {
if (loadgray) {
resultformat = QImage::Format_Grayscale16;
}
} else {
@ -381,7 +431,7 @@ bool QAVIFHandler::decode_one_frame()
}
#endif
if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) {
if (loadgray) {
resultformat = QImage::Format_Grayscale8;
}
}
@ -473,6 +523,8 @@ bool QAVIFHandler::decode_one_frame()
m_current_image = result.convertToFormat(resultformat);
}
m_current_image.setColorSpace(colorspace);
m_estimated_dimensions = m_current_image.size();
m_must_jump_to_next_image = false;
@ -642,6 +694,14 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
avif->transferCharacteristics = (avifTransferCharacteristics)13;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084:
avif->transferCharacteristics = (avifTransferCharacteristics)16;
break;
case QColorSpace::TransferFunction::Hlg:
avif->transferCharacteristics = (avifTransferCharacteristics)18;
break;
#endif
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
break;
@ -691,8 +751,14 @@ bool QAVIFHandler::write(const QImage &image)
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
tmpcolorimage = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), tmpformat);
}
else {
} else if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Gray) {
QColorSpace::TransferFunction trc_new = cs.transferFunction();
float gamma_new = cs.gamma();
if (trc_new == QColorSpace::TransferFunction::Custom) {
trc_new = QColorSpace::TransferFunction::SRgb;
}
tmpcolorimage = image.convertedToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, trc_new, gamma_new), tmpformat);
} else {
tmpcolorimage = image.convertToFormat(tmpformat);
}
#else
@ -757,6 +823,14 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
transfer_to_save = (avifTransferCharacteristics)13;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084:
transfer_to_save = (avifTransferCharacteristics)16;
break;
case QColorSpace::TransferFunction::Hlg:
transfer_to_save = (avifTransferCharacteristics)18;
break;
#endif
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
transfer_to_save = (avifTransferCharacteristics)2;
@ -792,6 +866,14 @@ bool QAVIFHandler::write(const QImage &image)
case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.8f));
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::St2084));
break;
case 18:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::Hlg));
break;
#endif
default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
transfer_to_save = (avifTransferCharacteristics)13;