Blame src/bmpimage.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:      bmpimage.cpp
Packit 01d647
  Author(s): Marco Piovanelli, Ovolab (marco)
Packit 01d647
  History:   05-Mar-2007, marco: created
Packit 01d647
 */
Packit 01d647
// *****************************************************************************
Packit 01d647
// included header files
Packit 01d647
#include "config.h"
Packit 01d647
Packit 01d647
#include "basicio.hpp"
Packit 01d647
#include "bmpimage.hpp"
Packit 01d647
#include "error.hpp"
Packit 01d647
#include "futils.hpp"
Packit 01d647
#include "image.hpp"
Packit 01d647
Packit 01d647
// + standard includes
Packit 01d647
#include <cstring>
Packit 01d647
#include <iostream>
Packit 01d647
#include <string>
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// class member definitions
Packit 01d647
namespace Exiv2
Packit 01d647
{
Packit 01d647
    BmpImage::BmpImage(BasicIo::AutoPtr io) : Image(ImageType::bmp, mdNone, io)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string BmpImage::mimeType() const
Packit 01d647
    {
Packit 01d647
        return "image/x-ms-bmp";
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void BmpImage::setExifData(const ExifData& /*exifData*/)
Packit 01d647
    {
Packit 01d647
        // Todo: implement me!
Packit 01d647
        throw(Error(kerInvalidSettingForImage, "Exif metadata", "BMP"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void BmpImage::setIptcData(const IptcData& /*iptcData*/)
Packit 01d647
    {
Packit 01d647
        // Todo: implement me!
Packit 01d647
        throw(Error(kerInvalidSettingForImage, "IPTC metadata", "BMP"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void BmpImage::setComment(const std::string& /*comment*/)
Packit 01d647
    {
Packit 01d647
        // not supported
Packit 01d647
        throw(Error(kerInvalidSettingForImage, "Image comment", "BMP"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void BmpImage::readMetadata()
Packit 01d647
    {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        std::cerr << "Exiv2::BmpImage::readMetadata: Reading Windows bitmap 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 (!isBmpType(*io_, false)) {
Packit 01d647
            if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
Packit 01d647
            throw Error(kerNotAnImage, "BMP");
Packit 01d647
        }
Packit 01d647
        clearMetadata();
Packit 01d647
Packit 01d647
        /*
Packit 01d647
          The Windows bitmap header goes as follows -- all numbers are in little-endian byte order:
Packit 01d647
Packit 01d647
          offset  length   name                   description
Packit 01d647
          ======  =======  =====================  =======
Packit 01d647
           0      2 bytes  signature              always 'BM'
Packit 01d647
           2      4 bytes  bitmap size
Packit 01d647
           6      4 bytes  reserved
Packit 01d647
          10      4 bytes  bitmap offset
Packit 01d647
          14      4 bytes  header size
Packit 01d647
          18      4 bytes  bitmap width
Packit 01d647
          22      4 bytes  bitmap height
Packit 01d647
          26      2 bytes  plane count
Packit 01d647
          28      2 bytes  depth
Packit 01d647
          30      4 bytes  compression            0 = none; 1 = RLE, 8 bits/pixel; 2 = RLE, 4 bits/pixel; 3 = bitfield; 4 = JPEG; 5 = PNG
Packit 01d647
          34      4 bytes  image size             size of the raw bitmap data, in bytes
Packit 01d647
          38      4 bytes  horizontal resolution  (in pixels per meter)
Packit 01d647
          42      4 bytes  vertical resolution    (in pixels per meter)
Packit 01d647
          46      4 bytes  color count
Packit 01d647
          50      4 bytes  important colors       number of "important" colors
Packit 01d647
        */
Packit 01d647
        byte buf[54];
Packit 01d647
        if (io_->read(buf, sizeof(buf)) == sizeof(buf)) {
Packit 01d647
            pixelWidth_ = getLong(buf + 18, littleEndian);
Packit 01d647
            pixelHeight_ = getLong(buf + 22, littleEndian);
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void BmpImage::writeMetadata()
Packit 01d647
    {
Packit 01d647
        // Todo: implement me!
Packit 01d647
        throw(Error(kerWritingImageFormatUnsupported, "BMP"));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    // *************************************************************************
Packit 01d647
    // free functions
Packit 01d647
    Image::AutoPtr newBmpInstance(BasicIo::AutoPtr io, bool /*create*/)
Packit 01d647
    {
Packit 01d647
        Image::AutoPtr image(new BmpImage(io));
Packit 01d647
        if (!image->good()) {
Packit 01d647
            image.reset();
Packit 01d647
        }
Packit 01d647
        return image;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    bool isBmpType(BasicIo& iIo, bool advance)
Packit 01d647
    {
Packit 01d647
        const int32_t len = 2;
Packit 01d647
        const unsigned char BmpImageId[2] = {'B', 'M'};
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
        bool matched = (memcmp(buf, BmpImageId, len) == 0);
Packit 01d647
        if (!advance || !matched) {
Packit 01d647
            iIo.seek(-len, BasicIo::cur);
Packit 01d647
        }
Packit 01d647
        return matched;
Packit 01d647
    }
Packit 01d647
}