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 (memcmp(buffer + 4,
"ftyp", 4) == 0) {
349 if (memcmp(buffer + 8,
"heic", 4) == 0) {
352 if (memcmp(buffer + 8,
"heis", 4) == 0) {
355 if (memcmp(buffer + 8,
"heix", 4) == 0) {
360 if (memcmp(buffer + 8,
"mif1", 4) == 0) {
361 for (
int offset = 16; offset <= 24; offset += 4) {
362 if (memcmp(buffer + offset,
"avif", 4) == 0) {
369 if (memcmp(buffer + 8,
"mif2", 4) == 0) {
372 if (memcmp(buffer + 8,
"msf1", 4) == 0) {
380bool HEIFHandler::isSupportedHEJ2(
const QByteArray &header)
382 if (header.
size() < 28) {
387 if (memcmp(buffer + 4,
"ftypj2ki", 8) == 0) {
394bool HEIFHandler::isSupportedAVCI(
const QByteArray &header)
396 if (header.
size() < 28) {
401 if (memcmp(buffer + 4,
"ftypavci", 8) == 0) {
408QVariant HEIFHandler::option(ImageOption option)
const
410 if (option == Quality) {
414 if (!supportsOption(option) || !ensureParsed()) {
420 return m_current_image.size();
428void HEIFHandler::setOption(ImageOption option,
const QVariant &value)
432 m_quality = value.
toInt();
433 if (m_quality > 100) {
435 }
else if (m_quality < 0) {
445bool HEIFHandler::supportsOption(ImageOption option)
const
447 return option == Quality || option == Size;
450bool HEIFHandler::ensureParsed()
const
452 if (m_parseState == ParseHeicSuccess) {
455 if (m_parseState == ParseHeicError) {
459 HEIFHandler *that =
const_cast<HEIFHandler *
>(
this);
461#if LIBHEIF_HAVE_VERSION(1, 13, 0)
465 bool success = that->ensureDecoder();
467#if LIBHEIF_HAVE_VERSION(1, 13, 0)
473bool HEIFHandler::ensureDecoder()
475 if (m_parseState != ParseHeicNotParsed) {
476 if (m_parseState == ParseHeicSuccess) {
482 const QByteArray buffer = device()->readAll();
483 if (!HEIFHandler::isSupportedBMFFType(buffer) && !HEIFHandler::isSupportedHEJ2(buffer) && !HEIFHandler::isSupportedAVCI(buffer)) {
484 m_parseState = ParseHeicError;
488 struct heif_context *ctx = heif_context_alloc();
489 struct heif_error err = heif_context_read_from_memory(ctx,
static_cast<const void *
>(buffer.
constData()), buffer.
size(),
nullptr);
492 qWarning() <<
"heif_context_read_from_memory error:" << err.message;
493 heif_context_free(ctx);
494 m_parseState = ParseHeicError;
498 struct heif_image_handle *handle =
nullptr;
499 err = heif_context_get_primary_image_handle(ctx, &handle);
501 qWarning() <<
"heif_context_get_primary_image_handle error:" << err.message;
502 heif_context_free(ctx);
503 m_parseState = ParseHeicError;
507 if ((heif_image_handle_get_width(handle) == 0) || (heif_image_handle_get_height(handle) == 0)) {
508 m_parseState = ParseHeicError;
509 heif_image_handle_release(handle);
510 heif_context_free(ctx);
511 qWarning() <<
"HEIC image has zero dimension";
515 const int bit_depth = heif_image_handle_get_luma_bits_per_pixel(handle);
518 m_parseState = ParseHeicError;
519 heif_image_handle_release(handle);
520 heif_context_free(ctx);
521 qWarning() <<
"HEIF image with undefined or unsupported bit depth.";
525 const bool hasAlphaChannel = heif_image_handle_has_alpha_channel(handle);
530 if (bit_depth == 10 || bit_depth == 12) {
531 if (hasAlphaChannel) {
538 }
else if (bit_depth == 8) {
539 if (hasAlphaChannel) {
540 chroma = heif_chroma_interleaved_RGBA;
543 chroma = heif_chroma_interleaved_RGB;
547 m_parseState = ParseHeicError;
548 heif_image_handle_release(handle);
549 heif_context_free(ctx);
550 qWarning() <<
"Unsupported bit depth:" << bit_depth;
554 struct heif_decoding_options *decoder_option = heif_decoding_options_alloc();
556#if LIBHEIF_HAVE_VERSION(1, 13, 0)
557 decoder_option->strict_decoding = 1;
560 struct heif_image *img =
nullptr;
561 err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option);
563#if LIBHEIF_HAVE_VERSION(1, 13, 0)
564 if (err.code == heif_error_Invalid_input && err.subcode == heif_suberror_Unknown_NCLX_matrix_coefficients && img ==
nullptr && buffer.
contains(
"Xiaomi")) {
565 qWarning() <<
"Non-standard HEIF image with invalid matrix_coefficients, probably made by a Xiaomi device!";
568 decoder_option->strict_decoding = 0;
569 err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option);
573 if (decoder_option) {
574 heif_decoding_options_free(decoder_option);
578 qWarning() <<
"heif_decode_image error:" << err.message;
579 heif_image_handle_release(handle);
580 heif_context_free(ctx);
581 m_parseState = ParseHeicError;
585 const int imageWidth = heif_image_get_width(img, heif_channel_interleaved);
586 const int imageHeight = heif_image_get_height(img, heif_channel_interleaved);
588 QSize imageSize(imageWidth, imageHeight);
590 if (!imageSize.isValid()) {
591 heif_image_release(img);
592 heif_image_handle_release(handle);
593 heif_context_free(ctx);
594 m_parseState = ParseHeicError;
595 qWarning() <<
"HEIC image size invalid:" << imageSize;
600 const uint8_t *
const src = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);
602 if (!src || stride <= 0) {
603 heif_image_release(img);
604 heif_image_handle_release(handle);
605 heif_context_free(ctx);
606 m_parseState = ParseHeicError;
607 qWarning() <<
"HEIC data pixels information not valid!";
611 m_current_image = imageAlloc(imageSize, target_image_format);
612 if (m_current_image.isNull()) {
613 heif_image_release(img);
614 heif_image_handle_release(handle);
615 heif_context_free(ctx);
616 m_parseState = ParseHeicError;
617 qWarning() <<
"Unable to allocate memory!";
623 if (hasAlphaChannel) {
624 for (
int y = 0; y < imageHeight; y++) {
625 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
626 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
627 for (
int x = 0; x < imageWidth; x++) {
630 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
631 tmpvalue = qBound(0, tmpvalue, 65535);
632 *dest_data = (uint16_t)tmpvalue;
636 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
637 tmpvalue = qBound(0, tmpvalue, 65535);
638 *dest_data = (uint16_t)tmpvalue;
642 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
643 tmpvalue = qBound(0, tmpvalue, 65535);
644 *dest_data = (uint16_t)tmpvalue;
648 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
649 tmpvalue = qBound(0, tmpvalue, 65535);
650 *dest_data = (uint16_t)tmpvalue;
656 for (
int y = 0; y < imageHeight; y++) {
657 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
658 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
659 for (
int x = 0; x < imageWidth; x++) {
662 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
663 tmpvalue = qBound(0, tmpvalue, 65535);
664 *dest_data = (uint16_t)tmpvalue;
668 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
669 tmpvalue = qBound(0, tmpvalue, 65535);
670 *dest_data = (uint16_t)tmpvalue;
674 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
675 tmpvalue = qBound(0, tmpvalue, 65535);
676 *dest_data = (uint16_t)tmpvalue;
687 if (hasAlphaChannel) {
688 for (
int y = 0; y < imageHeight; y++) {
689 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
690 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
691 for (
int x = 0; x < imageWidth; x++) {
694 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
695 tmpvalue = qBound(0, tmpvalue, 65535);
696 *dest_data = (uint16_t)tmpvalue;
700 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
701 tmpvalue = qBound(0, tmpvalue, 65535);
702 *dest_data = (uint16_t)tmpvalue;
706 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
707 tmpvalue = qBound(0, tmpvalue, 65535);
708 *dest_data = (uint16_t)tmpvalue;
712 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
713 tmpvalue = qBound(0, tmpvalue, 65535);
714 *dest_data = (uint16_t)tmpvalue;
720 for (
int y = 0; y < imageHeight; y++) {
721 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
722 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
723 for (
int x = 0; x < imageWidth; x++) {
726 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
727 tmpvalue = qBound(0, tmpvalue, 65535);
728 *dest_data = (uint16_t)tmpvalue;
732 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
733 tmpvalue = qBound(0, tmpvalue, 65535);
734 *dest_data = (uint16_t)tmpvalue;
738 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
739 tmpvalue = qBound(0, tmpvalue, 65535);
740 *dest_data = (uint16_t)tmpvalue;
751 if (hasAlphaChannel) {
752 for (
int y = 0; y < imageHeight; y++) {
753 const uint8_t *src_byte = src + (y * stride);
754 uint32_t *dest_pixel =
reinterpret_cast<uint32_t *
>(m_current_image.scanLine(y));
755 for (
int x = 0; x < imageWidth; x++) {
756 int red = *src_byte++;
757 int green = *src_byte++;
758 int blue = *src_byte++;
759 int alpha = *src_byte++;
760 *dest_pixel = qRgba(red, green, blue, alpha);
765 for (
int y = 0; y < imageHeight; y++) {
766 const uint8_t *src_byte = src + (y * stride);
767 uint32_t *dest_pixel =
reinterpret_cast<uint32_t *
>(m_current_image.scanLine(y));
768 for (
int x = 0; x < imageWidth; x++) {
769 int red = *src_byte++;
770 int green = *src_byte++;
771 int blue = *src_byte++;
772 *dest_pixel = qRgb(red, green, blue);
779 heif_image_release(img);
780 heif_image_handle_release(handle);
781 heif_context_free(ctx);
782 m_parseState = ParseHeicError;
783 qWarning() <<
"Unsupported bit depth:" << bit_depth;
788 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle);
789 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
790 size_t rawProfileSize = heif_image_handle_get_raw_color_profile_size(handle);
791 if (rawProfileSize > 0 && rawProfileSize < std::numeric_limits<int>::max()) {
793 err = heif_image_handle_get_raw_color_profile(handle, ba.data());
795 qWarning() <<
"icc profile loading failed";
798 if (!m_current_image.colorSpace().isValid()) {
799 qWarning() <<
"HEIC image has Qt-unsupported or invalid ICC profile!";
803 qWarning() <<
"icc profile is empty or above limits";
806 }
else if (profileType == heif_color_profile_type_nclx) {
807 struct heif_color_profile_nclx *nclx =
nullptr;
808 err = heif_image_handle_get_nclx_color_profile(handle, &nclx);
809 if (err.code || !nclx) {
810 qWarning() <<
"nclx profile loading failed";
812 const QPointF redPoint(nclx->color_primary_red_x, nclx->color_primary_red_y);
813 const QPointF greenPoint(nclx->color_primary_green_x, nclx->color_primary_green_y);
814 const QPointF bluePoint(nclx->color_primary_blue_x, nclx->color_primary_blue_y);
815 const QPointF whitePoint(nclx->color_primary_white_x, nclx->color_primary_white_y);
818 float q_trc_gamma = 0.0f;
820 switch (nclx->transfer_characteristics) {
822 q_trc = QColorSpace::TransferFunction::Gamma;
826 q_trc = QColorSpace::TransferFunction::Gamma;
830 q_trc = QColorSpace::TransferFunction::Linear;
834 q_trc = QColorSpace::TransferFunction::SRgb;
836#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
838 q_trc = QColorSpace::TransferFunction::St2084;
841 q_trc = QColorSpace::TransferFunction::Hlg;
845 qWarning(
"CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
846 nclx->color_primaries,
847 nclx->transfer_characteristics);
848 q_trc = QColorSpace::TransferFunction::SRgb;
852 if (q_trc != QColorSpace::TransferFunction::Custom) {
853 switch (nclx->color_primaries) {
856 m_current_image.setColorSpace(
QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma));
859 m_current_image.setColorSpace(
QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma));
862 m_current_image.setColorSpace(
QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma));
866 heif_nclx_color_profile_free(nclx);
868 if (!m_current_image.colorSpace().isValid()) {
869 qWarning() <<
"HEIC plugin created invalid QColorSpace from NCLX!";
877 heif_image_release(img);
878 heif_image_handle_release(handle);
879 heif_context_free(ctx);
880 m_parseState = ParseHeicSuccess;
884bool HEIFHandler::isHeifDecoderAvailable()
886 HEIFHandler::queryHeifLib();
888 return m_heif_decoder_available;
891bool HEIFHandler::isHeifEncoderAvailable()
893 HEIFHandler::queryHeifLib();
895 return m_heif_encoder_available;
898bool HEIFHandler::isHej2DecoderAvailable()
900 HEIFHandler::queryHeifLib();
902 return m_hej2_decoder_available;
905bool HEIFHandler::isAVCIDecoderAvailable()
907 HEIFHandler::queryHeifLib();
909 return m_avci_decoder_available;
912void HEIFHandler::queryHeifLib()
916 if (!m_plugins_queried) {
917#if LIBHEIF_HAVE_VERSION(1, 13, 0)
918 if (m_initialized_count == 0) {
923 m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
924 m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
925#if LIBHEIF_HAVE_VERSION(1, 13, 0)
926 m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
928#if LIBHEIF_HAVE_VERSION(1, 19, 0)
929 m_avci_decoder_available = heif_have_decoder_for_format(heif_compression_AVC);
931 m_plugins_queried =
true;
933#if LIBHEIF_HAVE_VERSION(1, 13, 0)
934 if (m_initialized_count == 0) {
941void HEIFHandler::startHeifLib()
943#if LIBHEIF_HAVE_VERSION(1, 13, 0)
946 if (m_initialized_count == 0) {
950 m_initialized_count++;
954void HEIFHandler::finishHeifLib()
956#if LIBHEIF_HAVE_VERSION(1, 13, 0)
959 if (m_initialized_count == 0) {
963 m_initialized_count--;
964 if (m_initialized_count == 0) {
971QMutex &HEIFHandler::getHEIFHandlerMutex()
973 static QMutex heif_handler_mutex;
974 return heif_handler_mutex;
979 if (format ==
"heif" || format ==
"heic") {
981 if (HEIFHandler::isHeifDecoderAvailable()) {
982 format_cap |= CanRead;
984 if (HEIFHandler::isHeifEncoderAvailable()) {
985 format_cap |= CanWrite;
990 if (format ==
"hej2") {
992 if (HEIFHandler::isHej2DecoderAvailable()) {
993 format_cap |= CanRead;
998 if (format ==
"avci") {
1000 if (HEIFHandler::isAVCIDecoderAvailable()) {
1001 format_cap |= CanRead;
1017 if ((HEIFHandler::isSupportedBMFFType(header) && HEIFHandler::isHeifDecoderAvailable())
1018 || (HEIFHandler::isSupportedHEJ2(header) && HEIFHandler::isHej2DecoderAvailable())
1019 || (HEIFHandler::isSupportedAVCI(header) && HEIFHandler::isAVCIDecoderAvailable())) {
1024 if (device->
isWritable() && HEIFHandler::isHeifEncoderAvailable()) {
1038#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