diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro index 8c79379edc86ab0a1615542267b949bbb4aa70a4..d6c59eeb6cbcfb7f41bbd48b9dc09f41d725b01b 100644 --- a/src/plugins/imageformats/imageformats.pro +++ b/src/plugins/imageformats/imageformats.pro @@ -6,6 +6,8 @@ SUBDIRS = \ wbmp \ webp +darwin: SUBDIRS += macheif + qtConfig(regularexpression): \ SUBDIRS += icns diff --git a/src/plugins/imageformats/macheif/macheif.json b/src/plugins/imageformats/macheif/macheif.json new file mode 100644 index 0000000000000000000000000000000000000000..52b0a89e91d72a15ee428da3bf784f2a86d4c33f --- /dev/null +++ b/src/plugins/imageformats/macheif/macheif.json @@ -0,0 +1,4 @@ +{ + "Keys": [ "heic", "heif" ], + "MimeTypes": [ "image/heic", "image/heif" ] +} diff --git a/src/plugins/imageformats/macheif/macheif.pro b/src/plugins/imageformats/macheif/macheif.pro new file mode 100644 index 0000000000000000000000000000000000000000..38e80872c77c40b44d8f110f61c5d8f2bba6e046 --- /dev/null +++ b/src/plugins/imageformats/macheif/macheif.pro @@ -0,0 +1,20 @@ +TARGET = qmacheif +PLUGIN_TYPE = imageformats +PLUGIN_CLASS_NAME = QMacHeifPlugin + +LIBS += -framework CoreFoundation -framework CoreGraphics -framework ImageIO + +QT += core-private gui-private + +SOURCES += \ + qmacheifhandler.cpp \ + main.cpp + +HEADERS += \ + qmacheifhandler.h + +include (../shared/qiiofhelpers.pri) + +OTHER_FILES += macheif.json + +load(qt_plugin) diff --git a/src/plugins/imageformats/macheif/main.cpp b/src/plugins/imageformats/macheif/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12d9a4abf105b26dd627857a6340a0f682cf46cd --- /dev/null +++ b/src/plugins/imageformats/macheif/main.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the MacHeif plugin in the Qt ImageFormats module. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_IMAGEFORMATPLUGIN + +#include <qmacheifhandler.h> +#include <qiiofhelpers_p.h> + +QT_BEGIN_NAMESPACE + +class QMacHeifPlugin : public QImageIOPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "macheif.json") + +public: + Capabilities capabilities(QIODevice *device, const QByteArray &format) const override; + QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override; +}; + +QImageIOPlugin::Capabilities QMacHeifPlugin::capabilities(QIODevice *device, const QByteArray &format) const +{ + static const Capabilities sysCaps = QIIOFHelpers::systemCapabilities(QStringLiteral("public.heic")); + + if (!sysCaps) + return 0; + if (format == "heic" || format == "heif") + return sysCaps; + if (!format.isEmpty()) + return 0; + if (!device->isOpen()) + return 0; + + Capabilities cap; + if (sysCaps.testFlag(CanRead) && device->isReadable() && QMacHeifHandler::canRead(device)) + cap |= CanRead; + if (sysCaps.testFlag(CanWrite) && device->isWritable()) + cap |= CanWrite; + return cap; +} + +QImageIOHandler *QMacHeifPlugin::create(QIODevice *device, const QByteArray &format) const +{ + QMacHeifHandler *handler = new QMacHeifHandler(); + handler->setDevice(device); + handler->setFormat(format); + return handler; +} + +QT_END_NAMESPACE + +#include "main.moc" + +#endif // !QT_NO_IMAGEFORMATPLUGIN diff --git a/src/plugins/imageformats/macheif/qmacheifhandler.cpp b/src/plugins/imageformats/macheif/qmacheifhandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c63e52a263f4ac129b7f62537669a17ae1a207c --- /dev/null +++ b/src/plugins/imageformats/macheif/qmacheifhandler.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the MacHeif plugin in the Qt ImageFormats module. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacheifhandler.h" +#include "qiiofhelpers_p.h" +#include <QVariant> + +QT_BEGIN_NAMESPACE + +class QMacHeifHandlerPrivate +{ + Q_DECLARE_PUBLIC(QMacHeifHandler) + Q_DISABLE_COPY(QMacHeifHandlerPrivate) +public: + QMacHeifHandlerPrivate(QMacHeifHandler *q_ptr) + : writeQuality(-1), q_ptr(q_ptr) + {} + + int writeQuality; + QMacHeifHandler *q_ptr; +}; + + +QMacHeifHandler::QMacHeifHandler() + : d_ptr(new QMacHeifHandlerPrivate(this)) +{ +} + +QMacHeifHandler::~QMacHeifHandler() +{ +} + +bool QMacHeifHandler::canRead(QIODevice *iod) +{ + bool bCanRead = false; + char buf[12]; + if (iod && iod->peek(buf, 12) == 12) { + bCanRead = (!qstrncmp(buf + 4, "ftyp", 4) && + (!qstrncmp(buf + 8, "heic", 4) || + !qstrncmp(buf + 8, "heix", 4) || + !qstrncmp(buf + 8, "mif1", 4))); + } + return bCanRead; +} + +bool QMacHeifHandler::canRead() const +{ + if (canRead(device())) { + setFormat("heic"); + return true; + } + return false; +} + +bool QMacHeifHandler::read(QImage *image) +{ + return QIIOFHelpers::readImage(this, image); +} + +bool QMacHeifHandler::write(const QImage &image) +{ + return QIIOFHelpers::writeImage(this, image, QStringLiteral("public.heic")); +} + +QVariant QMacHeifHandler::option(ImageOption option) const +{ + return QVariant(); +} + +void QMacHeifHandler::setOption(ImageOption option, const QVariant &value) +{ + Q_UNUSED(option) + Q_UNUSED(value) +} + +bool QMacHeifHandler::supportsOption(ImageOption option) const +{ + return false; +} + +QT_END_NAMESPACE diff --git a/src/plugins/imageformats/macheif/qmacheifhandler.h b/src/plugins/imageformats/macheif/qmacheifhandler.h new file mode 100644 index 0000000000000000000000000000000000000000..6e94a59623b9c095cc19f5044601cb3c916344d9 --- /dev/null +++ b/src/plugins/imageformats/macheif/qmacheifhandler.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the MacHeif plugin in the Qt ImageFormats module. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACHEIFHANDLER_H +#define QMACHEIFHANDLER_H + +#include <QScopedPointer> +#include <QImageIOHandler> + +QT_BEGIN_NAMESPACE + +class QImage; +class QByteArray; +class QIODevice; +class QVariant; +class QMacHeifHandlerPrivate; + +class QMacHeifHandler : public QImageIOHandler +{ +public: + QMacHeifHandler(); + ~QMacHeifHandler(); + + bool canRead() const override; + bool read(QImage *image) override; + bool write(const QImage &image) override; + QVariant option(ImageOption option) const override; + void setOption(ImageOption option, const QVariant &value) override; + bool supportsOption(ImageOption option) const override; + + static bool canRead(QIODevice *iod); + +private: + Q_DECLARE_PRIVATE(QMacHeifHandler) + QScopedPointer<QMacHeifHandlerPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QMACHEIFHANDLER_P_H diff --git a/src/plugins/imageformats/macjp2/macjp2.pro b/src/plugins/imageformats/macjp2/macjp2.pro index 66aafb4508da8149ca1e9db3b9566e15bd501b79..9a44b696d52ac5555f1763d93d6bff5a58f06cd0 100644 --- a/src/plugins/imageformats/macjp2/macjp2.pro +++ b/src/plugins/imageformats/macjp2/macjp2.pro @@ -8,12 +8,12 @@ QT += core-private gui-private SOURCES += \ qmacjp2handler.cpp \ - main.cpp \ - qiiofhelpers.cpp + main.cpp HEADERS += \ - qmacjp2handler.h \ - qiiofhelpers_p.h + qmacjp2handler.h + +include (../shared/qiiofhelpers.pri) OTHER_FILES += macjp2.json diff --git a/src/plugins/imageformats/macjp2/qiiofhelpers.cpp b/src/plugins/imageformats/shared/qiiofhelpers.cpp similarity index 91% rename from src/plugins/imageformats/macjp2/qiiofhelpers.cpp rename to src/plugins/imageformats/shared/qiiofhelpers.cpp index c8949323930f22141c9eed27d1dde057ef571bfe..2cd8b7462b2cc8ec0c11cfa8efbde864e0deb4b4 100644 --- a/src/plugins/imageformats/macjp2/qiiofhelpers.cpp +++ b/src/plugins/imageformats/shared/qiiofhelpers.cpp @@ -98,6 +98,24 @@ static size_t cbPutBytes(void *info, const void *buffer, size_t count) typedef QImage (*cgImageToQImagePtr)(CGImageRef image); typedef CGImageRef (*qImageToCGImagePtr)(const QImage &image); +QImageIOPlugin::Capabilities QIIOFHelpers::systemCapabilities(const QString &uti) +{ + QImageIOPlugin::Capabilities res; + QCFString cfUti(uti); + + QCFType<CFArrayRef> cfSourceTypes = CGImageSourceCopyTypeIdentifiers(); + CFIndex len = CFArrayGetCount(cfSourceTypes); + if (CFArrayContainsValue(cfSourceTypes, CFRangeMake(0, len), cfUti)) + res |= QImageIOPlugin::CanRead; + + QCFType<CFArrayRef> cfDestTypes = CGImageDestinationCopyTypeIdentifiers(); + len = CFArrayGetCount(cfDestTypes); + if (CFArrayContainsValue(cfDestTypes, CFRangeMake(0, len), cfUti)) + res |= QImageIOPlugin::CanWrite; + + return res; +} + bool QIIOFHelpers::readImage(QImageIOHandler *q_ptr, QImage *out) { static const CGDataProviderSequentialCallbacks cgCallbacks = { 0, &cbGetBytes, &cbSkipForward, &cbRewind, nullptr }; diff --git a/src/plugins/imageformats/shared/qiiofhelpers.pri b/src/plugins/imageformats/shared/qiiofhelpers.pri new file mode 100644 index 0000000000000000000000000000000000000000..8824281c328ddbb7cc45671d4b2484e4e097fb5a --- /dev/null +++ b/src/plugins/imageformats/shared/qiiofhelpers.pri @@ -0,0 +1,5 @@ +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/qiiofhelpers_p.h + +SOURCES += $$PWD/qiiofhelpers.cpp diff --git a/src/plugins/imageformats/macjp2/qiiofhelpers_p.h b/src/plugins/imageformats/shared/qiiofhelpers_p.h similarity index 95% rename from src/plugins/imageformats/macjp2/qiiofhelpers_p.h rename to src/plugins/imageformats/shared/qiiofhelpers_p.h index ef5a0228095b02f37696d3028fbe664e216e4f29..da517318b746035eca09ca20a3cf5c78a89ba700 100644 --- a/src/plugins/imageformats/macjp2/qiiofhelpers_p.h +++ b/src/plugins/imageformats/shared/qiiofhelpers_p.h @@ -51,10 +51,9 @@ // We mean it. // -QT_BEGIN_NAMESPACE +#include <QImageIOPlugin> -class QImageIOHandler; -class QImage; +QT_BEGIN_NAMESPACE /* Functions to utilize the native ImageIO Framework in OS X and iOS @@ -63,6 +62,7 @@ Functions to utilize the native ImageIO Framework in OS X and iOS class QIIOFHelpers { public: + static QImageIOPlugin::Capabilities systemCapabilities(const QString &uti); static bool readImage(QImageIOHandler *q_ptr, QImage *out); static bool writeImage(QImageIOHandler *q_ptr, const QImage &in, const QString &uti); }; diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index bf0f8e5cee06b8f3719e660206b01a76efccc32b..daa1dfbc26a697de249c292a6641b25c686a2cb3 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -6,5 +6,6 @@ SUBDIRS = \ icns \ jp2 \ webp \ + heif \ mng \ tiff diff --git a/tests/auto/heif/heif.pro b/tests/auto/heif/heif.pro new file mode 100644 index 0000000000000000000000000000000000000000..9ef108506772b8d87b58cda5df02ec7841ba0eac --- /dev/null +++ b/tests/auto/heif/heif.pro @@ -0,0 +1,8 @@ +TARGET = tst_qheif + +QT = core gui testlib +CONFIG -= app_bundle +CONFIG += testcase + +SOURCES += tst_qheif.cpp +RESOURCES += $$PWD/../../shared/images/heif.qrc diff --git a/tests/auto/heif/tst_qheif.cpp b/tests/auto/heif/tst_qheif.cpp new file mode 100644 index 0000000000000000000000000000000000000000..faf22fa1b5daa49dca2ea04c2db55411e57db7fe --- /dev/null +++ b/tests/auto/heif/tst_qheif.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the autotests in the Qt ImageFormats module. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtGui/QtGui> + +class tst_qheif: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void readImage_data(); + void readImage(); +}; + +void tst_qheif::initTestCase() +{ + if (!QImageReader::supportedImageFormats().contains("heic")) + QSKIP("The image format handler is not installed."); +} + +void tst_qheif::readImage_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QSize>("size"); + + QTest::newRow("col") << QString("col320x480.heic") << QSize(320, 480); +} + +void tst_qheif::readImage() +{ + QFETCH(QString, fileName); + QFETCH(QSize, size); + + QString path = QStringLiteral(":/heif/") + fileName; + QImageReader reader(path); + QVERIFY(reader.canRead()); + QImage image = reader.read(); + QVERIFY(!image.isNull()); + QCOMPARE(image.size(), size); +} + +QTEST_MAIN(tst_qheif) +#include "tst_qheif.moc" diff --git a/tests/shared/images/heif.qrc b/tests/shared/images/heif.qrc new file mode 100644 index 0000000000000000000000000000000000000000..2a41c36bc134e0810d85158a5cfc6fb77aa95393 --- /dev/null +++ b/tests/shared/images/heif.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>heif/col320x480.heic</file> + </qresource> +</RCC> diff --git a/tests/shared/images/heif/col320x480.heic b/tests/shared/images/heif/col320x480.heic new file mode 100644 index 0000000000000000000000000000000000000000..6ca3c7b69aebfe956918a43cff49837015ede92f Binary files /dev/null and b/tests/shared/images/heif/col320x480.heic differ