bool readPGFImageData(const QByteArray& data, QImage& img, bool verbose) { try { if (data.isEmpty()) { kDebug() << "PGF image data to decode : size is null"; return false; } CPGFMemoryStream stream((UINT8*)data.data(), (size_t)data.size()); if (verbose) kDebug() << "image data stream size is : " << stream.GetSize(); CPGFImage pgfImg; // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properlly with libppgf 6.11.24 pgfImg.ConfigureDecoder(false); pgfImg.Open(&stream); if (verbose) kDebug() << "PGF image is open"; if (pgfImg.Channels() != 4) { kDebug() << "PGF channels not supported"; return false; } img = QImage(pgfImg.Width(), pgfImg.Height(), QImage::Format_ARGB32); pgfImg.Read(); if (verbose) kDebug() << "PGF image is read"; if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { int map[] = {3, 2, 1, 0}; pgfImg.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } else { int map[] = {0, 1, 2, 3}; pgfImg.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } if (verbose) kDebug() << "PGF image is decoded"; } catch (IOException& e) { int err = e.error; if (err >= AppError) { err -= AppError; } kDebug() << "Error running libpgf (" << err << ")!"; return false; } return true; }
bool readPGFImageData(const QByteArray& data, QImage& img) { try { CPGFMemoryStream stream((UINT8*)data.data(), (size_t)data.size()); CPGFImage pgfImg; pgfImg.Open(&stream); if (pgfImg.Channels() != 4) { kDebug() << "PGF channels not supported"; return false; } img = QImage(pgfImg.Width(), pgfImg.Height(), QImage::Format_ARGB32); pgfImg.Read(); if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { int map[] = {3, 2, 1, 0}; pgfImg.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } else { int map[] = {0, 1, 2, 3}; pgfImg.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } } catch (IOException& e) { int err = e.error; if (err >= AppError) { err -= AppError; } kDebug() << "Error running libpgf (" << err << ")!"; return false; } return true; }
bool PGFLoader::load(const QString& filePath, DImgLoaderObserver* const observer) { m_observer = observer; readMetadata(filePath, DImg::PGF); FILE* 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 WIN32 #ifdef UNICODE HANDLE fd = CreateFile((LPCWSTR)(QFile::encodeName(filePath).constData()), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); #else HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); #endif if (fd == INVALID_HANDLE_VALUE) { loadingFailed(); return false; } #else int fd = 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 properlly with libppgf 6.11.24 pgf.ConfigureDecoder(false); int width = pgf.Width(); int height = pgf.Height(); uchar* data = 0; 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, NULL, 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 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 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 WIN32 CloseHandle(fd); #else close(fd); #endif loadingFailed(); return false; } return true; }
bool loadPGFScaled(QImage& img, const QString& path, int maximumSize) { FILE* file = fopen(QFile::encodeName(path), "rb"); if (!file) { kDebug() << "Error: Could not open source file."; return false; } unsigned char header[3]; if (fread(&header, 3, 1, file) != 1) { fclose(file); return false; } unsigned char pgfID[3] = { 0x50, 0x47, 0x46 }; if (memcmp(&header[0], &pgfID, 3) != 0) { // not a PGF file fclose(file); return false; } fclose(file); // ------------------------------------------------------------------- // Initialize PGF API. #ifdef WIN32 #ifdef UNICODE HANDLE fd = CreateFile((LPCWSTR)(QFile::encodeName(path).constData()), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); #else HANDLE fd = CreateFile(QFile::encodeName(path), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); #endif if (fd == INVALID_HANDLE_VALUE) { return false; } #else int fd = open(QFile::encodeName(path), O_RDONLY); if (fd == -1) { return false; } #endif try { CPGFFileStream stream(fd); CPGFImage pgf; pgf.Open(&stream); // Try to find the right PGF level to get reduced image accordingly // with preview size wanted. int i=0; if (pgf.Levels() > 0) { for (i=pgf.Levels()-1 ; i>=0 ; --i) { if (qMin((int)pgf.Width(i), (int)pgf.Height(i)) >= maximumSize) { break; } } } if (i<0) { i=0; } pgf.Read(i); // Read PGF image at reduced level i. img = QImage(pgf.Width(i), pgf.Height(i), QImage::Format_RGB32); /* const PGFHeader* header = pgf.GetHeader(); kDebug() << "PGF width = " << header->width; kDebug() << "PGF height = " << header->height; kDebug() << "PGF bbp = " << header->bpp; kDebug() << "PGF channels = " << header->channels; kDebug() << "PGF quality = " << header->quality; kDebug() << "PGF mode = " << header->mode; kDebug() << "PGF levels = " << header->nLevels; kDebug() << "Level (w x h)= " << i << "(" << pgf.Width(i) << " x " << pgf.Height(i) << ")"; kDebug() << "QImage depth = " << img.depth(); */ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { int map[] = {3, 2, 1, 0}; pgf.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } else { int map[] = {0, 1, 2, 3}; pgf.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); } } catch (IOException& e) { int err = e.error; if (err >= AppError) { err -= AppError; } kDebug() << "Error running libpgf (" << err << ")!"; return false; } return true; }