diff --git a/core/dplugins/dimg/pgf/CMakeLists.txt b/core/dplugins/dimg/pgf/CMakeLists.txt index 0218261e2f..9fdcb77dcf 100644 --- a/core/dplugins/dimg/pgf/CMakeLists.txt +++ b/core/dplugins/dimg/pgf/CMakeLists.txt @@ -1,24 +1,26 @@ # # Copyright (c) 2015-2019 by Gilles Caulier, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(MacroDPlugins) include_directories($ $ $ $ $ ) set(dimgpgfplugin_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/dimgpgfplugin.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dimgpgfloader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dimgpgfloader_load.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dimgpgfloader_save.cpp ) DIGIKAM_ADD_DIMG_PLUGIN(NAME PGF SOURCES ${dimgpgfplugin_SRCS} ) diff --git a/core/dplugins/dimg/pgf/dimgpgfloader.cpp b/core/dplugins/dimg/pgf/dimgpgfloader.cpp index 508a6a9745..9ea90137c8 100644 --- a/core/dplugins/dimg/pgf/dimgpgfloader.cpp +++ b/core/dplugins/dimg/pgf/dimgpgfloader.cpp @@ -1,573 +1,150 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2009-06-03 * Description : A PGF IO file for DImg framework * * Copyright (C) 2009-2019 by Gilles Caulier * - * This implementation use LibPGF API - * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "digikam_config.h" #include "dimgpgfloader.h" // krazy:exclude=includes // C Ansi includes extern "C" { #include #include #include #include } // C++ includes #include #include #include // Qt includes #include #include #include #include #include #include // Windows includes #ifdef Q_OS_WIN32 # include #endif // Libpgf includes // Pragma directives to reduce warnings from Libpgf header files. #if defined(Q_CC_GNU) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #endif #if defined(Q_CC_CLANG) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wkeyword-macro" #endif #include "PGFimage.h" // Restore warnings #if defined(Q_CC_CLANG) # pragma clang diagnostic pop #endif #if defined(Q_CC_GNU) # pragma GCC diagnostic pop #endif // Local includes #include "digikam_debug.h" #include "dimg.h" #include "dimgloaderobserver.h" #include "pgfutils.h" #include "metaengine.h" namespace Digikam { -static bool CallbackForLibPGF(double percent, bool escapeAllowed, void* data) -{ - if (data) - { - DImgPGFLoader* const d = static_cast(data); - - if (d) - { - return d->progressCallback(percent, escapeAllowed); - } - } - - return false; -} - DImgPGFLoader::DImgPGFLoader(DImg* const image) : DImgLoader(image) { m_hasAlpha = false; m_sixteenBit = false; m_observer = nullptr; } -bool DImgPGFLoader::load(const QString& filePath, DImgLoaderObserver* const observer) -{ - m_observer = observer; - readMetadata(filePath); - - FILE* const file = fopen(QFile::encodeName(filePath).constData(), "rb"); - - if (!file) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open source file."; - loadingFailed(); - return false; - } - - unsigned char header[3]; - - if (fread(&header, 3, 1, file) != 1) - { - fclose(file); - loadingFailed(); - return false; - } - - unsigned char pgfID[3] = { 0x50, 0x47, 0x46 }; - - if (memcmp(&header[0], &pgfID, 3) != 0) - { - // not a PGF file - fclose(file); - loadingFailed(); - return false; - } - - fclose(file); - - // ------------------------------------------------------------------- - // Initialize PGF API. - -#ifdef Q_OS_WIN32 -#ifdef UNICODE - HANDLE fd = CreateFileW((LPCWSTR)filePath.utf16(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); -#else - HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); -#endif - - if (fd == INVALID_HANDLE_VALUE) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open source file."; - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Last error code:" << GetLastError(); - loadingFailed(); - return false; - } - -#else - - int fd = QT_OPEN(QFile::encodeName(filePath).constData(), O_RDONLY); - - if (fd == -1) - { - loadingFailed(); - return false; - } - -#endif - - CPGFFileStream stream(fd); - CPGFImage pgf; - int colorModel = DImg::COLORMODELUNKNOWN; - - try - { - // open pgf image - pgf.Open(&stream); - - switch (pgf.Mode()) - { - case ImageModeRGBColor: - case ImageModeRGB48: - m_hasAlpha = false; - colorModel = DImg::RGB; - break; - - case ImageModeRGBA: - m_hasAlpha = true; - colorModel = DImg::RGB; - break; - - default: - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color mode not supported (" << pgf.Mode() << ")"; - loadingFailed(); - return false; - break; - } - - switch (pgf.Channels()) - { - case 3: - case 4: - break; - - default: - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color channels number not supported (" << pgf.Channels() << ")"; - loadingFailed(); - return false; - break; - } - - int bitDepth = pgf.BPP(); - - switch (bitDepth) - { - case 24: // RGB 8 bits. - case 32: // RGBA 8 bits. - m_sixteenBit = false; - break; - - case 48: // RGB 16 bits. - case 64: // RGBA 16 bits. - m_sixteenBit = true; - break; - - default: - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color bits depth not supported (" << bitDepth << ")"; - loadingFailed(); - return false; - break; - } - - if (DIGIKAM_DIMG_LOG_PGF().isDebugEnabled()) - { - const PGFHeader* header = pgf.GetHeader(); - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF width = " << header->width; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF height = " << header->height; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF bbp = " << header->bpp; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF channels = " << header->channels; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality = " << header->quality; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF mode = " << header->mode; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Has Alpha = " << m_hasAlpha; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Is 16 bits = " << m_sixteenBit; - } - - // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24 - pgf.ConfigureDecoder(false); - - int width = pgf.Width(); - int height = pgf.Height(); - uchar* data = nullptr; - - QSize originalSize(width, height); - - if (m_loadFlags & LoadImageData) - { - // ------------------------------------------------------------------- - // Find out if we do the fast-track loading with reduced size. PGF specific. - int level = 0; - QVariant attribute = imageGetAttribute(QLatin1String("scaledLoadingSize")); - - if (attribute.isValid() && pgf.Levels() > 0) - { - int scaledLoadingSize = attribute.toInt(); - int i, w, h; - - for (i = pgf.Levels() - 1 ; i >= 0 ; --i) - { - w = pgf.Width(i); - h = pgf.Height(i); - - if (qMin(w, h) >= scaledLoadingSize) - { - break; - } - } - - if (i >= 0) - { - width = w; - height = h; - level = i; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Loading PGF scaled version at level " << i - << " (" << w << " x " << h << ") for size " - << scaledLoadingSize; - } - } - - if (m_sixteenBit) - { - data = new_failureTolerant(width, height, 8); // 16 bits/color/pixel - } - else - { - data = new_failureTolerant(width, height, 4); // 8 bits/color/pixel - } - - // Fill all with 255 including alpha channel. - memset(data, 0xFF, width * height * (m_sixteenBit ? 8 : 4)); - - pgf.Read(level, CallbackForLibPGF, this); - pgf.GetBitmap(m_sixteenBit ? width * 8 : width * 4, - (UINT8*)data, - m_sixteenBit ? 64 : 32, - nullptr, - CallbackForLibPGF, this); - - if (observer) - { - observer->progressInfo(m_image, 1.0); - } - } - - // ------------------------------------------------------------------- - // Get ICC color profile. - - if (m_loadFlags & LoadICCData) - { - // TODO: Implement proper storage in PGF for color profiles - checkExifWorkingColorSpace(); - } - - imageWidth() = width; - imageHeight() = height; - imageData() = data; - imageSetAttribute(QLatin1String("format"), QLatin1String("PGF")); - imageSetAttribute(QLatin1String("originalColorModel"), colorModel); - imageSetAttribute(QLatin1String("originalBitDepth"), bitDepth); - imageSetAttribute(QLatin1String("originalSize"), originalSize); - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - - return true; - } - catch (IOException& e) - { - int err = e.error; - - if (err >= AppError) - { - err -= AppError; - } - - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Opening and reading PGF image failed (" << err << ")!"; - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - - loadingFailed(); - return false; - } - catch (std::bad_alloc& e) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Failed to allocate memory for loading" << filePath << e.what(); - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - - loadingFailed(); - return false; - } - return true; -} - -bool DImgPGFLoader::save(const QString& filePath, DImgLoaderObserver* const observer) +DImgPGFLoader::~DImgPGFLoader() { - m_observer = observer; - -#ifdef Q_OS_WIN32 -#ifdef UNICODE - HANDLE fd = CreateFileW((LPCWSTR)filePath.utf16(), GENERIC_READ | GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); -#else - HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ | GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); -#endif - - if (fd == INVALID_HANDLE_VALUE) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Last error code:" << GetLastError(); - return false; - } - -#elif defined(__POSIX__) - int fd = QT_OPEN(QFile::encodeName(filePath).constData(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - if (fd == -1) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; - return false; - } - -#endif - - try - { - QVariant qualityAttr = imageGetAttribute(QLatin1String("quality")); - int quality = qualityAttr.isValid() ? qualityAttr.toInt() : 3; - - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality: " << quality; - - CPGFFileStream stream(fd); - CPGFImage pgf; - PGFHeader header; - header.width = imageWidth(); - header.height = imageHeight(); - header.quality = quality; - - if (imageHasAlpha()) - { - if (imageSixteenBit()) - { - // NOTE : there is no PGF color mode in 16 bits with alpha. - header.channels = 3; - header.bpp = 48; - header.mode = ImageModeRGB48; - } - else - { - header.channels = 4; - header.bpp = 32; - header.mode = ImageModeRGBA; - } - } - else - { - if (imageSixteenBit()) - { - header.channels = 3; - header.bpp = 48; - header.mode = ImageModeRGB48; - } - else - { - header.channels = 3; - header.bpp = 24; - header.mode = ImageModeRGBColor; - } - } - -#ifdef PGFCodecVersionID -# if PGFCodecVersionID < 0x061142 - header.background.rgbtBlue = 0; - header.background.rgbtGreen = 0; - header.background.rgbtRed = 0; -# endif -#endif - - pgf.SetHeader(header); - - // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24 - pgf.ConfigureEncoder(false); - - pgf.ImportBitmap(4 * imageWidth() * (imageSixteenBit() ? 2 : 1), - (UINT8*)imageData(), - imageBitsDepth() * 4, - nullptr, - CallbackForLibPGF, this); - - UINT32 nWrittenBytes = 0; - -#ifdef PGFCodecVersionID -# if PGFCodecVersionID >= 0x061124 - pgf.Write(&stream, &nWrittenBytes, CallbackForLibPGF, this); -# endif -#else - pgf.Write(&stream, 0, CallbackForLibPGF, &nWrittenBytes, this); -#endif - - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF width = " << header.width; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF height = " << header.height; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF bbp = " << header.bpp; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF channels = " << header.channels; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality = " << header.quality; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF mode = " << header.mode; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Bytes Written = " << nWrittenBytes; - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - // TODO: Store ICC profile in an appropriate place in the image - storeColorProfileInMetadata(); - - if (observer) - { - observer->progressInfo(m_image, 1.0); - } - - imageSetAttribute(QLatin1String("savedFormat"), QLatin1String("PGF")); - saveMetadata(filePath); - - return true; - } - catch (IOException& e) - { - int err = e.error; - - if (err >= AppError) - { - err -= AppError; - } - - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Opening and saving PGF image failed (" << err << ")!"; - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - - return false; - } - - return true; } bool DImgPGFLoader::hasAlpha() const { return m_hasAlpha; } bool DImgPGFLoader::sixteenBit() const { return m_sixteenBit; } bool DImgPGFLoader::progressCallback(double percent, bool escapeAllowed) { if (m_observer) { m_observer->progressInfo(m_image, percent); if (escapeAllowed) { return (!m_observer->continueQuery(m_image)); } } return false; } bool DImgPGFLoader::isReadOnly() const { return false; } +bool DImgPGFLoader::CallbackForLibPGF(double percent, bool escapeAllowed, void* data) +{ + if (data) + { + DImgPGFLoader* const d = static_cast(data); + + if (d) + { + return d->progressCallback(percent, escapeAllowed); + } + } + + return false; +} + } // namespace Digikam diff --git a/core/dplugins/dimg/pgf/dimgpgfloader.h b/core/dplugins/dimg/pgf/dimgpgfloader.h index da34a9213b..7bd48e22a2 100644 --- a/core/dplugins/dimg/pgf/dimgpgfloader.h +++ b/core/dplugins/dimg/pgf/dimgpgfloader.h @@ -1,64 +1,69 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2009-06-03 * Description : A PGF IO file for DImg framework * * Copyright (C) 2009-2019 by Gilles Caulier * + * This implementation use LibPGF API + * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DIMG_PGF_LOADER_H #define DIGIKAM_DIMG_PGF_LOADER_H // Local includes #include "dimg.h" #include "dimgloader.h" #include "digikam_export.h" using namespace Digikam; namespace Digikam { class DIGIKAM_EXPORT DImgPGFLoader : public DImgLoader { public: explicit DImgPGFLoader(DImg* const image); + ~DImgPGFLoader(); bool load(const QString& filePath, DImgLoaderObserver* const observer) override; bool save(const QString& filePath, DImgLoaderObserver* const observer) override; virtual bool hasAlpha() const override; virtual bool sixteenBit() const override; virtual bool isReadOnly() const override; bool progressCallback(double percent, bool escapeAllowed); + static bool CallbackForLibPGF(double percent, bool escapeAllowed, void* data); + private: bool m_sixteenBit; bool m_hasAlpha; DImgLoaderObserver* m_observer; }; } // namespace Digikam #endif // DIGIKAM_DIMG_PGF_LOADER_H diff --git a/core/dplugins/dimg/pgf/dimgpgfloader.cpp b/core/dplugins/dimg/pgf/dimgpgfloader_load.cpp similarity index 61% copy from core/dplugins/dimg/pgf/dimgpgfloader.cpp copy to core/dplugins/dimg/pgf/dimgpgfloader_load.cpp index 508a6a9745..ddd5ee94f9 100644 --- a/core/dplugins/dimg/pgf/dimgpgfloader.cpp +++ b/core/dplugins/dimg/pgf/dimgpgfloader_load.cpp @@ -1,573 +1,367 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2009-06-03 - * Description : A PGF IO file for DImg framework + * Description : A PGF IO file for DImg framework - load operations * * Copyright (C) 2009-2019 by Gilles Caulier * - * This implementation use LibPGF API - * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "digikam_config.h" #include "dimgpgfloader.h" // krazy:exclude=includes // C Ansi includes extern "C" { #include #include #include #include } // C++ includes #include #include #include // Qt includes #include #include #include #include #include #include // Windows includes #ifdef Q_OS_WIN32 # include #endif // Libpgf includes // Pragma directives to reduce warnings from Libpgf header files. #if defined(Q_CC_GNU) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #endif #if defined(Q_CC_CLANG) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wkeyword-macro" #endif #include "PGFimage.h" // Restore warnings #if defined(Q_CC_CLANG) # pragma clang diagnostic pop #endif #if defined(Q_CC_GNU) # pragma GCC diagnostic pop #endif // Local includes #include "digikam_debug.h" #include "dimg.h" #include "dimgloaderobserver.h" #include "pgfutils.h" #include "metaengine.h" namespace Digikam { -static bool CallbackForLibPGF(double percent, bool escapeAllowed, void* data) -{ - if (data) - { - DImgPGFLoader* const d = static_cast(data); - - if (d) - { - return d->progressCallback(percent, escapeAllowed); - } - } - - return false; -} - -DImgPGFLoader::DImgPGFLoader(DImg* const image) - : DImgLoader(image) -{ - m_hasAlpha = false; - m_sixteenBit = false; - m_observer = nullptr; -} - bool DImgPGFLoader::load(const QString& filePath, DImgLoaderObserver* const observer) { m_observer = observer; readMetadata(filePath); FILE* const file = fopen(QFile::encodeName(filePath).constData(), "rb"); if (!file) { qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open source file."; loadingFailed(); return false; } unsigned char header[3]; if (fread(&header, 3, 1, file) != 1) { fclose(file); loadingFailed(); return false; } unsigned char pgfID[3] = { 0x50, 0x47, 0x46 }; if (memcmp(&header[0], &pgfID, 3) != 0) { // not a PGF file fclose(file); loadingFailed(); return false; } fclose(file); // ------------------------------------------------------------------- // Initialize PGF API. #ifdef Q_OS_WIN32 -#ifdef UNICODE +# ifdef UNICODE HANDLE fd = CreateFileW((LPCWSTR)filePath.utf16(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); -#else +# else HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); -#endif +# endif if (fd == INVALID_HANDLE_VALUE) { qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open source file."; qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Last error code:" << GetLastError(); loadingFailed(); return false; } #else int fd = QT_OPEN(QFile::encodeName(filePath).constData(), O_RDONLY); if (fd == -1) { loadingFailed(); return false; } #endif CPGFFileStream stream(fd); CPGFImage pgf; int colorModel = DImg::COLORMODELUNKNOWN; try { // open pgf image pgf.Open(&stream); switch (pgf.Mode()) { case ImageModeRGBColor: case ImageModeRGB48: m_hasAlpha = false; colorModel = DImg::RGB; break; case ImageModeRGBA: m_hasAlpha = true; colorModel = DImg::RGB; break; default: - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color mode not supported (" << pgf.Mode() << ")"; + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color mode not supported (" + << pgf.Mode() << ")"; loadingFailed(); return false; break; } switch (pgf.Channels()) { case 3: case 4: break; default: - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color channels number not supported (" << pgf.Channels() << ")"; + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color channels number not supported (" + << pgf.Channels() << ")"; loadingFailed(); return false; break; } int bitDepth = pgf.BPP(); switch (bitDepth) { case 24: // RGB 8 bits. case 32: // RGBA 8 bits. m_sixteenBit = false; break; case 48: // RGB 16 bits. case 64: // RGBA 16 bits. m_sixteenBit = true; break; default: - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color bits depth not supported (" << bitDepth << ")"; + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Cannot load PGF image: color bits depth not supported (" + << bitDepth << ")"; loadingFailed(); return false; break; } if (DIGIKAM_DIMG_LOG_PGF().isDebugEnabled()) { - const PGFHeader* header = pgf.GetHeader(); + const PGFHeader* const header = pgf.GetHeader(); qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF width = " << header->width; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF height = " << header->height; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF bbp = " << header->bpp; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF channels = " << header->channels; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality = " << header->quality; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF mode = " << header->mode; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Has Alpha = " << m_hasAlpha; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Is 16 bits = " << m_sixteenBit; } // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24 pgf.ConfigureDecoder(false); int width = pgf.Width(); int height = pgf.Height(); uchar* data = nullptr; QSize originalSize(width, height); if (m_loadFlags & LoadImageData) { // ------------------------------------------------------------------- // Find out if we do the fast-track loading with reduced size. PGF specific. int level = 0; QVariant attribute = imageGetAttribute(QLatin1String("scaledLoadingSize")); if (attribute.isValid() && pgf.Levels() > 0) { int scaledLoadingSize = attribute.toInt(); int i, w, h; for (i = pgf.Levels() - 1 ; i >= 0 ; --i) { w = pgf.Width(i); h = pgf.Height(i); if (qMin(w, h) >= scaledLoadingSize) { break; } } if (i >= 0) { width = w; height = h; level = i; qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Loading PGF scaled version at level " << i << " (" << w << " x " << h << ") for size " << scaledLoadingSize; } } if (m_sixteenBit) { data = new_failureTolerant(width, height, 8); // 16 bits/color/pixel } else { data = new_failureTolerant(width, height, 4); // 8 bits/color/pixel } // Fill all with 255 including alpha channel. memset(data, 0xFF, width * height * (m_sixteenBit ? 8 : 4)); - pgf.Read(level, CallbackForLibPGF, this); + pgf.Read(level, DImgPGFLoader::CallbackForLibPGF, this); pgf.GetBitmap(m_sixteenBit ? width * 8 : width * 4, (UINT8*)data, m_sixteenBit ? 64 : 32, nullptr, CallbackForLibPGF, this); if (observer) { observer->progressInfo(m_image, 1.0); } } // ------------------------------------------------------------------- // Get ICC color profile. if (m_loadFlags & LoadICCData) { // TODO: Implement proper storage in PGF for color profiles checkExifWorkingColorSpace(); } imageWidth() = width; imageHeight() = height; imageData() = data; imageSetAttribute(QLatin1String("format"), QLatin1String("PGF")); imageSetAttribute(QLatin1String("originalColorModel"), colorModel); imageSetAttribute(QLatin1String("originalBitDepth"), bitDepth); imageSetAttribute(QLatin1String("originalSize"), originalSize); #ifdef Q_OS_WIN32 CloseHandle(fd); #else close(fd); #endif return true; } catch (IOException& e) { int err = e.error; if (err >= AppError) { err -= AppError; } qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Opening and reading PGF image failed (" << err << ")!"; #ifdef Q_OS_WIN32 CloseHandle(fd); #else close(fd); #endif loadingFailed(); return false; } catch (std::bad_alloc& e) { qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Failed to allocate memory for loading" << filePath << e.what(); #ifdef Q_OS_WIN32 CloseHandle(fd); #else close(fd); #endif loadingFailed(); return false; } - return true; -} - -bool DImgPGFLoader::save(const QString& filePath, DImgLoaderObserver* const observer) -{ - m_observer = observer; - -#ifdef Q_OS_WIN32 -#ifdef UNICODE - HANDLE fd = CreateFileW((LPCWSTR)filePath.utf16(), GENERIC_READ | GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); -#else - HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ | GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); -#endif - - if (fd == INVALID_HANDLE_VALUE) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Last error code:" << GetLastError(); - return false; - } - -#elif defined(__POSIX__) - int fd = QT_OPEN(QFile::encodeName(filePath).constData(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - if (fd == -1) - { - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; - return false; - } - -#endif - - try - { - QVariant qualityAttr = imageGetAttribute(QLatin1String("quality")); - int quality = qualityAttr.isValid() ? qualityAttr.toInt() : 3; - - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality: " << quality; - - CPGFFileStream stream(fd); - CPGFImage pgf; - PGFHeader header; - header.width = imageWidth(); - header.height = imageHeight(); - header.quality = quality; - - if (imageHasAlpha()) - { - if (imageSixteenBit()) - { - // NOTE : there is no PGF color mode in 16 bits with alpha. - header.channels = 3; - header.bpp = 48; - header.mode = ImageModeRGB48; - } - else - { - header.channels = 4; - header.bpp = 32; - header.mode = ImageModeRGBA; - } - } - else - { - if (imageSixteenBit()) - { - header.channels = 3; - header.bpp = 48; - header.mode = ImageModeRGB48; - } - else - { - header.channels = 3; - header.bpp = 24; - header.mode = ImageModeRGBColor; - } - } - -#ifdef PGFCodecVersionID -# if PGFCodecVersionID < 0x061142 - header.background.rgbtBlue = 0; - header.background.rgbtGreen = 0; - header.background.rgbtRed = 0; -# endif -#endif - - pgf.SetHeader(header); - - // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24 - pgf.ConfigureEncoder(false); - - pgf.ImportBitmap(4 * imageWidth() * (imageSixteenBit() ? 2 : 1), - (UINT8*)imageData(), - imageBitsDepth() * 4, - nullptr, - CallbackForLibPGF, this); - - UINT32 nWrittenBytes = 0; - -#ifdef PGFCodecVersionID -# if PGFCodecVersionID >= 0x061124 - pgf.Write(&stream, &nWrittenBytes, CallbackForLibPGF, this); -# endif -#else - pgf.Write(&stream, 0, CallbackForLibPGF, &nWrittenBytes, this); -#endif - - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF width = " << header.width; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF height = " << header.height; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF bbp = " << header.bpp; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF channels = " << header.channels; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality = " << header.quality; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF mode = " << header.mode; - qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Bytes Written = " << nWrittenBytes; - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - // TODO: Store ICC profile in an appropriate place in the image - storeColorProfileInMetadata(); - - if (observer) - { - observer->progressInfo(m_image, 1.0); - } - - imageSetAttribute(QLatin1String("savedFormat"), QLatin1String("PGF")); - saveMetadata(filePath); - - return true; - } - catch (IOException& e) - { - int err = e.error; - - if (err >= AppError) - { - err -= AppError; - } - - qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Opening and saving PGF image failed (" << err << ")!"; - -#ifdef Q_OS_WIN32 - CloseHandle(fd); -#else - close(fd); -#endif - - return false; - } return true; } -bool DImgPGFLoader::hasAlpha() const -{ - return m_hasAlpha; -} - -bool DImgPGFLoader::sixteenBit() const -{ - return m_sixteenBit; -} - -bool DImgPGFLoader::progressCallback(double percent, bool escapeAllowed) -{ - if (m_observer) - { - m_observer->progressInfo(m_image, percent); - - if (escapeAllowed) - { - return (!m_observer->continueQuery(m_image)); - } - } - - return false; -} - -bool DImgPGFLoader::isReadOnly() const -{ - return false; -} - } // namespace Digikam diff --git a/core/dplugins/dimg/pgf/dimgpgfloader_save.cpp b/core/dplugins/dimg/pgf/dimgpgfloader_save.cpp new file mode 100644 index 0000000000..463f1f5bc0 --- /dev/null +++ b/core/dplugins/dimg/pgf/dimgpgfloader_save.cpp @@ -0,0 +1,249 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * https://www.digikam.org + * + * Date : 2009-06-03 + * Description : A PGF IO file for DImg framework - save operations + * + * Copyright (C) 2009-2019 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#include "digikam_config.h" +#include "dimgpgfloader.h" // krazy:exclude=includes + +// C Ansi includes + +extern "C" +{ +#include +#include +#include +#include +} + +// C++ includes + +#include +#include +#include + +// Qt includes + +#include +#include +#include +#include +#include +#include + +// Windows includes + +#ifdef Q_OS_WIN32 +# include +#endif + +// Libpgf includes + +// Pragma directives to reduce warnings from Libpgf header files. +#if defined(Q_CC_GNU) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#if defined(Q_CC_CLANG) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wkeyword-macro" +#endif + +#include "PGFimage.h" + +// Restore warnings +#if defined(Q_CC_CLANG) +# pragma clang diagnostic pop +#endif + +#if defined(Q_CC_GNU) +# pragma GCC diagnostic pop +#endif + +// Local includes + +#include "digikam_debug.h" +#include "dimg.h" +#include "dimgloaderobserver.h" +#include "pgfutils.h" +#include "metaengine.h" + +namespace Digikam +{ + +bool DImgPGFLoader::save(const QString& filePath, DImgLoaderObserver* const observer) +{ + m_observer = observer; + +#ifdef Q_OS_WIN32 +# ifdef UNICODE + HANDLE fd = CreateFileW((LPCWSTR)filePath.utf16(), GENERIC_READ | GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); +# else + HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ | GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); +# endif + + if (fd == INVALID_HANDLE_VALUE) + { + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Last error code:" << GetLastError(); + return false; + } + +#elif defined(__POSIX__) + int fd = QT_OPEN(QFile::encodeName(filePath).constData(), + O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if (fd == -1) + { + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file."; + return false; + } + +#endif + + try + { + QVariant qualityAttr = imageGetAttribute(QLatin1String("quality")); + int quality = qualityAttr.isValid() ? qualityAttr.toInt() : 3; + + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality: " << quality; + + CPGFFileStream stream(fd); + CPGFImage pgf; + PGFHeader header; + header.width = imageWidth(); + header.height = imageHeight(); + header.quality = quality; + + if (imageHasAlpha()) + { + if (imageSixteenBit()) + { + // NOTE : there is no PGF color mode in 16 bits with alpha. + header.channels = 3; + header.bpp = 48; + header.mode = ImageModeRGB48; + } + else + { + header.channels = 4; + header.bpp = 32; + header.mode = ImageModeRGBA; + } + } + else + { + if (imageSixteenBit()) + { + header.channels = 3; + header.bpp = 48; + header.mode = ImageModeRGB48; + } + else + { + header.channels = 3; + header.bpp = 24; + header.mode = ImageModeRGBColor; + } + } + +#ifdef PGFCodecVersionID +# if PGFCodecVersionID < 0x061142 + header.background.rgbtBlue = 0; + header.background.rgbtGreen = 0; + header.background.rgbtRed = 0; +# endif +#endif + + pgf.SetHeader(header); + + // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24 + pgf.ConfigureEncoder(false); + + pgf.ImportBitmap(4 * imageWidth() * (imageSixteenBit() ? 2 : 1), + (UINT8*)imageData(), + imageBitsDepth() * 4, + nullptr, + DImgPGFLoader::CallbackForLibPGF, this); + + UINT32 nWrittenBytes = 0; + +#ifdef PGFCodecVersionID +# if PGFCodecVersionID >= 0x061124 + pgf.Write(&stream, &nWrittenBytes, CallbackForLibPGF, this); +# endif +#else + pgf.Write(&stream, 0, CallbackForLibPGF, &nWrittenBytes, this); +#endif + + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF width = " << header.width; + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF height = " << header.height; + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF bbp = " << header.bpp; + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF channels = " << header.channels; + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF quality = " << header.quality; + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "PGF mode = " << header.mode; + qCDebug(DIGIKAM_DIMG_LOG_PGF) << "Bytes Written = " << nWrittenBytes; + +#ifdef Q_OS_WIN32 + CloseHandle(fd); +#else + close(fd); +#endif + // TODO: Store ICC profile in an appropriate place in the image + storeColorProfileInMetadata(); + + if (observer) + { + observer->progressInfo(m_image, 1.0); + } + + imageSetAttribute(QLatin1String("savedFormat"), QLatin1String("PGF")); + saveMetadata(filePath); + + return true; + } + catch (IOException& e) + { + int err = e.error; + + if (err >= AppError) + { + err -= AppError; + } + + qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Opening and saving PGF image failed (" << err << ")!"; + +#ifdef Q_OS_WIN32 + CloseHandle(fd); +#else + close(fd); +#endif + + return false; + } + + return true; +} + +} // namespace Digikam