Blame src/rw2image.cpp

Packit 01d647
// ***************************************************************** -*- C++ -*-
Packit 01d647
/*
Packit 01d647
 * Copyright (C) 2004-2018 Exiv2 authors
Packit 01d647
 * This program is part of the Exiv2 distribution.
Packit 01d647
 *
Packit 01d647
 * This program is free software; you can redistribute it and/or
Packit 01d647
 * modify it under the terms of the GNU General Public License
Packit 01d647
 * as published by the Free Software Foundation; either version 2
Packit 01d647
 * of the License, or (at your option) any later version.
Packit 01d647
 *
Packit 01d647
 * This program is distributed in the hope that it will be useful,
Packit 01d647
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 01d647
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 01d647
 * GNU General Public License for more details.
Packit 01d647
 *
Packit 01d647
 * You should have received a copy of the GNU General Public License
Packit 01d647
 * along with this program; if not, write to the Free Software
Packit 01d647
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
Packit 01d647
 */
Packit 01d647
/*
Packit 01d647
  File:      rw2image.cpp
Packit 01d647
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
Packit 01d647
  History:   06-Jan-09, ahu: created
Packit 01d647
Packit 01d647
 */
Packit 01d647
// *****************************************************************************
Packit 01d647
// included header files
Packit 01d647
#include "config.h"
Packit 01d647
Packit 01d647
#include "rw2image.hpp"
Packit 01d647
#include "rw2image_int.hpp"
Packit 01d647
#include "tiffcomposite_int.hpp"
Packit 01d647
#include "tiffimage_int.hpp"
Packit 01d647
#include "image.hpp"
Packit 01d647
#include "preview.hpp"
Packit 01d647
#include "error.hpp"
Packit 01d647
#include "futils.hpp"
Packit 01d647
Packit 01d647
// + standard includes
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
# include <iostream>
Packit 01d647
#endif
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// class member definitions
Packit 01d647
namespace Exiv2 {
Packit 01d647
Packit 01d647
    using namespace Internal;
Packit 01d647
Packit 01d647
    Rw2Image::Rw2Image(BasicIo::AutoPtr io)
Packit 01d647
        : Image(ImageType::rw2, mdExif | mdIptc | mdXmp, io)
Packit 01d647
    {
Packit 01d647
    } // Rw2Image::Rw2Image
Packit 01d647
Packit 01d647
    std::string Rw2Image::mimeType() const
Packit 01d647
    {
Packit 01d647
        return "image/x-panasonic-rw2";
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int Rw2Image::pixelWidth() const
Packit 01d647
    {
Packit 01d647
        ExifData::const_iterator imageWidth =
Packit 01d647
            exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorWidth"));
Packit 01d647
        if (imageWidth != exifData_.end() && imageWidth->count() > 0) {
Packit 01d647
            return imageWidth->toLong();
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int Rw2Image::pixelHeight() const
Packit 01d647
    {
Packit 01d647
        ExifData::const_iterator imageHeight =
Packit 01d647
            exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorHeight"));
Packit 01d647
        if (imageHeight != exifData_.end() && imageHeight->count() > 0) {
Packit 01d647
            return imageHeight->toLong();
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void Rw2Image::setExifData(const ExifData& /*exifData*/)
Packit 01d647
    {
Packit 01d647
        // Todo: implement me!
Packit 01d647
        throw(Error(kerInvalidSettingForImage, "Exif metadata", "RW2"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void Rw2Image::setIptcData(const IptcData& /*iptcData*/)
Packit 01d647
    {
Packit 01d647
        // Todo: implement me!
Packit 01d647
        throw(Error(kerInvalidSettingForImage, "IPTC metadata", "RW2"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void Rw2Image::setComment(const std::string& /*comment*/)
Packit 01d647
    {
Packit 01d647
        // not supported
Packit 01d647
        throw(Error(kerInvalidSettingForImage, "Image comment", "RW2"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void Rw2Image::printStructure(std::ostream& out, PrintStructureOption option, int depth) {
Packit 01d647
        out << "RW2 IMAGE" << std::endl;
Packit 01d647
        if (io_->open() != 0) throw Error(kerDataSourceOpenFailed, io_->path(), strError());
Packit 01d647
        // Ensure that this is the correct image type
Packit 01d647
        if ( imageType() == ImageType::none )
Packit 01d647
            if (!isRw2Type(*io_, false)) {
Packit 01d647
                if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
Packit 01d647
                throw Error(kerNotAJpeg);
Packit 01d647
            }
Packit 01d647
Packit 01d647
        io_->seek(0,BasicIo::beg);
Packit 01d647
Packit 01d647
        printTiffStructure(io(),out,option,depth-1);
Packit 01d647
    } // Rw2Image::printStructure
Packit 01d647
Packit 01d647
    void Rw2Image::readMetadata()
Packit 01d647
    {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cerr << "Reading RW2 file " << io_->path() << "\n";
Packit 01d647
#endif
Packit 01d647
        if (io_->open() != 0) {
Packit 01d647
            throw Error(kerDataSourceOpenFailed, io_->path(), strError());
Packit 01d647
        }
Packit 01d647
        IoCloser closer(*io_);
Packit 01d647
        // Ensure that this is the correct image type
Packit 01d647
        if (!isRw2Type(*io_, false)) {
Packit 01d647
            if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
Packit 01d647
            throw Error(kerNotAnImage, "RW2");
Packit 01d647
        }
Packit 01d647
        clearMetadata();
Packit 01d647
        ByteOrder bo = Rw2Parser::decode(exifData_,
Packit 01d647
                                         iptcData_,
Packit 01d647
                                         xmpData_,
Packit 01d647
                                         io_->mmap(),
Packit 01d647
                                         (uint32_t) io_->size());
Packit 01d647
        setByteOrder(bo);
Packit 01d647
Packit 01d647
        // A lot more metadata is hidden in the embedded preview image
Packit 01d647
        // Todo: This should go into the Rw2Parser, but for that it needs the Image
Packit 01d647
        PreviewManager loader(*this);
Packit 01d647
        PreviewPropertiesList list = loader.getPreviewProperties();
Packit 01d647
        // Todo: What if there are more preview images?
Packit 01d647
        if (list.size() > 1) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << "RW2 image contains more than one preview. None used.\n";
Packit 01d647
#endif
Packit 01d647
        }
Packit 01d647
        if (list.size() != 1) return;
Packit 01d647
        ExifData exifData;
Packit 01d647
        PreviewImage preview = loader.getPreviewImage(*list.begin());
Packit 01d647
        Image::AutoPtr image = ImageFactory::open(preview.pData(), preview.size());
Packit 01d647
        if (image.get() == 0) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << "Failed to open RW2 preview image.\n";
Packit 01d647
#endif
Packit 01d647
            return;
Packit 01d647
        }
Packit 01d647
        image->readMetadata();
Packit 01d647
        ExifData& prevData = image->exifData();
Packit 01d647
        if (!prevData.empty()) {
Packit 01d647
            // Filter duplicate tags
Packit 01d647
            for (ExifData::const_iterator pos = exifData_.begin(); pos != exifData_.end(); ++pos) {
Packit 01d647
                if (pos->ifdId() == panaRawId) continue;
Packit 01d647
                ExifData::iterator dup = prevData.findKey(ExifKey(pos->key()));
Packit 01d647
                if (dup != prevData.end()) {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
                    std::cerr << "Filtering duplicate tag " << pos->key()
Packit 01d647
                              << " (values '" << pos->value()
Packit 01d647
                              << "' and '" << dup->value() << "')\n";
Packit 01d647
#endif
Packit 01d647
                    prevData.erase(dup);
Packit 01d647
                }
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        // Remove tags not applicable for raw images
Packit 01d647
        static const char* filteredTags[] = {
Packit 01d647
            "Exif.Photo.ComponentsConfiguration",
Packit 01d647
            "Exif.Photo.CompressedBitsPerPixel",
Packit 01d647
            "Exif.Panasonic.ColorEffect",
Packit 01d647
            "Exif.Panasonic.Contrast",
Packit 01d647
            "Exif.Panasonic.NoiseReduction",
Packit 01d647
            "Exif.Panasonic.ColorMode",
Packit 01d647
            "Exif.Panasonic.OpticalZoomMode",
Packit 01d647
            "Exif.Panasonic.Contrast",
Packit 01d647
            "Exif.Panasonic.Saturation",
Packit 01d647
            "Exif.Panasonic.Sharpness",
Packit 01d647
            "Exif.Panasonic.FilmMode",
Packit 01d647
            "Exif.Panasonic.SceneMode",
Packit 01d647
            "Exif.Panasonic.WBRedLevel",
Packit 01d647
            "Exif.Panasonic.WBGreenLevel",
Packit 01d647
            "Exif.Panasonic.WBBlueLevel",
Packit 01d647
            "Exif.Photo.ColorSpace",
Packit 01d647
            "Exif.Photo.PixelXDimension",
Packit 01d647
            "Exif.Photo.PixelYDimension",
Packit 01d647
            "Exif.Photo.SceneType",
Packit 01d647
            "Exif.Photo.CustomRendered",
Packit 01d647
            "Exif.Photo.DigitalZoomRatio",
Packit 01d647
            "Exif.Photo.SceneCaptureType",
Packit 01d647
            "Exif.Photo.GainControl",
Packit 01d647
            "Exif.Photo.Contrast",
Packit 01d647
            "Exif.Photo.Saturation",
Packit 01d647
            "Exif.Photo.Sharpness",
Packit 01d647
            "Exif.Image.PrintImageMatching",
Packit 01d647
            "Exif.Image.YCbCrPositioning"
Packit 01d647
        };
Packit 01d647
        for (unsigned int i = 0; i < EXV_COUNTOF(filteredTags); ++i) {
Packit 01d647
            ExifData::iterator pos = prevData.findKey(ExifKey(filteredTags[i]));
Packit 01d647
            if (pos != prevData.end()) {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
                std::cerr << "Exif tag " << pos->key() << " removed\n";
Packit 01d647
#endif
Packit 01d647
                prevData.erase(pos);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Add the remaining tags
Packit 01d647
        for (ExifData::const_iterator pos = prevData.begin(); pos != prevData.end(); ++pos) {
Packit 01d647
            exifData_.add(*pos);
Packit 01d647
        }
Packit 01d647
Packit 01d647
    } // Rw2Image::readMetadata
Packit 01d647
Packit 01d647
    void Rw2Image::writeMetadata()
Packit 01d647
    {
Packit 01d647
        // Todo: implement me!
Packit 01d647
        throw(Error(kerWritingImageFormatUnsupported, "RW2"));
Packit 01d647
    } // Rw2Image::writeMetadata
Packit 01d647
Packit 01d647
    ByteOrder Rw2Parser::decode(
Packit 01d647
              ExifData& exifData,
Packit 01d647
              IptcData& iptcData,
Packit 01d647
              XmpData&  xmpData,
Packit 01d647
        const byte*     pData,
Packit 01d647
              uint32_t  size
Packit 01d647
    )
Packit 01d647
    {
Packit 01d647
        Rw2Header rw2Header;
Packit 01d647
        return TiffParserWorker::decode(exifData,
Packit 01d647
                                        iptcData,
Packit 01d647
                                        xmpData,
Packit 01d647
                                        pData,
Packit 01d647
                                        size,
Packit 01d647
                                        Tag::pana,
Packit 01d647
                                        TiffMapping::findDecoder,
Packit 01d647
                                        &rw2Header);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    // *************************************************************************
Packit 01d647
    // free functions
Packit 01d647
    Image::AutoPtr newRw2Instance(BasicIo::AutoPtr io, bool /*create*/)
Packit 01d647
    {
Packit 01d647
        Image::AutoPtr image(new Rw2Image(io));
Packit 01d647
        if (!image->good()) {
Packit 01d647
            image.reset();
Packit 01d647
        }
Packit 01d647
        return image;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    bool isRw2Type(BasicIo& iIo, bool advance)
Packit 01d647
    {
Packit 01d647
        const int32_t len = 24;
Packit 01d647
        byte buf[len];
Packit 01d647
        iIo.read(buf, len);
Packit 01d647
        if (iIo.error() || iIo.eof()) {
Packit 01d647
            return false;
Packit 01d647
        }
Packit 01d647
        Rw2Header header;
Packit 01d647
        bool rc = header.read(buf, len);
Packit 01d647
        if (!advance || !rc) {
Packit 01d647
            iIo.seek(-len, BasicIo::cur);
Packit 01d647
        }
Packit 01d647
        return rc;
Packit 01d647
    }
Packit 01d647
Packit 01d647
}                                       // namespace Exiv2