Blame src/crwimage.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:      crwimage.cpp
Packit Service 21b5d1
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
Packit Service 21b5d1
  History:   28-Aug-05, 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 "crwimage.hpp"
Packit Service 21b5d1
#include "crwimage_int.hpp"
Packit Service 21b5d1
#include "error.hpp"
Packit Service 21b5d1
#include "futils.hpp"
Packit Service 21b5d1
#include "value.hpp"
Packit Service 21b5d1
#include "tags.hpp"
Packit Service 21b5d1
#include "tags_int.hpp"
Packit Service 21b5d1
Packit Service 21b5d1
// + standard includes
Packit Service 21b5d1
#include <iostream>
Packit Service 21b5d1
#include <iomanip>
Packit Service 21b5d1
#include <stack>
Packit Service 21b5d1
#include <cstdlib>
Packit Service 21b5d1
#include <cstring>
Packit Service 21b5d1
#include <ctime>
Packit Service 21b5d1
#include <cmath>
Packit Service 21b5d1
#include <cassert>
Packit Service 21b5d1
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
    CrwImage::CrwImage(BasicIo::AutoPtr io, bool /*create*/)
Packit Service 21b5d1
        : Image(ImageType::crw, mdExif | mdComment, io)
Packit Service 21b5d1
    {
Packit Service 21b5d1
    } // CrwImage::CrwImage
