12#include <libheif/heif.h>
21size_t HEIFHandler::m_initialized_count = 0;
22bool HEIFHandler::m_plugins_queried =
false;
23bool HEIFHandler::m_heif_decoder_available =
false;
24bool HEIFHandler::m_heif_encoder_available =
false;
25bool HEIFHandler::m_hej2_decoder_available =
false;
26bool HEIFHandler::m_avci_decoder_available =
false;
29static struct heif_error heifhandler_write_callback(struct heif_context * ,
const void *data,
size_t size,
void *userdata)
32 error.code = heif_error_Ok;
33 error.subcode = heif_suberror_Unspecified;
34 error.message =
"Success";
36 if (!userdata || !data || size == 0) {
37 error.code = heif_error_Usage_error;
38 error.subcode = heif_suberror_Null_pointer_argument;
39 error.message =
"Wrong parameters!";
44 qint64 bytesWritten = ioDevice->
write(
static_cast<const char *
>(data), size);
46 if (bytesWritten <
static_cast<qint64
>(size)) {
47 error.code = heif_error_Encoding_error;
48 error.message =
"Bytes written to QIODevice are smaller than input data size";
49 error.subcode = heif_suberror_Cannot_write_output_data;
56HEIFHandler::HEIFHandler()
57 : m_parseState(ParseHeicNotParsed)
62bool HEIFHandler::canRead()
const
64 if (m_parseState == ParseHeicNotParsed) {
69 if (HEIFHandler::isSupportedBMFFType(header)) {
74 if (HEIFHandler::isSupportedHEJ2(header)) {
79 if (HEIFHandler::isSupportedAVCI(header)) {
87 if (m_parseState != ParseHeicError) {
93bool HEIFHandler::read(
QImage *outImage)
95 if (!ensureParsed()) {
99 *outImage = m_current_image;
103bool HEIFHandler::write(
const QImage &image)
106 qWarning(
"No image data to save");
110#if LIBHEIF_HAVE_VERSION(1, 13, 0)
114 bool success = write_helper(image);
116#if LIBHEIF_HAVE_VERSION(1, 13, 0)
123bool HEIFHandler::write_helper(
const QImage &image)
141 if (image.
depth() > 32) {
150 if (save_depth > 8) {
161 chroma = heif_chroma_interleaved_RGBA;
164 chroma = heif_chroma_interleaved_RGB;
168#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
171 if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.
format() == QImage::Format_CMYK8888) {
173 }
else if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Gray
176 float gamma_new = cs.gamma();
177 if (trc_new == QColorSpace::TransferFunction::Custom) {
178 trc_new = QColorSpace::TransferFunction::SRgb;
188 struct heif_context *context = heif_context_alloc();
189 struct heif_error err;
190 struct heif_image *h_image =
nullptr;
192 err = heif_image_create(tmpimage.
width(), tmpimage.
height(), heif_colorspace_RGB, chroma, &h_image);
194 qWarning() <<
"heif_image_create error:" << err.message;
195 heif_context_free(context);
200 if (iccprofile.
size() > 0) {
201 heif_image_set_raw_color_profile(h_image,
"prof", iccprofile.
constData(), iccprofile.
size());
204 heif_image_add_plane(h_image, heif_channel_interleaved, image.
width(), image.
height(), save_depth);
206 uint8_t *
const dst = heif_image_get_plane(h_image, heif_channel_interleaved, &stride);
209 switch (save_depth) {
212 for (
int y = 0; y < tmpimage.
height(); y++) {
213 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(tmpimage.
constScanLine(y));
214 uint16_t *dest_word =
reinterpret_cast<uint16_t *
>(dst + (y * stride));
215 for (
int x = 0; x < tmpimage.
width(); x++) {
218 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
219 *dest_word = qBound(0, tmp_pixelval, 1023);
223 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
224 *dest_word = qBound(0, tmp_pixelval, 1023);
228 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
229 *dest_word = qBound(0, tmp_pixelval, 1023);
233 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
234 *dest_word = qBound(0, tmp_pixelval, 1023);
240 for (
int y = 0; y < tmpimage.
height(); y++) {
241 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(tmpimage.
constScanLine(y));
242 uint16_t *dest_word =
reinterpret_cast<uint16_t *
>(dst + (y * stride));
243 for (
int x = 0; x < tmpimage.
width(); x++) {
246 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
247 *dest_word = qBound(0, tmp_pixelval, 1023);
251 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
252 *dest_word = qBound(0, tmp_pixelval, 1023);
256 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
257 *dest_word = qBound(0, tmp_pixelval, 1023);
267 rowbytes = save_alpha ? (tmpimage.
width() * 4) : (tmpimage.width() * 3);
268 for (
int y = 0; y < tmpimage.
height(); y++) {
269 memcpy(dst + (y * stride), tmpimage.
constScanLine(y), rowbytes);
273 qWarning() <<
"Unsupported depth:" << save_depth;
274 heif_image_release(h_image);
275 heif_context_free(context);
280 struct heif_encoder *encoder =
nullptr;
281 err = heif_context_get_encoder_for_format(context, heif_compression_HEVC, &encoder);
283 qWarning() <<
"Unable to get an encoder instance:" << err.message;
284 heif_image_release(h_image);
285 heif_context_free(context);
289 heif_encoder_set_lossy_quality(encoder, m_quality);
290 if (m_quality > 90) {
291 if (m_quality == 100) {
292 heif_encoder_set_lossless(encoder,
true);
294 heif_encoder_set_parameter_string(encoder,
"chroma",
"444");
297 struct heif_encoding_options *encoder_options = heif_encoding_options_alloc();
298 encoder_options->save_alpha_channel = save_alpha;
300 if ((tmpimage.
width() % 2 == 1) || (tmpimage.
height() % 2 == 1)) {
301 qWarning() <<
"Image has odd dimension!\nUse even-numbered dimension(s) for better compatibility with other HEIF implementations.";
304 encoder_options->macOS_compatibility_workaround = 0;
308 err = heif_context_encode_image(context, h_image, encoder, encoder_options,
nullptr);
310 if (encoder_options) {
311 heif_encoding_options_free(encoder_options);
315 qWarning() <<
"heif_context_encode_image failed:" << err.message;
316 heif_encoder_release(encoder);
317 heif_image_release(h_image);
318 heif_context_free(context);
322 struct heif_writer writer;
323 writer.writer_api_version = 1;
324 writer.write = heifhandler_write_callback;
326 err = heif_context_write(context, &writer, device());
328 heif_encoder_release(encoder);
329 heif_image_release(h_image);
332 qWarning() <<
"Writing HEIF image failed:" << err.message;
333 heif_context_free(context);
337 heif_context_free(context);
341bool HEIFHandler::isSupportedBMFFType(
const QByteArray &header)
343 if (header.
size() < 28) {
348 if (qstrncmp(buffer + 4,
"ftyp", 4) == 0) {
349 if (qstrncmp(buffer + 8,
"heic", 4) == 0) {
352 if (qstrncmp(buffer + 8,
"heis", 4) == 0) {
355 if (qstrncmp(buffer + 8,
"heix", 4) == 0) {
360 if (qstrncmp(buffer + 8,
"mif1", 4) == 0) {
361 for (
int offset = 16; offset <= 24; offset += 4) {
362 if (qstrncmp(buffer + offset,
"avif", 4) == 0) {
369 if (qstrncmp(buffer + 8,
"mif2", 4) == 0) {
372 if (qstrncmp(buffer + 8,
"msf1", 4) == 0) {
380bool HEIFHandler::isSupportedHEJ2(
const QByteArray &header)
382 if (header.
size() < 28) {
387 if (qstrncmp(buffer + 4,
"ftyp", 4) == 0) {
388 if (qstrncmp(buffer + 8,
"j2ki", 4) == 0) {
396bool HEIFHandler::isSupportedAVCI(
const QByteArray &header)
398 if (header.
size() < 28) {
403 if (qstrncmp(buffer + 4,
"ftyp", 4) == 0) {
404 if (qstrncmp(buffer + 8,
"avci", 4) == 0) {
412QVariant HEIFHandler::option(ImageOption option)
const
414 if (option == Quality) {
418 if (!supportsOption(option) || !ensureParsed()) {
424 return m_current_image.size();
432void HEIFHandler::setOption(ImageOption option,
const QVariant &value)
436 m_quality = value.
toInt();
437 if (m_quality > 100) {
439 }
else if (m_quality < 0) {
449bool HEIFHandler::supportsOption(ImageOption option)
const
451 return option == Quality || option == Size;
454bool HEIFHandler::ensureParsed()
const
456 if (m_parseState == ParseHeicSuccess) {
459 if (m_parseState == ParseHeicError) {
463 HEIFHandler *that =
const_cast<HEIFHandler *
>(
this);
465#if LIBHEIF_HAVE_VERSION(1, 13, 0)
469 bool success = that->ensureDecoder();
471#if LIBHEIF_HAVE_VERSION(1, 13, 0)
477bool HEIFHandler::ensureDecoder()
479 if (m_parseState != ParseHeicNotParsed) {
480 if (m_parseState == ParseHeicSuccess) {
486 const QByteArray buffer = device()->readAll();
487 if (!HEIFHandler::isSupportedBMFFType(buffer) && !HEIFHandler::isSupportedHEJ2(buffer) && !HEIFHandler::isSupportedAVCI(buffer)) {
488 m_parseState = ParseHeicError;
492 struct heif_context *ctx = heif_context_alloc();
493 struct heif_error err = heif_context_read_from_memory(ctx,
static_cast<const void *
>(buffer.
constData()), buffer.
size(),
nullptr);
496 qWarning() <<
"heif_context_read_from_memory error:" << err.message;
497 heif_context_free(ctx);
498 m_parseState = ParseHeicError;
502 struct heif_image_handle *handle =
nullptr;
503 err = heif_context_get_primary_image_handle(ctx, &handle);
505 qWarning() <<
"heif_context_get_primary_image_handle error:" << err.message;
506 heif_context_free(ctx);
507 m_parseState = ParseHeicError;
511 if ((heif_image_handle_get_width(handle) == 0) || (heif_image_handle_get_height(handle) == 0)) {
512 m_parseState = ParseHeicError;
513 heif_image_handle_release(handle);
514 heif_context_free(ctx);
515 qWarning() <<
"HEIC image has zero dimension";
519 const int bit_depth = heif_image_handle_get_luma_bits_per_pixel(handle);
522 m_parseState = ParseHeicError;
523 heif_image_handle_release(handle);
524 heif_context_free(ctx);
525 qWarning() <<
"HEIF image with undefined or unsupported bit depth.";
529 const bool hasAlphaChannel = heif_image_handle_has_alpha_channel(handle);
534 if (bit_depth == 10 || bit_depth == 12) {
535 if (hasAlphaChannel) {
542 }
else if (bit_depth == 8) {
543 if (hasAlphaChannel) {
544 chroma = heif_chroma_interleaved_RGBA;
547 chroma = heif_chroma_interleaved_RGB;
551 m_parseState = ParseHeicError;
552 heif_image_handle_release(handle);
553 heif_context_free(ctx);
554 qWarning() <<
"Unsupported bit depth:" << bit_depth;
558 struct heif_decoding_options *decoder_option = heif_decoding_options_alloc();
560#if LIBHEIF_HAVE_VERSION(1, 13, 0)
561 decoder_option->strict_decoding = 1;
564 struct heif_image *img =
nullptr;
565 err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option);
567#if LIBHEIF_HAVE_VERSION(1, 13, 0)
568 if (err.code == heif_error_Invalid_input && err.subcode == heif_suberror_Unknown_NCLX_matrix_coefficients && img ==
nullptr && buffer.
contains(
"Xiaomi")) {
569 qWarning() <<
"Non-standard HEIF image with invalid matrix_coefficients, probably made by a Xiaomi device!";
572 decoder_option->strict_decoding = 0;
573 err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option);
577 if (decoder_option) {
578 heif_decoding_options_free(decoder_option);
582 qWarning() <<
"heif_decode_image error:" << err.message;
583 heif_image_handle_release(handle);
584 heif_context_free(ctx);
585 m_parseState = ParseHeicError;
589 const int imageWidth = heif_image_get_width(img, heif_channel_interleaved);
590 const int imageHeight = heif_image_get_height(img, heif_channel_interleaved);
592 QSize imageSize(imageWidth, imageHeight);
594 if (!imageSize.isValid()) {
595 heif_image_release(img);
596 heif_image_handle_release(handle);
597 heif_context_free(ctx);
598 m_parseState = ParseHeicError;
599 qWarning() <<
"HEIC image size invalid:" << imageSize;
604 const uint8_t *
const src = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);
606 if (!src || stride <= 0) {
607 heif_image_release(img);
608 heif_image_handle_release(handle);
609 heif_context_free(ctx);
610 m_parseState = ParseHeicError;
611 qWarning() <<
"HEIC data pixels information not valid!";
615 m_current_image = imageAlloc(imageSize, target_image_format);
616 if (m_current_image.isNull()) {
617 heif_image_release(img);
618 heif_image_handle_release(handle);
619 heif_context_free(ctx);
620 m_parseState = ParseHeicError;
621 qWarning() <<
"Unable to allocate memory!";
627 if (hasAlphaChannel) {
628 for (
int y = 0; y < imageHeight; y++) {
629 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
630 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
631 for (
int x = 0; x < imageWidth; x++) {
634 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
635 tmpvalue = qBound(0, tmpvalue, 65535);
636 *dest_data = (uint16_t)tmpvalue;
640 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
641 tmpvalue = qBound(0, tmpvalue, 65535);
642 *dest_data = (uint16_t)tmpvalue;
646 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
647 tmpvalue = qBound(0, tmpvalue, 65535);
648 *dest_data = (uint16_t)tmpvalue;
652 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
653 tmpvalue = qBound(0, tmpvalue, 65535);
654 *dest_data = (uint16_t)tmpvalue;
660 for (
int y = 0; y < imageHeight; y++) {
661 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
662 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
663 for (
int x = 0; x < imageWidth; x++) {
666 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
667 tmpvalue = qBound(0, tmpvalue, 65535);
668 *dest_data = (uint16_t)tmpvalue;
672 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
673 tmpvalue = qBound(0, tmpvalue, 65535);
674 *dest_data = (uint16_t)tmpvalue;
678 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
679 tmpvalue = qBound(0, tmpvalue, 65535);
680 *dest_data = (uint16_t)tmpvalue;
691 if (hasAlphaChannel) {
692 for (
int y = 0; y < imageHeight; y++) {
693 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
694 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
695 for (
int x = 0; x < imageWidth; x++) {
698 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
699 tmpvalue = qBound(0, tmpvalue, 65535);
700 *dest_data = (uint16_t)tmpvalue;
704 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
705 tmpvalue = qBound(0, tmpvalue, 65535);
706 *dest_data = (uint16_t)tmpvalue;
710 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
711 tmpvalue = qBound(0, tmpvalue, 65535);
712 *dest_data = (uint16_t)tmpvalue;
716 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
717 tmpvalue = qBound(0, tmpvalue, 65535);
718 *dest_data = (uint16_t)tmpvalue;
724 for (
int y = 0; y < imageHeight; y++) {
725 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
726 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
727 for (
int x = 0; x < imageWidth; x++) {
730 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
731 tmpvalue = qBound(0, tmpvalue, 65535);
732 *dest_data = (uint16_t)tmpvalue;
736 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
737 tmpvalue = qBound(0, tmpvalue, 65535);
738 *dest_data = (uint16_t)tmpvalue;
742 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
743 tmpvalue = qBound(0, tmpvalue, 65535);
744 *dest_data = (uint16_t)tmpvalue;
755 if (hasAlphaChannel) {
756 for (
int y = 0; y < imageHeight; y++) {
757 const uint8_t *src_byte = src + (y * stride);
758 uint32_t *dest_pixel =
reinterpret_cast<uint32_t *
>(m_current_image.scanLine(y));
759 for (
int x = 0; x < imageWidth; x++) {
760 int red = *src_byte++;
761 int green = *src_byte++;
762 int blue = *src_byte++;
763 int alpha = *src_byte++;
764 *dest_pixel = qRgba(red, green, blue, alpha);
769 for (
int y = 0; y < imageHeight; y++) {
770 const uint8_t *src_byte = src + (y * stride);
771 uint32_t *dest_pixel =
reinterpret_cast<uint32_t *
>(m_current_image.scanLine(y));
772 for (
int x = 0; x < imageWidth; x++) {
773 int red = *src_byte++;
774 int green = *src_byte++;
775 int blue = *src_byte++;
776 *dest_pixel = qRgb(red, green, blue);
783 heif_image_release(img);
784 heif_image_handle_release(handle);
785 heif_context_free(ctx);
786 m_parseState = ParseHeicError;
787 qWarning() <<
"Unsupported bit depth:" << bit_depth;
792 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle);
793 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
794 size_t rawProfileSize = heif_image_handle_get_raw_color_profile_size(handle);
795 if (rawProfileSize > 0 && rawProfileSize < std::numeric_limits<int>::max()) {
797 err = heif_image_handle_get_raw_color_profile(handle, ba.data());
799 qWarning() <<
"icc profile loading failed";
802 if (!m_current_image.colorSpace().isValid()) {
803 qWarning() <<
"HEIC image has Qt-unsupported or invalid ICC profile!";
807 qWarning() <<
"icc profile is empty or above limits";
810 }
else if (profileType == heif_color_profile_type_nclx) {
811 struct heif_color_profile_nclx *nclx =
nullptr;
812 err = heif_image_handle_get_nclx_color_profile(handle, &nclx);
813 if (err.code || !nclx) {
814 qWarning() <<
"nclx profile loading failed";
816 const QPointF redPoint(nclx->color_primary_red_x, nclx->color_primary_red_y);
817 const QPointF greenPoint(nclx->color_primary_green_x, nclx->color_primary_green_y);
818 const QPointF bluePoint(nclx->color_primary_blue_x, nclx->color_primary_blue_y);
819 const QPointF whitePoint(nclx->color_primary_white_x, nclx->color_primary_white_y);
822 float q_trc_gamma = 0.0f;
824 switch (nclx->transfer_characteristics) {
826 q_trc = QColorSpace::TransferFunction::Gamma;
830 q_trc = QColorSpace::TransferFunction::Gamma;
834 q_trc = QColorSpace::TransferFunction::Linear;
838 q_trc = QColorSpace::TransferFunction::SRgb;
840#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
842 q_trc = QColorSpace::TransferFunction::St2084;
845 q_trc = QColorSpace::TransferFunction::Hlg;
849 qWarning(
"CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
850 nclx->color_primaries,
851 nclx->transfer_characteristics);
852 q_trc = QColorSpace::TransferFunction::SRgb;
856 if (q_trc != QColorSpace::TransferFunction::Custom) {
857 switch (nclx->color_primaries) {
860 m_current_image.setColorSpace(
QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma));
863 m_current_image.setColorSpace(
QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma));
866 m_current_image.setColorSpace(
QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma));
870 heif_nclx_color_profile_free(nclx);
872 if (!m_current_image.colorSpace().isValid()) {
873 qWarning() <<
"HEIC plugin created invalid QColorSpace from NCLX!";
881 heif_image_release(img);
882 heif_image_handle_release(handle);
883 heif_context_free(ctx);
884 m_parseState = ParseHeicSuccess;
888bool HEIFHandler::isHeifDecoderAvailable()
890 HEIFHandler::queryHeifLib();
892 return m_heif_decoder_available;
895bool HEIFHandler::isHeifEncoderAvailable()
897 HEIFHandler::queryHeifLib();
899 return m_heif_encoder_available;
902bool HEIFHandler::isHej2DecoderAvailable()
904 HEIFHandler::queryHeifLib();
906 return m_hej2_decoder_available;
909bool HEIFHandler::isAVCIDecoderAvailable()
911 HEIFHandler::queryHeifLib();
913 return m_avci_decoder_available;
916void HEIFHandler::queryHeifLib()
920 if (!m_plugins_queried) {
921#if LIBHEIF_HAVE_VERSION(1, 13, 0)
922 if (m_initialized_count == 0) {
927 m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
928 m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
929#if LIBHEIF_HAVE_VERSION(1, 13, 0)
930 m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
932#if LIBHEIF_HAVE_VERSION(1, 19, 0)
933 m_avci_decoder_available = heif_have_decoder_for_format(heif_compression_AVC);
935 m_plugins_queried =
true;
937#if LIBHEIF_HAVE_VERSION(1, 13, 0)
938 if (m_initialized_count == 0) {
945void HEIFHandler::startHeifLib()
947#if LIBHEIF_HAVE_VERSION(1, 13, 0)
950 if (m_initialized_count == 0) {
954 m_initialized_count++;
958void HEIFHandler::finishHeifLib()
960#if LIBHEIF_HAVE_VERSION(1, 13, 0)
963 if (m_initialized_count == 0) {
967 m_initialized_count--;
968 if (m_initialized_count == 0) {
975QMutex &HEIFHandler::getHEIFHandlerMutex()
977 static QMutex heif_handler_mutex;
978 return heif_handler_mutex;
983 if (format ==
"heif" || format ==
"heic") {
985 if (HEIFHandler::isHeifDecoderAvailable()) {
986 format_cap |= CanRead;
988 if (HEIFHandler::isHeifEncoderAvailable()) {
989 format_cap |= CanWrite;
994 if (format ==
"hej2") {
996 if (HEIFHandler::isHej2DecoderAvailable()) {
997 format_cap |= CanRead;
1002 if (format ==
"avci") {
1004 if (HEIFHandler::isAVCIDecoderAvailable()) {
1005 format_cap |= CanRead;
1021 if ((HEIFHandler::isSupportedBMFFType(header) && HEIFHandler::isHeifDecoderAvailable())
1022 || (HEIFHandler::isSupportedHEJ2(header) && HEIFHandler::isHej2DecoderAvailable())
1023 || (HEIFHandler::isSupportedAVCI(header) && HEIFHandler::isAVCIDecoderAvailable())) {
1028 if (device->
isWritable() && HEIFHandler::isHeifEncoderAvailable()) {
1042#include "moc_heif_p.cpp"
KGUIADDONS_EXPORT qreal chroma(const QColor &)
QFlags< Capability > Capabilities
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const char * constData() const const
bool contains(QByteArrayView bv) const const
bool isEmpty() const const
qsizetype size() const const
QColorSpace fromIccProfile(const QByteArray &iccProfile)
QByteArray iccProfile() const const
QColorSpace colorSpace() const const
const uchar * constScanLine(int i) const const
QImage convertedToColorSpace(const QColorSpace &colorSpace) const const
bool hasAlphaChannel() const const
bool isNull() const const
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