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-21 0007 * Description : Magick 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 "dimgimagemagickplugin.h" 0016 0017 // Qt includes 0018 0019 #include <QMimeDatabase> 0020 0021 // KDE includes 0022 0023 #include <klocalizedstring.h> 0024 0025 // Image Magick includes 0026 0027 // Pragma directives to reduce warnings from ImageMagick header files. 0028 #if !defined(Q_OS_DARWIN) && defined(Q_CC_GNU) 0029 # pragma GCC diagnostic push 0030 # pragma GCC diagnostic ignored "-Wignored-qualifiers" 0031 # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" 0032 #endif 0033 0034 #if defined(Q_CC_CLANG) 0035 # pragma clang diagnostic push 0036 # pragma clang diagnostic ignored "-Wignored-qualifiers" 0037 # pragma clang diagnostic ignored "-Wkeyword-macro" 0038 #endif 0039 0040 #include <Magick++.h> 0041 0042 #if MagickLibVersion < 0x700 0043 # include <magick/magick.h> 0044 #endif 0045 0046 using namespace Magick; 0047 using namespace MagickCore; 0048 0049 #if defined(Q_CC_CLANG) 0050 # pragma clang diagnostic pop 0051 #endif 0052 0053 #if defined(Q_CC_GNU) 0054 # pragma GCC diagnostic pop 0055 #endif 0056 0057 // Local includes 0058 0059 #include "digikam_debug.h" 0060 #include "digikam_globals.h" 0061 #include "dimgimagemagickloader.h" 0062 0063 namespace DigikamImageMagickDImgPlugin 0064 { 0065 0066 DImgImageMagickPlugin::DImgImageMagickPlugin(QObject* const parent) 0067 : DPluginDImg(parent) 0068 { 0069 MagickCoreGenesis((char*)nullptr, MagickFalse); 0070 0071 m_readFormats = decoderFormats(); 0072 m_writeFormats = encoderFormats(); 0073 } 0074 0075 DImgImageMagickPlugin::~DImgImageMagickPlugin() 0076 { 0077 } 0078 0079 void DImgImageMagickPlugin::cleanUp() 0080 { 0081 MagickCoreTerminus(); 0082 } 0083 0084 QString DImgImageMagickPlugin::name() const 0085 { 0086 return i18nc("@title", "ImageMagick loader"); 0087 } 0088 0089 QString DImgImageMagickPlugin::iid() const 0090 { 0091 return QLatin1String(DPLUGIN_IID); 0092 } 0093 0094 QIcon DImgImageMagickPlugin::icon() const 0095 { 0096 return QIcon::fromTheme(QLatin1String("image-x-generic")); 0097 } 0098 0099 QString DImgImageMagickPlugin::description() const 0100 { 0101 return i18nc("@info", "An image loader based on ImageMagick coders"); 0102 } 0103 0104 QString DImgImageMagickPlugin::details() const 0105 { 0106 return xi18nc("@info", "<para>This plugin allows users to load and save image using ImageMagick coders.</para>" 0107 "<para>ImageMagick is a free and open-source software suite for converting raster image and vector image files. " 0108 "It can read and write over 200 image file formats.</para>" 0109 "<para>See <a href='https://en.wikipedia.org/wiki/ImageMagick'>ImageMagick documentation</a> for details.</para>" 0110 ); 0111 } 0112 0113 QString DImgImageMagickPlugin::handbookSection() const 0114 { 0115 return QLatin1String("supported_materials"); 0116 } 0117 0118 QString DImgImageMagickPlugin::handbookChapter() const 0119 { 0120 return QLatin1String("image_formats"); 0121 } 0122 0123 QString DImgImageMagickPlugin::handbookReference() const 0124 { 0125 return QLatin1String("image-others"); 0126 } 0127 0128 QList<DPluginAuthor> DImgImageMagickPlugin::authors() const 0129 { 0130 return QList<DPluginAuthor>() 0131 << DPluginAuthor(QString::fromUtf8("Maik Qualmann"), 0132 QString::fromUtf8("metzpinguin at gmail dot com"), 0133 QString::fromUtf8("(C) 2019-2023")) 0134 << DPluginAuthor(QString::fromUtf8("Gilles Caulier"), 0135 QString::fromUtf8("caulier dot gilles at gmail dot com"), 0136 QString::fromUtf8("(C) 2006-2023")) 0137 ; 0138 } 0139 0140 void DImgImageMagickPlugin::setup(QObject* const /*parent*/) 0141 { 0142 // Nothing to do 0143 } 0144 0145 QMap<QString, QStringList> DImgImageMagickPlugin::extraAboutData() const 0146 { 0147 QString mimes = typeMimes(); 0148 QMap<QString, QStringList> map; 0149 0150 try 0151 { 0152 ExceptionInfo ex = *AcquireExceptionInfo(); 0153 size_t n = 0; 0154 const MagickInfo** inflst = GetMagickInfoList("*", &n, &ex); 0155 0156 if (!inflst) 0157 { 0158 qCWarning(DIGIKAM_DIMG_LOG_MAGICK) << "ImageMagick coders list is null!"; 0159 return QMap<QString, QStringList>(); 0160 } 0161 0162 for (uint i = 0 ; i < n ; ++i) 0163 { 0164 const MagickInfo* inf = inflst[i]; 0165 0166 if (inf) 0167 { 0168 QString mod = 0169 0170 #if (MagickLibVersion >= 0x69A && defined(magick_module)) 0171 0172 QString::fromLatin1(inf->magick_module).toUpper(); 0173 0174 #else 0175 0176 QString::fromLatin1(inf->module).toUpper(); 0177 0178 #endif 0179 0180 if (mimes.contains(mod)) 0181 { 0182 map.insert(mod, 0183 QStringList() << QLatin1String(inf->description) 0184 << (inf->decoder ? 0185 i18nc("@info: can read file format", "yes") : 0186 i18nc("@info: cannot read file format", "no")) 0187 << (inf->encoder ? 0188 i18nc("@info: can write file format", "yes") : 0189 i18nc("@info: cannot write file format", "no")) 0190 0191 ); 0192 } 0193 } 0194 } 0195 0196 free(inflst); 0197 } 0198 catch (Exception& error) 0199 { 0200 qCWarning(DIGIKAM_DIMG_LOG) << "ImageMagickInfo exception:" << error.what(); 0201 return QMap<QString, QStringList>(); 0202 } 0203 0204 return map; 0205 } 0206 0207 QString DImgImageMagickPlugin::loaderName() const 0208 { 0209 return QLatin1String("IMAGEMAGICK"); 0210 } 0211 0212 QString DImgImageMagickPlugin::typeMimes() const 0213 { 0214 QStringList formats = m_readFormats; 0215 formats.sort(); 0216 0217 QString ret; 0218 0219 Q_FOREACH (const QString& str, formats) 0220 { 0221 if (!ret.contains(str)) 0222 { 0223 ret += QString::fromUtf8("%1 ").arg(str.toUpper()); 0224 } 0225 } 0226 0227 return ret; 0228 } 0229 0230 int DImgImageMagickPlugin::canRead(const QFileInfo& fileInfo, bool magic) const 0231 { 0232 QString filePath = fileInfo.filePath(); 0233 QString format = fileInfo.suffix().toUpper(); 0234 0235 if (!magic) 0236 { 0237 QString mimeType(QMimeDatabase().mimeTypeForFile(filePath).name()); 0238 0239 // Ignore non image format. 0240 0241 if ( 0242 mimeType.startsWith(QLatin1String("video/")) || 0243 mimeType.startsWith(QLatin1String("audio/")) 0244 ) 0245 { 0246 return 0; 0247 } 0248 0249 if (!format.isEmpty() && m_readFormats.contains(format)) 0250 { 0251 return 90; 0252 } 0253 } 0254 0255 return 0; 0256 } 0257 0258 int DImgImageMagickPlugin::canWrite(const QString& format) const 0259 { 0260 if (m_writeFormats.contains(format.toUpper())) 0261 { 0262 return 90; 0263 } 0264 0265 return 0; 0266 } 0267 0268 DImgLoader* DImgImageMagickPlugin::loader(DImg* const image, const DRawDecoding&) const 0269 { 0270 return new DImgImageMagickLoader(image); 0271 } 0272 0273 QStringList DImgImageMagickPlugin::decoderFormats() const 0274 { 0275 QStringList formats; 0276 0277 try 0278 { 0279 ExceptionInfo ex = *AcquireExceptionInfo(); 0280 size_t n = 0; 0281 const MagickInfo** inflst = GetMagickInfoList("*", &n, &ex); 0282 0283 if (!inflst) 0284 { 0285 qWarning() << "ImageMagick coders list is null!"; 0286 return QStringList(); 0287 } 0288 0289 for (uint i = 0 ; i < n ; ++i) 0290 { 0291 const MagickInfo* inf = inflst[i]; 0292 0293 if (inf && inf->decoder) 0294 { 0295 0296 #if (MagickLibVersion >= 0x69A && defined(magick_module)) 0297 0298 formats.append(QString::fromLatin1(inf->magick_module).toUpper()); 0299 0300 #else 0301 0302 formats.append(QString::fromLatin1(inf->module).toUpper()); 0303 0304 #endif 0305 0306 } 0307 } 0308 0309 free(inflst); 0310 } 0311 catch (Exception& error) 0312 { 0313 qCWarning(DIGIKAM_DIMG_LOG) << "ImageMagickInfo exception:" << error.what(); 0314 return QStringList(); 0315 } 0316 0317 if (formats.contains(QLatin1String("JPEG"))) 0318 { 0319 formats.append(QLatin1String("JPG")); 0320 formats.append(QLatin1String("JPE")); 0321 } 0322 0323 if (formats.contains(QLatin1String("FITS"))) 0324 { 0325 formats.append(QLatin1String("FTS")); 0326 formats.append(QLatin1String("FIT")); 0327 } 0328 0329 // Remove known formats that are not stable. 0330 0331 formats.removeAll(QLatin1String("XCF")); 0332 0333 return formats; 0334 } 0335 0336 QStringList DImgImageMagickPlugin::encoderFormats() const 0337 { 0338 QStringList formats; 0339 0340 try 0341 { 0342 ExceptionInfo ex = *AcquireExceptionInfo(); 0343 size_t n = 0; 0344 const MagickInfo** inflst = GetMagickInfoList("*", &n, &ex); 0345 0346 if (!inflst) 0347 { 0348 qWarning() << "ImageMagick coders list is null!"; 0349 return QStringList(); 0350 } 0351 0352 for (uint i = 0 ; i < n ; ++i) 0353 { 0354 const MagickInfo* inf = inflst[i]; 0355 0356 if (inf && inf->encoder) 0357 { 0358 0359 #if (MagickLibVersion >= 0x69A && defined(magick_module)) 0360 0361 formats.append(QString::fromLatin1(inf->magick_module).toUpper()); 0362 0363 #else 0364 0365 formats.append(QString::fromLatin1(inf->module).toUpper()); 0366 0367 #endif 0368 0369 } 0370 } 0371 0372 free(inflst); 0373 } 0374 catch (Exception& error) 0375 { 0376 qCWarning(DIGIKAM_DIMG_LOG) << "ImageMagickInfo exception:" << error.what(); 0377 return QStringList(); 0378 } 0379 0380 if (formats.contains(QLatin1String("FITS"))) 0381 { 0382 formats.append(QLatin1String("FTS")); 0383 } 0384 0385 return formats; 0386 } 0387 0388 DImgLoaderSettings* DImgImageMagickPlugin::exportWidget(const QString& format) const 0389 { 0390 Q_UNUSED(format); 0391 0392 return nullptr; 0393 } 0394 0395 } // namespace DigikamImageMagickDImgPlugin 0396 0397 #include "moc_dimgimagemagickplugin.cpp"