PreviewPropertiesList PreviewManager::getPreviewProperties() const { PreviewPropertiesList list; // go through the loader table and store all successfully created loaders in the list for (PreviewId id = 0; id < Loader::getNumLoaders(); ++id) { Loader::AutoPtr loader = Loader::create(id, image_); if (loader.get() && loader->readDimensions()) { list.push_back(loader->getProperties()); } } std::sort(list.begin(), list.end(), cmpPreviewProperties); return list; }
void Rw2Image::readMetadata() { #ifdef DEBUG std::cerr << "Reading RW2 file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isRw2Type(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "RW2"); } clearMetadata(); std::ofstream devnull; printStructure(devnull, kpsRecursive, 0); ByteOrder bo = Rw2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size()); setByteOrder(bo); // A lot more metadata is hidden in the embedded preview image // Todo: This should go into the Rw2Parser, but for that it needs the Image PreviewManager loader(*this); PreviewPropertiesList list = loader.getPreviewProperties(); // Todo: What if there are more preview images? if (list.size() > 1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "RW2 image contains more than one preview. None used.\n"; #endif } if (list.size() != 1) return; ExifData exifData; PreviewImage preview = loader.getPreviewImage(*list.begin()); Image::AutoPtr image = ImageFactory::open(preview.pData(), preview.size()); if (image.get() == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to open RW2 preview image.\n"; #endif return; } image->readMetadata(); ExifData& prevData = image->exifData(); if (!prevData.empty()) { // Filter duplicate tags for (ExifData::const_iterator pos = exifData_.begin(); pos != exifData_.end(); ++pos) { if (pos->ifdId() == panaRawId) continue; ExifData::iterator dup = prevData.findKey(ExifKey(pos->key())); if (dup != prevData.end()) { #ifdef DEBUG std::cerr << "Filtering duplicate tag " << pos->key() << " (values '" << pos->value() << "' and '" << dup->value() << "')\n"; #endif prevData.erase(dup); } } } // Remove tags not applicable for raw images static const char* filteredTags[] = { "Exif.Photo.ComponentsConfiguration", "Exif.Photo.CompressedBitsPerPixel", "Exif.Panasonic.ColorEffect", "Exif.Panasonic.Contrast", "Exif.Panasonic.NoiseReduction", "Exif.Panasonic.ColorMode", "Exif.Panasonic.OpticalZoomMode", "Exif.Panasonic.Contrast", "Exif.Panasonic.Saturation", "Exif.Panasonic.Sharpness", "Exif.Panasonic.FilmMode", "Exif.Panasonic.SceneMode", "Exif.Panasonic.WBRedLevel", "Exif.Panasonic.WBGreenLevel", "Exif.Panasonic.WBBlueLevel", "Exif.Photo.ColorSpace", "Exif.Photo.PixelXDimension", "Exif.Photo.PixelYDimension", "Exif.Photo.SceneType", "Exif.Photo.CustomRendered", "Exif.Photo.DigitalZoomRatio", "Exif.Photo.SceneCaptureType", "Exif.Photo.GainControl", "Exif.Photo.Contrast", "Exif.Photo.Saturation", "Exif.Photo.Sharpness", "Exif.Image.PrintImageMatching", "Exif.Image.YCbCrPositioning" }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredTags); ++i) { ExifData::iterator pos = prevData.findKey(ExifKey(filteredTags[i])); if (pos != prevData.end()) { #ifdef DEBUG std::cerr << "Exif tag " << pos->key() << " removed\n"; #endif prevData.erase(pos); } } // Add the remaining tags for (ExifData::const_iterator pos = prevData.begin(); pos != prevData.end(); ++pos) { exifData_.add(*pos); } } // Rw2Image::readMetadata
QImage Exiv2Lib::getPreview() { PreviewManager loader(*mImageFile); PreviewPropertiesList list = loader.getPreviewProperties(); if (list.empty()) { qDebug() << "Image contains no thumbnail"; return QImage(); } PreviewProperties selected; // Take the last image in the list. // For Canon raw pictures, the 2nd preview has no white balance applied. // see http://lclevy.free.fr/cr2/ // section 2.6 IFD #2 selected = list.back(); // FIXME: crash hapened here when reading the QImage. // not quite sure what caused it // load the thumbnail PreviewImage thumbnail = loader.getPreviewImage(selected); const unsigned char* tmp = thumbnail.pData(); size_t size = thumbnail.size(); QImage thumb; thumb.loadFromData(tmp, size); // Read the EXIF orientation flag and rotate the image accordingly. ExifData& data = mImageFile->exifData(); ExifData::const_iterator pos; pos = data.findKey(ExifKey("Exif.Image.Orientation")); // TODO: should flip/rotate after resize if (pos != data.end()) { qDebug() << "rotation" << pos->toLong(); QTransform rotate; switch (pos->toLong()) { case 1: // no rotation needed break; case 2: // flip over y thumb = thumb.mirrored(true, false); break; case 3: // rotate 180 (or flip x flip y) thumb = thumb.mirrored(true, true); break; case 4: // flip over x thumb = thumb.mirrored(false, true); break; case 5: // rotate 90 CW & flip over y rotate.rotate(90); rotate.rotate(180, Qt::YAxis); thumb = thumb.transformed(rotate); break; case 6: // rotate 90 CW rotate.rotate(90); thumb = thumb.transformed(rotate); break; case 7: // rotate 90 CCW flip over y rotate.rotate(-90); rotate.rotate(180, Qt::YAxis); thumb = thumb.transformed(rotate); break; case 8: // rotate 90 CCW rotate.rotate(-90); thumb = thumb.transformed(rotate); break; } } return thumb; }