Compare commits
52 Commits
v5.111.0
...
work/fuf/r
Author | SHA1 | Date | |
---|---|---|---|
485e084fa9 | |||
75e1280073 | |||
0a6fbd88e9 | |||
fbf60f8bbb | |||
2799382c21 | |||
adc7da4f41 | |||
ac808679cd | |||
2aea982e9e | |||
9173f02ea3 | |||
4badb3088e | |||
8dc685df26 | |||
4bd9d5baec | |||
79e8e183eb | |||
7d63a1d8fa | |||
c11c5eff4f | |||
c02bf3dbcc | |||
6254529d2d | |||
35ff3efbbc | |||
7a0d95af92 | |||
4c3ade04dd | |||
b209e54b6f | |||
4dc2099fa4 | |||
491b223c15 | |||
6559bf8994 | |||
34ed3bad27 | |||
9c579fc1f8 | |||
93adb22632 | |||
d57ff91f8b | |||
edd6adcbac | |||
d787c12727 | |||
c9fec5e408 | |||
e60dfd4968 | |||
f5a9dd46d2 | |||
41f0411b62 | |||
e1a3751936 | |||
402dfb5de3 | |||
a3f7c03b61 | |||
20cec27ae8 | |||
d34c1668aa | |||
560d0483ae | |||
085c9c4841 | |||
b654f20ece | |||
21211cd63b | |||
5cc7a2b45c | |||
4451737d2f | |||
01ab0876f1 | |||
a67dcac7d1 | |||
cef8d08ad4 | |||
a4b9dd9400 | |||
6e6c1ab5f4 | |||
f205adf2e0 | |||
14742cb502 |
@ -2,9 +2,7 @@
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
include:
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-static.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-static.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
|
||||
|
@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
project(KImageFormats)
|
||||
|
||||
include(FeatureSummary)
|
||||
find_package(ECM 5.111.0 NO_MODULE)
|
||||
find_package(ECM 5.240.0 NO_MODULE)
|
||||
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)
|
||||
|
||||
@ -19,11 +19,11 @@ include(ECMDeprecationSettings)
|
||||
include(CheckIncludeFiles)
|
||||
include(FindPkgConfig)
|
||||
|
||||
set(REQUIRED_QT_VERSION 5.15.2)
|
||||
find_package(Qt${QT_MAJOR_VERSION}Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
|
||||
set(REQUIRED_QT_VERSION 6.5.0)
|
||||
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
|
||||
|
||||
find_package(KF5Archive)
|
||||
set_package_properties(KF5Archive PROPERTIES
|
||||
find_package(KF6Archive)
|
||||
set_package_properties(KF6Archive PROPERTIES
|
||||
TYPE OPTIONAL
|
||||
PURPOSE "Required for the QImage plugin for Krita and OpenRaster images"
|
||||
)
|
||||
@ -32,12 +32,12 @@ set_package_properties(KF5Archive PROPERTIES
|
||||
# this available in PATH
|
||||
set(BUILD_EPS_PLUGIN FALSE)
|
||||
if (UNIX)
|
||||
find_package(Qt${QT_MAJOR_VERSION}PrintSupport ${REQUIRED_QT_VERSION} NO_MODULE)
|
||||
set_package_properties(Qt${QT_MAJOR_VERSION}PrintSupport PROPERTIES
|
||||
find_package(Qt6PrintSupport ${REQUIRED_QT_VERSION} NO_MODULE)
|
||||
set_package_properties(Qt6PrintSupport PROPERTIES
|
||||
PURPOSE "Required for the QImage plugin for EPS images"
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
if (TARGET Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||
if (TARGET Qt6::PrintSupport)
|
||||
set(BUILD_EPS_PLUGIN TRUE)
|
||||
endif()
|
||||
endif()
|
||||
@ -81,8 +81,8 @@ set_package_properties(LibRaw PROPERTIES
|
||||
)
|
||||
|
||||
ecm_set_disabled_deprecation_versions(
|
||||
QT 5.15.2
|
||||
KF 5.95
|
||||
QT 6.4
|
||||
KF 5.102
|
||||
)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
@ -16,22 +16,24 @@ The following image formats have read-only support:
|
||||
- Animated Windows cursors (ani)
|
||||
- Camera RAW images (arw, cr2, cr3, dcs, dng, ...)
|
||||
- Gimp (xcf)
|
||||
- Krita (kra)
|
||||
- OpenEXR (exr)
|
||||
- OpenRaster (ora)
|
||||
- Photoshop documents (psd, psb, pdd, psdt)
|
||||
- Radiance HDR (hdr)
|
||||
- Sun Raster (ras)
|
||||
- Sun Raster (im1, im8, im24, im32, ras, sun)
|
||||
|
||||
The following image formats have read and write support:
|
||||
|
||||
- AV1 Image File Format (AVIF)
|
||||
- Encapsulated PostScript (eps)
|
||||
- High Efficiency Image File Format (heif). Can be enabled with the KIMAGEFORMATS_HEIF build option.
|
||||
- JPEG XL (jxl)
|
||||
- Personal Computer Exchange (pcx)
|
||||
- Quite OK Image format (qoi)
|
||||
- SGI images (rgb, rgba, sgi, bw)
|
||||
- Softimage PIC (pic)
|
||||
- Targa (tga): supports more formats than Qt's version
|
||||
- XView (xv)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
#find_package(Qt5Test ${REQUIRED_QT_VERSION} NO_MODULE)
|
||||
|
||||
include(ECMMarkAsTest)
|
||||
|
||||
add_definitions(-DPLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}/../bin")
|
||||
@ -14,7 +12,7 @@ macro(kimageformats_read_tests)
|
||||
|
||||
if (NOT TARGET readtest)
|
||||
add_executable(readtest readtest.cpp)
|
||||
target_link_libraries(readtest Qt${QT_MAJOR_VERSION}::Gui)
|
||||
target_link_libraries(readtest Qt6::Gui)
|
||||
target_compile_definitions(readtest
|
||||
PRIVATE IMAGEDIR="${CMAKE_CURRENT_SOURCE_DIR}/read")
|
||||
ecm_mark_as_test(readtest)
|
||||
@ -37,7 +35,7 @@ macro(kimageformats_write_tests)
|
||||
|
||||
if (NOT TARGET writetest)
|
||||
add_executable(writetest writetest.cpp)
|
||||
target_link_libraries(writetest Qt${QT_MAJOR_VERSION}::Gui)
|
||||
target_link_libraries(writetest Qt6::Gui)
|
||||
target_compile_definitions(writetest
|
||||
PRIVATE IMAGEDIR="${CMAKE_CURRENT_SOURCE_DIR}/write")
|
||||
ecm_mark_as_test(writetest)
|
||||
@ -75,7 +73,7 @@ kimageformats_read_tests(
|
||||
tga
|
||||
)
|
||||
|
||||
if (KF5Archive_FOUND)
|
||||
if (KF6Archive_FOUND)
|
||||
kimageformats_read_tests(
|
||||
kra
|
||||
ora
|
||||
@ -148,19 +146,19 @@ if (LibRaw_FOUND)
|
||||
)
|
||||
endif()
|
||||
|
||||
find_package(Qt${QT_MAJOR_VERSION}Test ${REQUIRED_QT_VERSION} CONFIG QUIET)
|
||||
find_package(Qt6Test ${REQUIRED_QT_VERSION} CONFIG QUIET)
|
||||
|
||||
if(NOT TARGET Qt${QT_MAJOR_VERSION}::Test)
|
||||
message(STATUS "Qt${QT_MAJOR_VERSION}Test not found, some autotests will not be built.")
|
||||
if(NOT TARGET Qt6::Test)
|
||||
message(STATUS "Qt6Test not found, some autotests will not be built.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(pictest pictest.cpp)
|
||||
target_link_libraries(pictest Qt${QT_MAJOR_VERSION}::Gui Qt${QT_MAJOR_VERSION}::Test)
|
||||
target_link_libraries(pictest Qt6::Gui Qt6::Test)
|
||||
ecm_mark_as_test(pictest)
|
||||
add_test(NAME kimageformats-pic COMMAND pictest)
|
||||
|
||||
add_executable(anitest anitest.cpp)
|
||||
target_link_libraries(anitest Qt${QT_MAJOR_VERSION}::Gui Qt${QT_MAJOR_VERSION}::Test)
|
||||
target_link_libraries(anitest Qt6::Gui Qt6::Test)
|
||||
ecm_mark_as_test(anitest)
|
||||
add_test(NAME kimageformats-ani COMMAND anitest)
|
||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
autotests/read/hdr/fake_earth.hdr
Normal file
BIN
autotests/read/hdr/fake_earth.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
BIN
autotests/read/ras/rgb-gimp-2.10-1bit.png
Normal file
After Width: | Height: | Size: 192 B |
BIN
autotests/read/ras/rgb-gimp-2.10-1bit.ras
Normal file
BIN
autotests/read/ras/rgb-gimp-2.10-gray.png
Normal file
After Width: | Height: | Size: 470 B |
BIN
autotests/read/ras/rgb-gimp-2.10-gray.ras
Normal file
BIN
autotests/read/ras/rgb-gimp-2.10-pal16.png
Normal file
After Width: | Height: | Size: 338 B |
BIN
autotests/read/ras/rgb-gimp-2.10-pal16.ras
Normal file
BIN
autotests/read/ras/rgb24.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
autotests/read/ras/rgb24.ras
Normal file
BIN
autotests/read/ras/rle_1bit.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
autotests/read/ras/rle_1bit.ras
Normal file
BIN
autotests/read/ras/rle_24bit.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
autotests/read/ras/rle_24bit.ras
Normal file
BIN
autotests/read/ras/rle_pal8bit.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/ras/rle_pal8bit.ras
Normal file
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
@ -162,13 +162,13 @@ int main(int argc, char **argv)
|
||||
if (!fi.suffix().compare("png", Qt::CaseInsensitive) || !fi.suffix().compare("tif", Qt::CaseInsensitive)) {
|
||||
continue;
|
||||
}
|
||||
int suffixPos = fi.filePath().count() - suffix.count();
|
||||
int suffixPos = fi.filePath().size() - suffix.size();
|
||||
QString inputfile = fi.filePath();
|
||||
QString fmt = QStringLiteral("png");
|
||||
QString expfile = fi.filePath().replace(suffixPos, suffix.count(), fmt);
|
||||
QString expfile = fi.filePath().replace(suffixPos, suffix.size(), fmt);
|
||||
if (!QFile::exists(expfile)) { // try with tiff
|
||||
fmt = QStringLiteral("tif");
|
||||
expfile = fi.filePath().replace(suffixPos, suffix.count(), fmt);
|
||||
expfile = fi.filePath().replace(suffixPos, suffix.size(), fmt);
|
||||
}
|
||||
QString expfilename = QFileInfo(expfile).fileName();
|
||||
|
||||
|
@ -85,8 +85,8 @@ int main(int argc, char **argv)
|
||||
if (parser.isSet(ignoreDataCheck)) {
|
||||
pngfile = fi.filePath();
|
||||
} else {
|
||||
int suffixPos = fi.filePath().count() - suffix.count();
|
||||
pngfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
|
||||
int suffixPos = fi.filePath().size() - suffix.size();
|
||||
pngfile = fi.filePath().replace(suffixPos, suffix.size(), QStringLiteral("png"));
|
||||
}
|
||||
QString pngfilename = QFileInfo(pngfile).fileName();
|
||||
|
||||
|
@ -11,9 +11,10 @@ function(kimageformats_add_plugin plugin)
|
||||
message(FATAL_ERROR "kimageformats_add_plugin called without SOURCES parameter")
|
||||
endif()
|
||||
|
||||
add_library(${plugin} MODULE ${KIF_ADD_PLUGIN_SOURCES})
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats")
|
||||
target_link_libraries(${plugin} Qt${QT_MAJOR_VERSION}::Gui)
|
||||
qt_add_plugin(${plugin} PLUGIN_TYPE imageformats)
|
||||
target_sources(${plugin} PRIVATE ${KIF_ADD_PLUGIN_SOURCES})
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats)
|
||||
target_link_libraries(${plugin} PRIVATE Qt6::Gui)
|
||||
install(TARGETS ${plugin} DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/imageformats)
|
||||
endfunction()
|
||||
|
||||
@ -21,43 +22,20 @@ endfunction()
|
||||
|
||||
kimageformats_add_plugin(kimg_ani SOURCES ani.cpp)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES ani.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (TARGET avif)
|
||||
kimageformats_add_plugin(kimg_avif SOURCES "avif.cpp")
|
||||
target_link_libraries(kimg_avif "avif")
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES avif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES dds-qt.desktop RENAME dds.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
target_link_libraries(kimg_avif PRIVATE "avif")
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (BUILD_EPS_PLUGIN)
|
||||
if (TARGET Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||
if (TARGET Qt6::PrintSupport)
|
||||
kimageformats_add_plugin(kimg_eps SOURCES eps.cpp)
|
||||
target_link_libraries(kimg_eps Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES eps.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
target_link_libraries(kimg_eps PRIVATE Qt6::PrintSupport)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
# need this for Qt's version of the plugin
|
||||
install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
@ -65,132 +43,84 @@ endif()
|
||||
if(OpenEXR_FOUND)
|
||||
kimageformats_add_plugin(kimg_exr SOURCES exr.cpp)
|
||||
if(TARGET OpenEXR::OpenEXR)
|
||||
target_link_libraries(kimg_exr OpenEXR::OpenEXR)
|
||||
target_link_libraries(kimg_exr PRIVATE OpenEXR::OpenEXR)
|
||||
else()
|
||||
if(OpenEXR_VERSION_STRING VERSION_LESS 2.3.0)
|
||||
# Older OpenEXR versions use dynamic exception specifications, so
|
||||
# cannot use C++17 with them
|
||||
set_target_properties(kimg_exr PROPERTIES CXX_STANDARD 14)
|
||||
endif()
|
||||
target_link_libraries(kimg_exr OpenEXR::IlmImf)
|
||||
target_link_libraries(kimg_exr PRIVATE OpenEXR::IlmImf)
|
||||
endif()
|
||||
kde_target_enable_exceptions(kimg_exr PRIVATE)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES exr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_hdr SOURCES hdr.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES hdr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (LibHeif_FOUND)
|
||||
kimageformats_add_plugin(kimg_heif SOURCES heif.cpp)
|
||||
target_link_libraries(kimg_heif PkgConfig::LibHeif)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES heif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
target_link_libraries(kimg_heif PRIVATE PkgConfig::LibHeif)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
|
||||
target_link_libraries(kimg_jxl PkgConfig::LibJXL PkgConfig::LibJXLThreads)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES jxl.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
target_link_libraries(kimg_jxl PRIVATE PkgConfig::LibJXL PkgConfig::LibJXLThreads)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pcx SOURCES pcx.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pic SOURCES pic.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES pic.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_psd SOURCES psd.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES psd.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_qoi SOURCES qoi.cpp scanlineconverter.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES qoi.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_ras SOURCES ras.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES ras.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_rgb SOURCES rgb.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES rgb.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES tga.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_xcf SOURCES xcf.cpp)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES xcf.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (LibRaw_FOUND)
|
||||
kimageformats_add_plugin(kimg_raw SOURCES raw.cpp)
|
||||
kde_enable_exceptions()
|
||||
target_link_libraries(kimg_raw LibRaw::LibRaw)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES raw.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
target_link_libraries(kimg_raw PRIVATE LibRaw::LibRaw)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (KF5Archive_FOUND)
|
||||
if (KF6Archive_FOUND)
|
||||
|
||||
kimageformats_add_plugin(kimg_kra SOURCES kra.cpp)
|
||||
target_link_libraries(kimg_kra KF5::Archive)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES kra.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
target_link_libraries(kimg_kra PRIVATE KF6::Archive)
|
||||
|
||||
kimageformats_add_plugin(kimg_ora SOURCES ora.cpp)
|
||||
target_link_libraries(kimg_ora KF5::Archive)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES ora.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
target_link_libraries(kimg_ora PRIVATE KF6::Archive)
|
||||
|
||||
endif()
|
||||
|
@ -90,7 +90,7 @@ bool ANIHandler::read(QImage *outImage)
|
||||
}
|
||||
|
||||
const QByteArray frameSizeData = device()->read(sizeof(quint32_le));
|
||||
if (frameSizeData.count() != sizeof(quint32_le)) {
|
||||
if (frameSizeData.size() != sizeof(quint32_le)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -384,7 +384,7 @@ bool ANIHandler::ensureScanned() const
|
||||
// TODO should we check that the number of rate entries matches nSteps?
|
||||
auto *dataPtr = data.data();
|
||||
QVector<int> list;
|
||||
for (int i = 0; i < data.count(); i += sizeof(quint32_le)) {
|
||||
for (int i = 0; i < data.size(); i += sizeof(quint32_le)) {
|
||||
const auto entry = *(reinterpret_cast<const quint32_le *>(dataPtr + i));
|
||||
list.append(entry);
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=ani
|
||||
X-KDE-MimeType=application/x-navi-animation
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -330,10 +330,6 @@ bool QAVIFHandler::decode_one_frame()
|
||||
avifRGBImage rgb;
|
||||
avifRGBImageSetDefaults(&rgb, m_decoder->image);
|
||||
|
||||
#if AVIF_VERSION >= 1000000
|
||||
rgb.maxThreads = m_decoder->maxThreads;
|
||||
#endif
|
||||
|
||||
if (m_decoder->image->depth > 8) {
|
||||
rgb.depth = 16;
|
||||
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
||||
@ -1043,11 +1039,6 @@ int QAVIFHandler::loopCount() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if AVIF_VERSION >= 1000000
|
||||
if (m_decoder->repetitionCount >= 0) {
|
||||
return m_decoder->repetitionCount;
|
||||
}
|
||||
#endif
|
||||
// Endless loop to work around https://github.com/AOMediaCodec/libavif/issues/347
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=avif
|
||||
X-KDE-MimeType=image/avif
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=dds
|
||||
X-KDE-MimeType=image/x-dds
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=eps,epsi,epsf
|
||||
X-KDE-MimeType=image/x-eps
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -54,9 +54,7 @@
|
||||
#include <QImage>
|
||||
#include <QImageIOPlugin>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
#include <QTimeZone>
|
||||
#endif
|
||||
|
||||
// Allow the code to works on all QT versions supported by KDE
|
||||
// project (Qt 5.15 and Qt 6.x) to easy backports fixes.
|
||||
@ -194,11 +192,7 @@ bool EXRHandler::read(QImage *outImage)
|
||||
}
|
||||
auto dateTime = QDateTime::fromString(QString::fromStdString(capDate->value()), QStringLiteral("yyyy:MM:dd HH:mm:ss"));
|
||||
if (dateTime.isValid()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
dateTime.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(off));
|
||||
#else
|
||||
dateTime.setOffsetFromUtc(off);
|
||||
#endif
|
||||
image.setText(QStringLiteral("Date"), dateTime.toString(Qt::ISODate));
|
||||
}
|
||||
}
|
||||
@ -255,7 +249,7 @@ bool EXRHandler::read(QImage *outImage)
|
||||
#endif // !EXR_ALLOW_LINEAR_COLORSPACE
|
||||
#endif // !EXR_USE_LEGACY_CONVERSIONS
|
||||
|
||||
*outImage = image;
|
||||
*outImage = std::move(image);
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &exc) {
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=exr
|
||||
X-KDE-MimeType=image/x-exr
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -11,12 +11,18 @@
|
||||
|
||||
#include <QColorSpace>
|
||||
#include <QDataStream>
|
||||
#include <QFloat16>
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
/* *** HDR_HALF_QUALITY ***
|
||||
* If defined, a 16-bits float image is created, otherwise a 32-bits float ones (default).
|
||||
*/
|
||||
//#define HDR_HALF_QUALITY // default commented -> you should define it in your cmake file
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
Q_LOGGING_CATEGORY(HDRPLUGIN, "kf.imageformats.plugins.hdr", QtWarningMsg)
|
||||
@ -27,12 +33,6 @@ namespace // Private.
|
||||
#define MINELEN 8 // minimum scanline length for encoding
|
||||
#define MAXELEN 0x7fff // maximum scanline length for encoding
|
||||
|
||||
static inline uchar ClipToByte(float value)
|
||||
{
|
||||
// we know value is positive.
|
||||
return uchar(std::min(value + 0.5f, 255.0f));
|
||||
}
|
||||
|
||||
// read an old style line from the hdr image file
|
||||
// if 'first' is true the first byte is already read
|
||||
static bool Read_Old_Line(uchar *image, int width, QDataStream &s)
|
||||
@ -75,7 +75,8 @@ static bool Read_Old_Line(uchar *image, int width, QDataStream &s)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void RGBE_To_QRgbLine(uchar *image, QRgb *scanline, int width)
|
||||
template<class float_T>
|
||||
void RGBE_To_QRgbLine(uchar *image, float_T *scanline, int width)
|
||||
{
|
||||
for (int j = 0; j < width; j++) {
|
||||
// v = ldexp(1.0, int(image[3]) - 128);
|
||||
@ -87,12 +88,25 @@ static void RGBE_To_QRgbLine(uchar *image, QRgb *scanline, int width)
|
||||
v = 1.0f / float(1 << -e);
|
||||
}
|
||||
|
||||
scanline[j] = qRgb(ClipToByte(float(image[0]) * v), ClipToByte(float(image[1]) * v), ClipToByte(float(image[2]) * v));
|
||||
|
||||
auto j4 = j * 4;
|
||||
auto vn = v / 255.0f;
|
||||
scanline[j4] = float_T(std::min(float(image[0]) * vn, 1.0f));
|
||||
scanline[j4 + 1] = float_T(std::min(float(image[1]) * vn, 1.0f));
|
||||
scanline[j4 + 2] = float_T(std::min(float(image[2]) * vn, 1.0f));
|
||||
scanline[j4 + 3] = float_T(1.0f);
|
||||
image += 4;
|
||||
}
|
||||
}
|
||||
|
||||
QImage::Format imageFormat()
|
||||
{
|
||||
#ifdef HDR_HALF_QUALITY
|
||||
return QImage::Format_RGBX16FPx4;
|
||||
#else
|
||||
return QImage::Format_RGBX32FPx4;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Load the HDR image.
|
||||
static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &img)
|
||||
{
|
||||
@ -100,7 +114,7 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
uchar code;
|
||||
|
||||
// Create dst image.
|
||||
img = imageAlloc(width, height, QImage::Format_RGB32);
|
||||
img = imageAlloc(width, height, imageFormat());
|
||||
if (img.isNull()) {
|
||||
qCDebug(HDRPLUGIN) << "Couldn't create image with size" << width << height << "and format RGB32";
|
||||
return false;
|
||||
@ -108,10 +122,14 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
|
||||
QByteArray lineArray;
|
||||
lineArray.resize(4 * width);
|
||||
uchar *image = (uchar *)lineArray.data();
|
||||
uchar *image = reinterpret_cast<uchar *>(lineArray.data());
|
||||
|
||||
for (int cline = 0; cline < height; cline++) {
|
||||
QRgb *scanline = (QRgb *)img.scanLine(cline);
|
||||
#ifdef HDR_HALF_QUALITY
|
||||
auto scanline = reinterpret_cast<qfloat16 *>(img.scanLine(cline));
|
||||
#else
|
||||
auto scanline = reinterpret_cast<float *>(img.scanLine(cline));
|
||||
#endif
|
||||
|
||||
// determine scanline type
|
||||
if ((width < MINELEN) || (MAXELEN < width)) {
|
||||
@ -193,9 +211,7 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool HDRHandler::read(QImage *outImage)
|
||||
static QSize readHeaderSize(QIODevice *device)
|
||||
{
|
||||
int len;
|
||||
QByteArray line(MAXLINE + 1, Qt::Uninitialized);
|
||||
@ -203,7 +219,7 @@ bool HDRHandler::read(QImage *outImage)
|
||||
|
||||
// Parse header
|
||||
do {
|
||||
len = device()->readLine(line.data(), MAXLINE);
|
||||
len = device->readLine(line.data(), MAXLINE);
|
||||
|
||||
if (line.startsWith("FORMAT=")) {
|
||||
format = line.mid(7, len - 7 - 1 /*\n*/);
|
||||
@ -213,10 +229,10 @@ bool HDRHandler::read(QImage *outImage)
|
||||
|
||||
if (format != "32-bit_rle_rgbe") {
|
||||
qCDebug(HDRPLUGIN) << "Unknown HDR format:" << format;
|
||||
return false;
|
||||
return QSize();
|
||||
}
|
||||
|
||||
len = device()->readLine(line.data(), MAXLINE);
|
||||
len = device->readLine(line.data(), MAXLINE);
|
||||
line.resize(len);
|
||||
|
||||
/*
|
||||
@ -236,21 +252,30 @@ bool HDRHandler::read(QImage *outImage)
|
||||
QRegularExpressionMatch match = resolutionRegExp.match(QString::fromLatin1(line));
|
||||
if (!match.hasMatch()) {
|
||||
qCDebug(HDRPLUGIN) << "Invalid HDR file, the first line after the header didn't have the expected format:" << line;
|
||||
return false;
|
||||
return QSize();
|
||||
}
|
||||
|
||||
if ((match.captured(1).at(1) != u'Y') || (match.captured(3).at(1) != u'X')) {
|
||||
qCDebug(HDRPLUGIN) << "Unsupported image orientation in HDR file.";
|
||||
return QSize();
|
||||
}
|
||||
|
||||
return QSize(match.captured(4).toInt(), match.captured(2).toInt());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool HDRHandler::read(QImage *outImage)
|
||||
{
|
||||
QDataStream s(device());
|
||||
|
||||
QSize size = readHeaderSize(s.device());
|
||||
if (!size.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int width = match.captured(4).toInt();
|
||||
const int height = match.captured(2).toInt();
|
||||
|
||||
QDataStream s(device());
|
||||
|
||||
QImage img;
|
||||
if (!LoadHDR(s, width, height, img)) {
|
||||
if (!LoadHDR(s, size.width(), size.height(), img)) {
|
||||
// qDebug() << "Error loading HDR file.";
|
||||
return false;
|
||||
}
|
||||
@ -258,10 +283,44 @@ bool HDRHandler::read(QImage *outImage)
|
||||
// By setting the linear color space, programs that support profiles display HDR files as in GIMP and Photoshop.
|
||||
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
|
||||
|
||||
*outImage = img;
|
||||
*outImage = std::move(img);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HDRHandler::supportsOption(ImageOption option) const
|
||||
{
|
||||
if (option == QImageIOHandler::Size) {
|
||||
return true;
|
||||
}
|
||||
if (option == QImageIOHandler::ImageFormat) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant HDRHandler::option(ImageOption option) const
|
||||
{
|
||||
QVariant v;
|
||||
|
||||
if (option == QImageIOHandler::Size) {
|
||||
if (auto d = device()) {
|
||||
// transactions works on both random and sequential devices
|
||||
d->startTransaction();
|
||||
auto size = readHeaderSize(d);
|
||||
d->rollbackTransaction();
|
||||
if (size.isValid()) {
|
||||
v = QVariant::fromValue(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (option == QImageIOHandler::ImageFormat) {
|
||||
v = QVariant::fromValue(imageFormat());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
HDRHandler::HDRHandler()
|
||||
{
|
||||
}
|
||||
@ -282,7 +341,20 @@ bool HDRHandler::canRead(QIODevice *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
return device->peek(11) == "#?RADIANCE\n" || device->peek(7) == "#?RGBE\n";
|
||||
// the .pic taken from official test cases does not start with this string but can be loaded.
|
||||
if(device->peek(11) == "#?RADIANCE\n" || device->peek(7) == "#?RGBE\n") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// allow to load offical test cases: https://radsite.lbl.gov/radiance/framed.html
|
||||
device->startTransaction();
|
||||
QSize size = readHeaderSize(device);
|
||||
device->rollbackTransaction();
|
||||
if (size.isValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities HDRPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=hdr
|
||||
X-KDE-MimeType=image/x-hdr
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -18,6 +18,9 @@ public:
|
||||
bool canRead() const override;
|
||||
bool read(QImage *outImage) override;
|
||||
|
||||
bool supportsOption(QImageIOHandler::ImageOption option) const override;
|
||||
QVariant option(QImageIOHandler::ImageOption option) const override;
|
||||
|
||||
static bool canRead(QIODevice *device);
|
||||
};
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=heif
|
||||
X-KDE-MimeType=image/heif
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=jp2
|
||||
X-KDE-MimeType=image/jp2
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=jxl
|
||||
X-KDE-MimeType=image/jxl
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=kra
|
||||
X-KDE-MimeType=application/x-krita
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=ora
|
||||
X-KDE-MimeType=image/openraster
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -383,8 +383,7 @@ static bool readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
|
||||
while (flag != 12 && s.status() == QDataStream::Ok) {
|
||||
s >> flag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
device->seek(device->size() - 769);
|
||||
s >> flag;
|
||||
}
|
||||
@ -613,7 +612,7 @@ static bool writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
|
||||
QByteArray b_buf(header.width(), 0);
|
||||
|
||||
for (int y = 0; y < header.height(); ++y) {
|
||||
auto p = (QRgb*)img.scanLine(y);
|
||||
auto p = (QRgb *)img.scanLine(y);
|
||||
|
||||
for (int x = 0; x < header.width(); ++x) {
|
||||
QRgb rgb = *p++;
|
||||
@ -684,7 +683,7 @@ bool PCXHandler::read(QImage *outImage)
|
||||
|
||||
img.setDotsPerMeterX(qRound(header.HDpi / 25.4 * 1000));
|
||||
img.setDotsPerMeterY(qRound(header.YDpi / 25.4 * 1000));
|
||||
*outImage = img;
|
||||
*outImage = std::move(img);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=pcx
|
||||
X-KDE-MimeType=image/x-pcx
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -255,7 +255,7 @@ bool SoftimagePICHandler::read(QImage *image)
|
||||
}
|
||||
}
|
||||
|
||||
*image = img;
|
||||
*image = std::move(img);
|
||||
m_state = Ready;
|
||||
|
||||
return true;
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=pic
|
||||
X-KDE-MimeType=image/x-pic
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -20,13 +20,13 @@
|
||||
|
||||
/*
|
||||
* Limitations of the current code:
|
||||
* - 32-bit float image are converted to 16-bit integer image.
|
||||
* - Other color spaces cannot directly be read due to lack of QImage support for
|
||||
* color spaces other than RGB (and Grayscale). Where possible, a conversion
|
||||
* to RGB is done:
|
||||
* - Color spaces other than RGB/Grayscale cannot be read due to lack of QImage
|
||||
* support. Where possible, a conversion to RGB is done:
|
||||
* - CMYK images are converted using an approximated way that ignores the color
|
||||
* information (ICC profile).
|
||||
* - LAB images are converted to sRGB using literature formulas.
|
||||
* - MULICHANNEL images more than 3 channels are converted as CMYK images.
|
||||
* - DUOTONE images are considered as Grayscale images.
|
||||
*
|
||||
* NOTE: The best way to convert between different color spaces is to use a
|
||||
* color management engine (e.g. LittleCMS).
|
||||
@ -733,7 +733,9 @@ static QImage::Format imageFormat(const PSDHeader &header, bool alpha)
|
||||
auto format = QImage::Format_Invalid;
|
||||
switch(header.color_mode) {
|
||||
case CM_RGB:
|
||||
if (header.depth == 16 || header.depth == 32)
|
||||
if (header.depth == 32)
|
||||
format = header.channel_count < 4 || !alpha ? QImage::Format_RGBX32FPx4 : QImage::Format_RGBA32FPx4_Premultiplied;
|
||||
else if (header.depth == 16)
|
||||
format = header.channel_count < 4 || !alpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64_Premultiplied;
|
||||
else
|
||||
format = header.channel_count < 4 || !alpha ? QImage::Format_RGB888 : QImage::Format_RGBA8888_Premultiplied;
|
||||
@ -789,11 +791,13 @@ static qint32 imageChannels(const QImage::Format& format)
|
||||
return c;
|
||||
}
|
||||
|
||||
inline quint8 xchg(quint8 v) {
|
||||
inline quint8 xchg(quint8 v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
inline quint16 xchg(quint16 v) {
|
||||
inline quint16 xchg(quint16 v)
|
||||
{
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
return quint16( (v>>8) | (v<<8) );
|
||||
#else
|
||||
@ -801,7 +805,8 @@ inline quint16 xchg(quint16 v) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline quint32 xchg(quint32 v) {
|
||||
inline quint32 xchg(quint32 v)
|
||||
{
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
return quint32( (v>>24) | ((v & 0x00FF0000)>>8) | ((v & 0x0000FF00)<<8) | (v<<24) );
|
||||
#else
|
||||
@ -858,8 +863,9 @@ enum class PremulConversion {
|
||||
template<class T>
|
||||
inline void premulConversion(char *stride, qint32 width, qint32 ac, qint32 cn, const PremulConversion &conv)
|
||||
{
|
||||
auto s = reinterpret_cast<T *>(stride);
|
||||
auto max = qint64(std::numeric_limits<T>::max());
|
||||
auto s = reinterpret_cast<T*>(stride);
|
||||
// NOTE: to avoid overflows, max is casted to qint64: that is possible because max is always an integer (even if T is float)
|
||||
auto max = qint64(std::numeric_limits<T>::is_integer ? std::numeric_limits<T>::max() : 1);
|
||||
|
||||
for (qint32 c = 0; c < ac; ++c) {
|
||||
if (conv == PremulConversion::PS2P) {
|
||||
@ -868,14 +874,16 @@ inline void premulConversion(char *stride, qint32 width, qint32 ac, qint32 cn, c
|
||||
auto alpha = *(s + xcn + ac);
|
||||
*(s + xcn + c) = *(s + xcn + c) + alpha - max;
|
||||
}
|
||||
} else if (conv == PremulConversion::PS2A || (conv == PremulConversion::PSLab2A && c == 0)) {
|
||||
}
|
||||
else if (conv == PremulConversion::PS2A || (conv == PremulConversion::PSLab2A && c == 0)) {
|
||||
for (qint32 x = 0; x < width; ++x) {
|
||||
auto xcn = x * cn;
|
||||
auto alpha = *(s + xcn + ac);
|
||||
if (alpha > 0)
|
||||
*(s + xcn + c) = ((*(s + xcn + c) + alpha - max) * max + alpha / 2) / alpha;
|
||||
}
|
||||
} else if (conv == PremulConversion::PSLab2A) {
|
||||
}
|
||||
else if (conv == PremulConversion::PSLab2A) {
|
||||
for (qint32 x = 0; x < width; ++x) {
|
||||
auto xcn = x * cn;
|
||||
auto alpha = *(s + xcn + ac);
|
||||
@ -898,8 +906,8 @@ inline void monoInvert(uchar *target, const char* source, qint32 bytes)
|
||||
template<class T>
|
||||
inline void rawChannelsCopy(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width)
|
||||
{
|
||||
auto s = reinterpret_cast<const T *>(source);
|
||||
auto t = reinterpret_cast<T *>(target);
|
||||
auto s = reinterpret_cast<const T*>(source);
|
||||
auto t = reinterpret_cast<T*>(target);
|
||||
for (qint32 c = 0, cs = std::min(targetChannels, sourceChannels); c < cs; ++c) {
|
||||
for (qint32 x = 0; x < width; ++x) {
|
||||
t[x * targetChannels + c] = s[x * sourceChannels + c];
|
||||
@ -1139,7 +1147,7 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
||||
if (randomAccess) {
|
||||
// In order to make a colorspace transformation, we need all channels of a scanline
|
||||
QByteArray psdScanline;
|
||||
psdScanline.resize(qsizetype(header.width * std::min(header.depth, quint16(16)) * header.channel_count + 7) / 8);
|
||||
psdScanline.resize(qsizetype(header.width * header.depth * header.channel_count + 7) / 8);
|
||||
for (qint32 y = 0, h = header.height; y < h; ++y) {
|
||||
for (qint32 c = 0; c < header.channel_count; ++c) {
|
||||
auto strideNumber = c * qsizetype(h) + y;
|
||||
@ -1156,32 +1164,37 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
||||
auto scanLine = reinterpret_cast<unsigned char*>(psdScanline.data());
|
||||
if (header.depth == 8) {
|
||||
planarToChunchy<quint8>(scanLine, rawStride.data(), header.width, c, header.channel_count);
|
||||
} else if (header.depth == 16) {
|
||||
}
|
||||
else if (header.depth == 16) {
|
||||
planarToChunchy<quint16>(scanLine, rawStride.data(), header.width, c, header.channel_count);
|
||||
} else if (header.depth == 32) {
|
||||
planarToChunchyFloatToUInt16<float>(scanLine, rawStride.data(), header.width, c, header.channel_count);
|
||||
}
|
||||
else if (header.depth == 32) {
|
||||
planarToChunchy<float>(scanLine, rawStride.data(), header.width, c, header.channel_count);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert premultiplied data to unassociated data
|
||||
if (img.hasAlphaChannel()) {
|
||||
auto scanLine = reinterpret_cast<char*>(psdScanline.data());
|
||||
if (header.color_mode == CM_CMYK) {
|
||||
if (header.depth == 8)
|
||||
premulConversion<quint8>(psdScanline.data(), header.width, 4, header.channel_count, PremulConversion::PS2A);
|
||||
premulConversion<quint8>(scanLine, header.width, 4, header.channel_count, PremulConversion::PS2A);
|
||||
else if (header.depth == 16)
|
||||
premulConversion<quint16>(psdScanline.data(), header.width, 4, header.channel_count, PremulConversion::PS2A);
|
||||
premulConversion<quint16>(scanLine, header.width, 4, header.channel_count, PremulConversion::PS2A);
|
||||
}
|
||||
if (header.color_mode == CM_LABCOLOR) {
|
||||
if (header.depth == 8)
|
||||
premulConversion<quint8>(psdScanline.data(), header.width, 3, header.channel_count, PremulConversion::PSLab2A);
|
||||
premulConversion<quint8>(scanLine, header.width, 3, header.channel_count, PremulConversion::PSLab2A);
|
||||
else if (header.depth == 16)
|
||||
premulConversion<quint16>(psdScanline.data(), header.width, 3, header.channel_count, PremulConversion::PSLab2A);
|
||||
premulConversion<quint16>(scanLine, header.width, 3, header.channel_count, PremulConversion::PSLab2A);
|
||||
}
|
||||
if (header.color_mode == CM_RGB) {
|
||||
if (header.depth == 8)
|
||||
premulConversion<quint8>(psdScanline.data(), header.width, 3, header.channel_count, PremulConversion::PS2P);
|
||||
else if (header.depth == 16 || header.depth == 32)
|
||||
premulConversion<quint16>(psdScanline.data(), header.width, 3, header.channel_count, PremulConversion::PS2P);
|
||||
premulConversion<quint8>(scanLine, header.width, 3, header.channel_count, PremulConversion::PS2P);
|
||||
else if (header.depth == 16)
|
||||
premulConversion<quint16>(scanLine, header.width, 3, header.channel_count, PremulConversion::PS2P);
|
||||
else if (header.depth == 32)
|
||||
premulConversion<float>(scanLine, header.width, 3, header.channel_count, PremulConversion::PS2P);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1201,11 +1214,14 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
||||
if (header.color_mode == CM_RGB) {
|
||||
if (header.depth == 8)
|
||||
rawChannelsCopy<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width);
|
||||
else if (header.depth == 16 || header.depth == 32)
|
||||
else if (header.depth == 16)
|
||||
rawChannelsCopy<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width);
|
||||
else if (header.depth == 32)
|
||||
rawChannelsCopy<float>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Linear read (no position jumps): optimized code usable only for the colorspaces supported by QImage
|
||||
for (qint32 c = 0; c < channel_num; ++c) {
|
||||
for (qint32 y = 0, h = header.height; y < h; ++y) {
|
||||
@ -1218,25 +1234,23 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
||||
auto scanLine = img.scanLine(y);
|
||||
if (header.depth == 1) { // Bitmap
|
||||
monoInvert(scanLine, rawStride.data(), std::min(rawStride.size(), img.bytesPerLine()));
|
||||
} else if (header.depth == 8) { // 8-bits images: Indexed, Grayscale, RGB/RGBA
|
||||
}
|
||||
else if (header.depth == 8) { // 8-bits images: Indexed, Grayscale, RGB/RGBA
|
||||
planarToChunchy<quint8>(scanLine, rawStride.data(), header.width, c, imgChannels);
|
||||
} else if (header.depth == 16) { // 16-bits integer images: Grayscale, RGB/RGBA
|
||||
}
|
||||
else if (header.depth == 16) { // 16-bits integer images: Grayscale, RGB/RGBA
|
||||
planarToChunchy<quint16>(scanLine, rawStride.data(), header.width, c, imgChannels);
|
||||
} else if (header.depth == 32) { // 32-bits float images: Grayscale, RGB/RGBA (coverted to equivalent integer 16-bits)
|
||||
}
|
||||
else if (header.depth == 32 && header.color_mode == CM_RGB) { // 32-bits float images: RGB/RGBA
|
||||
planarToChunchy<float>(scanLine, rawStride.data(), header.width, c, imgChannels);
|
||||
}
|
||||
else if (header.depth == 32 && header.color_mode == CM_GRAYSCALE) { // 32-bits float images: Grayscale (coverted to equivalent integer 16-bits)
|
||||
planarToChunchyFloatToUInt16<float>(scanLine, rawStride.data(), header.width, c, imgChannels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LAB conversion generates a sRGB image
|
||||
if (header.color_mode == CM_LABCOLOR) {
|
||||
#ifdef PSD_FAST_LAB_CONVERSION
|
||||
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
|
||||
#else
|
||||
img.setColorSpace(QColorSpace(QColorSpace::SRgb));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Resolution info
|
||||
if (!setResolution(img, irs)) {
|
||||
@ -1244,7 +1258,15 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
||||
}
|
||||
|
||||
// ICC profile
|
||||
if (!setColorSpace(img, irs)) {
|
||||
if (header.color_mode == CM_LABCOLOR) {
|
||||
// LAB conversion generates a sRGB image
|
||||
#ifdef PSD_FAST_LAB_CONVERSION
|
||||
img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
|
||||
#else
|
||||
img.setColorSpace(QColorSpace(QColorSpace::SRgb));
|
||||
#endif
|
||||
}
|
||||
else if (!setColorSpace(img, irs)) {
|
||||
// qDebug() << "No colorspace info set!";
|
||||
}
|
||||
|
||||
@ -1304,7 +1326,7 @@ bool PSDHandler::read(QImage *image)
|
||||
return false;
|
||||
}
|
||||
|
||||
*image = img;
|
||||
*image = std::move(img);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=psd,psb,pdd,psdt
|
||||
X-KDE-MimeType=image/vnd.adobe.photoshop
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=qoi
|
||||
X-KDE-MimeType=image/qoi
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -3,6 +3,7 @@
|
||||
SPDX-FileCopyrightText: 2003 Dominik Seichter <domseichter@web.de>
|
||||
SPDX-FileCopyrightText: 2004 Ignacio Castaño <castano@ludicon.com>
|
||||
SPDX-FileCopyrightText: 2010 Troy Unrau <troy@kde.org>
|
||||
SPDX-FileCopyrightText: 2023 Mirco Miranda <mircomir@outlook.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
@ -39,14 +40,14 @@ enum RASColorMapType {
|
||||
};
|
||||
|
||||
struct RasHeader {
|
||||
quint32 MagicNumber;
|
||||
quint32 Width;
|
||||
quint32 Height;
|
||||
quint32 Depth;
|
||||
quint32 Length;
|
||||
quint32 Type;
|
||||
quint32 ColorMapType;
|
||||
quint32 ColorMapLength;
|
||||
quint32 MagicNumber = 0;
|
||||
quint32 Width = 0;
|
||||
quint32 Height = 0;
|
||||
quint32 Depth = 0;
|
||||
quint32 Length = 0;
|
||||
quint32 Type = 0;
|
||||
quint32 ColorMapType = 0;
|
||||
quint32 ColorMapLength = 0;
|
||||
enum {
|
||||
SIZE = 32,
|
||||
}; // 8 fields of four bytes each
|
||||
@ -80,152 +81,251 @@ static bool IsSupported(const RasHeader &head)
|
||||
return false;
|
||||
}
|
||||
// check for an appropriate depth
|
||||
// we support 8bit+palette, 24bit and 32bit ONLY!
|
||||
// TODO: add support for 1bit
|
||||
if (!((head.Depth == 8 && head.ColorMapType == 1) || head.Depth == 24 || head.Depth == 32)) {
|
||||
if (head.Depth != 1 && head.Depth != 8 && head.Depth != 24 && head.Depth != 32) {
|
||||
return false;
|
||||
}
|
||||
if (head.Width == 0 || head.Height == 0) {
|
||||
return false;
|
||||
}
|
||||
// the Type field adds support for RLE(BGR), RGB and other encodings
|
||||
// we support Type 1: Normal(BGR) and Type 3: Normal(RGB) ONLY!
|
||||
// TODO: add support for Type 2: RLE(BGR) & Type 4,5: TIFF/IFF
|
||||
if (!(head.Type == 1 || head.Type == 3)) {
|
||||
return false;
|
||||
}
|
||||
// Old files didn't have Length set - reject them for now
|
||||
// TODO: add length recalculation to support old files
|
||||
if (!head.Length) {
|
||||
// we support Type 1: Normal(BGR), Type 2: RLE(BGR) and Type 3: Normal(RGB) ONLY!
|
||||
// TODO: add support for Type 4,5: TIFF/IFF
|
||||
if (!(head.Type == RAS_TYPE_STANDARD || head.Type == RAS_TYPE_RGB_FORMAT || head.Type == RAS_TYPE_BYTE_ENCODED)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static QImage::Format imageFormat(const RasHeader &header)
|
||||
{
|
||||
if (header.ColorMapType == RAS_COLOR_MAP_TYPE_RGB) {
|
||||
return QImage::Format_Indexed8;
|
||||
}
|
||||
if (header.Depth == 8 && header.ColorMapType == RAS_COLOR_MAP_TYPE_NONE) {
|
||||
return QImage::Format_Grayscale8;
|
||||
}
|
||||
if (header.Depth == 1) {
|
||||
return QImage::Format_Mono;
|
||||
}
|
||||
return QImage::Format_RGB32;
|
||||
}
|
||||
|
||||
class LineDecoder
|
||||
{
|
||||
public:
|
||||
LineDecoder(QIODevice *d, const RasHeader &ras)
|
||||
: device(d)
|
||||
, header(ras)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray readLine(qint64 size)
|
||||
{
|
||||
/* *** uncompressed
|
||||
*/
|
||||
if (header.Type != RAS_TYPE_BYTE_ENCODED) {
|
||||
return device->read(size);
|
||||
}
|
||||
|
||||
/* *** rle compressed
|
||||
* The Run-length encoding (RLE) scheme optionally used in Sun Raster
|
||||
* files (Type = 0002h) is used to encode bytes of image data
|
||||
* separately. RLE encoding may be found in any Sun Raster file
|
||||
* regardless of the type of image data it contains.
|
||||
*
|
||||
* The RLE packets are typically three bytes in size:
|
||||
* - The first byte is a Flag Value indicating the type of RLE packet.
|
||||
* - The second byte is the Run Count.
|
||||
* - The third byte is the Run Value.
|
||||
*
|
||||
* A Flag Value of 80h is followed by a Run Count in the range of 01h
|
||||
* to FFh. The Run Value follows the Run count and is in the range of
|
||||
* 00h to FFh. The pixel run is the Run Value repeated Run Count times.
|
||||
* There are two exceptions to this algorithm. First, if the Run Count
|
||||
* following the Flag Value is 00h, this is an indication that the run
|
||||
* is a single byte in length and has a value of 80h. And second, if
|
||||
* the Flag Value is not 80h, then it is assumed that the data is
|
||||
* unencoded pixel data and is written directly to the output stream.
|
||||
*
|
||||
* source: http://www.fileformat.info/format/sunraster/egff.htm
|
||||
*/
|
||||
for (qsizetype psz = 0, ptr = 0; uncBuffer.size() < size;) {
|
||||
rleBuffer.append(device->read(std::min(qint64(32768), size)));
|
||||
qsizetype sz = rleBuffer.size();
|
||||
if (psz == sz) {
|
||||
break; // avoid infinite loop (data corrupted?!)
|
||||
}
|
||||
auto data = reinterpret_cast<uchar *>(rleBuffer.data());
|
||||
for (; ptr < sz;) {
|
||||
auto flag = data[ptr++];
|
||||
if (flag == 0x80) {
|
||||
if (ptr >= sz) {
|
||||
ptr -= 1;
|
||||
break;
|
||||
}
|
||||
auto cnt = data[ptr++];
|
||||
if (cnt == 0) {
|
||||
uncBuffer.append(char(0x80));
|
||||
continue;
|
||||
} else if (ptr >= sz) {
|
||||
ptr -= 2;
|
||||
break;
|
||||
}
|
||||
auto val = data[ptr++];
|
||||
uncBuffer.append(QByteArray(1 + cnt, char(val)));
|
||||
} else {
|
||||
uncBuffer.append(char(flag));
|
||||
}
|
||||
}
|
||||
if (ptr) { // remove consumed data
|
||||
rleBuffer.remove(0, ptr);
|
||||
ptr = 0;
|
||||
}
|
||||
psz = rleBuffer.size();
|
||||
}
|
||||
if (uncBuffer.size() < size) {
|
||||
return QByteArray(); // something wrong
|
||||
}
|
||||
auto line = uncBuffer.mid(0, size);
|
||||
uncBuffer.remove(0, line.size()); // remove consumed data
|
||||
return line;
|
||||
}
|
||||
|
||||
private:
|
||||
QIODevice *device;
|
||||
RasHeader header;
|
||||
|
||||
// RLE decoding buffers
|
||||
QByteArray rleBuffer;
|
||||
QByteArray uncBuffer;
|
||||
};
|
||||
|
||||
static bool LoadRAS(QDataStream &s, const RasHeader &ras, QImage &img)
|
||||
{
|
||||
s.device()->seek(RasHeader::SIZE);
|
||||
|
||||
if (ras.ColorMapLength > kMaxQVectorSize) {
|
||||
qWarning() << "LoadRAS() unsupported image color map length in file header" << ras.ColorMapLength;
|
||||
// The width of a scan line is always a multiple of 16 bits, padded when necessary.
|
||||
auto rasLineSize = (qint64(ras.Width) * ras.Depth + 7) / 8;
|
||||
if (rasLineSize & 1)
|
||||
++rasLineSize;
|
||||
if (rasLineSize > kMaxQVectorSize) {
|
||||
qWarning() << "LoadRAS() unsupported line size" << rasLineSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read palette if needed.
|
||||
QVector<quint8> palette(ras.ColorMapLength);
|
||||
if (ras.ColorMapType == 1) {
|
||||
for (quint32 i = 0; i < ras.ColorMapLength; ++i) {
|
||||
s >> palette[i];
|
||||
}
|
||||
}
|
||||
|
||||
const int bpp = ras.Depth / 8;
|
||||
if (ras.Height == 0) {
|
||||
return false;
|
||||
}
|
||||
if (bpp == 0) {
|
||||
return false;
|
||||
}
|
||||
if (ras.Length / ras.Height / bpp < ras.Width) {
|
||||
qWarning() << "LoadRAS() mistmatch between height and width" << ras.Width << ras.Height << ras.Length << ras.Depth;
|
||||
return false;
|
||||
}
|
||||
if (ras.Length > kMaxQVectorSize) {
|
||||
qWarning() << "LoadRAS() unsupported image length in file header" << ras.Length;
|
||||
return false;
|
||||
}
|
||||
|
||||
// each line must be a factor of 16 bits, so they may contain padding
|
||||
// this will be 1 if padding required, 0 otherwise
|
||||
const int paddingrequired = (ras.Width * bpp % 2);
|
||||
|
||||
// qDebug() << "paddingrequired: " << paddingrequired;
|
||||
// don't trust ras.Length
|
||||
QVector<quint8> input(ras.Length);
|
||||
|
||||
int i = 0;
|
||||
while (!s.atEnd() && i < input.size()) {
|
||||
s >> input[i];
|
||||
// I guess we need to find out if we're at the end of a line
|
||||
if (paddingrequired && i != 0 && !(i % (ras.Width * bpp))) {
|
||||
s >> input[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Allocate image
|
||||
img = imageAlloc(ras.Width, ras.Height, QImage::Format_ARGB32);
|
||||
img = imageAlloc(ras.Width, ras.Height, imageFormat(ras));
|
||||
if (img.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reconstruct image from RGB palette if we have a palette
|
||||
// TODO: make generic so it works with 24bit or 32bit palettes
|
||||
if (ras.ColorMapType == 1 && ras.Depth == 8) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
for (quint32 y = 0; y < ras.Height; y++) {
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = palette.value((int)input[y * ras.Width + x]);
|
||||
green = palette.value((int)input[y * ras.Width + x] + (ras.ColorMapLength / 3));
|
||||
blue = palette.value((int)input[y * ras.Width + x] + 2 * (ras.ColorMapLength / 3));
|
||||
img.setPixel(x, y, qRgb(red, green, blue));
|
||||
// Read palette if needed.
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_RGB) {
|
||||
QVector<quint8> palette(ras.ColorMapLength);
|
||||
for (quint32 i = 0; i < ras.ColorMapLength; ++i) {
|
||||
s >> palette[i];
|
||||
}
|
||||
QList<QRgb> colorTable;
|
||||
for (quint32 i = 0, n = ras.ColorMapLength / 3; i < n; ++i) {
|
||||
colorTable << qRgb(palette.at(i), palette.at(i + n), palette.at(i + 2 * n));
|
||||
}
|
||||
for (; colorTable.size() < 256;) {
|
||||
colorTable << qRgb(255, 255, 255);
|
||||
}
|
||||
img.setColorTable(colorTable);
|
||||
if (s.status() != QDataStream::Ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ras.ColorMapType == 0 && ras.Depth == 24 && (ras.Type == 1 || ras.Type == 2)) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
for (quint32 y = 0; y < ras.Height; y++) {
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = input[y * 3 * ras.Width + x * 3 + 2];
|
||||
green = input[y * 3 * ras.Width + x * 3 + 1];
|
||||
blue = input[y * 3 * ras.Width + x * 3];
|
||||
img.setPixel(x, y, qRgb(red, green, blue));
|
||||
}
|
||||
}
|
||||
LineDecoder dec(s.device(), ras);
|
||||
auto bytesPerLine = std::min(img.bytesPerLine(), qsizetype(rasLineSize));
|
||||
for (quint32 y = 0; y < ras.Height; ++y) {
|
||||
auto rasLine = dec.readLine(rasLineSize);
|
||||
if (rasLine.size() != rasLineSize) {
|
||||
qWarning() << "LoadRAS() unable to read line" << y << ": the seems corrupted!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ras.ColorMapType == 0 && ras.Depth == 24 && ras.Type == 3) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
for (quint32 y = 0; y < ras.Height; y++) {
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = input[y * 3 * ras.Width + x * 3];
|
||||
green = input[y * 3 * ras.Width + x * 3 + 1];
|
||||
blue = input[y * 3 * ras.Width + x * 3 + 2];
|
||||
img.setPixel(x, y, qRgb(red, green, blue));
|
||||
}
|
||||
// Grayscale 1-bit / Grayscale 8-bit (never seen)
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_NONE && (ras.Depth == 1 || ras.Depth == 8)) {
|
||||
for (auto &&b : rasLine) {
|
||||
b = ~b;
|
||||
}
|
||||
std::memcpy(img.scanLine(y), rasLine.constData(), bytesPerLine);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ras.ColorMapType == 0 && ras.Depth == 32 && (ras.Type == 1 || ras.Type == 2)) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
for (quint32 y = 0; y < ras.Height; y++) {
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = input[y * 4 * ras.Width + x * 4 + 3];
|
||||
green = input[y * 4 * ras.Width + x * 4 + 2];
|
||||
blue = input[y * 4 * ras.Width + x * 4 + 1];
|
||||
img.setPixel(x, y, qRgb(red, green, blue));
|
||||
}
|
||||
}
|
||||
// Image with palette
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_RGB && (ras.Depth == 1 || ras.Depth == 8)) {
|
||||
std::memcpy(img.scanLine(y), rasLine.constData(), bytesPerLine);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ras.ColorMapType == 0 && ras.Depth == 32 && ras.Type == 3) {
|
||||
// BGR 24-bit
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_NONE && ras.Depth == 24 && (ras.Type == RAS_TYPE_STANDARD || ras.Type == RAS_TYPE_BYTE_ENCODED)) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
for (quint32 y = 0; y < ras.Height; y++) {
|
||||
auto scanLine = reinterpret_cast<QRgb *>(img.scanLine(y));
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = input[y * 4 * ras.Width + x * 4 + 1];
|
||||
green = input[y * 4 * ras.Width + x * 4 + 2];
|
||||
blue = input[y * 4 * ras.Width + x * 4 + 3];
|
||||
img.setPixel(x, y, qRgb(red, green, blue));
|
||||
red = rasLine.at(x * 3 + 2);
|
||||
green = rasLine.at(x * 3 + 1);
|
||||
blue = rasLine.at(x * 3);
|
||||
*(scanLine + x) = qRgb(red, green, blue);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// RGB 24-bit
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_NONE && ras.Depth == 24 && ras.Type == RAS_TYPE_RGB_FORMAT) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
auto scanLine = reinterpret_cast<QRgb *>(img.scanLine(y));
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = rasLine.at(x * 3);
|
||||
green = rasLine.at(x * 3 + 1);
|
||||
blue = rasLine.at(x * 3 + 2);
|
||||
*(scanLine + x) = qRgb(red, green, blue);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// BGR 32-bit (not tested: test case missing)
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_NONE && ras.Depth == 32 && (ras.Type == RAS_TYPE_STANDARD || ras.Type == RAS_TYPE_BYTE_ENCODED)) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
auto scanLine = reinterpret_cast<QRgb *>(img.scanLine(y));
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = rasLine.at(x * 4 + 3);
|
||||
green = rasLine.at(x * 4 + 2);
|
||||
blue = rasLine.at(x * 4 + 1);
|
||||
*(scanLine + x) = qRgb(red, green, blue);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// RGB 32-bit (tested: test case missing due to image too large)
|
||||
if (ras.ColorMapType == RAS_COLOR_MAP_TYPE_NONE && ras.Depth == 32 && ras.Type == RAS_TYPE_RGB_FORMAT) {
|
||||
quint8 red;
|
||||
quint8 green;
|
||||
quint8 blue;
|
||||
auto scanLine = reinterpret_cast<QRgb *>(img.scanLine(y));
|
||||
for (quint32 x = 0; x < ras.Width; x++) {
|
||||
red = rasLine.at(x * 4 + 1);
|
||||
green = rasLine.at(x * 4 + 2);
|
||||
blue = rasLine.at(x * 4 + 3);
|
||||
*(scanLine + x) = qRgb(red, green, blue);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
qWarning() << "LoadRAS() unsupported format!"
|
||||
<< "ColorMapType:" << ras.ColorMapType << "Type:" << ras.Type << "Depth:" << ras.Depth;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -283,16 +383,8 @@ bool RASHandler::read(QImage *outImage)
|
||||
RasHeader ras;
|
||||
s >> ras;
|
||||
|
||||
if (ras.ColorMapLength > std::numeric_limits<int>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: add support for old versions of RAS where Length may be zero in header
|
||||
s.device()->seek(RasHeader::SIZE + ras.Length + ras.ColorMapLength);
|
||||
|
||||
// Check image file format. Type 2 is RLE, which causing seeking to be silly.
|
||||
if (!s.atEnd() && ras.Type != 2) {
|
||||
// qDebug() << "This RAS file is not valid, or an older version of the format.";
|
||||
if (ras.ColorMapLength > kMaxQVectorSize) {
|
||||
qWarning() << "LoadRAS() unsupported image color map length in file header" << ras.ColorMapLength;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -310,13 +402,69 @@ bool RASHandler::read(QImage *outImage)
|
||||
return false;
|
||||
}
|
||||
|
||||
*outImage = img;
|
||||
*outImage = std::move(img);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RASHandler::supportsOption(ImageOption option) const
|
||||
{
|
||||
if (option == QImageIOHandler::Size) {
|
||||
return true;
|
||||
}
|
||||
if (option == QImageIOHandler::ImageFormat) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant RASHandler::option(ImageOption option) const
|
||||
{
|
||||
QVariant v;
|
||||
|
||||
if (option == QImageIOHandler::Size) {
|
||||
if (auto d = device()) {
|
||||
// transactions works on both random and sequential devices
|
||||
d->startTransaction();
|
||||
auto ba = d->read(RasHeader::SIZE);
|
||||
d->rollbackTransaction();
|
||||
|
||||
QDataStream s(ba);
|
||||
s.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
RasHeader header;
|
||||
s >> header;
|
||||
|
||||
if (s.status() == QDataStream::Ok && IsSupported(header)) {
|
||||
v = QVariant::fromValue(QSize(header.Width, header.Height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (option == QImageIOHandler::ImageFormat) {
|
||||
if (auto d = device()) {
|
||||
// transactions works on both random and sequential devices
|
||||
d->startTransaction();
|
||||
auto ba = d->read(RasHeader::SIZE);
|
||||
d->rollbackTransaction();
|
||||
|
||||
QDataStream s(ba);
|
||||
s.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
RasHeader header;
|
||||
s >> header;
|
||||
|
||||
if (s.status() == QDataStream::Ok && IsSupported(header)) {
|
||||
v = QVariant::fromValue(imageFormat(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities RASPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
if (format == "ras") {
|
||||
if (format == "im1" || format == "im8" || format == "im24" || format == "im32" || format == "ras" || format == "sun") {
|
||||
return Capabilities(CanRead);
|
||||
}
|
||||
if (!format.isEmpty()) {
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=ras
|
||||
X-KDE-MimeType=image/x-sun-raster
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"Keys": [ "ras" ],
|
||||
"MimeTypes": [ "image/x-sun-raster" ]
|
||||
"Keys": [ "im1", "im8", "im24", "im32", "ras", "sun" ],
|
||||
"MimeTypes": [ "image/x-sun-raster", "image/x-sun-raster", "image/x-sun-raster", "image/x-sun-raster", "image/x-sun-raster", "image/x-sun-raster" ]
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ public:
|
||||
bool canRead() const override;
|
||||
bool read(QImage *image) override;
|
||||
|
||||
bool supportsOption(QImageIOHandler::ImageOption option) const override;
|
||||
QVariant option(QImageIOHandler::ImageOption option) const override;
|
||||
|
||||
static bool canRead(QIODevice *device);
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
#include <QSet>
|
||||
#include <QTimeZone>
|
||||
|
||||
#if defined(Q_OS_WINDOWS) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
@ -222,7 +223,7 @@ QString createTag(char *asciiz, const char *tag)
|
||||
|
||||
QString createTimeTag(time_t time, const char *tag)
|
||||
{
|
||||
auto value = QDateTime::fromSecsSinceEpoch(time, Qt::UTC);
|
||||
auto value = QDateTime::fromSecsSinceEpoch(time, QTimeZone::utc());
|
||||
if (value.isValid() && time > 0) {
|
||||
return createTag(value.toString(Qt::ISODate), tag);
|
||||
}
|
||||
@ -417,7 +418,7 @@ inline void rgbToRgbX(uchar *target, const uchar *source, qint32 targetSize, qin
|
||||
#define C_NR(a) (((a) & 0x3) << 17)
|
||||
#define C_FC(a) (((a) & 0x1) << 19)
|
||||
#define C_SR(a) (((a) & 0x1) << 20)
|
||||
#define C_PRESET(a) ((a) & 0xF)
|
||||
#define C_FLAGS(a) (((a) & 0x1) << 31) // flags mode
|
||||
|
||||
#define T_IQ(a) (((a) >> 4) & 0xF)
|
||||
#define T_OC(a) (((a) >> 8) & 0xF)
|
||||
@ -429,10 +430,10 @@ inline void rgbToRgbX(uchar *target, const uchar *source, qint32 targetSize, qin
|
||||
#define T_NR(a) (((a) >> 17) & 0x3)
|
||||
#define T_FC(a) (((a) >> 19) & 0x1)
|
||||
#define T_SR(a) (((a) >> 20) & 0x1)
|
||||
#define T_PRESET(a) ((a) & 0xF)
|
||||
#define T_FLAGS(a) (((a) >> 31) & 0x1)
|
||||
// clang-format on
|
||||
|
||||
#define DEFAULT_QUALITY (C_IQ(3) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0))
|
||||
#define DEFAULT_QUALITY (C_IQ(3) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0) | C_FLAGS(1))
|
||||
|
||||
void setParams(QImageIOHandler *handler, LibRaw *rawProcessor)
|
||||
{
|
||||
@ -443,9 +444,7 @@ void setParams(QImageIOHandler *handler, LibRaw *rawProcessor)
|
||||
auto &&rawparams = rawProcessor->imgdata.rawparams;
|
||||
#endif
|
||||
// Select one raw image from input file (0 - first, ...)
|
||||
if (handler->currentImageNumber() > -1) {
|
||||
rawparams.shot_select = handler->currentImageNumber();
|
||||
}
|
||||
|
||||
// *** Set processing parameters
|
||||
|
||||
@ -460,47 +459,45 @@ void setParams(QImageIOHandler *handler, LibRaw *rawProcessor)
|
||||
if (handler->supportsOption(QImageIOHandler::Quality)) {
|
||||
quality = handler->option(QImageIOHandler::Quality).toInt();
|
||||
}
|
||||
if (quality < 0) {
|
||||
quality = DEFAULT_QUALITY;
|
||||
}
|
||||
|
||||
switch (T_PRESET(quality)) {
|
||||
if (quality > -1) {
|
||||
switch (quality / 10) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
quality = C_IQ(0) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(0) | C_HS(1);
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
quality = C_IQ(0) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(0) | C_HS(0);
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
quality = C_IQ(3) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(0) | C_HS(0);
|
||||
break;
|
||||
case 4:
|
||||
case 3:
|
||||
quality = C_IQ(3) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0);
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
quality = C_IQ(3) | C_OC(2) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0);
|
||||
break;
|
||||
case 6:
|
||||
case 5:
|
||||
quality = C_IQ(3) | C_OC(4) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0);
|
||||
break;
|
||||
case 7:
|
||||
case 6:
|
||||
quality = C_IQ(11) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(0) | C_HS(0);
|
||||
break;
|
||||
case 8:
|
||||
case 7:
|
||||
quality = C_IQ(11) | C_OC(1) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0);
|
||||
break;
|
||||
case 9:
|
||||
case 8:
|
||||
quality = C_IQ(11) | C_OC(2) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0);
|
||||
break;
|
||||
case 10:
|
||||
default:
|
||||
quality = C_IQ(11) | C_OC(4) | C_CW(1) | C_AW(1) | C_BT(1) | C_HS(0);
|
||||
break;
|
||||
default:
|
||||
quality = DEFAULT_QUALITY;
|
||||
break;
|
||||
}
|
||||
quality |= C_FLAGS(1);
|
||||
}
|
||||
if (quality == -1) {
|
||||
quality = DEFAULT_QUALITY;
|
||||
}
|
||||
Q_ASSERT(T_FLAGS(quality));
|
||||
|
||||
auto &¶ms = rawProcessor->imgdata.params;
|
||||
|
||||
@ -725,7 +722,6 @@ RAWHandler::RAWHandler()
|
||||
: m_imageNumber(0)
|
||||
, m_imageCount(0)
|
||||
, m_quality(-1)
|
||||
, m_startPos(-1)
|
||||
{
|
||||
}
|
||||
|
||||
@ -742,15 +738,6 @@ bool RAWHandler::read(QImage *image)
|
||||
{
|
||||
auto dev = device();
|
||||
|
||||
// set the image position after the first run.
|
||||
if (!dev->isSequential()) {
|
||||
if (m_startPos < 0) {
|
||||
m_startPos = dev->pos();
|
||||
} else {
|
||||
dev->seek(m_startPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Check image file format.
|
||||
if (dev->atEnd()) {
|
||||
return false;
|
||||
@ -761,7 +748,7 @@ bool RAWHandler::read(QImage *image)
|
||||
return false;
|
||||
}
|
||||
|
||||
*image = img;
|
||||
*image = std::move(img);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -832,7 +819,7 @@ bool RAWHandler::jumpToNextImage()
|
||||
|
||||
bool RAWHandler::jumpToImage(int imageNumber)
|
||||
{
|
||||
if (imageNumber < 0 || imageNumber >= imageCount()) {
|
||||
if (imageNumber >= imageCount()) {
|
||||
return false;
|
||||
}
|
||||
m_imageNumber = imageNumber;
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=3fr,arw,arq,bay,bmq,crw,cr2,cr3,cap,cine,cs1,dcs,dc2,dcr,dng,drf,dxo,eip,erf,fff,hdr,iiq,k25,kdc,kc2,mdc,mef,mfw,mos,mrw,nef,nrw,obm,orf,ori,pef,ptx,pxn,qtk,r3d,raf,raw,rdc,rwl,rw2,rwz,sr2,srf,srw,sti,x3f
|
||||
X-KDE-MimeType=image/x-hasselblad-3fr,image/x-sony-arw,image/x-arq,image/x-bay,image/x-bmq,image/x-canon-crw,image/x-canon-cr2,image/x-canon-cr3,image/x-cap,image/x-cine,image/x-cs1,image/x-kodak-dcs,image/x-dc2,image/x-kodak-dcr,image/x-adobe-dng,image/x-drf,image/x-dxo,image/x-epson-eip,image/x-epson-erf,image/x-fff,image/x-hdr,image/x-iiq,image/x-kodak-k25,image/x-kodak-kdc,image/x-kodak-kc2,image/x-minolta-mdc,image/x-mamiya-mef,image/x-mfw,image/x-aptus-mos,image/x-minolta-mrw,image/x-nikon-nef,image/x-nikon-nrw,image/x-obm,image/x-olympus-orf,image/x-ori,image/x-pentax-pef,image/x-ptx,image/x-pxn,image/x-qtk,image/x-r3d,image/x-fuji-raf,image/x-raw,image/x-rdc,image/x-rwl,image/x-panasonic-rw2,image/x-rwz,image/x-sony-sr2,image/x-sony-srf,image/x-samsung-srw,image/x-sti,image/x-sigma-x3f
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -40,30 +40,13 @@ private:
|
||||
* Change the quality of the conversion. If -1, default quality is used.
|
||||
* @note Verify that the quality change support has been compiled with supportsOption()
|
||||
*
|
||||
* When the quality value is negative (but not -1), we assume we want to work with flags according to the following scheme:
|
||||
* 3 2 1 0
|
||||
* 1 0 9 8 7 6 5 4 3 2 1 0 9 87 6 5 4 3 2 1098 7654 3210
|
||||
* _ _ _ _ _ _ _ _ _ _ _ S F NN E H B A W CCCC IIII PPPP
|
||||
* 1 _ _ _ _ _ _ _ _ _ _ S F NN E H B A W CCCC IIII ____
|
||||
*
|
||||
* Where:
|
||||
*
|
||||
* _: reserved
|
||||
* P: preset values: *** if set, other flags are ignored! ***
|
||||
* - 0: Use other flags (no preset)
|
||||
* - 1: I = 0, C = 1, B = 0, W = 1, A = 1, H = 1 (Linear, sRGB, 8-bits, Camera White, Auto White, Half-size)
|
||||
* - 2: I = 0, C = 1, B = 0, W = 1, A = 1, H = 0 (Linear, sRGB, 8-bits, Camera White, Auto White)
|
||||
* - 3: I = 3, C = 1, B = 0, W = 1, A = 1, H = 0 (AHD, sRGB, 8-bits, Camera White, Auto White)
|
||||
* - 4: I = 3, C = 1, B = 1, W = 1, A = 1, H = 0 (AHD, sRGB, 16-bits, Camera White, Auto White)
|
||||
* - 5: I = 3, C = 2, B = 1, W = 1, A = 1, H = 0 (AHD, Adobe, 16-bits, Camera White, Auto White)
|
||||
* - 6: I = 3, C = 4, B = 1, W = 1, A = 1, H = 0 (AHD, ProPhoto, 16-bits, Camera White, Auto White)
|
||||
* - 7: I = 11, C = 1, B = 0, W = 1, A = 1, H = 0 (DHT, sRGB, 8-bits, Camera White, Auto White)
|
||||
* - 8: I = 11, C = 1, B = 1, W = 1, A = 1, H = 0 (DHT, sRGB, 16-bits, Camera White, Auto White)
|
||||
* - 9: I = 11, C = 2, B = 1, W = 1, A = 1, H = 0 (DHT, Adobe, 16-bits, Camera White, Auto White)
|
||||
* - 10: I = 11, C = 4, B = 1, W = 1, A = 1, H = 0 (DHT, ProPhoto, 16-bits, Camera White, Auto White)
|
||||
* - 11: reserved
|
||||
* - 12: reserved
|
||||
* - 13: reserved
|
||||
* - 14: reserved
|
||||
* - 15: reserved
|
||||
* _: reserved (should be zero)
|
||||
* I: interpolation quality (0 - linear, 1 - VNG, 2 - PPG, 3 - AHD, 4 - DCB, 11 - DHT, 12 - AAHD)
|
||||
* C: output colorspace (0 - raw, 1 - sRGB, 2 - Adobe, 3 - Wide, 4 - ProPhoto, 5 - XYZ, 6 - ACES, 7 - DCI-P3, 8 - Rec2020)
|
||||
* W: use camera white balace (0 - off, 1 - on)
|
||||
@ -74,16 +57,23 @@ private:
|
||||
* N: FBDD noise reduction (0 - off, 1 - light, 2 - full)
|
||||
* F: Interpolate RGGB as four colors (0 - off, 1 - on)
|
||||
* S: Don't stretch or rotate raw pixels (0 - rotate and stretch, 1 - don't rotate and stretch)
|
||||
*
|
||||
* @note It is safe to set both W and A: W is used if camera white balance is found, otherwise A is used.
|
||||
*
|
||||
* When quality is a positive value, a value between 0 and 100 is expected. The values are interpreted as follows:
|
||||
* - 00-09: I = 0, C = 1, B = 0, W = 1, A = 1, H = 1 (Linear, sRGB, 8-bits, Camera White, Auto White, Half-size)
|
||||
* - 10-19: I = 0, C = 1, B = 0, W = 1, A = 1, H = 0 (Linear, sRGB, 8-bits, Camera White, Auto White)
|
||||
* - 20-29: I = 3, C = 1, B = 0, W = 1, A = 1, H = 0 (AHD, sRGB, 8-bits, Camera White, Auto White)
|
||||
* - 30-39: I = 3, C = 1, B = 1, W = 1, A = 1, H = 0 (AHD, sRGB, 16-bits, Camera White, Auto White) [Default]
|
||||
* - 40-49: I = 3, C = 2, B = 1, W = 1, A = 1, H = 0 (AHD, Adobe, 16-bits, Camera White, Auto White)
|
||||
* - 50-59: I = 3, C = 4, B = 1, W = 1, A = 1, H = 0 (AHD, ProPhoto, 16-bits, Camera White, Auto White)
|
||||
* - 60-69: I = 11, C = 1, B = 0, W = 1, A = 1, H = 0 (DHT, sRGB, 8-bits, Camera White, Auto White)
|
||||
* - 70-79: I = 11, C = 1, B = 1, W = 1, A = 1, H = 0 (DHT, sRGB, 16-bits, Camera White, Auto White)
|
||||
* - 80-89: I = 11, C = 2, B = 1, W = 1, A = 1, H = 0 (DHT, Adobe, 16-bits, Camera White, Auto White)
|
||||
* - >= 90: I = 11, C = 4, B = 1, W = 1, A = 1, H = 0 (DHT, ProPhoto, 16-bits, Camera White, Auto White)
|
||||
*
|
||||
* When the quality is -1, default quality is used.
|
||||
*/
|
||||
qint32 m_quality;
|
||||
|
||||
/*!
|
||||
* \brief m_startPos
|
||||
* The initial device position to allow multi image load (cache value).
|
||||
*/
|
||||
qint64 m_startPos;
|
||||
};
|
||||
|
||||
class RAWPlugin : public QImageIOPlugin
|
||||
|
@ -678,9 +678,9 @@ bool SGIImage::writeImage(const QImage &image)
|
||||
}
|
||||
|
||||
if (hasAlpha && img.format() != QImage::Format_ARGB32) {
|
||||
img = img.convertToFormat(QImage::Format_ARGB32);
|
||||
img.convertTo(QImage::Format_ARGB32);
|
||||
} else if (!hasAlpha && img.format() != QImage::Format_RGB32) {
|
||||
img = img.convertToFormat(QImage::Format_RGB32);
|
||||
img.convertTo(QImage::Format_RGB32);
|
||||
}
|
||||
if (img.isNull()) {
|
||||
// qDebug() << "can't convert image to depth 32";
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=rgb,rgba,bw,sgi
|
||||
X-KDE-MimeType=image/x-rgb
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -419,7 +419,7 @@ bool TGAHandler::read(QImage *outImage)
|
||||
return false;
|
||||
}
|
||||
|
||||
*outImage = img;
|
||||
*outImage = std::move(img);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=tga
|
||||
X-KDE-MimeType=image/x-tga
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=true
|
@ -11,10 +11,7 @@
|
||||
#include <limits>
|
||||
|
||||
#include <QImage>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QImageIOHandler>
|
||||
#endif
|
||||
|
||||
// QVector uses some extra space for stuff, hence the 32 here suggested by Thiago Macieira
|
||||
static constexpr int kMaxQVectorSize = std::numeric_limits<int>::max() - 32;
|
||||
@ -24,13 +21,9 @@ static constexpr int kMaxQVectorSize = std::numeric_limits<int>::max() - 32;
|
||||
inline QImage imageAlloc(const QSize &size, const QImage::Format &format)
|
||||
{
|
||||
QImage img;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
img = QImage(size, format);
|
||||
#else
|
||||
if (!QImageIOHandler::allocateImage(size, format, &img)) {
|
||||
img = QImage(); // paranoia
|
||||
}
|
||||
#endif
|
||||
return img;
|
||||
}
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=xcf
|
||||
X-KDE-MimeType=image/x-xcf
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -5,7 +5,7 @@ include(ECMMarkAsTest)
|
||||
macro(kimageformats_executable_tests)
|
||||
foreach(_testname ${ARGN})
|
||||
add_executable(${_testname} ${_testname}.cpp)
|
||||
target_link_libraries(${_testname} Qt${QT_MAJOR_VERSION}::Gui)
|
||||
target_link_libraries(${_testname} Qt6::Gui)
|
||||
ecm_mark_as_test(${_testname})
|
||||
endforeach(_testname)
|
||||
endmacro()
|
||||
|
@ -103,7 +103,7 @@ int main(int argc, char **argv)
|
||||
QTextStream(stderr) << "Unknown QImage data format " << parser.value(qimgformat) << '\n';
|
||||
return 4;
|
||||
}
|
||||
img = img.convertToFormat(qformat);
|
||||
img.convertTo(qformat);
|
||||
}
|
||||
qint64 written = output.write(reinterpret_cast<const char *>(img.bits()), img.sizeInBytes());
|
||||
if (written != img.sizeInBytes()) {
|
||||
|