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;
28static struct heif_error heifhandler_write_callback(struct heif_context * ,
const void *data,
size_t size,
void *userdata)
31 error.code = heif_error_Ok;
32 error.subcode = heif_suberror_Unspecified;
33 error.message =
"Success";
35 if (!userdata || !data || size == 0) {
36 error.code = heif_error_Usage_error;
37 error.subcode = heif_suberror_Null_pointer_argument;
38 error.message =
"Wrong parameters!";
43 qint64 bytesWritten = ioDevice->
write(
static_cast<const char *
>(data), size);
45 if (bytesWritten <
static_cast<qint64
>(size)) {
46 error.code = heif_error_Encoding_error;
47 error.message =
"Bytes written to QIODevice are smaller than input data size";
48 error.subcode = heif_suberror_Cannot_write_output_data;
55HEIFHandler::HEIFHandler()
56 : m_parseState(ParseHeicNotParsed)
61bool HEIFHandler::canRead()
const
63 if (m_parseState == ParseHeicNotParsed) {
68 if (HEIFHandler::isSupportedBMFFType(header)) {
73 if (HEIFHandler::isSupportedHEJ2(header)) {
81 if (m_parseState != ParseHeicError) {
87bool HEIFHandler::read(
QImage *outImage)
89 if (!ensureParsed()) {
93 *outImage = m_current_image;
97bool HEIFHandler::write(
const QImage &image)
100 qWarning(
"No image data to save");
104#if LIBHEIF_HAVE_VERSION(1, 13, 0)
108 bool success = write_helper(image);
110#if LIBHEIF_HAVE_VERSION(1, 13, 0)
117bool HEIFHandler::write_helper(
const QImage &image)
135 if (image.
depth() > 32) {
144 if (save_depth > 8) {
155 chroma = heif_chroma_interleaved_RGBA;
158 chroma = heif_chroma_interleaved_RGB;
162#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
165 if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.
format() == QImage::Format_CMYK8888) {
175 struct heif_context *context = heif_context_alloc();
176 struct heif_error err;
177 struct heif_image *h_image =
nullptr;
179 err = heif_image_create(tmpimage.
width(), tmpimage.
height(), heif_colorspace_RGB, chroma, &h_image);
181 qWarning() <<
"heif_image_create error:" << err.message;
182 heif_context_free(context);
187 if (iccprofile.
size() > 0) {
188 heif_image_set_raw_color_profile(h_image,
"prof", iccprofile.
constData(), iccprofile.
size());
191 heif_image_add_plane(h_image, heif_channel_interleaved, image.
width(), image.
height(), save_depth);
193 uint8_t *
const dst = heif_image_get_plane(h_image, heif_channel_interleaved, &stride);
196 switch (save_depth) {
199 for (
int y = 0; y < tmpimage.
height(); y++) {
200 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(tmpimage.
constScanLine(y));
201 uint16_t *dest_word =
reinterpret_cast<uint16_t *
>(dst + (y * stride));
202 for (
int x = 0; x < tmpimage.
width(); x++) {
205 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
206 *dest_word = qBound(0, tmp_pixelval, 1023);
210 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
211 *dest_word = qBound(0, tmp_pixelval, 1023);
215 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
216 *dest_word = qBound(0, tmp_pixelval, 1023);
220 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
221 *dest_word = qBound(0, tmp_pixelval, 1023);
227 for (
int y = 0; y < tmpimage.
height(); y++) {
228 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(tmpimage.
constScanLine(y));
229 uint16_t *dest_word =
reinterpret_cast<uint16_t *
>(dst + (y * stride));
230 for (
int x = 0; x < tmpimage.
width(); x++) {
233 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
234 *dest_word = qBound(0, tmp_pixelval, 1023);
238 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
239 *dest_word = qBound(0, tmp_pixelval, 1023);
243 tmp_pixelval = (int)(((
float)(*src_word) / 65535.0f) * 1023.0f + 0.5f);
244 *dest_word = qBound(0, tmp_pixelval, 1023);
254 rowbytes = save_alpha ? (tmpimage.
width() * 4) : (tmpimage.width() * 3);
255 for (
int y = 0; y < tmpimage.
height(); y++) {
256 memcpy(dst + (y * stride), tmpimage.
constScanLine(y), rowbytes);
260 qWarning() <<
"Unsupported depth:" << save_depth;
261 heif_image_release(h_image);
262 heif_context_free(context);
267 struct heif_encoder *encoder =
nullptr;
268 err = heif_context_get_encoder_for_format(context, heif_compression_HEVC, &encoder);
270 qWarning() <<
"Unable to get an encoder instance:" << err.message;
271 heif_image_release(h_image);
272 heif_context_free(context);
276 heif_encoder_set_lossy_quality(encoder, m_quality);
277 if (m_quality > 90) {
278 if (m_quality == 100) {
279 heif_encoder_set_lossless(encoder,
true);
281 heif_encoder_set_parameter_string(encoder,
"chroma",
"444");
284 struct heif_encoding_options *encoder_options = heif_encoding_options_alloc();
285 encoder_options->save_alpha_channel = save_alpha;
287 if ((tmpimage.
width() % 2 == 1) || (tmpimage.
height() % 2 == 1)) {
288 qWarning() <<
"Image has odd dimension!\nUse even-numbered dimension(s) for better compatibility with other HEIF implementations.";
291 encoder_options->macOS_compatibility_workaround = 0;
295 err = heif_context_encode_image(context, h_image, encoder, encoder_options,
nullptr);
297 if (encoder_options) {
298 heif_encoding_options_free(encoder_options);
302 qWarning() <<
"heif_context_encode_image failed:" << err.message;
303 heif_encoder_release(encoder);
304 heif_image_release(h_image);
305 heif_context_free(context);
309 struct heif_writer writer;
310 writer.writer_api_version = 1;
311 writer.write = heifhandler_write_callback;
313 err = heif_context_write(context, &writer, device());
315 heif_encoder_release(encoder);
316 heif_image_release(h_image);
319 qWarning() <<
"Writing HEIF image failed:" << err.message;
320 heif_context_free(context);
324 heif_context_free(context);
328bool HEIFHandler::isSupportedBMFFType(
const QByteArray &header)
330 if (header.
size() < 28) {
335 if (qstrncmp(buffer + 4,
"ftyp", 4) == 0) {
336 if (qstrncmp(buffer + 8,
"heic", 4) == 0) {
339 if (qstrncmp(buffer + 8,
"heis", 4) == 0) {
342 if (qstrncmp(buffer + 8,
"heix", 4) == 0) {
347 if (qstrncmp(buffer + 8,
"mif1", 4) == 0) {
348 for (
int offset = 16; offset <= 24; offset += 4) {
349 if (qstrncmp(buffer + offset,
"avif", 4) == 0) {
356 if (qstrncmp(buffer + 8,
"mif2", 4) == 0) {
359 if (qstrncmp(buffer + 8,
"msf1", 4) == 0) {
367bool HEIFHandler::isSupportedHEJ2(
const QByteArray &header)
369 if (header.
size() < 28) {
374 if (qstrncmp(buffer + 4,
"ftyp", 4) == 0) {
375 if (qstrncmp(buffer + 8,
"j2ki", 4) == 0) {
383QVariant HEIFHandler::option(ImageOption option)
const
385 if (option == Quality) {
389 if (!supportsOption(option) || !ensureParsed()) {
395 return m_current_image.size();
403void HEIFHandler::setOption(ImageOption option,
const QVariant &value)
407 m_quality = value.
toInt();
408 if (m_quality > 100) {
410 }
else if (m_quality < 0) {
420bool HEIFHandler::supportsOption(ImageOption option)
const
422 return option == Quality || option == Size;
425bool HEIFHandler::ensureParsed()
const
427 if (m_parseState == ParseHeicSuccess) {
430 if (m_parseState == ParseHeicError) {
434 HEIFHandler *that =
const_cast<HEIFHandler *
>(
this);
436#if LIBHEIF_HAVE_VERSION(1, 13, 0)
440 bool success = that->ensureDecoder();
442#if LIBHEIF_HAVE_VERSION(1, 13, 0)
448bool HEIFHandler::ensureDecoder()
450 if (m_parseState != ParseHeicNotParsed) {
451 if (m_parseState == ParseHeicSuccess) {
457 const QByteArray buffer = device()->readAll();
458 if (!HEIFHandler::isSupportedBMFFType(buffer) && !HEIFHandler::isSupportedHEJ2(buffer)) {
459 m_parseState = ParseHeicError;
463 struct heif_context *ctx = heif_context_alloc();
464 struct heif_error err = heif_context_read_from_memory(ctx,
static_cast<const void *
>(buffer.
constData()), buffer.
size(),
nullptr);
467 qWarning() <<
"heif_context_read_from_memory error:" << err.message;
468 heif_context_free(ctx);
469 m_parseState = ParseHeicError;
473 struct heif_image_handle *handle =
nullptr;
474 err = heif_context_get_primary_image_handle(ctx, &handle);
476 qWarning() <<
"heif_context_get_primary_image_handle error:" << err.message;
477 heif_context_free(ctx);
478 m_parseState = ParseHeicError;
482 if ((heif_image_handle_get_width(handle) == 0) || (heif_image_handle_get_height(handle) == 0)) {
483 m_parseState = ParseHeicError;
484 heif_image_handle_release(handle);
485 heif_context_free(ctx);
486 qWarning() <<
"HEIC image has zero dimension";
490 const int bit_depth = heif_image_handle_get_luma_bits_per_pixel(handle);
493 m_parseState = ParseHeicError;
494 heif_image_handle_release(handle);
495 heif_context_free(ctx);
496 qWarning() <<
"HEIF image with undefined or unsupported bit depth.";
500 const bool hasAlphaChannel = heif_image_handle_has_alpha_channel(handle);
505 if (bit_depth == 10 || bit_depth == 12) {
506 if (hasAlphaChannel) {
513 }
else if (bit_depth == 8) {
514 if (hasAlphaChannel) {
515 chroma = heif_chroma_interleaved_RGBA;
518 chroma = heif_chroma_interleaved_RGB;
522 m_parseState = ParseHeicError;
523 heif_image_handle_release(handle);
524 heif_context_free(ctx);
525 qWarning() <<
"Unsupported bit depth:" << bit_depth;
529 struct heif_decoding_options *decoder_option = heif_decoding_options_alloc();
531#if LIBHEIF_HAVE_VERSION(1, 13, 0)
532 decoder_option->strict_decoding = 1;
535 struct heif_image *img =
nullptr;
536 err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option);
538#if LIBHEIF_HAVE_VERSION(1, 13, 0)
539 if (err.code == heif_error_Invalid_input && err.subcode == heif_suberror_Unknown_NCLX_matrix_coefficients && img ==
nullptr && buffer.
contains(
"Xiaomi")) {
540 qWarning() <<
"Non-standard HEIF image with invalid matrix_coefficients, probably made by a Xiaomi device!";
543 decoder_option->strict_decoding = 0;
544 err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option);
548 if (decoder_option) {
549 heif_decoding_options_free(decoder_option);
553 qWarning() <<
"heif_decode_image error:" << err.message;
554 heif_image_handle_release(handle);
555 heif_context_free(ctx);
556 m_parseState = ParseHeicError;
560 const int imageWidth = heif_image_get_width(img, heif_channel_interleaved);
561 const int imageHeight = heif_image_get_height(img, heif_channel_interleaved);
563 QSize imageSize(imageWidth, imageHeight);
565 if (!imageSize.isValid()) {
566 heif_image_release(img);
567 heif_image_handle_release(handle);
568 heif_context_free(ctx);
569 m_parseState = ParseHeicError;
570 qWarning() <<
"HEIC image size invalid:" << imageSize;
575 const uint8_t *
const src = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);
577 if (!src || stride <= 0) {
578 heif_image_release(img);
579 heif_image_handle_release(handle);
580 heif_context_free(ctx);
581 m_parseState = ParseHeicError;
582 qWarning() <<
"HEIC data pixels information not valid!";
586 m_current_image = imageAlloc(imageSize, target_image_format);
587 if (m_current_image.isNull()) {
588 heif_image_release(img);
589 heif_image_handle_release(handle);
590 heif_context_free(ctx);
591 m_parseState = ParseHeicError;
592 qWarning() <<
"Unable to allocate memory!";
598 if (hasAlphaChannel) {
599 for (
int y = 0; y < imageHeight; y++) {
600 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
601 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
602 for (
int x = 0; x < imageWidth; x++) {
605 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
606 tmpvalue = qBound(0, tmpvalue, 65535);
607 *dest_data = (uint16_t)tmpvalue;
611 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
612 tmpvalue = qBound(0, tmpvalue, 65535);
613 *dest_data = (uint16_t)tmpvalue;
617 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
618 tmpvalue = qBound(0, tmpvalue, 65535);
619 *dest_data = (uint16_t)tmpvalue;
623 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
624 tmpvalue = qBound(0, tmpvalue, 65535);
625 *dest_data = (uint16_t)tmpvalue;
631 for (
int y = 0; y < imageHeight; y++) {
632 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
633 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
634 for (
int x = 0; x < imageWidth; x++) {
637 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
638 tmpvalue = qBound(0, tmpvalue, 65535);
639 *dest_data = (uint16_t)tmpvalue;
643 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
644 tmpvalue = qBound(0, tmpvalue, 65535);
645 *dest_data = (uint16_t)tmpvalue;
649 tmpvalue = (int)(((
float)(0x0fff & (*src_word)) / 4095.0f) * 65535.0f + 0.5f);
650 tmpvalue = qBound(0, tmpvalue, 65535);
651 *dest_data = (uint16_t)tmpvalue;
662 if (hasAlphaChannel) {
663 for (
int y = 0; y < imageHeight; y++) {
664 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
665 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
666 for (
int x = 0; x < imageWidth; x++) {
669 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
670 tmpvalue = qBound(0, tmpvalue, 65535);
671 *dest_data = (uint16_t)tmpvalue;
675 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
676 tmpvalue = qBound(0, tmpvalue, 65535);
677 *dest_data = (uint16_t)tmpvalue;
681 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
682 tmpvalue = qBound(0, tmpvalue, 65535);
683 *dest_data = (uint16_t)tmpvalue;
687 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
688 tmpvalue = qBound(0, tmpvalue, 65535);
689 *dest_data = (uint16_t)tmpvalue;
695 for (
int y = 0; y < imageHeight; y++) {
696 const uint16_t *src_word =
reinterpret_cast<const uint16_t *
>(src + (y * stride));
697 uint16_t *dest_data =
reinterpret_cast<uint16_t *
>(m_current_image.scanLine(y));
698 for (
int x = 0; x < imageWidth; x++) {
701 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
702 tmpvalue = qBound(0, tmpvalue, 65535);
703 *dest_data = (uint16_t)tmpvalue;
707 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
708 tmpvalue = qBound(0, tmpvalue, 65535);
709 *dest_data = (uint16_t)tmpvalue;
713 tmpvalue = (int)(((
float)(0x03ff & (*src_word)) / 1023.0f) * 65535.0f + 0.5f);
714 tmpvalue = qBound(0, tmpvalue, 65535);
715 *dest_data = (uint16_t)tmpvalue;
726 if (hasAlphaChannel) {
727 for (
int y = 0; y < imageHeight; y++) {
728 const uint8_t *src_byte = src + (y * stride);
729 uint32_t *dest_pixel =
reinterpret_cast<uint32_t *
>(m_current_image.scanLine(y));
730 for (
int x = 0; x < imageWidth; x++) {
731 int red = *src_byte++;
732 int green = *src_byte++;
733 int blue = *src_byte++;
734 int alpha = *src_byte++;
735 *dest_pixel = qRgba(red, green, blue, alpha);
740 for (
int y = 0; y < imageHeight; y++) {
741 const uint8_t *src_byte = src + (y * stride);
742 uint32_t *dest_pixel =
reinterpret_cast<uint32_t *
>(m_current_image.scanLine(y));
743 for (
int x = 0; x < imageWidth; x++) {
744 int red = *src_byte++;
745 int green = *src_byte++;
746 int blue = *src_byte++;
747 *dest_pixel = qRgb(red, green, blue);
754 heif_image_release(img);
755 heif_image_handle_release(handle);
756 heif_context_free(ctx);
757 m_parseState = ParseHeicError;
758 qWarning() <<
"Unsupported bit depth:" << bit_depth;
763 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle);
764 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
765 size_t rawProfileSize = heif_image_handle_get_raw_color_profile_size(handle);
766 if (rawProfileSize > 0 && rawProfileSize < std::numeric_limits<int>::max()) {
768 err = heif_image_handle_get_raw_color_profile(handle, ba.data());
770 qWarning() <<
"icc profile loading failed";
773 if (!m_current_image.colorSpace().isValid()) {
774 qWarning() <<
"HEIC image has Qt-unsupported or invalid ICC profile!";
778 qWarning() <<
"icc profile is empty or above limits";
781 }
else if (profileType == heif_color_profile_type_nclx) {
782 struct heif_color_profile_nclx *nclx =
nullptr;
783 err = heif_image_handle_get_nclx_color_profile(handle, &nclx);
784 if (err.code || !nclx) {
785 qWarning() <<
"nclx profile loading failed";
787 const QPointF redPoint(nclx->color_primary_red_x, nclx->color_primary_red_y);
788 const QPointF greenPoint(nclx->color_primary_green_x, nclx->color_primary_green_y);
789 const QPointF bluePoint(nclx->color_primary_blue_x, nclx->color_primary_blue_y);
790 const QPointF whitePoint(nclx->color_primary_white_x, nclx->color_primary_white_y);
793 float q_trc_gamma = 0.0f;
795 switch (nclx->transfer_characteristics) {
797 q_trc = QColorSpace::TransferFunction::Gamma;
801 q_trc = QColorSpace::TransferFunction::Gamma;
805 q_trc = QColorSpace::TransferFunction::Linear;
809 q_trc = QColorSpace::TransferFunction::SRgb;
812 qWarning(
"CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
813 nclx->color_primaries,
814 nclx->transfer_characteristics);
815 q_trc = QColorSpace::TransferFunction::SRgb;
819 if (q_trc != QColorSpace::TransferFunction::Custom) {
820 switch (nclx->color_primaries) {
823 m_current_image.setColorSpace(
QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma));
826 m_current_image.setColorSpace(
QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma));
829 m_current_image.setColorSpace(
QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma));
833 heif_nclx_color_profile_free(nclx);
835 if (!m_current_image.colorSpace().isValid()) {
836 qWarning() <<
"HEIC plugin created invalid QColorSpace from NCLX!";
844 heif_image_release(img);
845 heif_image_handle_release(handle);
846 heif_context_free(ctx);
847 m_parseState = ParseHeicSuccess;
851bool HEIFHandler::isHeifDecoderAvailable()
855 if (!m_plugins_queried) {
856#if LIBHEIF_HAVE_VERSION(1, 13, 0)
857 if (m_initialized_count == 0) {
862#if LIBHEIF_HAVE_VERSION(1, 13, 0)
863 m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
865 m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
866 m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
867 m_plugins_queried =
true;
869#if LIBHEIF_HAVE_VERSION(1, 13, 0)
870 if (m_initialized_count == 0) {
876 return m_heif_decoder_available;
879bool HEIFHandler::isHeifEncoderAvailable()
883 if (!m_plugins_queried) {
884#if LIBHEIF_HAVE_VERSION(1, 13, 0)
885 if (m_initialized_count == 0) {
890#if LIBHEIF_HAVE_VERSION(1, 13, 0)
891 m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
893 m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
894 m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
895 m_plugins_queried =
true;
897#if LIBHEIF_HAVE_VERSION(1, 13, 0)
898 if (m_initialized_count == 0) {
904 return m_heif_encoder_available;
907bool HEIFHandler::isHej2DecoderAvailable()
911 if (!m_plugins_queried) {
912#if LIBHEIF_HAVE_VERSION(1, 13, 0)
913 if (m_initialized_count == 0) {
918 m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
919 m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
920#if LIBHEIF_HAVE_VERSION(1, 13, 0)
921 m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
923 m_plugins_queried =
true;
925#if LIBHEIF_HAVE_VERSION(1, 13, 0)
926 if (m_initialized_count == 0) {
932 return m_hej2_decoder_available;
935void HEIFHandler::startHeifLib()
937#if LIBHEIF_HAVE_VERSION(1, 13, 0)
940 if (m_initialized_count == 0) {
944 m_initialized_count++;
948void HEIFHandler::finishHeifLib()
950#if LIBHEIF_HAVE_VERSION(1, 13, 0)
953 if (m_initialized_count == 0) {
957 m_initialized_count--;
958 if (m_initialized_count == 0) {
965QMutex &HEIFHandler::getHEIFHandlerMutex()
967 static QMutex heif_handler_mutex;
968 return heif_handler_mutex;
973 if (format ==
"heif" || format ==
"heic") {
975 if (HEIFHandler::isHeifDecoderAvailable()) {
976 format_cap |= CanRead;
978 if (HEIFHandler::isHeifEncoderAvailable()) {
979 format_cap |= CanWrite;
984 if (format ==
"hej2") {
986 if (HEIFHandler::isHej2DecoderAvailable()) {
987 format_cap |= CanRead;
1003 if (HEIFHandler::isSupportedBMFFType(header) && HEIFHandler::isHeifDecoderAvailable()) {
1007 if (HEIFHandler::isSupportedHEJ2(header) && HEIFHandler::isHej2DecoderAvailable()) {
1012 if (device->
isWritable() && HEIFHandler::isHeifEncoderAvailable()) {
1026#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