Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
bool PGFLoader::save(const QString& filePath, DImgLoaderObserver* const observer)
{
    m_observer = observer;

#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)
    {
        qCWarning(DIGIKAM_DIMG_LOG_PGF) << "Error: Could not open destination file.";
        return false;
    }

#elif defined(__POSIX__)
    int fd = 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 properlly with libppgf 6.11.24
        pgf.ConfigureEncoder(false);

        pgf.ImportBitmap(4 * imageWidth() * (imageSixteenBit() ? 2 : 1),
                         (UINT8*)imageData(),
                         imageBitsDepth() * 4,
                         NULL,
                         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 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 WIN32
        CloseHandle(fd);
#else
        close(fd);
#endif

        return false;
    }
    return true;
}
Esempio n. 5
0
bool writePGFImageData(const QImage& img, QByteArray& data, int quality)
{
    try
    {
        if (img.isNull())
        {
            kDebug() << "Thumb image is null";
            return false;
        }

        // No need Alpha to optimize space on DB.
        if (img.format() != QImage::Format_ARGB32)
        {
            img.convertToFormat(QImage::Format_ARGB32);
        }

        CPGFImage pgfImg;

        PGFHeader header;
        header.width    = img.width();
        header.height   = img.height();
        header.bpp      = img.depth();
        header.channels = 4;
        header.quality  = quality;
        header.mode     = ImageModeRGBA;
        header.background.rgbtBlue = header.background.rgbtGreen = header.background.rgbtRed = 0;
        pgfImg.SetHeader(header);

        if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
        {
            int map[] = {3, 2, 1, 0};
            pgfImg.ImportBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map);
        }
        else
        {
            int map[] = {0, 1, 2, 3};
            pgfImg.ImportBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map);
        }

        // TODO : optimize memory allocation...
        CPGFMemoryStream stream(256000);
        UINT32 nWrittenBytes = 0;
        pgfImg.Write(&stream, 0, NULL, &nWrittenBytes);

        data = QByteArray((const char*)stream.GetBuffer(), nWrittenBytes);
    }
    catch (IOException& e)
    {
        int err = e.error;

        if (err >= AppError)
        {
            err -= AppError;
        }

        kDebug() << "Error running libpgf (" << err << ")!";
        return false;
    }

    return true;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
bool writePGFImageDataToStream(const QImage& image, CPGFStream& stream, int quality, UINT32& nWrittenBytes, bool verbose)
{
    try
    {
        if (image.isNull())
        {
            kDebug() << "Thumb image is null";
            return false;
        }

        QImage img;

        // Convert image with Alpha channel.
        if (image.format() != QImage::Format_ARGB32)
        {
            img = image.convertToFormat(QImage::Format_ARGB32);
            if (verbose) kDebug() << "RGB => ARGB";
        }
        else
        {
            img = image;
        }

        CPGFImage pgfImg;
        PGFHeader header;
        header.width                = img.width();
        header.height               = img.height();
        header.nLevels              = 0;             // Auto.
        header.quality              = quality;
        header.bpp                  = img.depth();
        header.channels             = 4;
        header.mode                 = ImageModeRGBA;
        header.usedBitsPerChannel   = 0;             // Auto

#ifdef PGFCodecVersionID
#   if PGFCodecVersionID < 0x061142
        header.background.rgbtBlue  = 0;
        header.background.rgbtGreen = 0;
        header.background.rgbtRed   = 0;
#   endif
#endif
        pgfImg.SetHeader(header);

        // NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properlly with libppgf 6.11.24
        pgfImg.ConfigureEncoder(false);

        if (verbose)
        {
            kDebug() << "PGF image settings:";
            kDebug() << "   width: "              << header.width;
            kDebug() << "   height: "             << header.height;
            kDebug() << "   nLevels: "            << header.nLevels;
            kDebug() << "   quality: "            << header.quality;
            kDebug() << "   bpp: "                << header.bpp;
            kDebug() << "   channels: "           << header.channels;
            kDebug() << "   mode: "               << header.mode;
            kDebug() << "   usedBitsPerChannel: " << header.usedBitsPerChannel;
        }

        if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
        {
            int map[] = {3, 2, 1, 0};
            pgfImg.ImportBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map);
        }
        else
        {
            int map[] = {0, 1, 2, 3};
            pgfImg.ImportBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map);
        }

        nWrittenBytes = 0;

#ifdef PGFCodecVersionID
#   if PGFCodecVersionID >= 0x061124
        pgfImg.Write(&stream, &nWrittenBytes);
#   else
        pgfImg.Write(&stream, 0, 0, &nWrittenBytes);
#   endif
#else
        pgfImg.Write(&stream, 0, 0, &nWrittenBytes);
#endif

    }
    catch (IOException& e)
    {
        int err = e.error;

        if (err >= AppError)
        {
            err -= AppError;
        }

        kDebug() << "Error running libpgf (" << err << ")!";
        return false;
    }

    return true;
}