Check primaries returned from libavif

Due to various double vs float arithmetic,
some primaries could be rejected by Qt.
If necessary, we adjust the values so they
will be accepted by Qt.

Remove newline from the ends of error strings.
This commit is contained in:
Daniel Novomesky 2021-02-27 19:11:56 +01:00
parent ca52d4ddf5
commit 1462c3abd6
2 changed files with 35 additions and 19 deletions

View File

@ -12,6 +12,7 @@
#include <QColorSpace>
#include "avif_p.h"
#include <cfloat>
QAVIFHandler::QAVIFHandler() :
@ -102,7 +103,7 @@ bool QAVIFHandler::ensureDecoder()
decodeResult = avifDecoderSetIOMemory(m_decoder, m_rawAvifData.data, m_rawAvifData.size);
if (decodeResult != AVIF_RESULT_OK) {
qWarning("ERROR: avifDecoderSetIOMemory failed: %s\n", avifResultToString(decodeResult));
qWarning("ERROR: avifDecoderSetIOMemory failed: %s", avifResultToString(decodeResult));
avifDecoderDestroy(m_decoder);
m_decoder = nullptr;
@ -112,7 +113,7 @@ bool QAVIFHandler::ensureDecoder()
decodeResult = avifDecoderParse(m_decoder);
if (decodeResult != AVIF_RESULT_OK) {
qWarning("ERROR: Failed to parse input: %s\n", avifResultToString(decodeResult));
qWarning("ERROR: Failed to parse input: %s", avifResultToString(decodeResult));
avifDecoderDestroy(m_decoder);
m_decoder = nullptr;
@ -147,7 +148,7 @@ bool QAVIFHandler::ensureDecoder()
return false;
}
} else {
qWarning("ERROR: Failed to decode image: %s\n", avifResultToString(decodeResult));
qWarning("ERROR: Failed to decode image: %s", avifResultToString(decodeResult));
}
avifDecoderDestroy(m_decoder);
@ -195,16 +196,17 @@ bool QAVIFHandler::decode_one_frame()
if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) {
result.setColorSpace(QColorSpace::fromIccProfile(QByteArray::fromRawData((const char *) m_decoder->image->icc.data, (int) m_decoder->image->icc.size)));
if (! result.colorSpace().isValid()) {
qWarning("Invalid QColorSpace created from ICC!\n");
qWarning("Invalid QColorSpace created from ICC!");
}
} else {
float prim[8]; // outPrimaries: rX, rY, gX, gY, bX, bY, wX, wY
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
avifColorPrimariesGetValues(m_decoder->image->colorPrimaries, prim);
QPointF redPoint(prim[0], prim[1]);
QPointF greenPoint(prim[2], prim[3]);
QPointF bluePoint(prim[4], prim[5]);
QPointF whitePoint(prim[6], prim[7]);
const QPointF redPoint(QAVIFHandler::CompatibleChromacity(prim[0], prim[1]));
const QPointF greenPoint(QAVIFHandler::CompatibleChromacity(prim[2], prim[3]));
const QPointF bluePoint(QAVIFHandler::CompatibleChromacity(prim[4], prim[5]));
const QPointF whitePoint(QAVIFHandler::CompatibleChromacity(prim[6], prim[7]));
QColorSpace::TransferFunction q_trc = QColorSpace::TransferFunction::Custom;
@ -257,7 +259,7 @@ bool QAVIFHandler::decode_one_frame()
}
if (! result.colorSpace().isValid()) {
qWarning("Invalid QColorSpace created from NCLX/CICP!\n");
qWarning("Invalid QColorSpace created from NCLX/CICP!");
}
}
@ -296,7 +298,7 @@ bool QAVIFHandler::decode_one_frame()
avifResult res = avifImageYUVToRGB(m_decoder->image, &rgb);
if (res != AVIF_RESULT_OK) {
qWarning("ERROR in avifImageYUVToRGB: %s\n", avifResultToString(res));
qWarning("ERROR in avifImageYUVToRGB: %s", avifResultToString(res));
return false;
}
@ -338,7 +340,7 @@ bool QAVIFHandler::decode_one_frame()
}
else { //Zero values, we need to avoid 0 divide.
qWarning("ERROR: Wrong values in avifCleanApertureBox\n");
qWarning("ERROR: Wrong values in avifCleanApertureBox");
}
}
@ -680,7 +682,7 @@ bool QAVIFHandler::write(const QImage &image)
res = avifImageRGBToYUV(avif, &rgb);
if (res != AVIF_RESULT_OK) {
qWarning("ERROR in avifImageRGBToYUV: %s\n", avifResultToString(res));
qWarning("ERROR in avifImageRGBToYUV: %s", avifResultToString(res));
return false;
}
}
@ -709,11 +711,11 @@ bool QAVIFHandler::write(const QImage &image)
if (status > 0) {
return true;
} else if (status == -1) {
qWarning("Write error: %s\n", qUtf8Printable(device()->errorString()));
qWarning("Write error: %s", qUtf8Printable(device()->errorString()));
return false;
}
} else {
qWarning("ERROR: Failed to encode: %s\n", avifResultToString(res));
qWarning("ERROR: Failed to encode: %s", avifResultToString(res));
}
return false;
@ -810,14 +812,14 @@ bool QAVIFHandler::jumpToNextImage()
avifResult decodeResult = avifDecoderNextImage(m_decoder);
if (decodeResult != AVIF_RESULT_OK) {
qWarning("ERROR: Failed to decode Next image in sequence: %s\n", avifResultToString(decodeResult));
qWarning("ERROR: Failed to decode Next image in sequence: %s", avifResultToString(decodeResult));
m_parseState = ParseAvifError;
return false;
}
if ((m_container_width != m_decoder->image->width) ||
(m_container_height != m_decoder->image->height)) {
qWarning("Decoded image sequence size (%dx%d) do not match first image size (%dx%d)!\n",
qWarning("Decoded image sequence size (%dx%d) do not match first image size (%dx%d)!",
m_decoder->image->width, m_decoder->image->height,
m_container_width, m_container_height);
@ -859,14 +861,14 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
avifResult decodeResult = avifDecoderNthImage(m_decoder, imageNumber);
if (decodeResult != AVIF_RESULT_OK) {
qWarning("ERROR: Failed to decode %d th Image in sequence: %s\n", imageNumber, avifResultToString(decodeResult));
qWarning("ERROR: Failed to decode %d th Image in sequence: %s", imageNumber, avifResultToString(decodeResult));
m_parseState = ParseAvifError;
return false;
}
if ((m_container_width != m_decoder->image->width) ||
(m_container_height != m_decoder->image->height)) {
qWarning("Decoded image sequence size (%dx%d) do not match declared container size (%dx%d)!\n",
qWarning("Decoded image sequence size (%dx%d) do not match declared container size (%dx%d)!",
m_decoder->image->width, m_decoder->image->height,
m_container_width, m_container_height);
@ -912,6 +914,18 @@ int QAVIFHandler::loopCount() const
return 1;
}
QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
{
chrX = qBound(qreal(0.0), chrX, qreal(1.0));
chrY = qBound(qreal(DBL_MIN), chrY, qreal(1.0));
if ((chrX + chrY) > qreal(1.0)) {
chrX = qreal(1.0) - chrY;
}
return QPointF(chrX, chrY);
}
QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "avif") {

View File

@ -14,6 +14,7 @@
#include <qimageiohandler.h>
#include <QImageIOPlugin>
#include <QByteArray>
#include <QPointF>
#include <avif/avif.h>
class QAVIFHandler : public QImageIOHandler
@ -41,6 +42,7 @@ public:
int loopCount() const override;
private:
static QPointF CompatibleChromacity(qreal chrX, qreal chrY);
bool ensureParsed() const;
bool ensureDecoder();
bool decode_one_frame();