File indexing completed on 2025-01-19 03:51:00

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2019-09-22
0007  * Description : HEIF DImg plugin.
0008  *
0009  * SPDX-FileCopyrightText: 2019-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "dimgheifplugin.h"
0016 
0017 // Qt includes
0018 
0019 #include <QFile>
0020 
0021 // KDE includes
0022 
0023 #include <klocalizedstring.h>
0024 
0025 // Local includes
0026 
0027 #include "digikam_debug.h"
0028 #include "digikam_config.h"
0029 #include "digikam_globals.h"
0030 #include "dimgheifloader.h"
0031 #include "dimgheifexportsettings.h"
0032 
0033 namespace DigikamHEIFDImgPlugin
0034 {
0035 
0036 DImgHEIFPlugin::DImgHEIFPlugin(QObject* const parent)
0037     : DPluginDImg(parent)
0038 {
0039 }
0040 
0041 DImgHEIFPlugin::~DImgHEIFPlugin()
0042 {
0043 }
0044 
0045 QString DImgHEIFPlugin::name() const
0046 {
0047     return i18nc("@title", "HEIF loader");
0048 }
0049 
0050 QString DImgHEIFPlugin::iid() const
0051 {
0052     return QLatin1String(DPLUGIN_IID);
0053 }
0054 
0055 QIcon DImgHEIFPlugin::icon() const
0056 {
0057     return QIcon::fromTheme(QLatin1String("image-x-generic"));
0058 }
0059 
0060 QString DImgHEIFPlugin::description() const
0061 {
0062     return i18nc("@info", "An image loader based on Libheif codec");
0063 }
0064 
0065 QString DImgHEIFPlugin::details() const
0066 {
0067     QString x265Notice = i18nc("@info", "This library is not present on your system.");
0068 
0069 #ifdef HAVE_X265
0070 
0071     int depth = DImgHEIFLoader::x265MaxBitsDepth();
0072 
0073     if (depth != -1)
0074     {
0075         x265Notice = i18nc("@info", "This library is available on your system with a maximum color depth "
0076                            "support of %1 bits.", depth);
0077     }
0078     else
0079     {
0080         x265Notice = i18nc("@info", "This library is available on your system but is not able to encode "
0081                            "image with a suitable color depth.");
0082     }
0083 
0084 #endif
0085 
0086     return xi18nc("@info",
0087                   "<para>This plugin allows users to load and save image using Libheif codec.</para>"
0088                   "<para>High Efficiency Image File Format (HEIF), also known as High Efficiency Image Coding (HEIC), "
0089                   "is a file format for individual images and image sequences. It was developed by the "
0090                   "Moving Picture Experts Group (MPEG) and it claims that twice as much information can be "
0091                   "stored in a HEIF image as in a JPEG image of the same size, resulting in a better quality image. "
0092                   "HEIF also supports animation, and is capable of storing more information than an animated GIF "
0093                   "at a small fraction of the size.</para>"
0094                   "<para>Encoding HEIC is relevant of optional libde265 codec. %1</para>"
0095                   "<para>See <a href='https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format'>"
0096                   "High Efficiency Image File Format</a> for details.</para>", x265Notice);
0097 }
0098 
0099 QString DImgHEIFPlugin::handbookSection() const
0100 {
0101     return QLatin1String("supported_materials");
0102 }
0103 
0104 QString DImgHEIFPlugin::handbookChapter() const
0105 {
0106     return QLatin1String("image_formats");
0107 }
0108 
0109 QString DImgHEIFPlugin::handbookReference() const
0110 {
0111     return QLatin1String("image-heif");
0112 }
0113 
0114 QList<DPluginAuthor> DImgHEIFPlugin::authors() const
0115 {
0116     return QList<DPluginAuthor>()
0117             << DPluginAuthor(QString::fromUtf8("Gilles Caulier"),
0118                              QString::fromUtf8("caulier dot gilles at gmail dot com"),
0119                              QString::fromUtf8("(C) 2019-2022"))
0120             ;
0121 }
0122 
0123 void DImgHEIFPlugin::setup(QObject* const /*parent*/)
0124 {
0125     // Nothing to do
0126 }
0127 
0128 QMap<QString, QStringList> DImgHEIFPlugin::extraAboutData() const
0129 {
0130     QMap<QString, QStringList> map;
0131     map.insert(QLatin1String("HEIC"),
0132                QStringList() << i18nc("@title", "High efficiency image coding")
0133                              << i18nc("@info: can read file format", "yes")
0134 #ifdef HAVE_X265
0135                              << i18nc("@info: can write file format", "yes")
0136 #else
0137                              << i18nc("@info: cannot write file format", "no")
0138 #endif
0139     );
0140 
0141     map.insert(QLatin1String("HEIF"),
0142                QStringList() << i18nc("@title", "High efficiency image coding")
0143                              << i18nc("@info: can read file format", "yes")
0144 #ifdef HAVE_X265
0145                              << i18nc("@info: can write file format", "yes")
0146 #else
0147                              << i18nc("@info: cannot write file format", "no")
0148 #endif
0149     );
0150 
0151     return map;
0152 }
0153 
0154 bool DImgHEIFPlugin::previewSupported() const
0155 {
0156     return true;
0157 }
0158 
0159 QString DImgHEIFPlugin::loaderName() const
0160 {
0161     return QLatin1String("HEIF");
0162 }
0163 
0164 QString DImgHEIFPlugin::typeMimes() const
0165 {
0166     return QLatin1String("HEIC HEIF HIF");
0167 }
0168 
0169 int DImgHEIFPlugin::canRead(const QFileInfo& fileInfo, bool magic) const
0170 {
0171     QString filePath = fileInfo.filePath();
0172     QString format   = fileInfo.suffix().toUpper();
0173 
0174     // First simply check file extension
0175 
0176     if (!magic)
0177     {
0178         return (!format.isEmpty() && typeMimes().contains(format)) ? 10 : 0;
0179     }
0180 
0181     // In second, we trying to parse file header.
0182 
0183     QFile file(filePath);
0184 
0185     if (!file.open(QIODevice::ReadOnly))
0186     {
0187         qCDebug(DIGIKAM_DIMG_LOG) << "Failed to open file " << filePath;
0188 
0189         return 0;
0190     }
0191 
0192     const qint64 headerLen = 12;
0193 
0194     QByteArray header(headerLen, '\0');
0195 
0196     if (file.read((char*)header.data(), headerLen) != headerLen)
0197     {
0198         qCDebug(DIGIKAM_DIMG_LOG) << "Failed to read header of file " << filePath;
0199 
0200         return 0;
0201     }
0202 
0203     if (
0204         (memcmp(&header.data()[4], "ftypheic", 8) == 0) ||
0205         (memcmp(&header.data()[4], "ftypheix", 8) == 0) ||
0206         (memcmp(&header.data()[4], "ftypmif1", 8) == 0)
0207        )
0208     {
0209         return 10;
0210     }
0211 
0212     return 0;
0213 }
0214 
0215 int DImgHEIFPlugin::canWrite(const QString& format) const
0216 {
0217 
0218 #ifdef HAVE_X265
0219 
0220     return typeMimes().contains(format.toUpper()) ? 10 : 0;
0221 
0222 #else
0223 
0224     Q_UNUSED(format);
0225 
0226     return 0;
0227 
0228 #endif
0229 }
0230 
0231 DImgLoader* DImgHEIFPlugin::loader(DImg* const image, const DRawDecoding&) const
0232 {
0233     return (new DImgHEIFLoader(image));
0234 }
0235 
0236 DImgLoaderSettings* DImgHEIFPlugin::exportWidget(const QString& format) const
0237 {
0238     if (canWrite(format))
0239     {
0240         return (new DImgHEIFExportSettings());
0241     }
0242 
0243     return nullptr;
0244 }
0245 
0246 } // namespace DigikamHEIFDImgPlugin
0247 
0248 #include "moc_dimgheifplugin.cpp"