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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2019-09-22
0007  * Description : JPEG-2000 DImg plugin.
0008  *
0009  * SPDX-FileCopyrightText: 2020-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 "dimgjpeg2000plugin.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 "dimgjpeg2000loader.h"
0031 #include "dimgjpeg2000exportsettings.h"
0032 
0033 // Jasper includes
0034 
0035 #ifndef Q_CC_MSVC
0036 extern "C"
0037 {
0038 #endif
0039 
0040 #if defined(Q_OS_DARWIN) && defined(Q_CC_CLANG)
0041 #   pragma clang diagnostic push
0042 #   pragma clang diagnostic ignored "-Wshift-negative-value"
0043 #endif
0044 
0045 #include <jasper/jasper.h>
0046 #include <jasper/jas_version.h>
0047 
0048 #if defined(Q_OS_DARWIN) && defined(Q_CC_CLANG)
0049 #   pragma clang diagnostic pop
0050 #endif
0051 
0052 #ifndef Q_CC_MSVC
0053 }
0054 #endif
0055 
0056 namespace DigikamJPEG2000DImgPlugin
0057 {
0058 
0059 DImgJPEG2000Plugin::DImgJPEG2000Plugin(QObject* const parent)
0060     : DPluginDImg (parent),
0061       m_initJasper(false)
0062 {
0063 
0064 #if defined JAS_VERSION_MAJOR && JAS_VERSION_MAJOR >= 3
0065 
0066     size_t max_mem = jas_get_total_mem_size();
0067 
0068     if (max_mem)
0069     {
0070         max_mem = 0.75 * max_mem;
0071     }
0072     else
0073     {
0074         max_mem = (size_t)1024 * 1024 * 1024;
0075     }
0076 
0077     jas_conf_clear();
0078     jas_conf_set_debug_level(0);
0079     jas_conf_set_multithread(1);
0080     jas_conf_set_max_mem_usage(max_mem);
0081 
0082     if (!jas_init_library())
0083     {
0084         m_initJasper = true;
0085     }
0086 
0087 #else
0088 
0089     m_initJasper = true;
0090 
0091 #endif
0092 
0093 }
0094 
0095 DImgJPEG2000Plugin::~DImgJPEG2000Plugin()
0096 {
0097 
0098 #if defined JAS_VERSION_MAJOR && JAS_VERSION_MAJOR >= 3
0099 
0100     jas_cleanup_library();
0101 
0102 #endif
0103 
0104 }
0105 
0106 QString DImgJPEG2000Plugin::name() const
0107 {
0108     return i18nc("@title", "JPEG-2000 loader");
0109 }
0110 
0111 QString DImgJPEG2000Plugin::iid() const
0112 {
0113     return QLatin1String(DPLUGIN_IID);
0114 }
0115 
0116 QIcon DImgJPEG2000Plugin::icon() const
0117 {
0118     return QIcon::fromTheme(QLatin1String("image-jpeg"));
0119 }
0120 
0121 QString DImgJPEG2000Plugin::description() const
0122 {
0123     return i18nc("@info", "An image loader based on Libjasper codec");
0124 }
0125 
0126 QString DImgJPEG2000Plugin::details() const
0127 {
0128     return xi18nc("@info", "<para>This plugin allows users to load and save image using Libjasper codec</para>"
0129                   "<para>The JPEG (Joint Photographic Experts Group) 2000 standard, finalized in 2001, "
0130                   "defines a image-coding scheme using state-of-the-art compression techniques based "
0131                   "on wavelet technology. Its architecture is useful for many diverse applications, "
0132                   "including image archiving, security systems, digital photography, and medical imaging.</para>"
0133                   "<para>See <a href='https://en.wikipedia.org/wiki/JPEG_2000'>"
0134                   "Joint Photographic Experts Group documentation</a> for details.</para>"
0135     );
0136 }
0137 
0138 QString DImgJPEG2000Plugin::handbookSection() const
0139 {
0140     return QLatin1String("supported_materials");
0141 }
0142 
0143 QString DImgJPEG2000Plugin::handbookChapter() const
0144 {
0145     return QLatin1String("image_formats");
0146 }
0147 
0148 QString DImgJPEG2000Plugin::handbookReference() const
0149 {
0150     return QLatin1String("image-jpeg2000");
0151 }
0152 
0153 QList<DPluginAuthor> DImgJPEG2000Plugin::authors() const
0154 {
0155     return QList<DPluginAuthor>()
0156             << DPluginAuthor(QString::fromUtf8("Gilles Caulier"),
0157                              QString::fromUtf8("caulier dot gilles at gmail dot com"),
0158                              QString::fromUtf8("(C) 2006-2023"))
0159             ;
0160 }
0161 
0162 void DImgJPEG2000Plugin::setup(QObject* const /*parent*/)
0163 {
0164     // Nothing to do
0165 }
0166 
0167 QMap<QString, QStringList> DImgJPEG2000Plugin::extraAboutData() const
0168 {
0169     QMap<QString, QStringList> map;
0170     map.insert(QLatin1String("JP2"), QStringList() << i18nc("@title", "JPEG-2000 image")
0171                                                    << i18nc("@info: can read file format",  "yes")
0172                                                    << i18nc("@info: can write file format", "yes")
0173     );
0174     map.insert(QLatin1String("JPX"), QStringList() << i18nc("@title", "JPEG-2000 image")
0175                                                    << i18nc("@info: can read file format",  "yes")
0176                                                    << i18nc("@info: can write file format", "yes")
0177     );
0178     map.insert(QLatin1String("JPC"), QStringList() << i18nc("@title", "JPEG-2000 stream")
0179                                                    << i18nc("@info: can read file format",  "yes")
0180                                                    << i18nc("@info: can write file format", "yes")
0181     );
0182     map.insert(QLatin1String("J2K"), QStringList() << i18nc("@title", "JPEG-2000 stream")
0183                                                    << i18nc("@info: can read file format",  "yes")
0184                                                    << i18nc("@info: can write file format", "yes")
0185     );
0186     map.insert(QLatin1String("PGX"), QStringList() << i18nc("@title", "JPEG-2000 verification model")
0187                                                    << i18nc("@info: can read file format",  "yes")
0188                                                    << i18nc("@info: can write file format", "yes")
0189     );
0190 
0191     return map;
0192 }
0193 
0194 QString DImgJPEG2000Plugin::loaderName() const
0195 {
0196     return QLatin1String("JPEG2000");
0197 }
0198 
0199 QString DImgJPEG2000Plugin::typeMimes() const
0200 {
0201     return QLatin1String("JP2 JPX JPC J2K JP2K PGX");
0202 }
0203 
0204 int DImgJPEG2000Plugin::canRead(const QFileInfo& fileInfo, bool magic) const
0205 {
0206     if (!m_initJasper)
0207     {
0208         return 0;
0209     }
0210 
0211     QString filePath = fileInfo.filePath();
0212     QString format   = fileInfo.suffix().toUpper();
0213 
0214     // First simply check file extension
0215 
0216     if (!magic)
0217     {
0218         return (!format.isEmpty() && typeMimes().contains(format)) ? 10 : 0;
0219     }
0220 
0221     // In second, we trying to parse file header.
0222 
0223     QFile file(filePath);
0224 
0225     if (!file.open(QIODevice::ReadOnly))
0226     {
0227         qCDebug(DIGIKAM_DIMG_LOG) << "Failed to open file " << filePath;
0228 
0229         return 0;
0230     }
0231 
0232     const qint64 headerLen = 9;
0233 
0234     QByteArray header(headerLen, '\0');
0235 
0236     if (file.read((char*)header.data(), headerLen) != headerLen)
0237     {
0238         qCDebug(DIGIKAM_DIMG_LOG) << "Failed to read header of file " << filePath;
0239 
0240         return 0;
0241     }
0242 
0243     uchar jp2ID[5] = { 0x6A, 0x50, 0x20, 0x20, 0x0D, };
0244     uchar jpcID[2] = { 0xFF, 0x4F };
0245 
0246     if (memcmp(&header.data()[4], &jp2ID, 5) == 0 ||
0247         memcmp(header.data(),     &jpcID, 2) == 0)
0248     {
0249         return 10;
0250     }
0251 
0252     return 0;
0253 }
0254 
0255 int DImgJPEG2000Plugin::canWrite(const QString& format) const
0256 {
0257     if (!m_initJasper)
0258     {
0259         return 0;
0260     }
0261 
0262     return typeMimes().contains(format.toUpper()) ? 10 : 0;
0263 }
0264 
0265 DImgLoader* DImgJPEG2000Plugin::loader(DImg* const image, const DRawDecoding&) const
0266 {
0267     return new DImgJPEG2000Loader(image);
0268 }
0269 
0270 DImgLoaderSettings* DImgJPEG2000Plugin::exportWidget(const QString& format) const
0271 {
0272     if (canWrite(format))
0273     {
0274         return (new DImgJPEG2000ExportSettings());
0275     }
0276 
0277     return nullptr;
0278 }
0279 
0280 } // namespace DigikamJPEG2000DImgPlugin
0281 
0282 #include "moc_dimgjpeg2000plugin.cpp"