mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-07-16 03:24:17 -04:00
Compare commits
1 Commits
v6.14.0-rc
...
v6.12.0
Author | SHA1 | Date | |
---|---|---|---|
a33446f86a |
@ -7,5 +7,5 @@ Dependencies:
|
|||||||
Options:
|
Options:
|
||||||
test-before-installing: True
|
test-before-installing: True
|
||||||
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
|
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
|
||||||
cmake-options: "-DKIMAGEFORMATS_DDS=ON -DKIMAGEFORMATS_JXR=ON -DKIMAGEFORMATS_HEIF=ON"
|
cmake-options: "-DKIMAGEFORMATS_DDS=ON -DKIMAGEFORMATS_JXR=ON"
|
||||||
per-test-timeout: 90
|
per-test-timeout: 90
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
set(KF_VERSION "6.14.0") # handled by release scripts
|
set(KF_VERSION "6.12.0") # handled by release scripts
|
||||||
set(KF_DEP_VERSION "6.14.0") # handled by release scripts
|
set(KF_DEP_VERSION "6.12.0") # handled by release scripts
|
||||||
project(KImageFormats VERSION ${KF_VERSION})
|
project(KImageFormats VERSION ${KF_VERSION})
|
||||||
|
|
||||||
include(FeatureSummary)
|
include(FeatureSummary)
|
||||||
find_package(ECM 6.14.0 NO_MODULE)
|
find_package(ECM 6.12.0 NO_MODULE)
|
||||||
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
|
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
|
||||||
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ include(ECMDeprecationSettings)
|
|||||||
include(CheckIncludeFiles)
|
include(CheckIncludeFiles)
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
|
|
||||||
set(REQUIRED_QT_VERSION 6.7.0)
|
set(REQUIRED_QT_VERSION 6.6.0)
|
||||||
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
|
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
|
||||||
|
|
||||||
find_package(KF6Archive ${KF_DEP_VERSION})
|
find_package(KF6Archive ${KF_DEP_VERSION})
|
||||||
@ -99,8 +99,8 @@ endif()
|
|||||||
add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images")
|
add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images")
|
||||||
|
|
||||||
ecm_set_disabled_deprecation_versions(
|
ecm_set_disabled_deprecation_versions(
|
||||||
QT 6.9.0
|
QT 6.8.0
|
||||||
KF 6.12.0
|
KF 6.11.0
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
@ -122,12 +122,9 @@ if (LibHeif_FOUND)
|
|||||||
kimageformats_read_tests(FUZZ 1
|
kimageformats_read_tests(FUZZ 1
|
||||||
hej2
|
hej2
|
||||||
)
|
)
|
||||||
kimageformats_write_tests(FUZZ 1
|
|
||||||
hej2-nodatacheck-lossless
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.6")
|
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.0")
|
||||||
kimageformats_read_tests(FUZZ 4
|
kimageformats_read_tests(FUZZ 4
|
||||||
avci
|
avci
|
||||||
)
|
)
|
||||||
|
@ -258,15 +258,6 @@ int main(int argc, char **argv)
|
|||||||
});
|
});
|
||||||
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
|
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
|
||||||
|
|
||||||
if (!formats.contains(format)) {
|
|
||||||
if (format == "avci" || format == "heif" || format == "hej2") {
|
|
||||||
QTextStream(stdout) << "WARNING : " << suffix << " is not supported with current libheif configuration!\n"
|
|
||||||
<< "********* "
|
|
||||||
<< "Finished basic read tests for " << suffix << " images *********\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
||||||
// Launch 2 runs for each test: first run on a random access device, second run on a sequential access device
|
// Launch 2 runs for each test: first run on a random access device, second run on a sequential access device
|
||||||
for (int seq = 0; seq < 2; ++seq) {
|
for (int seq = 0; seq < 2; ++seq) {
|
||||||
@ -332,12 +323,7 @@ int main(int argc, char **argv)
|
|||||||
OptionTest optionTest;
|
OptionTest optionTest;
|
||||||
if (!optionTest.store(&inputReader)) {
|
if (!optionTest.store(&inputReader)) {
|
||||||
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": error while reading options\n";
|
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": error while reading options\n";
|
||||||
if (format == "heif") {
|
++failed;
|
||||||
// libheif + ffmpeg decoder is unable to load all HEIF files.
|
|
||||||
++skipped;
|
|
||||||
} else {
|
|
||||||
++failed;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key" : "Description",
|
"key" : "Description",
|
||||||
"value" : "テレビ放送テスト映像。(TV broadcast test image.)"
|
"value" : "TV broadcast test image."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key" : "Latitude",
|
"key" : "Latitude",
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key" : "Description",
|
"key" : "Description",
|
||||||
"value" : "テレビ放送テスト映像。(TV broadcast test image.)"
|
"value" : "TV broadcast test image."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key" : "Latitude",
|
"key" : "Latitude",
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
{
|
|
||||||
"format" : "hej2",
|
|
||||||
"metadata" : [
|
|
||||||
{
|
|
||||||
"key" : "CreationDate",
|
|
||||||
"value" : "2025-01-14T13:53:32+01:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Direction",
|
|
||||||
"value" : "123.7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "ModificationDate",
|
|
||||||
"value" : "2025-02-14T15:58:44+01:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Software" ,
|
|
||||||
"value" : "Adobe Photoshop 26.2 (Windows)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Altitude",
|
|
||||||
"value" : "34"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Author",
|
|
||||||
"value" : "KDE Project"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Copyright",
|
|
||||||
"value" : "@2025 KDE Project"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Description",
|
|
||||||
"value" : "TV broadcast test image."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Latitude",
|
|
||||||
"value" : "44.6478"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "LensManufacturer",
|
|
||||||
"value" : "KDE Glasses"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "LensModel",
|
|
||||||
"value" : "A1234"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Longitude",
|
|
||||||
"value" : "10.9254"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Manufacturer",
|
|
||||||
"value" : "KFramework"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Model",
|
|
||||||
"value" : "KImageFormats"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resolution" : {
|
|
||||||
"dotsPerMeterX" : 11811,
|
|
||||||
"dotsPerMeterY" : 11812
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key" : "Description",
|
"key" : "Description",
|
||||||
"value" : "テレビ放送テスト映像。(TV broadcast test image.)"
|
"value" : "TV broadcast test image."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key" : "Latitude",
|
"key" : "Latitude",
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -370,12 +370,7 @@ int formatTest(const QString &suffix, bool createTemplates)
|
|||||||
QBuffer buffer(&ba);
|
QBuffer buffer(&ba);
|
||||||
auto writtenImage = QImageReader(&buffer, suffix.toLatin1()).read();
|
auto writtenImage = QImageReader(&buffer, suffix.toLatin1()).read();
|
||||||
if (writtenImage.isNull()) {
|
if (writtenImage.isNull()) {
|
||||||
if (suffix.toLatin1() == "heif") {
|
++failed;
|
||||||
// libheif + ffmpeg decoder is unable to load all HEIF files.
|
|
||||||
++skipped;
|
|
||||||
} else {
|
|
||||||
++failed;
|
|
||||||
}
|
|
||||||
QTextStream(stdout) << "FAIL : error while reading the image " << formatName << "\n";
|
QTextStream(stdout) << "FAIL : error while reading the image " << formatName << "\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -627,28 +622,8 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto suffix = args.at(0);
|
|
||||||
|
|
||||||
// skip test if libheif configuration is obviously incomplete
|
|
||||||
QByteArray format = suffix.toLatin1();
|
|
||||||
const QList<QByteArray> read_formats = QImageReader::supportedImageFormats();
|
|
||||||
const QList<QByteArray> write_formats = QImageWriter::supportedImageFormats();
|
|
||||||
|
|
||||||
if (!read_formats.contains(format)) {
|
|
||||||
if (format == "heif" || format == "hej2") {
|
|
||||||
QTextStream(stdout) << "WARNING : libheif configuration is missing necessary decoder(s)!\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!write_formats.contains(format)) {
|
|
||||||
if (format == "heif" || format == "hej2") {
|
|
||||||
QTextStream(stdout) << "WARNING : libheif configuration is missing necessary encoder(s)!\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// run test
|
// run test
|
||||||
|
auto suffix = args.at(0);
|
||||||
auto ret = basicTest(suffix, parser.isSet(lossless), parser.isSet(ignoreDataCheck), parser.isSet(skipOptTest), fuzzarg);
|
auto ret = basicTest(suffix, parser.isSet(lossless), parser.isSet(ignoreDataCheck), parser.isSet(skipOptTest), fuzzarg);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = formatTest(suffix, parser.isSet(createFormatTempates));
|
ret = formatTest(suffix, parser.isSet(createFormatTempates));
|
||||||
|
@ -15,16 +15,6 @@ function(kimageformats_add_plugin plugin)
|
|||||||
target_sources(${plugin} PRIVATE ${KIF_ADD_PLUGIN_SOURCES})
|
target_sources(${plugin} PRIVATE ${KIF_ADD_PLUGIN_SOURCES})
|
||||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats)
|
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats)
|
||||||
target_link_libraries(${plugin} PRIVATE Qt6::Gui)
|
target_link_libraries(${plugin} PRIVATE Qt6::Gui)
|
||||||
|
|
||||||
if(ANDROID)
|
|
||||||
# Plugins should be named with lib prefix on Android
|
|
||||||
# Working name: libplugins_imageformats_kimg_avif_armeabi-v7a.so
|
|
||||||
# Doesn't work: plugins_imageformats_kimg_avif_armeabi-v7a.so
|
|
||||||
if(NOT ${CMAKE_SHARED_LIBRARY_PREFIX} STREQUAL "")
|
|
||||||
set_target_properties(${plugin} PROPERTIES PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install(TARGETS ${plugin} DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/imageformats)
|
install(TARGETS ${plugin} DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/imageformats)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
@ -2557,5 +2557,3 @@ QImageIOHandler *QDDSPlugin::create(QIODevice *device, const QByteArray &format)
|
|||||||
handler->setFormat(format);
|
handler->setFormat(format);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_dds_p.cpp"
|
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <cstring>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef HEIF_MAX_METADATA_SIZE
|
#ifndef HEIF_MAX_METADATA_SIZE
|
||||||
/*!
|
/*!
|
||||||
@ -26,12 +26,12 @@
|
|||||||
#define HEIF_MAX_METADATA_SIZE (4 * 1024 * 1024)
|
#define HEIF_MAX_METADATA_SIZE (4 * 1024 * 1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
size_t HEIFHandler::m_initialized_count = 0;
|
size_t HEIFHandler::m_initialized_count = 0;
|
||||||
bool HEIFHandler::m_plugins_queried = false;
|
bool HEIFHandler::m_plugins_queried = false;
|
||||||
bool HEIFHandler::m_heif_decoder_available = false;
|
bool HEIFHandler::m_heif_decoder_available = false;
|
||||||
bool HEIFHandler::m_heif_encoder_available = false;
|
bool HEIFHandler::m_heif_encoder_available = false;
|
||||||
bool HEIFHandler::m_hej2_decoder_available = false;
|
bool HEIFHandler::m_hej2_decoder_available = false;
|
||||||
bool HEIFHandler::m_hej2_encoder_available = false;
|
|
||||||
bool HEIFHandler::m_avci_decoder_available = false;
|
bool HEIFHandler::m_avci_decoder_available = false;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -155,14 +155,6 @@ bool HEIFHandler::write_helper(const QImage &image)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
heif_compression_format encoder_codec = heif_compression_HEVC;
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
|
||||||
if (format() == "hej2") {
|
|
||||||
encoder_codec = heif_compression_JPEG2000;
|
|
||||||
save_depth = 8; // for compatibility reasons
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
heif_chroma chroma;
|
heif_chroma chroma;
|
||||||
if (save_depth > 8) {
|
if (save_depth > 8) {
|
||||||
if (save_alpha) {
|
if (save_alpha) {
|
||||||
@ -295,7 +287,7 @@ bool HEIFHandler::write_helper(const QImage &image)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct heif_encoder *encoder = nullptr;
|
struct heif_encoder *encoder = nullptr;
|
||||||
err = heif_context_get_encoder_for_format(context, encoder_codec, &encoder);
|
err = heif_context_get_encoder_for_format(context, heif_compression_HEVC, &encoder);
|
||||||
if (err.code) {
|
if (err.code) {
|
||||||
qWarning() << "Unable to get an encoder instance:" << err.message;
|
qWarning() << "Unable to get an encoder instance:" << err.message;
|
||||||
heif_image_release(h_image);
|
heif_image_release(h_image);
|
||||||
@ -322,7 +314,7 @@ bool HEIFHandler::write_helper(const QImage &image)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct heif_image_handle *handle;
|
struct heif_image_handle* handle;
|
||||||
err = heif_context_encode_image(context, h_image, encoder, encoder_options, &handle);
|
err = heif_context_encode_image(context, h_image, encoder, encoder_options, &handle);
|
||||||
|
|
||||||
// exif metadata
|
// exif metadata
|
||||||
@ -562,7 +554,7 @@ bool HEIFHandler::ensureDecoder()
|
|||||||
|
|
||||||
QImage::Format target_image_format;
|
QImage::Format target_image_format;
|
||||||
|
|
||||||
if (bit_depth == 10 || bit_depth == 12 || bit_depth == 16) {
|
if (bit_depth == 10 || bit_depth == 12) {
|
||||||
if (hasAlphaChannel) {
|
if (hasAlphaChannel) {
|
||||||
chroma = (QSysInfo::ByteOrder == QSysInfo::LittleEndian) ? heif_chroma_interleaved_RRGGBBAA_LE : heif_chroma_interleaved_RRGGBBAA_BE;
|
chroma = (QSysInfo::ByteOrder == QSysInfo::LittleEndian) ? heif_chroma_interleaved_RRGGBBAA_LE : heif_chroma_interleaved_RRGGBBAA_BE;
|
||||||
target_image_format = QImage::Format_RGBA64;
|
target_image_format = QImage::Format_RGBA64;
|
||||||
@ -654,35 +646,6 @@ bool HEIFHandler::ensureDecoder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (bit_depth) {
|
switch (bit_depth) {
|
||||||
case 16:
|
|
||||||
if (hasAlphaChannel) {
|
|
||||||
for (int y = 0; y < imageHeight; y++) {
|
|
||||||
memcpy(m_current_image.scanLine(y), src + (y * stride), 8 * size_t(imageWidth));
|
|
||||||
}
|
|
||||||
} else { // no alpha channel
|
|
||||||
for (int y = 0; y < imageHeight; y++) {
|
|
||||||
const uint16_t *src_word = reinterpret_cast<const uint16_t *>(src + (y * stride));
|
|
||||||
uint16_t *dest_data = reinterpret_cast<uint16_t *>(m_current_image.scanLine(y));
|
|
||||||
for (int x = 0; x < imageWidth; x++) {
|
|
||||||
// R
|
|
||||||
*dest_data = *src_word;
|
|
||||||
src_word++;
|
|
||||||
dest_data++;
|
|
||||||
// G
|
|
||||||
*dest_data = *src_word;
|
|
||||||
src_word++;
|
|
||||||
dest_data++;
|
|
||||||
// B
|
|
||||||
*dest_data = *src_word;
|
|
||||||
src_word++;
|
|
||||||
dest_data++;
|
|
||||||
// X = 0xffff
|
|
||||||
*dest_data = 0xffff;
|
|
||||||
dest_data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 12:
|
case 12:
|
||||||
if (hasAlphaChannel) {
|
if (hasAlphaChannel) {
|
||||||
for (int y = 0; y < imageHeight; y++) {
|
for (int y = 0; y < imageHeight; y++) {
|
||||||
@ -1028,13 +991,6 @@ bool HEIFHandler::isHej2DecoderAvailable()
|
|||||||
return m_hej2_decoder_available;
|
return m_hej2_decoder_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HEIFHandler::isHej2EncoderAvailable()
|
|
||||||
{
|
|
||||||
HEIFHandler::queryHeifLib();
|
|
||||||
|
|
||||||
return m_hej2_encoder_available;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HEIFHandler::isAVCIDecoderAvailable()
|
bool HEIFHandler::isAVCIDecoderAvailable()
|
||||||
{
|
{
|
||||||
HEIFHandler::queryHeifLib();
|
HEIFHandler::queryHeifLib();
|
||||||
@ -1057,9 +1013,8 @@ void HEIFHandler::queryHeifLib()
|
|||||||
m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
|
m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||||
m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
|
m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
|
||||||
m_hej2_encoder_available = heif_have_encoder_for_format(heif_compression_JPEG2000);
|
|
||||||
#endif
|
#endif
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 19, 6)
|
#if LIBHEIF_HAVE_VERSION(1, 19, 0)
|
||||||
m_avci_decoder_available = heif_have_decoder_for_format(heif_compression_AVC);
|
m_avci_decoder_available = heif_have_decoder_for_format(heif_compression_AVC);
|
||||||
#endif
|
#endif
|
||||||
m_plugins_queried = true;
|
m_plugins_queried = true;
|
||||||
@ -1126,9 +1081,6 @@ QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const Q
|
|||||||
if (HEIFHandler::isHej2DecoderAvailable()) {
|
if (HEIFHandler::isHej2DecoderAvailable()) {
|
||||||
format_cap |= CanRead;
|
format_cap |= CanRead;
|
||||||
}
|
}
|
||||||
if (HEIFHandler::isHej2EncoderAvailable()) {
|
|
||||||
format_cap |= CanWrite;
|
|
||||||
}
|
|
||||||
return format_cap;
|
return format_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1158,7 +1110,7 @@ QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const Q
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->isWritable() && (HEIFHandler::isHeifEncoderAvailable() || HEIFHandler::isHej2EncoderAvailable())) {
|
if (device->isWritable() && HEIFHandler::isHeifEncoderAvailable()) {
|
||||||
cap |= CanWrite;
|
cap |= CanWrite;
|
||||||
}
|
}
|
||||||
return cap;
|
return cap;
|
||||||
|
@ -31,7 +31,6 @@ public:
|
|||||||
static bool isHeifDecoderAvailable();
|
static bool isHeifDecoderAvailable();
|
||||||
static bool isHeifEncoderAvailable();
|
static bool isHeifEncoderAvailable();
|
||||||
static bool isHej2DecoderAvailable();
|
static bool isHej2DecoderAvailable();
|
||||||
static bool isHej2EncoderAvailable();
|
|
||||||
static bool isAVCIDecoderAvailable();
|
static bool isAVCIDecoderAvailable();
|
||||||
|
|
||||||
static bool isSupportedBMFFType(const QByteArray &header);
|
static bool isSupportedBMFFType(const QByteArray &header);
|
||||||
@ -63,7 +62,6 @@ private:
|
|||||||
static bool m_heif_decoder_available;
|
static bool m_heif_decoder_available;
|
||||||
static bool m_heif_encoder_available;
|
static bool m_heif_encoder_available;
|
||||||
static bool m_hej2_decoder_available;
|
static bool m_hej2_decoder_available;
|
||||||
static bool m_hej2_encoder_available;
|
|
||||||
static bool m_avci_decoder_available;
|
static bool m_avci_decoder_available;
|
||||||
|
|
||||||
static QMutex &getHEIFHandlerMutex();
|
static QMutex &getHEIFHandlerMutex();
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
|
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 3)
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 7) && QT_VERSION < QT_VERSION_CHECK(6, 6, 0)) || (QT_VERSION >= QT_VERSION_CHECK(6, 7, 3))
|
||||||
#ifndef JXL_QT_AUTOTRANSFORM
|
#ifndef JXL_QT_AUTOTRANSFORM
|
||||||
#define JXL_QT_AUTOTRANSFORM
|
#define JXL_QT_AUTOTRANSFORM
|
||||||
#endif
|
#endif
|
||||||
|
@ -720,11 +720,11 @@ public:
|
|||||||
|
|
||||||
auto exif = MicroExif::fromImage(image);
|
auto exif = MicroExif::fromImage(image);
|
||||||
if (!exif.isEmpty()) {
|
if (!exif.isEmpty()) {
|
||||||
auto exifIfd = exif.exifIfdByteArray(QDataStream::LittleEndian, MicroExif::V2);
|
auto exifIfd = exif.exifIfdByteArray(QDataStream::LittleEndian);
|
||||||
if (auto err = PKImageEncode_SetEXIFMetadata_WMP(pEncoder, reinterpret_cast<const quint8 *>(exifIfd.constData()), exifIfd.size())) {
|
if (auto err = PKImageEncode_SetEXIFMetadata_WMP(pEncoder, reinterpret_cast<const quint8 *>(exifIfd.constData()), exifIfd.size())) {
|
||||||
qCWarning(LOG_JXRPLUGIN) << "JXRHandler::write() error while setting EXIF data:" << err;
|
qCWarning(LOG_JXRPLUGIN) << "JXRHandler::write() error while setting EXIF data:" << err;
|
||||||
}
|
}
|
||||||
auto gpsIfd = exif.gpsIfdByteArray(QDataStream::LittleEndian, MicroExif::V2);
|
auto gpsIfd = exif.gpsIfdByteArray(QDataStream::LittleEndian);
|
||||||
if (auto err = PKImageEncode_SetGPSInfoMetadata_WMP(pEncoder, reinterpret_cast<const quint8 *>(gpsIfd.constData()), gpsIfd.size())) {
|
if (auto err = PKImageEncode_SetGPSInfoMetadata_WMP(pEncoder, reinterpret_cast<const quint8 *>(gpsIfd.constData()), gpsIfd.size())) {
|
||||||
qCWarning(LOG_JXRPLUGIN) << "JXRHandler::write() error while setting GPS data:" << err;
|
qCWarning(LOG_JXRPLUGIN) << "JXRHandler::write() error while setting GPS data:" << err;
|
||||||
}
|
}
|
||||||
@ -991,7 +991,7 @@ bool JXRHandler::read(QImage *outImage)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (qint32 y = 0, h = img.height(); y < h; ++y) {
|
for (qint32 y = 0, h = img.height(); y < h; ++y) {
|
||||||
std::memcpy(img.scanLine(y), ba.data() + convStrideSize * y, (std::min)(convStrideSize, qint64(img.bytesPerLine())));
|
std::memcpy(img.scanLine(y), ba.data() + convStrideSize * y, (std::min)(convStrideSize, img.bytesPerLine()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PKFormatConverter_Release(&pConverter);
|
PKFormatConverter_Release(&pConverter);
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QStringDecoder>
|
|
||||||
#include <QTimeZone>
|
#include <QTimeZone>
|
||||||
|
|
||||||
// TIFF 6 specs
|
// TIFF 6 specs
|
||||||
@ -112,17 +111,17 @@ static const KnownTags staticTagTypes = {
|
|||||||
TagInfo(TIFF_IMAGEWIDTH, ExifTagType::Long),
|
TagInfo(TIFF_IMAGEWIDTH, ExifTagType::Long),
|
||||||
TagInfo(TIFF_IMAGEHEIGHT, ExifTagType::Long),
|
TagInfo(TIFF_IMAGEHEIGHT, ExifTagType::Long),
|
||||||
TagInfo(TIFF_BITSPERSAMPLE, ExifTagType::Short),
|
TagInfo(TIFF_BITSPERSAMPLE, ExifTagType::Short),
|
||||||
TagInfo(TIFF_IMAGEDESCRIPTION, ExifTagType::Utf8),
|
TagInfo(TIFF_IMAGEDESCRIPTION, ExifTagType::Ascii),
|
||||||
TagInfo(TIFF_MAKE, ExifTagType::Utf8),
|
TagInfo(TIFF_MAKE, ExifTagType::Ascii),
|
||||||
TagInfo(TIFF_MODEL, ExifTagType::Utf8),
|
TagInfo(TIFF_MODEL, ExifTagType::Ascii),
|
||||||
TagInfo(TIFF_ORIENT, ExifTagType::Short),
|
TagInfo(TIFF_ORIENT, ExifTagType::Short),
|
||||||
TagInfo(TIFF_XRES, ExifTagType::Rational),
|
TagInfo(TIFF_XRES, ExifTagType::Rational),
|
||||||
TagInfo(TIFF_YRES, ExifTagType::Rational),
|
TagInfo(TIFF_YRES, ExifTagType::Rational),
|
||||||
TagInfo(TIFF_URES, ExifTagType::Short),
|
TagInfo(TIFF_URES, ExifTagType::Short),
|
||||||
TagInfo(TIFF_SOFTWARE, ExifTagType::Utf8),
|
TagInfo(TIFF_SOFTWARE, ExifTagType::Ascii),
|
||||||
TagInfo(TIFF_ARTIST, ExifTagType::Utf8),
|
TagInfo(TIFF_ARTIST, ExifTagType::Ascii),
|
||||||
TagInfo(TIFF_DATETIME, ExifTagType::Ascii),
|
TagInfo(TIFF_DATETIME, ExifTagType::Ascii),
|
||||||
TagInfo(TIFF_COPYRIGHT, ExifTagType::Utf8),
|
TagInfo(TIFF_COPYRIGHT, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_EXIFIFD, ExifTagType::Long),
|
TagInfo(EXIF_EXIFIFD, ExifTagType::Long),
|
||||||
TagInfo(EXIF_GPSIFD, ExifTagType::Long),
|
TagInfo(EXIF_GPSIFD, ExifTagType::Long),
|
||||||
TagInfo(EXIF_DATETIMEORIGINAL, ExifTagType::Ascii),
|
TagInfo(EXIF_DATETIMEORIGINAL, ExifTagType::Ascii),
|
||||||
@ -135,10 +134,10 @@ static const KnownTags staticTagTypes = {
|
|||||||
TagInfo(EXIF_PIXELYDIM, ExifTagType::Long),
|
TagInfo(EXIF_PIXELYDIM, ExifTagType::Long),
|
||||||
TagInfo(EXIF_IMAGEUNIQUEID, ExifTagType::Ascii),
|
TagInfo(EXIF_IMAGEUNIQUEID, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_BODYSERIALNUMBER, ExifTagType::Ascii),
|
TagInfo(EXIF_BODYSERIALNUMBER, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_LENSMAKE, ExifTagType::Utf8),
|
TagInfo(EXIF_LENSMAKE, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_LENSMODEL, ExifTagType::Utf8),
|
TagInfo(EXIF_LENSMODEL, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_LENSSERIALNUMBER, ExifTagType::Ascii),
|
TagInfo(EXIF_LENSSERIALNUMBER, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_IMAGETITLE, ExifTagType::Utf8),
|
TagInfo(EXIF_IMAGETITLE, ExifTagType::Ascii),
|
||||||
TagInfo(EXIF_EXIFVERSION, ExifTagType::Undefined)
|
TagInfo(EXIF_EXIFVERSION, ExifTagType::Undefined)
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@ -368,28 +367,6 @@ static void writeData(QDataStream &ds, const QVariant &value, const ExifTagType&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExifTagType updateDataType(const ExifTagType &dataType, const QVariant &value, const MicroExif::Version &ver)
|
|
||||||
{
|
|
||||||
if (dataType != ExifTagType::Utf8)
|
|
||||||
return dataType;
|
|
||||||
|
|
||||||
if (ver == MicroExif::V2)
|
|
||||||
return ExifTagType::Ascii;
|
|
||||||
|
|
||||||
// Note that in EXIF specs, UTF-8 is backward compatible with ASCII: all UTF-8 tags can also be ASCII.
|
|
||||||
// To maximize compatibility, I check if the string can be encoded in ASCII.
|
|
||||||
auto txt = value.toString();
|
|
||||||
|
|
||||||
// Exif ASCII data type allow only values up to 127 (7-bit ASCII).
|
|
||||||
auto u8 = txt.toUtf8();
|
|
||||||
for (auto &&c : u8) {
|
|
||||||
if (uchar(c) > 127)
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExifTagType::Ascii;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief writeIfd
|
* \brief writeIfd
|
||||||
* \param ds The stream.
|
* \param ds The stream.
|
||||||
@ -398,12 +375,7 @@ static ExifTagType updateDataType(const ExifTagType &dataType, const QVariant &v
|
|||||||
* \param knownTags List of known and supported tags.
|
* \param knownTags List of known and supported tags.
|
||||||
* \return True on success, otherwise false.
|
* \return True on success, otherwise false.
|
||||||
*/
|
*/
|
||||||
static bool writeIfd(QDataStream &ds,
|
static bool writeIfd(QDataStream &ds, const MicroExif::Tags &tags, TagPos &positions, quint32 pos = 0, const KnownTags &knownTags = staticTagTypes)
|
||||||
const MicroExif::Version &ver,
|
|
||||||
const MicroExif::Tags &tags,
|
|
||||||
TagPos &positions,
|
|
||||||
quint32 pos = 0,
|
|
||||||
const KnownTags &knownTags = staticTagTypes)
|
|
||||||
{
|
{
|
||||||
if (tags.isEmpty())
|
if (tags.isEmpty())
|
||||||
return true;
|
return true;
|
||||||
@ -418,7 +390,7 @@ static bool writeIfd(QDataStream &ds,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto value = tags.value(key);
|
auto value = tags.value(key);
|
||||||
auto dataType = updateDataType(knownTags.value(key), value, ver);
|
auto dataType = knownTags.value(key);
|
||||||
auto count = countBytes(dataType, value);
|
auto count = countBytes(dataType, value);
|
||||||
|
|
||||||
ds << quint16(key);
|
ds << quint16(key);
|
||||||
@ -440,8 +412,9 @@ static bool writeIfd(QDataStream &ds,
|
|||||||
if (!knownTags.contains(key)) {
|
if (!knownTags.contains(key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value = tags.value(key);
|
auto value = tags.value(key);
|
||||||
auto dataType = updateDataType(knownTags.value(key), value, ver);
|
auto dataType = knownTags.value(key);
|
||||||
auto count = countBytes(dataType, value);
|
auto count = countBytes(dataType, value);
|
||||||
auto valueSize = count * EXIF_TAG_SIZEOF(dataType);
|
auto valueSize = count * EXIF_TAG_SIZEOF(dataType);
|
||||||
if (valueSize <= 4)
|
if (valueSize <= 4)
|
||||||
@ -561,16 +534,8 @@ static bool readIfd(QDataStream &ds, MicroExif::Tags &tags, quint32 pos = 0, con
|
|||||||
|
|
||||||
if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Ascii) || dataType == EXIF_TAG_DATATYPE(ExifTagType::Utf8)) {
|
if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Ascii) || dataType == EXIF_TAG_DATATYPE(ExifTagType::Utf8)) {
|
||||||
auto l = readBytes(ds, count, true);
|
auto l = readBytes(ds, count, true);
|
||||||
if (!l.isEmpty()) {
|
if (!l.isEmpty())
|
||||||
// It seems that converting to Latin 1 never detects errors so, using UTF-8.
|
tags.insert(tagId, dataType == EXIF_TAG_DATATYPE(ExifTagType::Utf8) ? QString::fromUtf8(l) : QString::fromLatin1(l));
|
||||||
// Note that if the dataType is ASCII, by EXIF specification, it must use only the
|
|
||||||
// first 128 values so the UTF-8 conversion is correct.
|
|
||||||
auto dec = QStringDecoder(QStringDecoder::Utf8);
|
|
||||||
// QStringDecoder raise an error only after converting to QString
|
|
||||||
auto ut8 = QString(dec(l));
|
|
||||||
// If there are errors in the conversion to UTF-8, then I try with latin1 (extended ASCII)
|
|
||||||
tags.insert(tagId, dec.hasError() ? QString::fromLatin1(l) : ut8);
|
|
||||||
}
|
|
||||||
} else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Undefined)) {
|
} else if (dataType == EXIF_TAG_DATATYPE(ExifTagType::Undefined)) {
|
||||||
auto l = readBytes(ds, count, false);
|
auto l = readBytes(ds, count, false);
|
||||||
if (!l.isEmpty())
|
if (!l.isEmpty())
|
||||||
@ -1067,7 +1032,7 @@ void MicroExif::setImageDirection(double degree, bool isMagnetic)
|
|||||||
m_gpsTags.insert(GPS_IMGDIRECTION, degree);
|
m_gpsTags.insert(GPS_IMGDIRECTION, degree);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray MicroExif::toByteArray(const QDataStream::ByteOrder &byteOrder, const Version &version) const
|
QByteArray MicroExif::toByteArray(const QDataStream::ByteOrder &byteOrder) const
|
||||||
{
|
{
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
{
|
{
|
||||||
@ -1078,16 +1043,16 @@ QByteArray MicroExif::toByteArray(const QDataStream::ByteOrder &byteOrder, const
|
|||||||
return ba;
|
return ba;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray MicroExif::exifIfdByteArray(const QDataStream::ByteOrder &byteOrder, const Version &version) const
|
QByteArray MicroExif::exifIfdByteArray(const QDataStream::ByteOrder &byteOrder) const
|
||||||
{
|
{
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
{
|
{
|
||||||
QDataStream ds(&ba, QIODevice::WriteOnly);
|
QDataStream ds(&ba, QIODevice::WriteOnly);
|
||||||
ds.setByteOrder(byteOrder);
|
ds.setByteOrder(byteOrder);
|
||||||
auto exifTags = m_exifTags;
|
auto exifTags = m_exifTags;
|
||||||
exifTags.insert(EXIF_EXIFVERSION, version == Version::V3 ? QByteArray("0300") : QByteArray("0232"));
|
exifTags.insert(EXIF_EXIFVERSION, QByteArray("0300"));
|
||||||
TagPos positions;
|
TagPos positions;
|
||||||
if (!writeIfd(ds, version, exifTags, positions))
|
if (!writeIfd(ds, exifTags, positions))
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return ba;
|
return ba;
|
||||||
@ -1100,7 +1065,7 @@ bool MicroExif::setExifIfdByteArray(const QByteArray &ba, const QDataStream::Byt
|
|||||||
return readIfd(ds, m_exifTags, 0, staticTagTypes);
|
return readIfd(ds, m_exifTags, 0, staticTagTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray MicroExif::gpsIfdByteArray(const QDataStream::ByteOrder &byteOrder, const Version &version) const
|
QByteArray MicroExif::gpsIfdByteArray(const QDataStream::ByteOrder &byteOrder) const
|
||||||
{
|
{
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
{
|
{
|
||||||
@ -1109,7 +1074,7 @@ QByteArray MicroExif::gpsIfdByteArray(const QDataStream::ByteOrder &byteOrder, c
|
|||||||
auto gpsTags = m_gpsTags;
|
auto gpsTags = m_gpsTags;
|
||||||
gpsTags.insert(GPS_GPSVERSION, QByteArray("2400"));
|
gpsTags.insert(GPS_GPSVERSION, QByteArray("2400"));
|
||||||
TagPos positions;
|
TagPos positions;
|
||||||
if (!writeIfd(ds, version, gpsTags, positions, 0, staticGpsTagTypes))
|
if (!writeIfd(ds, gpsTags, positions, 0, staticGpsTagTypes))
|
||||||
return {};
|
return {};
|
||||||
return ba;
|
return ba;
|
||||||
}
|
}
|
||||||
@ -1122,7 +1087,7 @@ bool MicroExif::setGpsIfdByteArray(const QByteArray &ba, const QDataStream::Byte
|
|||||||
return readIfd(ds, m_gpsTags, 0, staticGpsTagTypes);
|
return readIfd(ds, m_gpsTags, 0, staticGpsTagTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicroExif::write(QIODevice *device, const QDataStream::ByteOrder &byteOrder, const Version &version) const
|
bool MicroExif::write(QIODevice *device, const QDataStream::ByteOrder &byteOrder) const
|
||||||
{
|
{
|
||||||
if (device == nullptr || device->isSequential() || isEmpty())
|
if (device == nullptr || device->isSequential() || isEmpty())
|
||||||
return false;
|
return false;
|
||||||
@ -1131,7 +1096,7 @@ bool MicroExif::write(QIODevice *device, const QDataStream::ByteOrder &byteOrder
|
|||||||
ds.setByteOrder(byteOrder);
|
ds.setByteOrder(byteOrder);
|
||||||
if (!writeHeader(ds))
|
if (!writeHeader(ds))
|
||||||
return false;
|
return false;
|
||||||
if (!writeIfds(ds, version))
|
if (!writeIfds(ds))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
device->close();
|
device->close();
|
||||||
@ -1362,30 +1327,30 @@ bool MicroExif::writeHeader(QDataStream &ds) const
|
|||||||
return ds.status() == QDataStream::Ok;
|
return ds.status() == QDataStream::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicroExif::writeIfds(QDataStream &ds, const Version &version) const
|
bool MicroExif::writeIfds(QDataStream &ds) const
|
||||||
{
|
{
|
||||||
auto tiffTags = m_tiffTags;
|
auto tiffTags = m_tiffTags;
|
||||||
auto exifTags = m_exifTags;
|
auto exifTags = m_exifTags;
|
||||||
auto gpsTags = m_gpsTags;
|
auto gpsTags = m_gpsTags;
|
||||||
updateTags(tiffTags, exifTags, gpsTags, version);
|
updateTags(tiffTags, exifTags, gpsTags);
|
||||||
|
|
||||||
TagPos positions;
|
TagPos positions;
|
||||||
if (!writeIfd(ds, version, tiffTags, positions))
|
if (!writeIfd(ds, tiffTags, positions))
|
||||||
return false;
|
return false;
|
||||||
if (!writeIfd(ds, version, exifTags, positions, positions.value(EXIF_EXIFIFD)))
|
if (!writeIfd(ds, exifTags, positions, positions.value(EXIF_EXIFIFD)))
|
||||||
return false;
|
return false;
|
||||||
if (!writeIfd(ds, version, gpsTags, positions, positions.value(EXIF_GPSIFD), staticGpsTagTypes))
|
if (!writeIfd(ds, gpsTags, positions, positions.value(EXIF_GPSIFD), staticGpsTagTypes))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroExif::updateTags(Tags &tiffTags, Tags &exifTags, Tags &gpsTags, const Version &version) const
|
void MicroExif::updateTags(Tags &tiffTags, Tags &exifTags, Tags &gpsTags) const
|
||||||
{
|
{
|
||||||
if (exifTags.isEmpty()) {
|
if (exifTags.isEmpty()) {
|
||||||
tiffTags.remove(EXIF_EXIFIFD);
|
tiffTags.remove(EXIF_EXIFIFD);
|
||||||
} else {
|
} else {
|
||||||
tiffTags.insert(EXIF_EXIFIFD, quint32());
|
tiffTags.insert(EXIF_EXIFIFD, quint32());
|
||||||
exifTags.insert(EXIF_EXIFVERSION, version == Version::V3 ? QByteArray("0300") : QByteArray("0232"));
|
exifTags.insert(EXIF_EXIFVERSION, QByteArray("0300"));
|
||||||
}
|
}
|
||||||
if (gpsTags.isEmpty()) {
|
if (gpsTags.isEmpty()) {
|
||||||
tiffTags.remove(EXIF_GPSIFD);
|
tiffTags.remove(EXIF_GPSIFD);
|
||||||
|
@ -37,15 +37,6 @@ class MicroExif
|
|||||||
public:
|
public:
|
||||||
using Tags = QMap<quint16, QVariant>;
|
using Tags = QMap<quint16, QVariant>;
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The Version enum
|
|
||||||
* Exif specs version used when writing.
|
|
||||||
*/
|
|
||||||
enum Version {
|
|
||||||
V2, // V2.xx
|
|
||||||
V3 // V3.xx, use of UTF-8 data type (default)
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief MicroExif
|
* \brief MicroExif
|
||||||
* Constructs an empty class.
|
* Constructs an empty class.
|
||||||
@ -274,20 +265,18 @@ public:
|
|||||||
* - EXIF IFD
|
* - EXIF IFD
|
||||||
* - GPS IFD
|
* - GPS IFD
|
||||||
* \param byteOrder Sets the serialization byte order for EXIF data.
|
* \param byteOrder Sets the serialization byte order for EXIF data.
|
||||||
* \param version The EXIF specs version to use.
|
|
||||||
* \return A byte array containing the serialized data.
|
* \return A byte array containing the serialized data.
|
||||||
* \sa write
|
* \sa write
|
||||||
*/
|
*/
|
||||||
QByteArray toByteArray(const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER, const Version &version = Version::V3) const;
|
QByteArray toByteArray(const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief exifIfdByteArray
|
* \brief exifIfdByteArray
|
||||||
* Convert the EXIF IFD only to RAW data. Useful when you want to add EXIF data to an existing TIFF container.
|
* Convert the EXIF IFD only to RAW data. Useful when you want to add EXIF data to an existing TIFF container.
|
||||||
* \param byteOrder Sets the serialization byte order for the data.
|
* \param byteOrder Sets the serialization byte order for the data.
|
||||||
* \param version The EXIF specs version to use.
|
|
||||||
* \return A byte array containing the serialized data.
|
* \return A byte array containing the serialized data.
|
||||||
*/
|
*/
|
||||||
QByteArray exifIfdByteArray(const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER, const Version &version = Version::V3) const;
|
QByteArray exifIfdByteArray(const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER) const;
|
||||||
/*!
|
/*!
|
||||||
* \brief setExifIfdByteArray
|
* \brief setExifIfdByteArray
|
||||||
* \param ba The RAW data of EXIF IFD.
|
* \param ba The RAW data of EXIF IFD.
|
||||||
@ -300,10 +289,9 @@ public:
|
|||||||
* \brief gpsIfdByteArray
|
* \brief gpsIfdByteArray
|
||||||
* Convert the GPS IFD only to RAW data. Useful when you want to add GPS data to an existing TIFF container.
|
* Convert the GPS IFD only to RAW data. Useful when you want to add GPS data to an existing TIFF container.
|
||||||
* \param byteOrder Sets the serialization byte order for the data.
|
* \param byteOrder Sets the serialization byte order for the data.
|
||||||
* \param version The EXIF specs version to use.
|
|
||||||
* \return A byte array containing the serialized data.
|
* \return A byte array containing the serialized data.
|
||||||
*/
|
*/
|
||||||
QByteArray gpsIfdByteArray(const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER, const Version &version = Version::V3) const;
|
QByteArray gpsIfdByteArray(const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER) const;
|
||||||
/*!
|
/*!
|
||||||
* \brief setGpsIfdByteArray
|
* \brief setGpsIfdByteArray
|
||||||
* \param ba The RAW data of GPS IFD.
|
* \param ba The RAW data of GPS IFD.
|
||||||
@ -321,11 +309,10 @@ public:
|
|||||||
* - GPS IFD
|
* - GPS IFD
|
||||||
* \param device A random access device.
|
* \param device A random access device.
|
||||||
* \param byteOrder Sets the serialization byte order for EXIF data.
|
* \param byteOrder Sets the serialization byte order for EXIF data.
|
||||||
* \param version The EXIF specs version to use.
|
|
||||||
* \return True on success, otherwise false.
|
* \return True on success, otherwise false.
|
||||||
* \sa toByteArray
|
* \sa toByteArray
|
||||||
*/
|
*/
|
||||||
bool write(QIODevice *device, const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER, const Version &version = Version::V3) const;
|
bool write(QIODevice *device, const QDataStream::ByteOrder &byteOrder = EXIF_DEFAULT_BYTEORDER) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief updateImageMetadata
|
* \brief updateImageMetadata
|
||||||
@ -386,8 +373,8 @@ private:
|
|||||||
void setGpsString(quint16 tagId, const QString& s);
|
void setGpsString(quint16 tagId, const QString& s);
|
||||||
QString gpsString(quint16 tagId) const;
|
QString gpsString(quint16 tagId) const;
|
||||||
bool writeHeader(QDataStream &ds) const;
|
bool writeHeader(QDataStream &ds) const;
|
||||||
bool writeIfds(QDataStream &ds, const Version &version) const;
|
bool writeIfds(QDataStream &ds) const;
|
||||||
void updateTags(Tags &tiffTags, Tags &exifTags, Tags &gpsTags, const Version &version) const;
|
void updateTags(Tags &tiffTags, Tags &exifTags, Tags &gpsTags) const;
|
||||||
|
|
||||||
static void setString(Tags &tags, quint16 tagId, const QString &s);
|
static void setString(Tags &tags, quint16 tagId, const QString &s);
|
||||||
static QString string(const Tags &tags, quint16 tagId);
|
static QString string(const Tags &tags, quint16 tagId);
|
||||||
|
@ -1504,18 +1504,7 @@ bool PSDHandler::read(QImage *image)
|
|||||||
img.setColorSpace(QColorSpace(QColorSpace::SRgb));
|
img.setColorSpace(QColorSpace(QColorSpace::SRgb));
|
||||||
#endif
|
#endif
|
||||||
} else if (!setColorSpace(img, irs)) {
|
} else if (!setColorSpace(img, irs)) {
|
||||||
// Float images are used by Photoshop as linear: if no color space
|
// qDebug() << "No colorspace info set!";
|
||||||
// is present, a linear one should be chosen.
|
|
||||||
if (header.color_mode == CM_RGB && header.depth == 32) {
|
|
||||||
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
|
|
||||||
}
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
|
||||||
if (header.color_mode == CM_GRAYSCALE && header.depth == 32) {
|
|
||||||
auto qs = QColorSpace(QPointF(0.3127, 0.3291), QColorSpace::TransferFunction::Linear);
|
|
||||||
qs.setDescription(QStringLiteral("Linear grayscale"));
|
|
||||||
img.setColorSpace(qs);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XMP data
|
// XMP data
|
||||||
|
@ -457,4 +457,3 @@ QImageIOHandler *ScitexPlugin::create(QIODevice *device, const QByteArray &forma
|
|||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_sct_p.cpp"
|
|
||||||
|
@ -962,7 +962,11 @@ bool XCFImageFormat::loadImageProperties(QDataStream &xcf_io, XCFImage &xcf_imag
|
|||||||
case PROP_PARASITES:
|
case PROP_PARASITES:
|
||||||
while (!property.atEnd()) {
|
while (!property.atEnd()) {
|
||||||
char *tag;
|
char *tag;
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
|
||||||
|
quint32 size;
|
||||||
|
#else
|
||||||
qint64 size;
|
qint64 size;
|
||||||
|
#endif
|
||||||
|
|
||||||
property.readBytes(tag, size);
|
property.readBytes(tag, size);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user