28#ifndef KIMG_AVIF_DEFAULT_QUALITY
29#define KIMG_AVIF_DEFAULT_QUALITY 68
32#ifndef KIMG_AVIF_QUALITY_BEST
33#define KIMG_AVIF_QUALITY_BEST 90
36#ifndef KIMG_AVIF_QUALITY_HIGH
37#define KIMG_AVIF_QUALITY_HIGH 80
40#ifndef KIMG_AVIF_QUALITY_LOW
41#define KIMG_AVIF_QUALITY_LOW 51
44QAVIFHandler::QAVIFHandler()
45 : m_parseState(ParseAvifNotParsed)
46 , m_quality(KIMG_AVIF_DEFAULT_QUALITY)
47 , m_container_width(0)
48 , m_container_height(0)
49 , m_rawAvifData(AVIF_DATA_EMPTY)
51 , m_must_jump_to_next_image(false)
55QAVIFHandler::~QAVIFHandler()
58 avifDecoderDestroy(m_decoder);
62bool QAVIFHandler::canRead()
const
64 if (m_parseState == ParseAvifNotParsed && !canRead(device())) {
68 if (m_parseState != ParseAvifError) {
71 if (m_parseState == ParseAvifFinished) {
80bool QAVIFHandler::canRead(
QIODevice *device)
86 if (header.
size() < 12) {
91 input.
data =
reinterpret_cast<const uint8_t *
>(header.
constData());
92 input.size = header.
size();
94 if (avifPeekCompatibleFileType(&input)) {
100bool QAVIFHandler::ensureParsed()
const
102 if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifMetadata || m_parseState == ParseAvifFinished) {
105 if (m_parseState == ParseAvifError) {
109 QAVIFHandler *that =
const_cast<QAVIFHandler *
>(
this);
111 return that->ensureDecoder();
114bool QAVIFHandler::ensureOpened()
const
116 if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifFinished) {
119 if (m_parseState == ParseAvifError) {
123 QAVIFHandler *that =
const_cast<QAVIFHandler *
>(
this);
124 if (ensureParsed()) {
125 if (m_parseState == ParseAvifMetadata) {
126 bool success = that->jumpToNextImage();
127 that->m_parseState = success ? ParseAvifSuccess : ParseAvifError;
132 that->m_parseState = ParseAvifError;
136bool QAVIFHandler::ensureDecoder()
142 m_rawData = device()->
readAll();
144 m_rawAvifData.
data =
reinterpret_cast<const uint8_t *
>(m_rawData.constData());
145 m_rawAvifData.size = m_rawData.size();
147 if (avifPeekCompatibleFileType(&m_rawAvifData) == AVIF_FALSE) {
148 m_parseState = ParseAvifError;
152 m_decoder = avifDecoderCreate();
154 m_decoder->ignoreExif = AVIF_TRUE;
155 m_decoder->ignoreXMP = AVIF_TRUE;
157#if AVIF_VERSION >= 80400
161#if AVIF_VERSION >= 90100
162 m_decoder->strictFlags = AVIF_STRICT_DISABLED;
165#if AVIF_VERSION >= 110000
166 m_decoder->imageDimensionLimit = 65535;
169 avifResult decodeResult;
171 decodeResult = avifDecoderSetIOMemory(m_decoder, m_rawAvifData.data, m_rawAvifData.size);
172 if (decodeResult != AVIF_RESULT_OK) {
173 qWarning(
"ERROR: avifDecoderSetIOMemory failed: %s", avifResultToString(decodeResult));
175 avifDecoderDestroy(m_decoder);
177 m_parseState = ParseAvifError;
181 decodeResult = avifDecoderParse(m_decoder);
182 if (decodeResult != AVIF_RESULT_OK) {
183 qWarning(
"ERROR: Failed to parse input: %s", avifResultToString(decodeResult));
185 avifDecoderDestroy(m_decoder);
187 m_parseState = ParseAvifError;
191 m_container_width = m_decoder->image->width;
192 m_container_height = m_decoder->image->height;
194 if ((m_container_width > 65535) || (m_container_height > 65535)) {
195 qWarning(
"AVIF image (%dx%d) is too large!", m_container_width, m_container_height);
196 m_parseState = ParseAvifError;
200 if ((m_container_width == 0) || (m_container_height == 0)) {
201 qWarning(
"Empty image, nothing to decode");
202 m_parseState = ParseAvifError;
206 if (m_container_width > ((16384 * 16384) / m_container_height)) {
207 qWarning(
"AVIF image (%dx%d) has more than 256 megapixels!", m_container_width, m_container_height);
208 m_parseState = ParseAvifError;
213 int new_width = m_container_width;
214 int new_height = m_container_height;
216 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_CLAP) {
217 if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) && (m_decoder->image->clap.horizOffD > 0)
218 && (m_decoder->image->clap.vertOffD > 0)) {
219 int crop_width = (int)((
double)(m_decoder->image->clap.widthN) / (m_decoder->image->clap.widthD) + 0.5);
220 if (crop_width < new_width && crop_width > 0) {
221 new_width = crop_width;
223 int crop_height = (int)((
double)(m_decoder->image->clap.heightN) / (m_decoder->image->clap.heightD) + 0.5);
224 if (crop_height < new_height && crop_height > 0) {
225 new_height = crop_height;
230 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IROT) {
231 if (m_decoder->image->irot.angle == 1 || m_decoder->image->irot.angle == 3) {
233 new_width = new_height;
238 m_estimated_dimensions.setWidth(new_width);
239 m_estimated_dimensions.setHeight(new_height);
241 m_parseState = ParseAvifMetadata;
245bool QAVIFHandler::decode_one_frame()
247 if (!ensureParsed()) {
253 if (m_decoder->image->alphaPlane) {
261 if (m_decoder->image->depth > 8) {
275 QImage result = imageAlloc(m_decoder->image->width, m_decoder->image->height, resultformat);
277 qWarning(
"Memory cannot be allocated");
282 if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) {
283 const QByteArray icc_data(
reinterpret_cast<const char *
>(m_decoder->image->icc.data), m_decoder->image->icc.size);
286 qWarning(
"AVIF image has Qt-unsupported or invalid ICC profile!");
289 float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f};
291 avifColorPrimariesGetValues(m_decoder->image->colorPrimaries, prim);
293 const QPointF redPoint(QAVIFHandler::CompatibleChromacity(prim[0], prim[1]));
294 const QPointF greenPoint(QAVIFHandler::CompatibleChromacity(prim[2], prim[3]));
295 const QPointF bluePoint(QAVIFHandler::CompatibleChromacity(prim[4], prim[5]));
296 const QPointF whitePoint(QAVIFHandler::CompatibleChromacity(prim[6], prim[7]));
299 float q_trc_gamma = 0.0f;
301 switch (m_decoder->image->transferCharacteristics) {
304 q_trc = QColorSpace::TransferFunction::Gamma;
309 q_trc = QColorSpace::TransferFunction::Gamma;
314 q_trc = QColorSpace::TransferFunction::Linear;
320 q_trc = QColorSpace::TransferFunction::SRgb;
323 qWarning(
"CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
324 m_decoder->image->colorPrimaries,
325 m_decoder->image->transferCharacteristics);
326 q_trc = QColorSpace::TransferFunction::SRgb;
330 if (q_trc != QColorSpace::TransferFunction::Custom) {
331 switch (m_decoder->image->colorPrimaries) {
336 colorspace =
QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
340 colorspace =
QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
343 colorspace =
QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
349 qWarning(
"AVIF plugin created invalid QColorSpace from NCLX/CICP!");
356 avifRGBImageSetDefaults(&rgb, m_decoder->image);
358#if AVIF_VERSION >= 1000000
359 rgb.maxThreads = m_decoder->maxThreads;
362 if (m_decoder->image->depth > 8) {
364 rgb.format = AVIF_RGB_FORMAT_RGBA;
366 if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) {
371#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
372 rgb.format = AVIF_RGB_FORMAT_BGRA;
374 rgb.format = AVIF_RGB_FORMAT_ARGB;
377#if AVIF_VERSION >= 80400
378 if (m_decoder->imageCount > 1) {
380 rgb.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
384 if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) {
390 rgb.pixels = result.
bits();
392 avifResult res = avifImageYUVToRGB(m_decoder->image, &rgb);
393 if (res != AVIF_RESULT_OK) {
394 qWarning(
"ERROR in avifImageYUVToRGB: %s", avifResultToString(res));
398 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_CLAP) {
399 if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) && (m_decoder->image->clap.horizOffD > 0)
400 && (m_decoder->image->clap.vertOffD > 0)) {
401 int new_width = (int)((
double)(m_decoder->image->clap.widthN) / (m_decoder->image->clap.widthD) + 0.5);
402 if (new_width > result.
width()) {
403 new_width = result.
width();
406 int new_height = (int)((
double)(m_decoder->image->clap.heightN) / (m_decoder->image->clap.heightD) + 0.5);
407 if (new_height > result.
height()) {
408 new_height = result.
height();
411 if (new_width > 0 && new_height > 0) {
413 ((double)((int32_t)m_decoder->image->clap.horizOffN)) / (m_decoder->image->clap.horizOffD) + (result.
width() - new_width) / 2.0 + 0.5;
416 }
else if (offx > (result.
width() - new_width)) {
417 offx = result.
width() - new_width;
421 ((double)((int32_t)m_decoder->image->clap.vertOffN)) / (m_decoder->image->clap.vertOffD) + (result.
height() - new_height) / 2.0 + 0.5;
424 }
else if (offy > (result.
height() - new_height)) {
425 offy = result.
height() - new_height;
428 result = result.
copy(offx, offy, new_width, new_height);
433 qWarning(
"ERROR: Wrong values in avifCleanApertureBox");
437 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IROT) {
439 switch (m_decoder->image->irot.angle) {
455 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IMIR) {
456#if AVIF_VERSION > 90100 && AVIF_VERSION < 1000000
457 switch (m_decoder->image->imir.mode) {
459 switch (m_decoder->image->imir.axis) {
462 result = result.
mirrored(
false,
true);
465 result = result.
mirrored(
true,
false);
470 if (resultformat == result.
format()) {
471 m_current_image = result;
476 m_estimated_dimensions = m_current_image.size();
478 m_must_jump_to_next_image =
false;
482bool QAVIFHandler::read(
QImage *image)
484 if (!ensureOpened()) {
488 if (m_must_jump_to_next_image) {
492 *image = m_current_image;
493 if (imageCount() >= 2) {
494 m_must_jump_to_next_image =
true;
495 if (m_decoder->imageIndex >= m_decoder->imageCount - 1) {
497 m_parseState = ParseAvifFinished;
501 m_parseState = ParseAvifFinished;
506bool QAVIFHandler::write(
const QImage &image)
509 qWarning(
"No image data to save!");
514 if ((image.
width() > 65535) || (image.
height() > 65535)) {
515 qWarning(
"Image (%dx%d) is too large to save!", image.
width(), image.
height());
519 if (image.
width() > ((16384 * 16384) / image.
height())) {
520 qWarning(
"Image (%dx%d) will not be saved because it has more than 256 megapixels!", image.
width(), image.
height());
524 if ((image.
width() > 32768) || (image.
height() > 32768)) {
525 qWarning(
"Image (%dx%d) has a dimension above 32768 pixels, saved AVIF may not work in other software!", image.
width(), image.
height());
528 qWarning(
"Image has zero dimension!");
532 const char *encoder_name = avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE);
534 qWarning(
"Cannot save AVIF images because libavif was built without AV1 encoders!");
538 bool lossless =
false;
539 if (m_quality >= 100) {
540 if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE)) {
543 qWarning(
"You are using %s encoder. It is recommended to enable libAOM encoder in libavif to use lossless compression.", encoder_name);
547 if (m_quality > 100) {
549 }
else if (m_quality < 0) {
550 m_quality = KIMG_AVIF_DEFAULT_QUALITY;
553#if AVIF_VERSION < 1000000
554 int maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY * (100 - qBound(0, m_quality, 100)) / 100;
555 int minQuantizer = 0;
556 int maxQuantizerAlpha = 0;
564 avifImage *avif =
nullptr;
572 save_grayscale =
true;
578 save_grayscale =
false;
595 if (image.
depth() > 32) {
603#if AVIF_VERSION < 1000000
605 if (maxQuantizer > 20) {
606 minQuantizer = maxQuantizer - 20;
607 if (maxQuantizer > 40) {
608 maxQuantizerAlpha = maxQuantizer - 40;
614 if (save_depth > 8) {
621 avif = avifImageCreate(tmpgrayimage.
width(), tmpgrayimage.
height(), save_depth, AVIF_PIXEL_FORMAT_YUV400);
622#if AVIF_VERSION >= 110000
623 res = avifImageAllocatePlanes(avif, AVIF_PLANES_YUV);
624 if (res != AVIF_RESULT_OK) {
625 qWarning(
"ERROR in avifImageAllocatePlanes: %s", avifResultToString(res));
629 avifImageAllocatePlanes(avif, AVIF_PLANES_YUV);
633 avif->colorPrimaries = (avifColorPrimaries)1;
634 avif->matrixCoefficients = (avifMatrixCoefficients)1;
637 case QColorSpace::TransferFunction::Linear:
639 avif->transferCharacteristics = (avifTransferCharacteristics)8;
641 case QColorSpace::TransferFunction::SRgb:
643 avif->transferCharacteristics = (avifTransferCharacteristics)13;
651 if (save_depth > 8) {
652 for (
int y = 0; y < tmpgrayimage.
height(); y++) {
653 const uint16_t *src16bit =
reinterpret_cast<const uint16_t *
>(tmpgrayimage.
constScanLine(y));
654 uint16_t *dest16bit =
reinterpret_cast<uint16_t *
>(avif->yuvPlanes[0] + y * avif->yuvRowBytes[0]);
655 for (
int x = 0; x < tmpgrayimage.
width(); x++) {
656 int tmp_pixelval = (int)(((
float)(*src16bit) / 65535.0f) * 1023.0f + 0.5f);
657 *dest16bit = qBound(0, tmp_pixelval, 1023);
663 for (
int y = 0; y < tmpgrayimage.
height(); y++) {
665 uint8_t *dest8bit = avif->yuvPlanes[0] + y * avif->yuvRowBytes[0];
666 for (
int x = 0; x < tmpgrayimage.
width(); x++) {
667 *dest8bit = *src8bit;
675 if (save_depth > 8) {
689#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
692 if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.
format() == QImage::Format_CMYK8888) {
702 avifPixelFormat pixel_format = AVIF_PIXEL_FORMAT_YUV420;
703 if (m_quality >= KIMG_AVIF_QUALITY_HIGH) {
704 if (m_quality >= KIMG_AVIF_QUALITY_BEST) {
705 pixel_format = AVIF_PIXEL_FORMAT_YUV444;
707 pixel_format = AVIF_PIXEL_FORMAT_YUV422;
711 avifMatrixCoefficients matrix_to_save = (avifMatrixCoefficients)1;
713 avifColorPrimaries primaries_to_save = (avifColorPrimaries)2;
714 avifTransferCharacteristics transfer_to_save = (avifTransferCharacteristics)2;
719 case QColorSpace::Primaries::SRgb:
721 primaries_to_save = (avifColorPrimaries)1;
723 matrix_to_save = (avifMatrixCoefficients)1;
725 case QColorSpace::Primaries::DciP3D65:
727 primaries_to_save = (avifColorPrimaries)12;
729 matrix_to_save = (avifMatrixCoefficients)12;
733 primaries_to_save = (avifColorPrimaries)2;
735 matrix_to_save = (avifMatrixCoefficients)2;
740 case QColorSpace::TransferFunction::Linear:
742 transfer_to_save = (avifTransferCharacteristics)8;
744 case QColorSpace::TransferFunction::Gamma:
747 transfer_to_save = (avifTransferCharacteristics)4;
750 transfer_to_save = (avifTransferCharacteristics)5;
753 transfer_to_save = (avifTransferCharacteristics)2;
756 case QColorSpace::TransferFunction::SRgb:
758 transfer_to_save = (avifTransferCharacteristics)13;
762 transfer_to_save = (avifTransferCharacteristics)2;
767 if ((primaries_to_save == 2) || (transfer_to_save == 2)) {
772 if (save_depth == 8) {
781 if ((primaries_to_save == 2) && (transfer_to_save != 2)) {
782 primaries_to_save = (avifColorPrimaries)1;
783 matrix_to_save = (avifMatrixCoefficients)1;
785 switch (transfer_to_save) {
797 transfer_to_save = (avifTransferCharacteristics)13;
800 }
else if ((primaries_to_save != 2) && (transfer_to_save == 2)) {
801 transfer_to_save = (avifTransferCharacteristics)13;
804 primaries_to_save = (avifColorPrimaries)1;
805 transfer_to_save = (avifTransferCharacteristics)13;
806 matrix_to_save = (avifMatrixCoefficients)1;
813 if (iccprofile.
size() > 0) {
814 matrix_to_save = (avifMatrixCoefficients)6;
818 if (lossless && pixel_format == AVIF_PIXEL_FORMAT_YUV444) {
819 matrix_to_save = (avifMatrixCoefficients)0;
821 avif = avifImageCreate(tmpcolorimage.
width(), tmpcolorimage.
height(), save_depth, pixel_format);
822 avif->matrixCoefficients = matrix_to_save;
824 avif->colorPrimaries = primaries_to_save;
825 avif->transferCharacteristics = transfer_to_save;
827 if (iccprofile.
size() > 0) {
828#if AVIF_VERSION >= 1000000
829 res = avifImageSetProfileICC(avif,
reinterpret_cast<const uint8_t *
>(iccprofile.
constData()), iccprofile.
size());
830 if (res != AVIF_RESULT_OK) {
831 qWarning(
"ERROR in avifImageSetProfileICC: %s", avifResultToString(res));
835 avifImageSetProfileICC(avif,
reinterpret_cast<const uint8_t *
>(iccprofile.
constData()), iccprofile.
size());
840 avifRGBImageSetDefaults(&rgb, avif);
842 rgb.pixels =
const_cast<uint8_t *
>(tmpcolorimage.
constBits());
844 if (save_depth > 8) {
848 rgb.ignoreAlpha = AVIF_TRUE;
851 rgb.format = AVIF_RGB_FORMAT_RGBA;
856 rgb.format = AVIF_RGB_FORMAT_RGBA;
858 rgb.format = AVIF_RGB_FORMAT_RGB;
862 res = avifImageRGBToYUV(avif, &rgb);
863 if (res != AVIF_RESULT_OK) {
864 qWarning(
"ERROR in avifImageRGBToYUV: %s", avifResultToString(res));
869 avifRWData raw = AVIF_DATA_EMPTY;
870 avifEncoder *encoder = avifEncoderCreate();
873#if AVIF_VERSION < 1000000
874 encoder->minQuantizer = minQuantizer;
875 encoder->maxQuantizer = maxQuantizer;
878 encoder->minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
879 encoder->maxQuantizerAlpha = maxQuantizerAlpha;
882 encoder->quality = m_quality;
885 if (m_quality >= KIMG_AVIF_QUALITY_LOW) {
886 encoder->qualityAlpha = 100;
888 encoder->qualityAlpha = 100 - (KIMG_AVIF_QUALITY_LOW - m_quality) / 2;
895 res = avifEncoderWrite(encoder, avif, &raw);
896 avifEncoderDestroy(encoder);
897 avifImageDestroy(avif);
899 if (res == AVIF_RESULT_OK) {
900 qint64
status = device()->
write(
reinterpret_cast<const char *
>(raw.data), raw.size);
901 avifRWDataFree(&raw);
905 }
else if (
status == -1) {
906 qWarning(
"Write error: %s", qUtf8Printable(device()->errorString()));
910 qWarning(
"ERROR: Failed to encode: %s", avifResultToString(res));
916QVariant QAVIFHandler::option(ImageOption option)
const
918 if (option == Quality) {
922 if (!supportsOption(option) || !ensureParsed()) {
928 return m_estimated_dimensions;
930 if (imageCount() >= 2) {
940void QAVIFHandler::setOption(ImageOption option,
const QVariant &value)
944 m_quality = value.
toInt();
945 if (m_quality > 100) {
947 }
else if (m_quality < 0) {
948 m_quality = KIMG_AVIF_DEFAULT_QUALITY;
957bool QAVIFHandler::supportsOption(ImageOption option)
const
959 return option == Quality || option == Size || option ==
Animation;
962int QAVIFHandler::imageCount()
const
964 if (!ensureParsed()) {
968 if (m_decoder->imageCount >= 1) {
969 return m_decoder->imageCount;
974int QAVIFHandler::currentImageNumber()
const
976 if (m_parseState == ParseAvifNotParsed) {
980 if (m_parseState == ParseAvifError || !m_decoder) {
984 if (m_parseState == ParseAvifMetadata) {
985 if (m_decoder->imageCount >= 2) {
992 return m_decoder->imageIndex;
995bool QAVIFHandler::jumpToNextImage()
997 if (!ensureParsed()) {
1001 avifResult decodeResult;
1003 if (m_decoder->imageIndex >= 0) {
1004 if (m_decoder->imageCount < 2) {
1005 m_parseState = ParseAvifSuccess;
1009 if (m_decoder->imageIndex >= m_decoder->imageCount - 1) {
1010 decodeResult = avifDecoderReset(m_decoder);
1011 if (decodeResult != AVIF_RESULT_OK) {
1012 qWarning(
"ERROR in avifDecoderReset: %s", avifResultToString(decodeResult));
1013 m_parseState = ParseAvifError;
1019 decodeResult = avifDecoderNextImage(m_decoder);
1021 if (decodeResult != AVIF_RESULT_OK) {
1022 qWarning(
"ERROR: Failed to decode Next image in sequence: %s", avifResultToString(decodeResult));
1023 m_parseState = ParseAvifError;
1027 if ((m_container_width != m_decoder->image->width) || (m_container_height != m_decoder->image->height)) {
1028 qWarning(
"Decoded image sequence size (%dx%d) do not match first image size (%dx%d)!",
1029 m_decoder->image->width,
1030 m_decoder->image->height,
1032 m_container_height);
1034 m_parseState = ParseAvifError;
1038 if (decode_one_frame()) {
1039 m_parseState = ParseAvifSuccess;
1042 m_parseState = ParseAvifError;
1047bool QAVIFHandler::jumpToImage(
int imageNumber)
1049 if (!ensureParsed()) {
1053 if (m_decoder->imageCount < 2) {
1054 if (imageNumber == 0) {
1055 if (ensureOpened()) {
1056 m_parseState = ParseAvifSuccess;
1063 if (imageNumber < 0 || imageNumber >= m_decoder->imageCount) {
1067 if (imageNumber == m_decoder->imageIndex) {
1068 m_must_jump_to_next_image =
false;
1069 m_parseState = ParseAvifSuccess;
1073 avifResult decodeResult = avifDecoderNthImage(m_decoder, imageNumber);
1075 if (decodeResult != AVIF_RESULT_OK) {
1076 qWarning(
"ERROR: Failed to decode %d th Image in sequence: %s", imageNumber, avifResultToString(decodeResult));
1077 m_parseState = ParseAvifError;
1081 if ((m_container_width != m_decoder->image->width) || (m_container_height != m_decoder->image->height)) {
1082 qWarning(
"Decoded image sequence size (%dx%d) do not match declared container size (%dx%d)!",
1083 m_decoder->image->width,
1084 m_decoder->image->height,
1086 m_container_height);
1088 m_parseState = ParseAvifError;
1092 if (decode_one_frame()) {
1093 m_parseState = ParseAvifSuccess;
1096 m_parseState = ParseAvifError;
1101int QAVIFHandler::nextImageDelay()
const
1103 if (!ensureOpened()) {
1107 if (m_decoder->imageCount < 2) {
1111 int delay_ms = 1000.0 * m_decoder->imageTiming.duration;
1118int QAVIFHandler::loopCount()
const
1120 if (!ensureParsed()) {
1124 if (m_decoder->imageCount < 2) {
1128#if AVIF_VERSION >= 1000000
1129 if (m_decoder->repetitionCount >= 0) {
1130 return m_decoder->repetitionCount;
1137QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
1139 chrX = qBound(qreal(0.0), chrX, qreal(1.0));
1140 chrY = qBound(qreal(DBL_MIN), chrY, qreal(1.0));
1142 if ((chrX + chrY) > qreal(1.0)) {
1143 chrX = qreal(1.0) - chrY;
1151 static const bool isAvifDecoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_DECODE) !=
nullptr);
1152 static const bool isAvifEncoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE) !=
nullptr);
1154 if (format ==
"avif") {
1156 if (isAvifDecoderAvailable) {
1157 format_cap |= CanRead;
1159 if (isAvifEncoderAvailable) {
1160 format_cap |= CanWrite;
1165 if (format ==
"avifs") {
1167 if (isAvifDecoderAvailable) {
1168 format_cap |= CanRead;
1181 if (device->
isReadable() && QAVIFHandler::canRead(device) && isAvifDecoderAvailable) {
1184 if (device->
isWritable() && isAvifEncoderAvailable) {
1198#include "moc_avif_p.cpp"
Q_SCRIPTABLE CaptureState status()
QFlags< Capability > Capabilities
const char * constData() const const
bool isEmpty() const const
qsizetype size() const const
QColorSpace fromIccProfile(const QByteArray &iccProfile)
float gamma() const const
QByteArray iccProfile() const const
bool isValid() const const
Primaries primaries() const const
TransferFunction transferFunction() const const
QColorSpace withTransferFunction(TransferFunction transferFunction, float gamma) const const
qsizetype bytesPerLine() const const
QColorSpace colorSpace() const const
const uchar * constBits() const const
const uchar * constScanLine(int i) const const
void convertTo(Format format, Qt::ImageConversionFlags flags)
void convertToColorSpace(const QColorSpace &colorSpace)
QImage convertedToColorSpace(const QColorSpace &colorSpace) const const
QImage copy(const QRect &rectangle) const const
bool hasAlphaChannel() const const
bool isGrayscale() const const
bool isNull() const const
QImage mirrored(bool horizontal, bool vertical) &&
void setColorSpace(const QColorSpace &colorSpace)
void setDevice(QIODevice *device)
virtual void setOption(ImageOption option, const QVariant &value)
bool isOpen() const const
bool isReadable() const const
bool isWritable() const const
QByteArray peek(qint64 maxSize)
qint64 write(const QByteArray &data)
int toInt(bool *ok) const const