Blame src/rw2image.cpp

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