Packit Service 21b5d1
Packit Service 21b5d1
    std::string CrwImage::mimeType() const
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return "image/x-canon-crw";
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    int CrwImage::pixelWidth() const
Packit Service 21b5d1
    {
Packit Service 21b5d1
        Exiv2::ExifData::const_iterator widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
Packit Service 21b5d1
        if (widthIter != exifData_.end() && widthIter->count() > 0) {
Packit Service 21b5d1
            return widthIter->toLong();
Packit Service 21b5d1
        }
Packit Service 21b5d1
        return 0;
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    int CrwImage::pixelHeight() const
Packit Service 21b5d1
    {
Packit Service 21b5d1
        Exiv2::ExifData::const_iterator heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension"));
Packit Service 21b5d1
        if (heightIter != exifData_.end() && heightIter->count() > 0) {
Packit Service 21b5d1
            return heightIter->toLong();
Packit Service 21b5d1
        }
Packit Service 21b5d1
        return 0;
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    void CrwImage::setIptcData(const IptcData& /*iptcData*/)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        // not supported
Packit Service 21b5d1
        throw(Error(kerInvalidSettingForImage, "IPTC metadata", "CRW"));
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    void CrwImage::readMetadata()
Packit Service 21b5d1
    {
Packit Service 21b5d1
#ifdef EXIV2_DEBUG_MESSAGES
Packit Service 21b5d1
        std::cerr << "Reading CRW 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 (!isCrwType(*io_, false)) {
Packit Service 21b5d1
            if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
Packit Service 21b5d1
            throw Error(kerNotACrwImage);
Packit Service 21b5d1
        }
Packit Service 21b5d1
        clearMetadata();
Packit Service 21b5d1
        DataBuf file( (long) io().size());
Packit Service 21b5d1
        io_->read(file.pData_,file.size_);
Packit Service 21b5d1
Packit Service 21b5d1
        CrwParser::decode(this, io_->mmap(), (uint32_t) io_->size());
Packit Service 21b5d1
Packit Service 21b5d1
    } // CrwImage::readMetadata
Packit Service 21b5d1
Packit Service 21b5d1
    void CrwImage::writeMetadata()
Packit Service 21b5d1
    {
Packit Service 21b5d1
#ifdef EXIV2_DEBUG_MESSAGES
Packit Service 21b5d1
        std::cerr << "Writing CRW file " << io_->path() << "\n";
Packit Service 21b5d1
#endif
Packit Service 21b5d1
        // Read existing image
Packit Service 21b5d1
        DataBuf buf;
Packit Service 21b5d1
        if (io_->open() == 0) {
Packit Service 21b5d1
            IoCloser closer(*io_);
Packit Service 21b5d1
            // Ensure that this is the correct image type
Packit Service 21b5d1
            if (isCrwType(*io_, false)) {
Packit Service 21b5d1
                // Read the image into a memory buffer
Packit Service 21b5d1
                buf.alloc((long) io_->size());
Packit Service 21b5d1
                io_->read(buf.pData_, buf.size_);
Packit Service 21b5d1
                if (io_->error() || io_->eof()) {
Packit Service 21b5d1
                    buf.reset();
Packit Service 21b5d1
                }
Packit Service 21b5d1
            }
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        Blob blob;
Packit Service 21b5d1
        CrwParser::encode(blob, buf.pData_, buf.size_, this);
Packit Service 21b5d1
Packit Service 21b5d1
        // Write new buffer to file
Packit Service 21b5d1
        MemIo::AutoPtr tempIo(new MemIo);
Packit Service 21b5d1
        assert(tempIo.get() != 0);
Packit Service 21b5d1
        tempIo->write((blob.size() > 0 ? &blob[0] : 0), static_cast<long>(blob.size()));
Packit Service 21b5d1
        io_->close();
Packit Service 21b5d1
        io_->transfer(*tempIo); // may throw
Packit Service 21b5d1
Packit Service 21b5d1
    } // CrwImage::writeMetadata
Packit Service 21b5d1
Packit Service 21b5d1
    void CrwParser::decode(CrwImage* pCrwImage, const byte* pData, uint32_t size)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        assert(pCrwImage != 0);
Packit Service 21b5d1
        assert(pData != 0);
Packit Service 21b5d1
Packit Service 21b5d1
        // Parse the image, starting with a CIFF header component
Packit Service 21b5d1
        CiffHeader::AutoPtr head(new CiffHeader);
Packit Service 21b5d1
        head->read(pData, size);
Packit Service 21b5d1
#ifdef EXIV2_DEBUG_MESSAGES
Packit Service 21b5d1
        head->print(std::cerr);
Packit Service 21b5d1
#endif
Packit Service 21b5d1
        head->decode(*pCrwImage);
Packit Service 21b5d1
Packit Service 21b5d1
        // a hack to get absolute offset of preview image inside CRW structure
Packit Service 21b5d1
        CiffComponent* preview = head->findComponent(0x2007, 0x0000);
Packit Service 21b5d1
        if (preview) {
Packit Service 21b5d1
            (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormat"] = uint32_t(preview->pData() - pData);
Packit Service 21b5d1
            (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormatLength"] = preview->size();
Packit Service 21b5d1
        }
Packit Service 21b5d1
    } // CrwParser::decode
Packit Service 21b5d1
Packit Service 21b5d1
    void CrwParser::encode(
Packit Service 21b5d1
              Blob&     blob,
Packit Service 21b5d1
        const byte*     pData,
Packit Service 21b5d1
              uint32_t  size,
Packit Service 21b5d1
        const CrwImage* pCrwImage
Packit Service 21b5d1
    )
Packit Service 21b5d1
    {
Packit Service 21b5d1
        // Parse image, starting with a CIFF header component
Packit Service 21b5d1
        CiffHeader::AutoPtr head(new CiffHeader);
Packit Service 21b5d1
        if (size != 0) {
Packit Service 21b5d1
            head->read(pData, size);
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        // Encode Exif tags from image into the CRW parse tree and write the
Packit Service 21b5d1
        // structure to the binary image blob
Packit Service 21b5d1
        CrwMap::encode(head.get(), *pCrwImage);
Packit Service 21b5d1
        head->write(blob);
Packit Service 21b5d1
Packit Service 21b5d1
    } // CrwParser::encode
Packit Service 21b5d1
Packit Service 21b5d1
    // *************************************************************************
Packit Service 21b5d1
    // free functions
Packit Service 21b5d1
    Image::AutoPtr newCrwInstance(BasicIo::AutoPtr io, bool create)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        Image::AutoPtr image(new CrwImage(io, create));
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 isCrwType(BasicIo& iIo, bool advance)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        bool result = true;
Packit Service 21b5d1
        byte tmpBuf[14];
Packit Service 21b5d1
        iIo.read(tmpBuf, 14);
Packit Service 21b5d1
        if (iIo.error() || iIo.eof()) {
Packit Service 21b5d1
            return false;
Packit Service 21b5d1
        }
Packit Service 21b5d1
        if (!(   ('I' == tmpBuf[0] && 'I' == tmpBuf[1])
Packit Service 21b5d1
              || ('M' == tmpBuf[0] && 'M' == tmpBuf[1]))) {
Packit Service 21b5d1
            result = false;
Packit Service 21b5d1
        }
Packit Service 21b5d1
        if (   true == result
Packit Service 21b5d1
            && std::memcmp(tmpBuf + 6, CiffHeader::signature(), 8) != 0) {
Packit Service 21b5d1
            result = false;
Packit Service 21b5d1
        }
Packit Service 21b5d1
        if (!advance || !result) iIo.seek(-14, BasicIo::cur);
Packit Service 21b5d1
        return result;
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
}                                       // namespace Exiv2