diff --git a/CMakeLists.txt b/CMakeLists.txt index c27416f6..32bae819 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ set_package_properties(LibLZMA PROPERTIES kde4_optional_find_package(ImageMagick COMPONENTS Magick++) set_package_properties(ImageMagick PROPERTIES + DESCRIPTION "Software suite to create, edit, and compose bitmap images" URL "https://imagemagick.org/" PURPOSE "Support for various image formats" TYPE OPTIONAL @@ -172,6 +173,15 @@ kde4_optional_find_package(WebP) set_package_properties(WebP PROPERTIES DESCRIPTION "A new image format for the Web" URL "https://developers.google.com/speed/webp" + PURPOSE "Support for WebP image format" + TYPE OPTIONAL +) + +kde4_optional_find_package(LibRaw) +set_package_properties(LibRaw PROPERTIES + DESCRIPTION "Simple and unified interface for extracting out of RAW files" + URL "https://www.libraw.org/" + PURPOSE "Support for RAW image format" TYPE OPTIONAL ) diff --git a/kdeui/util/kimageio.h b/kdeui/util/kimageio.h index 0c8a065f..8959c90b 100644 --- a/kdeui/util/kimageio.h +++ b/kdeui/util/kimageio.h @@ -25,6 +25,7 @@ * * Currently supported formats include: * @li WEBP \ \ + * @li RAW \ * @li PGM \ * @li XBM \ * @li BMP \ @@ -32,7 +33,6 @@ * @li JPEG \ * @li JP2 \ * @li GIF \ - * @li RAW \ * * @todo move to kdeui */ diff --git a/kimgio/CMakeLists.txt b/kimgio/CMakeLists.txt index 7fb13787..09e188a9 100644 --- a/kimgio/CMakeLists.txt +++ b/kimgio/CMakeLists.txt @@ -42,3 +42,24 @@ if(WEBP_FOUND) DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}/plugins/imageformats ) endif(WEBP_FOUND) + +################################## + +if(LIBRAW_FOUND) + include_directories(${LIBRAW_INCLUDE_DIR}) + kde4_add_plugin(kimg_raw raw.cpp) + target_link_libraries(kimg_raw + ${KDE4_KDECORE_LIBS} + ${QT_QTGUI_LIBRARY} + ${LIBRAW_LIBRARIES} + ) + set_target_properties(kimg_raw PROPERTIES + COMPILE_FLAGS "${KDE4_ENABLE_EXCEPTIONS}" + OUTPUT_NAME raw + ) + + install( + TARGETS kimg_raw + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}/plugins/imageformats + ) +endif(LIBRAW_FOUND) diff --git a/kimgio/README b/kimgio/README index fc46f161..df973e84 100644 --- a/kimgio/README +++ b/kimgio/README @@ -4,6 +4,7 @@ writing a new handler. Current formats include: WEBP +RAW along with whatever ImageMagick supports but it is assumed that it supports reading atleast the following formats (even if they cannot be loaded because @@ -16,7 +17,6 @@ ICO JPEG JP2 GIF -RAW If you want to contribute plugin for image format and there is no solid C/C++ library for it (like there is for WebP) then it is unlikely it will be diff --git a/kimgio/magick.cpp b/kimgio/magick.cpp index 56b522cf..f1f20fb1 100644 --- a/kimgio/magick.cpp +++ b/kimgio/magick.cpp @@ -59,24 +59,15 @@ static const struct HeadersTblData { }; static const qint16 HeadersTblSize = sizeof(HeadersTbl) / sizeof(HeadersTblData); -static QList s_blacklist = QList() - // borked coders - << std::string("PDF") - << std::string("EPDF") - << std::string("PS") - << std::string("HTML") - << std::string("SHTML") - << std::string("TXT") - << std::string("VIDEO") - << std::string("TTF") - // kdelibs provides these - << std::string("WEBP") - // Katie provides these, SVG coders are very borked - << std::string("SVG") - << std::string("SVGZ") - << std::string("XPM") - << std::string("PBM") - << std::string("PPM"); +static QList s_whitelist = QList() + << std::string("PGM") + << std::string("XBM") + << std::string("BMP") + << std::string("ICO") + << std::string("JPEG") + << std::string("JP2") + << std::string("GIF") + << std::string("PNG"); int initMagick() { @@ -97,19 +88,18 @@ int initMagick() kWarning() << "Exception raised"; } foreach (const Magick::CoderInfo &magickcoder, magickcoderlist) { - foreach (const std::string &blacklist, s_blacklist) { - if (magickcoder.name() == blacklist) { - kDebug() << "Blacklisting coder" << blacklist.c_str(); - try { - magickcoder.unregister(); - } catch(Magick::Exception &err) { - kWarning() << err.what(); - } catch(std::exception &err) { - kWarning() << err.what(); - } catch (...) { - kWarning() << "Exception raised"; - } - } + if (s_whitelist.contains(magickcoder.name())) { + continue; + } + try { + kDebug() << "Blacklisting coder" << magickcoder.name().c_str(); + magickcoder.unregister(); + } catch(Magick::Exception &err) { + kWarning() << err.what(); + } catch(std::exception &err) { + kWarning() << err.what(); + } catch (...) { + kWarning() << "Exception raised"; } } return 0; @@ -267,7 +257,11 @@ bool MagickHandler::canRead(QIODevice *device, QByteArray *actualformat) ); if (isvalid) { kDebug() << "Magick format detected" << magickformat; - actualformat->append(magickformat); + if (s_whitelist.contains(std::string(magickformat, qstrlen(magickformat)))) { + actualformat->append(magickformat); + } else { + isvalid = false; + } } } catch(Magick::Exception &err) { kWarning() << err.what(); @@ -343,7 +337,6 @@ QList MagickPlugin::mimeTypes() const << "image/x-portable-bitmap" << "image/x-portable-graymap" << "image/x-portable-pixmap" - << "image/x-dcraw" << "image/x-xbitmap"; return list; } diff --git a/kimgio/raw.cpp b/kimgio/raw.cpp new file mode 100644 index 00000000..f957e1ec --- /dev/null +++ b/kimgio/raw.cpp @@ -0,0 +1,203 @@ +/* This file is part of the KDE libraries + Copyright (C) 2022 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "raw.h" + +#include +#include + +#include + +static const char* const s_rawpluginformat = "raw"; + +RAWHandler::RAWHandler() +{ +} + +RAWHandler::~RAWHandler() +{ +} + +bool RAWHandler::canRead() const +{ + if (RAWHandler::canRead(device())) { + setFormat(s_rawpluginformat); + return true; + } + return false; +} + +bool RAWHandler::read(QImage *image) +{ + const qint64 devicepos = device()->pos(); + QByteArray data = device()->readAll(); + device()->seek(devicepos); + + if (Q_UNLIKELY(data.isEmpty())) { + return false; + } + + try { + LibRaw raw; + raw.imgdata.params.output_color = LIBRAW_COLORSPACE_sRGB; + + int rawresult = raw.open_buffer(data.data(), data.size()); + if (rawresult != LIBRAW_SUCCESS) { + kWarning() << libraw_strerror(rawresult); + raw.recycle(); + return false; + } + + rawresult = raw.unpack(); + if (rawresult != LIBRAW_SUCCESS) { + kWarning() << libraw_strerror(rawresult); + raw.recycle(); + return false; + } + + rawresult = raw.dcraw_process(); + if (rawresult != LIBRAW_SUCCESS) { + kWarning() << libraw_strerror(rawresult); + raw.recycle(); + return false; + } + + libraw_processed_image_t* rawimg = raw.dcraw_make_mem_image(&rawresult); + if (!rawimg || rawresult != LIBRAW_SUCCESS) { + kWarning() << libraw_strerror(rawresult); + raw.recycle(); + return false; + } + + if (rawimg->colors != 3) { + kWarning() << "Color components count not supported" << rawimg->colors; + raw.dcraw_clear_mem(rawimg); + raw.recycle(); + return false; + } + + *image = QImage(rawimg->width, rawimg->height, QImage::Format_ARGB32); + if (image->isNull()) { + kWarning() << "Could not create QImage"; + raw.dcraw_clear_mem(rawimg); + raw.recycle(); + return false; + } + + QRgb* imagebits = reinterpret_cast(image->bits()); + for (uint i = 0 ; i < rawimg->data_size; i += 3) { + *imagebits = qRgba(rawimg->data[i], rawimg->data[i + 1], rawimg->data[i + 2], 0xff); + imagebits++; + } + + raw.dcraw_clear_mem(rawimg); + raw.recycle(); + } catch (...) { + kWarning() << "Exception raised"; + return false; + } + + return true; +} + +bool RAWHandler::write(const QImage &image) +{ + // this plugin is a read-only kind of plugin + return false; +} + +QByteArray RAWHandler::name() const +{ + return s_rawpluginformat; +} + +bool RAWHandler::canRead(QIODevice *device) +{ + if (Q_UNLIKELY(!device)) { + kWarning() << "Called with no device"; + return false; + } + + const qint64 devicepos = device->pos(); + QByteArray data = device->readAll(); + device->seek(devicepos); + + if (Q_UNLIKELY(data.isEmpty())) { + return false; + } + + try { + LibRaw raw; + raw.imgdata.params.output_color = LIBRAW_COLORSPACE_sRGB; + + const int rawresult = raw.open_buffer(data.data(), data.size()); + if (rawresult == LIBRAW_FILE_UNSUPPORTED) { + kDebug() << libraw_strerror(rawresult); + raw.recycle(); + return false; + } else if (rawresult != LIBRAW_SUCCESS) { + kWarning() << libraw_strerror(rawresult); + raw.recycle(); + return false; + } + + raw.recycle(); + } catch (...) { + kWarning() << "Exception raised"; + return false; + } + + return true; +} + +QStringList RAWPlugin::keys() const +{ + return QStringList() << s_rawpluginformat; +} + +QList RAWPlugin::mimeTypes() const +{ + static const QList list = QList() + << "image/x-dcraw"; + return list; +} + +QImageIOPlugin::Capabilities RAWPlugin::capabilities(QIODevice *device, const QByteArray &format) const +{ + if (format == s_rawpluginformat) + return QImageIOPlugin::Capabilities(QImageIOPlugin::CanRead); + if (!format.isEmpty()) + return 0; + if (!device->isOpen()) + return 0; + + QImageIOPlugin::Capabilities cap; + if (device->isReadable() && RAWHandler::canRead(device)) + cap |= QImageIOPlugin::CanRead; + return cap; +} + +QImageIOHandler *RAWPlugin::create(QIODevice *device, const QByteArray &format) const +{ + QImageIOHandler *handler = new RAWHandler(); + handler->setDevice(device); + handler->setFormat(format); + return handler; +} + +Q_EXPORT_PLUGIN2(raw, RAWPlugin) diff --git a/kimgio/raw.h b/kimgio/raw.h new file mode 100644 index 00000000..e3d4e875 --- /dev/null +++ b/kimgio/raw.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE libraries + Copyright (C) 2022 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KIMG_RAW_H +#define KIMG_RAW_H + +#include +#include + +class RAWHandler : public QImageIOHandler +{ +public: + RAWHandler(); + ~RAWHandler(); + + bool canRead() const final; + bool read(QImage *image) final; + bool write(const QImage &image) final; + + QByteArray name() const final; + + static bool canRead(QIODevice *device); +}; + +class RAWPlugin : public QImageIOPlugin +{ +public: + QStringList keys() const; + QList mimeTypes() const; + Capabilities capabilities(QIODevice *device, const QByteArray &format) const final; + QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const final; +}; + +#endif // KIMG_RAW_H +