QString readInfo(cmsInfoType info) { GV_RETURN_VALUE_IF_FAIL(mProfile, QString()); wchar_t buffer[1024]; int size = cmsGetProfileInfo(mProfile, info, "en", "US", buffer, 1024); return QString::fromWCharArray(buffer, size); }
cmsHPROFILE loadFromPngData(const QByteArray& data) { QBuffer buffer; buffer.setBuffer(const_cast<QByteArray*>(&data)); buffer.open(QIODevice::ReadOnly); // Initialize the internal structures png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); GV_RETURN_VALUE_IF_FAIL(png_ptr, 0); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); kWarning() << "Could not create info_struct"; return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); kWarning() << "Could not create info_struct2"; return 0; } // Catch errors if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); kWarning() << "Error decoding png file"; return 0; } // Initialize the special png_set_read_fn(png_ptr, &buffer, readPngChunk); // read all PNG info up to image data png_read_info(png_ptr, info_ptr); // Get profile png_charp profile_name; #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5 png_bytep profile_data; #else png_charp profile_data; #endif int compression_type; png_uint_32 proflen; cmsHPROFILE profile = 0; if (png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen)) { profile = cmsOpenProfileFromMem(profile_data, proflen); } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return profile; }
bool loadMetaInfo() { LOG("mFormatHint" << mFormatHint); QBuffer buffer; buffer.setBuffer(&mData); buffer.open(QIODevice::ReadOnly); #ifdef KDCRAW_FOUND if (KDcrawIface::KDcraw::rawFilesList().contains(QString(mFormatHint))) { QByteArray previewData; // if the image is in format supported by dcraw, fetch its embedded preview mJpegContent.reset(new JpegContent()); // use KDcraw for getting the embedded preview // KDcraw functionality cloned locally (temp. solution) bool ret = KDcrawIface::KDcraw::loadEmbeddedPreview(previewData, buffer); QImage originalImage; if (!ret || !originalImage.loadFromData(previewData) || qMin(originalImage.width(), originalImage.height()) < MIN_PREV_SIZE) { // if the embedded preview loading failed or gets just a small image, load // half preview instead. That's slower but it works even for images containing // small (160x120px) or none embedded preview. if (!KDcrawIface::KDcraw::loadHalfPreview(previewData, buffer)) { qWarning() << "unable to get half preview for " << q->document()->url().fileName(); return false; } } buffer.close(); // now it's safe to replace mData with the jpeg data mData = previewData; // need to fill mFormat so gwenview can tell the type when trying to save mFormat = mFormatHint; } else { #else { #endif QImageReader reader(&buffer, mFormatHint); mImageSize = reader.size(); if (!reader.canRead()) { qWarning() << "QImageReader::read() using format hint" << mFormatHint << "failed:" << reader.errorString(); if (buffer.pos() != 0) { qWarning() << "A bad Qt image decoder moved the buffer to" << buffer.pos() << "in a call to canRead()! Rewinding."; buffer.seek(0); } reader.setFormat(QByteArray()); // Set buffer again, otherwise QImageReader won't restart from scratch reader.setDevice(&buffer); if (!reader.canRead()) { qWarning() << "QImageReader::read() without format hint failed:" << reader.errorString(); return false; } qWarning() << "Image format is actually" << reader.format() << "not" << mFormatHint; } mFormat = reader.format(); if (mFormat == "jpg") { // if mFormatHint was "jpg", then mFormat is "jpg", but the rest of // Gwenview code assumes JPEG images have "jpeg" format. mFormat = "jpeg"; } } LOG("mFormat" << mFormat); GV_RETURN_VALUE_IF_FAIL(!mFormat.isEmpty(), false); Exiv2ImageLoader loader; if (loader.load(mData)) { mExiv2Image = loader.popImage(); } if (mFormat == "jpeg" && mExiv2Image.get()) { mJpegContent.reset(new JpegContent()); } if (mJpegContent.get()) { if (!mJpegContent->loadFromData(mData, mExiv2Image.get()) && !mJpegContent->loadFromData(mData)) { qWarning() << "Unable to use preview of " << q->document()->url().fileName(); return false; } // Use the size from JpegContent, as its correctly transposed if the // image has been rotated mImageSize = mJpegContent->size(); mCmsProfile = Cms::Profile::loadFromExiv2Image(mExiv2Image.get()); } LOG("mImageSize" << mImageSize); if (!mCmsProfile) { mCmsProfile = Cms::Profile::loadFromImageData(mData, mFormat); } return true; } void loadImageData() { QBuffer buffer; buffer.setBuffer(&mData); buffer.open(QIODevice::ReadOnly); QImageReader reader(&buffer, mFormat); LOG("mImageDataInvertedZoom=" << mImageDataInvertedZoom); if (mImageSize.isValid() && mImageDataInvertedZoom != 1 && reader.supportsOption(QImageIOHandler::ScaledSize) ) { // Do not use mImageSize here: QImageReader needs a non-transposed // image size QSize size = reader.size() / mImageDataInvertedZoom; if (!size.isEmpty()) { LOG("Setting scaled size to" << size); reader.setScaledSize(size); } else { LOG("Not setting scaled size as it is empty" << size); } } bool ok = reader.read(&mImage); if (!ok) { LOG("QImageReader::read() failed"); return; } if (mJpegContent.get() && GwenviewConfig::applyExifOrientation()) { Gwenview::Orientation orientation = mJpegContent->orientation(); QMatrix matrix = ImageUtils::transformMatrix(orientation); mImage = mImage.transformed(matrix); } if (reader.supportsAnimation() && reader.nextImageDelay() > 0 // Assume delay == 0 <=> only one frame ) { /* * QImageReader is not really helpful to detect animated gif: * - QImageReader::imageCount() returns 0 * - QImageReader::nextImageDelay() may return something > 0 if the * image consists of only one frame but includes a "Graphic * Control Extension" (usually only present if we have an * animation) (Bug #185523) * * Decoding the next frame is the only reliable way I found to * detect an animated gif */ LOG("May be an animated image. delay:" << reader.nextImageDelay()); QImage nextImage; if (reader.read(&nextImage)) { LOG("Really an animated image (more than one frame)"); mAnimated = true; } else { qWarning() << q->document()->url() << "is not really an animated image (only one frame)"; } } }