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"