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 : 2009-06-03 0007 * Description : A PGF IO file for DImg framework - save operations 0008 * 0009 * SPDX-FileCopyrightText: 2009-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 "digikam_config.h" 0016 #include "dimgpgfloader.h" // krazy:exclude=includes 0017 0018 // C Ansi includes 0019 0020 extern "C" 0021 { 0022 #ifndef Q_CC_MSVC 0023 # include <unistd.h> 0024 #endif 0025 #include <sys/types.h> 0026 #include <sys/stat.h> 0027 #include <fcntl.h> 0028 } 0029 0030 // C++ includes 0031 0032 #include <iostream> 0033 #include <cmath> 0034 #include <cstdio> 0035 0036 // Qt includes 0037 0038 #include <QFile> 0039 #include <QVariant> 0040 #include <QByteArray> 0041 #include <QTextStream> 0042 #include <QDataStream> 0043 #include <qplatformdefs.h> 0044 0045 // Windows includes 0046 0047 #ifdef Q_OS_WIN 0048 # include <windows.h> 0049 #endif 0050 0051 // Libpgf includes 0052 0053 // Pragma directives to reduce warnings from Libpgf header files. 0054 #if defined(Q_CC_GNU) 0055 # pragma GCC diagnostic push 0056 # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" 0057 #endif 0058 0059 #if defined(Q_CC_CLANG) 0060 # pragma clang diagnostic push 0061 # pragma clang diagnostic ignored "-Wkeyword-macro" 0062 #endif 0063 0064 #include "PGFimage.h" 0065 0066 // Restore warnings 0067 #if defined(Q_CC_CLANG) 0068 # pragma clang diagnostic pop 0069 #endif 0070 0071 #if defined(Q_CC_GNU) 0072 # pragma GCC diagnostic pop 0073 #endif 0074 0075 // Local includes 0076 0077 #include "digikam_debug.h" 0078 #include "dimg.h" 0079 #include "dimgloaderobserver.h" 0080 #include "pgfutils.h" 0081 #include "metaengine.h" 0082 0083 namespace Digikam 0084 { 0085 0086 bool DImgPGFLoader::save(const QString& filePath, DImgLoaderObserver* const observer) 0087 { 0088 m_observer = observer; 0089 0090 #ifdef Q_OS_WIN 0091 0092 HANDLE fd = CreateFileW((LPCWSTR)filePath.utf16(), GENERIC_READ | GENERIC_WRITE, 0, 0093 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 0094 0095 if (fd == INVALID_HANDLE_VALUE) 0096 { 0097 qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; 0098 qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Last error code:" << GetLastError(); 0099 0100 return false; 0101 } 0102 0103 #else 0104 0105 int fd = QT_OPEN(filePath.toUtf8().constData(), 0106 O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 0107 0108 if (fd == -1) 0109 { 0110 qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; 0111 0112 return false; 0113 } 0114 0115 #endif 0116 0117 try 0118 { 0119 QVariant losslessAttr = imageGetAttribute(QLatin1String("lossless")); 0120 bool lossless = losslessAttr.isValid() ? losslessAttr.toBool() : false; 0121 0122 // NOTE: if quality = 0 -> lossless compression. 0123 0124 int quality = 0; 0125 0126 if (!lossless) 0127 { 0128 QVariant qualityAttr = imageGetAttribute(QLatin1String("quality")); 0129 quality = qualityAttr.isValid() ? qualityAttr.toInt() : 3; 0130 } 0131 0132 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality: " << quality; 0133 0134 CPGFFileStream stream(fd); 0135 CPGFImage pgf; 0136 PGFHeader header; 0137 header.width = imageWidth(); 0138 header.height = imageHeight(); 0139 header.quality = quality; 0140 0141 if (imageHasAlpha()) 0142 { 0143 if (imageSixteenBit()) 0144 { 0145 // NOTE : there is no PGF color mode in 16 bits with alpha. 0146 0147 header.channels = 3; 0148 header.bpp = 48; 0149 header.mode = ImageModeRGB48; 0150 } 0151 else 0152 { 0153 header.channels = 4; 0154 header.bpp = 32; 0155 header.mode = ImageModeRGBA; 0156 } 0157 } 0158 else 0159 { 0160 if (imageSixteenBit()) 0161 { 0162 header.channels = 3; 0163 header.bpp = 48; 0164 header.mode = ImageModeRGB48; 0165 } 0166 else 0167 { 0168 header.channels = 3; 0169 header.bpp = 24; 0170 header.mode = ImageModeRGBColor; 0171 } 0172 } 0173 0174 #ifdef PGFCodecVersionID 0175 0176 # if PGFCodecVersionID < 0x061142 0177 0178 header.background.rgbtBlue = 0; 0179 header.background.rgbtGreen = 0; 0180 header.background.rgbtRed = 0; 0181 0182 # endif 0183 0184 #endif 0185 0186 pgf.SetHeader(header); 0187 0188 // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24 0189 0190 pgf.ConfigureEncoder(false); 0191 0192 pgf.ImportBitmap(4 * imageWidth() * (imageSixteenBit() ? 2 : 1), 0193 (UINT8*)imageData(), 0194 imageBitsDepth() * 4, 0195 nullptr, 0196 DImgPGFLoader::CallbackForLibPGF, this); 0197 0198 UINT32 nWrittenBytes = 0; 0199 0200 #ifdef PGFCodecVersionID 0201 0202 # if PGFCodecVersionID >= 0x061124 0203 0204 pgf.Write(&stream, &nWrittenBytes, CallbackForLibPGF, this); 0205 0206 # endif 0207 0208 #else 0209 0210 pgf.Write(&stream, 0, CallbackForLibPGF, &nWrittenBytes, this); 0211 0212 #endif 0213 0214 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF width = " << header.width; 0215 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF height = " << header.height; 0216 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF bbp = " << header.bpp; 0217 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF channels = " << header.channels; 0218 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality = " << header.quality; 0219 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF mode = " << header.mode; 0220 qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Bytes Written = " << nWrittenBytes; 0221 0222 #ifdef Q_OS_WIN 0223 0224 CloseHandle(fd); 0225 0226 #else 0227 0228 close(fd); 0229 0230 #endif 0231 0232 // TODO: Store ICC profile in an appropriate place in the image 0233 0234 storeColorProfileInMetadata(); 0235 0236 if (observer) 0237 { 0238 observer->progressInfo(1.0F); 0239 } 0240 0241 imageSetAttribute(QLatin1String("savedFormat"), QLatin1String("PGF")); 0242 saveMetadata(filePath); 0243 0244 return true; 0245 } 0246 catch (IOException& e) 0247 { 0248 int err = e.error; 0249 0250 if (err >= AppError) 0251 { 0252 err -= AppError; 0253 } 0254 0255 qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Opening and saving PGF image failed (" << err << ")!"; 0256 0257 #ifdef Q_OS_WIN 0258 0259 CloseHandle(fd); 0260 0261 #else 0262 0263 close(fd); 0264 0265 #endif 0266 0267 return false; 0268 } 0269 0270 return true; 0271 } 0272 0273 } // namespace Digikam