File indexing completed on 2024-04-28 15:25:39
0001 /* 0002 AV1 Image File Format (AVIF) support for QImage. 0003 0004 SPDX-FileCopyrightText: 2020 Daniel Novomesky <dnovomesky@gmail.com> 0005 0006 SPDX-License-Identifier: BSD-2-Clause 0007 */ 0008 0009 #include <QThread> 0010 #include <QtGlobal> 0011 0012 #include <QColorSpace> 0013 0014 #include "avif_p.h" 0015 #include "util_p.h" 0016 0017 #include <cfloat> 0018 0019 /* 0020 Quality range - compression/subsampling 0021 100 - lossless RGB compression 0022 < KIMG_AVIF_QUALITY_BEST, 100 ) - YUV444 color subsampling 0023 < KIMG_AVIF_QUALITY_HIGH, KIMG_AVIF_QUALITY_BEST ) - YUV422 color subsampling 0024 < 0, KIMG_AVIF_QUALITY_HIGH ) - YUV420 color subsampling 0025 < 0, KIMG_AVIF_QUALITY_LOW ) - lossy compression of alpha channel 0026 */ 0027 0028 #ifndef KIMG_AVIF_DEFAULT_QUALITY 0029 #define KIMG_AVIF_DEFAULT_QUALITY 68 0030 #endif 0031 0032 #ifndef KIMG_AVIF_QUALITY_BEST 0033 #define KIMG_AVIF_QUALITY_BEST 90 0034 #endif 0035 0036 #ifndef KIMG_AVIF_QUALITY_HIGH 0037 #define KIMG_AVIF_QUALITY_HIGH 80 0038 #endif 0039 0040 #ifndef KIMG_AVIF_QUALITY_LOW 0041 #define KIMG_AVIF_QUALITY_LOW 51 0042 #endif 0043 0044 QAVIFHandler::QAVIFHandler() 0045 : m_parseState(ParseAvifNotParsed) 0046 , m_quality(KIMG_AVIF_DEFAULT_QUALITY) 0047 , m_container_width(0) 0048 , m_container_height(0) 0049 , m_rawAvifData(AVIF_DATA_EMPTY) 0050 , m_decoder(nullptr) 0051 , m_must_jump_to_next_image(false) 0052 { 0053 } 0054 0055 QAVIFHandler::~QAVIFHandler() 0056 { 0057 if (m_decoder) { 0058 avifDecoderDestroy(m_decoder); 0059 } 0060 } 0061 0062 bool QAVIFHandler::canRead() const 0063 { 0064 if (m_parseState == ParseAvifNotParsed && !canRead(device())) { 0065 return false; 0066 } 0067 0068 if (m_parseState != ParseAvifError) { 0069 setFormat("avif"); 0070 0071 if (m_parseState == ParseAvifFinished) { 0072 return false; 0073 } 0074 0075 return true; 0076 } 0077 return false; 0078 } 0079 0080 bool QAVIFHandler::canRead(QIODevice *device) 0081 { 0082 if (!device) { 0083 return false; 0084 } 0085 QByteArray header = device->peek(144); 0086 if (header.size() < 12) { 0087 return false; 0088 } 0089 0090 avifROData input; 0091 input.data = reinterpret_cast<const uint8_t *>(header.constData()); 0092 input.size = header.size(); 0093 0094 if (avifPeekCompatibleFileType(&input)) { 0095 return true; 0096 } 0097 return false; 0098 } 0099 0100 bool QAVIFHandler::ensureParsed() const 0101 { 0102 if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifMetadata || m_parseState == ParseAvifFinished) { 0103 return true; 0104 } 0105 if (m_parseState == ParseAvifError) { 0106 return false; 0107 } 0108 0109 QAVIFHandler *that = const_cast<QAVIFHandler *>(this); 0110 0111 return that->ensureDecoder(); 0112 } 0113 0114 bool QAVIFHandler::ensureOpened() const 0115 { 0116 if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifFinished) { 0117 return true; 0118 } 0119 if (m_parseState == ParseAvifError) { 0120 return false; 0121 } 0122 0123 QAVIFHandler *that = const_cast<QAVIFHandler *>(this); 0124 if (ensureParsed()) { 0125 if (m_parseState == ParseAvifMetadata) { 0126 bool success = that->jumpToNextImage(); 0127 that->m_parseState = success ? ParseAvifSuccess : ParseAvifError; 0128 return success; 0129 } 0130 } 0131 0132 that->m_parseState = ParseAvifError; 0133 return false; 0134 } 0135 0136 bool QAVIFHandler::ensureDecoder() 0137 { 0138 if (m_decoder) { 0139 return true; 0140 } 0141 0142 m_rawData = device()->readAll(); 0143 0144 m_rawAvifData.data = reinterpret_cast<const uint8_t *>(m_rawData.constData()); 0145 m_rawAvifData.size = m_rawData.size(); 0146 0147 if (avifPeekCompatibleFileType(&m_rawAvifData) == AVIF_FALSE) { 0148 m_parseState = ParseAvifError; 0149 return false; 0150 } 0151 0152 m_decoder = avifDecoderCreate(); 0153 0154 m_decoder->ignoreExif = AVIF_TRUE; 0155 m_decoder->ignoreXMP = AVIF_TRUE; 0156 0157 #if AVIF_VERSION >= 80400 0158 m_decoder->maxThreads = qBound(1, QThread::idealThreadCount(), 64); 0159 #endif 0160 0161 #if AVIF_VERSION >= 90100 0162 m_decoder->strictFlags = AVIF_STRICT_DISABLED; 0163 #endif 0164 0165 #if AVIF_VERSION >= 110000 0166 m_decoder->imageDimensionLimit = 65535; 0167 #endif 0168 0169 avifResult decodeResult; 0170 0171 decodeResult = avifDecoderSetIOMemory(m_decoder, m_rawAvifData.data, m_rawAvifData.size); 0172 if (decodeResult != AVIF_RESULT_OK) { 0173 qWarning("ERROR: avifDecoderSetIOMemory failed: %s", avifResultToString(decodeResult)); 0174 0175 avifDecoderDestroy(m_decoder); 0176 m_decoder = nullptr; 0177 m_parseState = ParseAvifError; 0178 return false; 0179 } 0180 0181 decodeResult = avifDecoderParse(m_decoder); 0182 if (decodeResult != AVIF_RESULT_OK) { 0183 qWarning("ERROR: Failed to parse input: %s", avifResultToString(decodeResult)); 0184 0185 avifDecoderDestroy(m_decoder); 0186 m_decoder = nullptr; 0187 m_parseState = ParseAvifError; 0188 return false; 0189 } 0190 0191 m_container_width = m_decoder->image->width; 0192 m_container_height = m_decoder->image->height; 0193 0194 if ((m_container_width > 65535) || (m_container_height > 65535)) { 0195 qWarning("AVIF image (%dx%d) is too large!", m_container_width, m_container_height); 0196 m_parseState = ParseAvifError; 0197 return false; 0198 } 0199 0200 if ((m_container_width == 0) || (m_container_height == 0)) { 0201 qWarning("Empty image, nothing to decode"); 0202 m_parseState = ParseAvifError; 0203 return false; 0204 } 0205 0206 if (m_container_width > ((16384 * 16384) / m_container_height)) { 0207 qWarning("AVIF image (%dx%d) has more than 256 megapixels!", m_container_width, m_container_height); 0208 m_parseState = ParseAvifError; 0209 return false; 0210 } 0211 0212 // calculate final dimensions with crop and rotate operations applied 0213 int new_width = m_container_width; 0214 int new_height = m_container_height; 0215 0216 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_CLAP) { 0217 if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) && (m_decoder->image->clap.horizOffD > 0) 0218 && (m_decoder->image->clap.vertOffD > 0)) { 0219 int crop_width = (int)((double)(m_decoder->image->clap.widthN) / (m_decoder->image->clap.widthD) + 0.5); 0220 if (crop_width < new_width && crop_width > 0) { 0221 new_width = crop_width; 0222 } 0223 int crop_height = (int)((double)(m_decoder->image->clap.heightN) / (m_decoder->image->clap.heightD) + 0.5); 0224 if (crop_height < new_height && crop_height > 0) { 0225 new_height = crop_height; 0226 } 0227 } 0228 } 0229 0230 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IROT) { 0231 if (m_decoder->image->irot.angle == 1 || m_decoder->image->irot.angle == 3) { 0232 int tmp = new_width; 0233 new_width = new_height; 0234 new_height = tmp; 0235 } 0236 } 0237 0238 m_estimated_dimensions.setWidth(new_width); 0239 m_estimated_dimensions.setHeight(new_height); 0240 0241 m_parseState = ParseAvifMetadata; 0242 return true; 0243 } 0244 0245 bool QAVIFHandler::decode_one_frame() 0246 { 0247 if (!ensureParsed()) { 0248 return false; 0249 } 0250 0251 bool loadalpha; 0252 0253 if (m_decoder->image->alphaPlane) { 0254 loadalpha = true; 0255 } else { 0256 loadalpha = false; 0257 } 0258 0259 QImage::Format resultformat; 0260 0261 if (m_decoder->image->depth > 8) { 0262 if (loadalpha) { 0263 resultformat = QImage::Format_RGBA64; 0264 } else { 0265 resultformat = QImage::Format_RGBX64; 0266 } 0267 } else { 0268 if (loadalpha) { 0269 resultformat = QImage::Format_ARGB32; 0270 } else { 0271 resultformat = QImage::Format_RGB32; 0272 } 0273 } 0274 0275 QImage result = imageAlloc(m_decoder->image->width, m_decoder->image->height, resultformat); 0276 if (result.isNull()) { 0277 qWarning("Memory cannot be allocated"); 0278 return false; 0279 } 0280 0281 QColorSpace colorspace; 0282 if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) { 0283 const QByteArray icc_data(reinterpret_cast<const char *>(m_decoder->image->icc.data), m_decoder->image->icc.size); 0284 colorspace = QColorSpace::fromIccProfile(icc_data); 0285 if (!colorspace.isValid()) { 0286 qWarning("AVIF image has Qt-unsupported or invalid ICC profile!"); 0287 } 0288 } else { 0289 float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f}; 0290 // outPrimaries: rX, rY, gX, gY, bX, bY, wX, wY 0291 avifColorPrimariesGetValues(m_decoder->image->colorPrimaries, prim); 0292 0293 const QPointF redPoint(QAVIFHandler::CompatibleChromacity(prim[0], prim[1])); 0294 const QPointF greenPoint(QAVIFHandler::CompatibleChromacity(prim[2], prim[3])); 0295 const QPointF bluePoint(QAVIFHandler::CompatibleChromacity(prim[4], prim[5])); 0296 const QPointF whitePoint(QAVIFHandler::CompatibleChromacity(prim[6], prim[7])); 0297 0298 QColorSpace::TransferFunction q_trc = QColorSpace::TransferFunction::Custom; 0299 float q_trc_gamma = 0.0f; 0300 0301 switch (m_decoder->image->transferCharacteristics) { 0302 /* AVIF_TRANSFER_CHARACTERISTICS_BT470M */ 0303 case 4: 0304 q_trc = QColorSpace::TransferFunction::Gamma; 0305 q_trc_gamma = 2.2f; 0306 break; 0307 /* AVIF_TRANSFER_CHARACTERISTICS_BT470BG */ 0308 case 5: 0309 q_trc = QColorSpace::TransferFunction::Gamma; 0310 q_trc_gamma = 2.8f; 0311 break; 0312 /* AVIF_TRANSFER_CHARACTERISTICS_LINEAR */ 0313 case 8: 0314 q_trc = QColorSpace::TransferFunction::Linear; 0315 break; 0316 /* AVIF_TRANSFER_CHARACTERISTICS_SRGB */ 0317 case 0: 0318 case 2: /* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */ 0319 case 13: 0320 q_trc = QColorSpace::TransferFunction::SRgb; 0321 break; 0322 default: 0323 qWarning("CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.", 0324 m_decoder->image->colorPrimaries, 0325 m_decoder->image->transferCharacteristics); 0326 q_trc = QColorSpace::TransferFunction::SRgb; 0327 break; 0328 } 0329 0330 if (q_trc != QColorSpace::TransferFunction::Custom) { // we create new colorspace using Qt 0331 switch (m_decoder->image->colorPrimaries) { 0332 /* AVIF_COLOR_PRIMARIES_BT709 */ 0333 case 0: 0334 case 1: 0335 case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */ 0336 colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma); 0337 break; 0338 /* AVIF_COLOR_PRIMARIES_SMPTE432 */ 0339 case 12: 0340 colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma); 0341 break; 0342 default: 0343 colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma); 0344 break; 0345 } 0346 } 0347 0348 if (!colorspace.isValid()) { 0349 qWarning("AVIF plugin created invalid QColorSpace from NCLX/CICP!"); 0350 } 0351 } 0352 0353 result.setColorSpace(colorspace); 0354 0355 avifRGBImage rgb; 0356 avifRGBImageSetDefaults(&rgb, m_decoder->image); 0357 0358 #if AVIF_VERSION >= 1000000 0359 rgb.maxThreads = m_decoder->maxThreads; 0360 #endif 0361 0362 if (m_decoder->image->depth > 8) { 0363 rgb.depth = 16; 0364 rgb.format = AVIF_RGB_FORMAT_RGBA; 0365 0366 if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) { 0367 resultformat = QImage::Format_Grayscale16; 0368 } 0369 } else { 0370 rgb.depth = 8; 0371 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 0372 rgb.format = AVIF_RGB_FORMAT_BGRA; 0373 #else 0374 rgb.format = AVIF_RGB_FORMAT_ARGB; 0375 #endif 0376 0377 #if AVIF_VERSION >= 80400 0378 if (m_decoder->imageCount > 1) { 0379 /* accelerate animated AVIF */ 0380 rgb.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST; 0381 } 0382 #endif 0383 0384 if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) { 0385 resultformat = QImage::Format_Grayscale8; 0386 } 0387 } 0388 0389 rgb.rowBytes = result.bytesPerLine(); 0390 rgb.pixels = result.bits(); 0391 0392 avifResult res = avifImageYUVToRGB(m_decoder->image, &rgb); 0393 if (res != AVIF_RESULT_OK) { 0394 qWarning("ERROR in avifImageYUVToRGB: %s", avifResultToString(res)); 0395 return false; 0396 } 0397 0398 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_CLAP) { 0399 if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) && (m_decoder->image->clap.horizOffD > 0) 0400 && (m_decoder->image->clap.vertOffD > 0)) { 0401 int new_width = (int)((double)(m_decoder->image->clap.widthN) / (m_decoder->image->clap.widthD) + 0.5); 0402 if (new_width > result.width()) { 0403 new_width = result.width(); 0404 } 0405 0406 int new_height = (int)((double)(m_decoder->image->clap.heightN) / (m_decoder->image->clap.heightD) + 0.5); 0407 if (new_height > result.height()) { 0408 new_height = result.height(); 0409 } 0410 0411 if (new_width > 0 && new_height > 0) { 0412 int offx = 0413 ((double)((int32_t)m_decoder->image->clap.horizOffN)) / (m_decoder->image->clap.horizOffD) + (result.width() - new_width) / 2.0 + 0.5; 0414 if (offx < 0) { 0415 offx = 0; 0416 } else if (offx > (result.width() - new_width)) { 0417 offx = result.width() - new_width; 0418 } 0419 0420 int offy = 0421 ((double)((int32_t)m_decoder->image->clap.vertOffN)) / (m_decoder->image->clap.vertOffD) + (result.height() - new_height) / 2.0 + 0.5; 0422 if (offy < 0) { 0423 offy = 0; 0424 } else if (offy > (result.height() - new_height)) { 0425 offy = result.height() - new_height; 0426 } 0427 0428 result = result.copy(offx, offy, new_width, new_height); 0429 } 0430 } 0431 0432 else { // Zero values, we need to avoid 0 divide. 0433 qWarning("ERROR: Wrong values in avifCleanApertureBox"); 0434 } 0435 } 0436 0437 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IROT) { 0438 QTransform transform; 0439 switch (m_decoder->image->irot.angle) { 0440 case 1: 0441 transform.rotate(-90); 0442 result = result.transformed(transform); 0443 break; 0444 case 2: 0445 transform.rotate(180); 0446 result = result.transformed(transform); 0447 break; 0448 case 3: 0449 transform.rotate(90); 0450 result = result.transformed(transform); 0451 break; 0452 } 0453 } 0454 0455 if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IMIR) { 0456 #if AVIF_VERSION > 90100 && AVIF_VERSION < 1000000 0457 switch (m_decoder->image->imir.mode) { 0458 #else 0459 switch (m_decoder->image->imir.axis) { 0460 #endif 0461 case 0: // top-to-bottom 0462 result = result.mirrored(false, true); 0463 break; 0464 case 1: // left-to-right 0465 result = result.mirrored(true, false); 0466 break; 0467 } 0468 } 0469 0470 if (resultformat == result.format()) { 0471 m_current_image = result; 0472 } else { 0473 m_current_image = result.convertToFormat(resultformat); 0474 } 0475 0476 m_estimated_dimensions = m_current_image.size(); 0477 0478 m_must_jump_to_next_image = false; 0479 return true; 0480 } 0481 0482 bool QAVIFHandler::read(QImage *image) 0483 { 0484 if (!ensureOpened()) { 0485 return false; 0486 } 0487 0488 if (m_must_jump_to_next_image) { 0489 jumpToNextImage(); 0490 } 0491 0492 *image = m_current_image; 0493 if (imageCount() >= 2) { 0494 m_must_jump_to_next_image = true; 0495 if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { 0496 // all frames in animation have been read 0497 m_parseState = ParseAvifFinished; 0498 } 0499 } else { 0500 // the static image has been read 0501 m_parseState = ParseAvifFinished; 0502 } 0503 return true; 0504 } 0505 0506 bool QAVIFHandler::write(const QImage &image) 0507 { 0508 if (image.format() == QImage::Format_Invalid) { 0509 qWarning("No image data to save!"); 0510 return false; 0511 } 0512 0513 if ((image.width() > 0) && (image.height() > 0)) { 0514 if ((image.width() > 65535) || (image.height() > 65535)) { 0515 qWarning("Image (%dx%d) is too large to save!", image.width(), image.height()); 0516 return false; 0517 } 0518 0519 if (image.width() > ((16384 * 16384) / image.height())) { 0520 qWarning("Image (%dx%d) will not be saved because it has more than 256 megapixels!", image.width(), image.height()); 0521 return false; 0522 } 0523 0524 if ((image.width() > 32768) || (image.height() > 32768)) { 0525 qWarning("Image (%dx%d) has a dimension above 32768 pixels, saved AVIF may not work in other software!", image.width(), image.height()); 0526 } 0527 } else { 0528 qWarning("Image has zero dimension!"); 0529 return false; 0530 } 0531 0532 const char *encoder_name = avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE); 0533 if (!encoder_name) { 0534 qWarning("Cannot save AVIF images because libavif was built without AV1 encoders!"); 0535 return false; 0536 } 0537 0538 bool lossless = false; 0539 if (m_quality >= 100) { 0540 if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE)) { 0541 lossless = true; 0542 } else { 0543 qWarning("You are using %s encoder. It is recommended to enable libAOM encoder in libavif to use lossless compression.", encoder_name); 0544 } 0545 } 0546 0547 if (m_quality > 100) { 0548 m_quality = 100; 0549 } else if (m_quality < 0) { 0550 m_quality = KIMG_AVIF_DEFAULT_QUALITY; 0551 } 0552 0553 #if AVIF_VERSION < 1000000 0554 int maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY * (100 - qBound(0, m_quality, 100)) / 100; 0555 int minQuantizer = 0; 0556 int maxQuantizerAlpha = 0; 0557 #endif 0558 avifResult res; 0559 0560 bool save_grayscale; // true - monochrome, false - colors 0561 int save_depth; // 8 or 10bit per channel 0562 QImage::Format tmpformat; // format for temporary image 0563 0564 avifImage *avif = nullptr; 0565 0566 // grayscale detection 0567 switch (image.format()) { 0568 case QImage::Format_Mono: 0569 case QImage::Format_MonoLSB: 0570 case QImage::Format_Grayscale8: 0571 case QImage::Format_Grayscale16: 0572 save_grayscale = true; 0573 break; 0574 case QImage::Format_Indexed8: 0575 save_grayscale = image.isGrayscale(); 0576 break; 0577 default: 0578 save_grayscale = false; 0579 break; 0580 } 0581 0582 // depth detection 0583 switch (image.format()) { 0584 case QImage::Format_BGR30: 0585 case QImage::Format_A2BGR30_Premultiplied: 0586 case QImage::Format_RGB30: 0587 case QImage::Format_A2RGB30_Premultiplied: 0588 case QImage::Format_Grayscale16: 0589 case QImage::Format_RGBX64: 0590 case QImage::Format_RGBA64: 0591 case QImage::Format_RGBA64_Premultiplied: 0592 save_depth = 10; 0593 break; 0594 default: 0595 if (image.depth() > 32) { 0596 save_depth = 10; 0597 } else { 0598 save_depth = 8; 0599 } 0600 break; 0601 } 0602 0603 #if AVIF_VERSION < 1000000 0604 // deprecated quality settings 0605 if (maxQuantizer > 20) { 0606 minQuantizer = maxQuantizer - 20; 0607 if (maxQuantizer > 40) { // we decrease quality of alpha channel here 0608 maxQuantizerAlpha = maxQuantizer - 40; 0609 } 0610 } 0611 #endif 0612 0613 if (save_grayscale && !image.hasAlphaChannel()) { // we are going to save grayscale image without alpha channel 0614 if (save_depth > 8) { 0615 tmpformat = QImage::Format_Grayscale16; 0616 } else { 0617 tmpformat = QImage::Format_Grayscale8; 0618 } 0619 QImage tmpgrayimage = image.convertToFormat(tmpformat); 0620 0621 avif = avifImageCreate(tmpgrayimage.width(), tmpgrayimage.height(), save_depth, AVIF_PIXEL_FORMAT_YUV400); 0622 avifImageAllocatePlanes(avif, AVIF_PLANES_YUV); 0623 0624 if (tmpgrayimage.colorSpace().isValid()) { 0625 avif->colorPrimaries = (avifColorPrimaries)1; 0626 avif->matrixCoefficients = (avifMatrixCoefficients)1; 0627 0628 switch (tmpgrayimage.colorSpace().transferFunction()) { 0629 case QColorSpace::TransferFunction::Linear: 0630 /* AVIF_TRANSFER_CHARACTERISTICS_LINEAR */ 0631 avif->transferCharacteristics = (avifTransferCharacteristics)8; 0632 break; 0633 case QColorSpace::TransferFunction::SRgb: 0634 /* AVIF_TRANSFER_CHARACTERISTICS_SRGB */ 0635 avif->transferCharacteristics = (avifTransferCharacteristics)13; 0636 break; 0637 default: 0638 /* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */ 0639 break; 0640 } 0641 } 0642 0643 if (save_depth > 8) { // QImage::Format_Grayscale16 0644 for (int y = 0; y < tmpgrayimage.height(); y++) { 0645 const uint16_t *src16bit = reinterpret_cast<const uint16_t *>(tmpgrayimage.constScanLine(y)); 0646 uint16_t *dest16bit = reinterpret_cast<uint16_t *>(avif->yuvPlanes[0] + y * avif->yuvRowBytes[0]); 0647 for (int x = 0; x < tmpgrayimage.width(); x++) { 0648 int tmp_pixelval = (int)(((float)(*src16bit) / 65535.0f) * 1023.0f + 0.5f); // downgrade to 10 bits 0649 *dest16bit = qBound(0, tmp_pixelval, 1023); 0650 dest16bit++; 0651 src16bit++; 0652 } 0653 } 0654 } else { // QImage::Format_Grayscale8 0655 for (int y = 0; y < tmpgrayimage.height(); y++) { 0656 const uchar *src8bit = tmpgrayimage.constScanLine(y); 0657 uint8_t *dest8bit = avif->yuvPlanes[0] + y * avif->yuvRowBytes[0]; 0658 for (int x = 0; x < tmpgrayimage.width(); x++) { 0659 *dest8bit = *src8bit; 0660 dest8bit++; 0661 src8bit++; 0662 } 0663 } 0664 } 0665 0666 } else { // we are going to save color image 0667 if (save_depth > 8) { 0668 if (image.hasAlphaChannel()) { 0669 tmpformat = QImage::Format_RGBA64; 0670 } else { 0671 tmpformat = QImage::Format_RGBX64; 0672 } 0673 } else { // 8bit depth 0674 if (image.hasAlphaChannel()) { 0675 tmpformat = QImage::Format_RGBA8888; 0676 } else { 0677 tmpformat = QImage::Format_RGB888; 0678 } 0679 } 0680 0681 QImage tmpcolorimage = image.convertToFormat(tmpformat); 0682 0683 avifPixelFormat pixel_format = AVIF_PIXEL_FORMAT_YUV420; 0684 if (m_quality >= KIMG_AVIF_QUALITY_HIGH) { 0685 if (m_quality >= KIMG_AVIF_QUALITY_BEST) { 0686 pixel_format = AVIF_PIXEL_FORMAT_YUV444; // best quality 0687 } else { 0688 pixel_format = AVIF_PIXEL_FORMAT_YUV422; // high quality 0689 } 0690 } 0691 0692 avifMatrixCoefficients matrix_to_save = (avifMatrixCoefficients)1; // default for Qt 5.12 and 5.13; 0693 0694 avifColorPrimaries primaries_to_save = (avifColorPrimaries)2; 0695 avifTransferCharacteristics transfer_to_save = (avifTransferCharacteristics)2; 0696 QByteArray iccprofile; 0697 0698 if (tmpcolorimage.colorSpace().isValid()) { 0699 switch (tmpcolorimage.colorSpace().primaries()) { 0700 case QColorSpace::Primaries::SRgb: 0701 /* AVIF_COLOR_PRIMARIES_BT709 */ 0702 primaries_to_save = (avifColorPrimaries)1; 0703 /* AVIF_MATRIX_COEFFICIENTS_BT709 */ 0704 matrix_to_save = (avifMatrixCoefficients)1; 0705 break; 0706 case QColorSpace::Primaries::DciP3D65: 0707 /* AVIF_NCLX_COLOUR_PRIMARIES_P3, AVIF_NCLX_COLOUR_PRIMARIES_SMPTE432 */ 0708 primaries_to_save = (avifColorPrimaries)12; 0709 /* AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL */ 0710 matrix_to_save = (avifMatrixCoefficients)12; 0711 break; 0712 default: 0713 /* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */ 0714 primaries_to_save = (avifColorPrimaries)2; 0715 /* AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED */ 0716 matrix_to_save = (avifMatrixCoefficients)2; 0717 break; 0718 } 0719 0720 switch (tmpcolorimage.colorSpace().transferFunction()) { 0721 case QColorSpace::TransferFunction::Linear: 0722 /* AVIF_TRANSFER_CHARACTERISTICS_LINEAR */ 0723 transfer_to_save = (avifTransferCharacteristics)8; 0724 break; 0725 case QColorSpace::TransferFunction::Gamma: 0726 if (qAbs(tmpcolorimage.colorSpace().gamma() - 2.2f) < 0.1f) { 0727 /* AVIF_TRANSFER_CHARACTERISTICS_BT470M */ 0728 transfer_to_save = (avifTransferCharacteristics)4; 0729 } else if (qAbs(tmpcolorimage.colorSpace().gamma() - 2.8f) < 0.1f) { 0730 /* AVIF_TRANSFER_CHARACTERISTICS_BT470BG */ 0731 transfer_to_save = (avifTransferCharacteristics)5; 0732 } else { 0733 /* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */ 0734 transfer_to_save = (avifTransferCharacteristics)2; 0735 } 0736 break; 0737 case QColorSpace::TransferFunction::SRgb: 0738 /* AVIF_TRANSFER_CHARACTERISTICS_SRGB */ 0739 transfer_to_save = (avifTransferCharacteristics)13; 0740 break; 0741 default: 0742 /* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */ 0743 transfer_to_save = (avifTransferCharacteristics)2; 0744 break; 0745 } 0746 0747 // in case primaries or trc were not identified 0748 if ((primaries_to_save == 2) || (transfer_to_save == 2)) { 0749 if (lossless) { 0750 iccprofile = tmpcolorimage.colorSpace().iccProfile(); 0751 } else { 0752 // upgrade image to higher bit depth 0753 if (save_depth == 8) { 0754 save_depth = 10; 0755 if (tmpcolorimage.hasAlphaChannel()) { 0756 tmpcolorimage.convertTo(QImage::Format_RGBA64); 0757 } else { 0758 tmpcolorimage.convertTo(QImage::Format_RGBX64); 0759 } 0760 } 0761 0762 if ((primaries_to_save == 2) && (transfer_to_save != 2)) { // other primaries but known trc 0763 primaries_to_save = (avifColorPrimaries)1; // AVIF_COLOR_PRIMARIES_BT709 0764 matrix_to_save = (avifMatrixCoefficients)1; // AVIF_MATRIX_COEFFICIENTS_BT709 0765 0766 switch (transfer_to_save) { 0767 case 8: // AVIF_TRANSFER_CHARACTERISTICS_LINEAR 0768 tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::Linear)); 0769 break; 0770 case 4: // AVIF_TRANSFER_CHARACTERISTICS_BT470M 0771 tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.2f)); 0772 break; 0773 case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG 0774 tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.8f)); 0775 break; 0776 default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other 0777 tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb)); 0778 transfer_to_save = (avifTransferCharacteristics)13; 0779 break; 0780 } 0781 } else if ((primaries_to_save != 2) && (transfer_to_save == 2)) { // recognized primaries but other trc 0782 transfer_to_save = (avifTransferCharacteristics)13; 0783 tmpcolorimage.convertToColorSpace(tmpcolorimage.colorSpace().withTransferFunction(QColorSpace::TransferFunction::SRgb)); 0784 } else { // unrecognized profile 0785 primaries_to_save = (avifColorPrimaries)1; // AVIF_COLOR_PRIMARIES_BT709 0786 transfer_to_save = (avifTransferCharacteristics)13; 0787 matrix_to_save = (avifMatrixCoefficients)1; // AVIF_MATRIX_COEFFICIENTS_BT709 0788 tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb)); 0789 } 0790 } 0791 } 0792 } else { // profile is unsupported by Qt 0793 iccprofile = tmpcolorimage.colorSpace().iccProfile(); 0794 if (iccprofile.size() > 0) { 0795 matrix_to_save = (avifMatrixCoefficients)6; 0796 } 0797 } 0798 0799 if (lossless && pixel_format == AVIF_PIXEL_FORMAT_YUV444) { 0800 matrix_to_save = (avifMatrixCoefficients)0; 0801 } 0802 avif = avifImageCreate(tmpcolorimage.width(), tmpcolorimage.height(), save_depth, pixel_format); 0803 avif->matrixCoefficients = matrix_to_save; 0804 0805 avif->colorPrimaries = primaries_to_save; 0806 avif->transferCharacteristics = transfer_to_save; 0807 0808 if (iccprofile.size() > 0) { 0809 avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size()); 0810 } 0811 0812 avifRGBImage rgb; 0813 avifRGBImageSetDefaults(&rgb, avif); 0814 rgb.rowBytes = tmpcolorimage.bytesPerLine(); 0815 rgb.pixels = const_cast<uint8_t *>(tmpcolorimage.constBits()); 0816 0817 if (save_depth > 8) { // 10bit depth 0818 rgb.depth = 16; 0819 0820 if (!tmpcolorimage.hasAlphaChannel()) { 0821 rgb.ignoreAlpha = AVIF_TRUE; 0822 } 0823 0824 rgb.format = AVIF_RGB_FORMAT_RGBA; 0825 } else { // 8bit depth 0826 rgb.depth = 8; 0827 0828 if (tmpcolorimage.hasAlphaChannel()) { 0829 rgb.format = AVIF_RGB_FORMAT_RGBA; 0830 } else { 0831 rgb.format = AVIF_RGB_FORMAT_RGB; 0832 } 0833 } 0834 0835 res = avifImageRGBToYUV(avif, &rgb); 0836 if (res != AVIF_RESULT_OK) { 0837 qWarning("ERROR in avifImageRGBToYUV: %s", avifResultToString(res)); 0838 return false; 0839 } 0840 } 0841 0842 avifRWData raw = AVIF_DATA_EMPTY; 0843 avifEncoder *encoder = avifEncoderCreate(); 0844 encoder->maxThreads = qBound(1, QThread::idealThreadCount(), 64); 0845 0846 #if AVIF_VERSION < 1000000 0847 encoder->minQuantizer = minQuantizer; 0848 encoder->maxQuantizer = maxQuantizer; 0849 0850 if (image.hasAlphaChannel()) { 0851 encoder->minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS; 0852 encoder->maxQuantizerAlpha = maxQuantizerAlpha; 0853 } 0854 #else 0855 encoder->quality = m_quality; 0856 0857 if (image.hasAlphaChannel()) { 0858 if (m_quality >= KIMG_AVIF_QUALITY_LOW) { 0859 encoder->qualityAlpha = 100; 0860 } else { 0861 encoder->qualityAlpha = 100 - (KIMG_AVIF_QUALITY_LOW - m_quality) / 2; 0862 } 0863 } 0864 #endif 0865 0866 encoder->speed = 6; 0867 0868 res = avifEncoderWrite(encoder, avif, &raw); 0869 avifEncoderDestroy(encoder); 0870 avifImageDestroy(avif); 0871 0872 if (res == AVIF_RESULT_OK) { 0873 qint64 status = device()->write(reinterpret_cast<const char *>(raw.data), raw.size); 0874 avifRWDataFree(&raw); 0875 0876 if (status > 0) { 0877 return true; 0878 } else if (status == -1) { 0879 qWarning("Write error: %s", qUtf8Printable(device()->errorString())); 0880 return false; 0881 } 0882 } else { 0883 qWarning("ERROR: Failed to encode: %s", avifResultToString(res)); 0884 } 0885 0886 return false; 0887 } 0888 0889 QVariant QAVIFHandler::option(ImageOption option) const 0890 { 0891 if (option == Quality) { 0892 return m_quality; 0893 } 0894 0895 if (!supportsOption(option) || !ensureParsed()) { 0896 return QVariant(); 0897 } 0898 0899 switch (option) { 0900 case Size: 0901 return m_estimated_dimensions; 0902 case Animation: 0903 if (imageCount() >= 2) { 0904 return true; 0905 } else { 0906 return false; 0907 } 0908 default: 0909 return QVariant(); 0910 } 0911 } 0912 0913 void QAVIFHandler::setOption(ImageOption option, const QVariant &value) 0914 { 0915 switch (option) { 0916 case Quality: 0917 m_quality = value.toInt(); 0918 if (m_quality > 100) { 0919 m_quality = 100; 0920 } else if (m_quality < 0) { 0921 m_quality = KIMG_AVIF_DEFAULT_QUALITY; 0922 } 0923 return; 0924 default: 0925 break; 0926 } 0927 QImageIOHandler::setOption(option, value); 0928 } 0929 0930 bool QAVIFHandler::supportsOption(ImageOption option) const 0931 { 0932 return option == Quality || option == Size || option == Animation; 0933 } 0934 0935 int QAVIFHandler::imageCount() const 0936 { 0937 if (!ensureParsed()) { 0938 return 0; 0939 } 0940 0941 if (m_decoder->imageCount >= 1) { 0942 return m_decoder->imageCount; 0943 } 0944 return 0; 0945 } 0946 0947 int QAVIFHandler::currentImageNumber() const 0948 { 0949 if (m_parseState == ParseAvifNotParsed) { 0950 return -1; 0951 } 0952 0953 if (m_parseState == ParseAvifError || !m_decoder) { 0954 return 0; 0955 } 0956 0957 if (m_parseState == ParseAvifMetadata) { 0958 if (m_decoder->imageCount >= 2) { 0959 return -1; 0960 } else { 0961 return 0; 0962 } 0963 } 0964 0965 return m_decoder->imageIndex; 0966 } 0967 0968 bool QAVIFHandler::jumpToNextImage() 0969 { 0970 if (!ensureParsed()) { 0971 return false; 0972 } 0973 0974 if (m_decoder->imageIndex >= 0) { 0975 if (m_decoder->imageCount < 2) { 0976 m_parseState = ParseAvifSuccess; 0977 return true; 0978 } 0979 0980 if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning 0981 avifDecoderReset(m_decoder); 0982 } 0983 } 0984 0985 avifResult decodeResult = avifDecoderNextImage(m_decoder); 0986 0987 if (decodeResult != AVIF_RESULT_OK) { 0988 qWarning("ERROR: Failed to decode Next image in sequence: %s", avifResultToString(decodeResult)); 0989 m_parseState = ParseAvifError; 0990 return false; 0991 } 0992 0993 if ((m_container_width != m_decoder->image->width) || (m_container_height != m_decoder->image->height)) { 0994 qWarning("Decoded image sequence size (%dx%d) do not match first image size (%dx%d)!", 0995 m_decoder->image->width, 0996 m_decoder->image->height, 0997 m_container_width, 0998 m_container_height); 0999 1000 m_parseState = ParseAvifError; 1001 return false; 1002 } 1003 1004 if (decode_one_frame()) { 1005 m_parseState = ParseAvifSuccess; 1006 return true; 1007 } else { 1008 m_parseState = ParseAvifError; 1009 return false; 1010 } 1011 } 1012 1013 bool QAVIFHandler::jumpToImage(int imageNumber) 1014 { 1015 if (!ensureParsed()) { 1016 return false; 1017 } 1018 1019 if (m_decoder->imageCount < 2) { // not an animation 1020 if (imageNumber == 0) { 1021 if (ensureOpened()) { 1022 m_parseState = ParseAvifSuccess; 1023 return true; 1024 } 1025 } 1026 return false; 1027 } 1028 1029 if (imageNumber < 0 || imageNumber >= m_decoder->imageCount) { // wrong index 1030 return false; 1031 } 1032 1033 if (imageNumber == m_decoder->imageIndex) { // we are here already 1034 m_must_jump_to_next_image = false; 1035 m_parseState = ParseAvifSuccess; 1036 return true; 1037 } 1038 1039 avifResult decodeResult = avifDecoderNthImage(m_decoder, imageNumber); 1040 1041 if (decodeResult != AVIF_RESULT_OK) { 1042 qWarning("ERROR: Failed to decode %d th Image in sequence: %s", imageNumber, avifResultToString(decodeResult)); 1043 m_parseState = ParseAvifError; 1044 return false; 1045 } 1046 1047 if ((m_container_width != m_decoder->image->width) || (m_container_height != m_decoder->image->height)) { 1048 qWarning("Decoded image sequence size (%dx%d) do not match declared container size (%dx%d)!", 1049 m_decoder->image->width, 1050 m_decoder->image->height, 1051 m_container_width, 1052 m_container_height); 1053 1054 m_parseState = ParseAvifError; 1055 return false; 1056 } 1057 1058 if (decode_one_frame()) { 1059 m_parseState = ParseAvifSuccess; 1060 return true; 1061 } else { 1062 m_parseState = ParseAvifError; 1063 return false; 1064 } 1065 } 1066 1067 int QAVIFHandler::nextImageDelay() const 1068 { 1069 if (!ensureOpened()) { 1070 return 0; 1071 } 1072 1073 if (m_decoder->imageCount < 2) { 1074 return 0; 1075 } 1076 1077 int delay_ms = 1000.0 * m_decoder->imageTiming.duration; 1078 if (delay_ms < 1) { 1079 delay_ms = 1; 1080 } 1081 return delay_ms; 1082 } 1083 1084 int QAVIFHandler::loopCount() const 1085 { 1086 if (!ensureParsed()) { 1087 return 0; 1088 } 1089 1090 if (m_decoder->imageCount < 2) { 1091 return 0; 1092 } 1093 1094 #if AVIF_VERSION >= 1000000 1095 if (m_decoder->repetitionCount >= 0) { 1096 return m_decoder->repetitionCount; 1097 } 1098 #endif 1099 // Endless loop to work around https://github.com/AOMediaCodec/libavif/issues/347 1100 return -1; 1101 } 1102 1103 QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY) 1104 { 1105 chrX = qBound(qreal(0.0), chrX, qreal(1.0)); 1106 chrY = qBound(qreal(DBL_MIN), chrY, qreal(1.0)); 1107 1108 if ((chrX + chrY) > qreal(1.0)) { 1109 chrX = qreal(1.0) - chrY; 1110 } 1111 1112 return QPointF(chrX, chrY); 1113 } 1114 1115 QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const 1116 { 1117 static const bool isAvifDecoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_DECODE) != nullptr); 1118 static const bool isAvifEncoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE) != nullptr); 1119 1120 if (format == "avif") { 1121 Capabilities format_cap; 1122 if (isAvifDecoderAvailable) { 1123 format_cap |= CanRead; 1124 } 1125 if (isAvifEncoderAvailable) { 1126 format_cap |= CanWrite; 1127 } 1128 return format_cap; 1129 } 1130 1131 if (format == "avifs") { 1132 Capabilities format_cap; 1133 if (isAvifDecoderAvailable) { 1134 format_cap |= CanRead; 1135 } 1136 return format_cap; 1137 } 1138 1139 if (!format.isEmpty()) { 1140 return {}; 1141 } 1142 if (!device->isOpen()) { 1143 return {}; 1144 } 1145 1146 Capabilities cap; 1147 if (device->isReadable() && QAVIFHandler::canRead(device) && isAvifDecoderAvailable) { 1148 cap |= CanRead; 1149 } 1150 if (device->isWritable() && isAvifEncoderAvailable) { 1151 cap |= CanWrite; 1152 } 1153 return cap; 1154 } 1155 1156 QImageIOHandler *QAVIFPlugin::create(QIODevice *device, const QByteArray &format) const 1157 { 1158 QImageIOHandler *handler = new QAVIFHandler; 1159 handler->setDevice(device); 1160 handler->setFormat(format); 1161 return handler; 1162 } 1163 1164 #include "moc_avif_p.cpp"