/src/exiv2/src/bmpimage.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | File: bmpimage.cpp |
4 | | Author(s): Marco Piovanelli, Ovolab (marco) |
5 | | History: 05-Mar-2007, marco: created |
6 | | */ |
7 | | |
8 | | #include "bmpimage.hpp" |
9 | | #include "basicio.hpp" |
10 | | #include "error.hpp" |
11 | | #include "futils.hpp" |
12 | | #include "image.hpp" |
13 | | |
14 | | // + standard includes |
15 | | #include <array> |
16 | | #include <cstring> |
17 | | #include <string> |
18 | | |
19 | | #ifdef EXIV2_DEBUG_MESSAGES |
20 | | #include <iostream> |
21 | | #endif |
22 | | |
23 | | // ***************************************************************************** |
24 | | // class member definitions |
25 | | namespace Exiv2 { |
26 | 11 | BmpImage::BmpImage(BasicIo::UniquePtr io) : Image(ImageType::bmp, mdNone, std::move(io)) { |
27 | 11 | } |
28 | | |
29 | 0 | std::string BmpImage::mimeType() const { |
30 | | // "image/bmp" is a Generic Bitmap |
31 | 0 | return "image/x-ms-bmp"; // Microsoft Bitmap |
32 | 0 | } |
33 | | |
34 | 0 | void BmpImage::setExifData(const ExifData& /*exifData*/) { |
35 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "Exif metadata", "BMP")); |
36 | 0 | } |
37 | | |
38 | 0 | void BmpImage::setIptcData(const IptcData& /*iptcData*/) { |
39 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "BMP")); |
40 | 0 | } |
41 | | |
42 | 0 | void BmpImage::setComment(const std::string&) { |
43 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMP")); |
44 | 0 | } |
45 | | |
46 | 10 | void BmpImage::readMetadata() { |
47 | | #ifdef EXIV2_DEBUG_MESSAGES |
48 | | std::cerr << "Exiv2::BmpImage::readMetadata: Reading Windows bitmap file " << io_->path() << "\n"; |
49 | | #endif |
50 | 10 | if (io_->open() != 0) { |
51 | 0 | throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); |
52 | 0 | } |
53 | 10 | IoCloser closer(*io_); |
54 | | |
55 | | // Ensure that this is the correct image type |
56 | 10 | if (!isBmpType(*io_, false)) { |
57 | 0 | if (io_->error() || io_->eof()) |
58 | 0 | throw Error(ErrorCode::kerFailedToReadImageData); |
59 | 0 | throw Error(ErrorCode::kerNotAnImage, "BMP"); |
60 | 0 | } |
61 | 10 | clearMetadata(); |
62 | | |
63 | | /* |
64 | | The Windows bitmap header goes as follows -- all numbers are in little-endian byte order: |
65 | | |
66 | | offset length name description |
67 | | ====== ======= ===================== ======= |
68 | | 0 2 bytes signature always 'BM' |
69 | | 2 4 bytes bitmap size |
70 | | 6 4 bytes reserved |
71 | | 10 4 bytes bitmap offset |
72 | | 14 4 bytes header size |
73 | | 18 4 bytes bitmap width |
74 | | 22 4 bytes bitmap height |
75 | | 26 2 bytes plane count |
76 | | 28 2 bytes depth |
77 | | 30 4 bytes compression 0 = none; 1 = RLE, 8 bits/pixel; 2 = RLE, 4 bits/pixel; 3 = bitfield; |
78 | | 4 = JPEG; 5 = PNG 34 4 bytes image size size of the raw bitmap data, in bytes 38 4 |
79 | | bytes horizontal resolution (in pixels per meter) 42 4 bytes vertical resolution (in pixels per |
80 | | meter) 46 4 bytes color count 50 4 bytes important colors number of "important" colors |
81 | | */ |
82 | 10 | byte buf[26]; |
83 | 10 | if (io_->read(buf, sizeof(buf)) == sizeof(buf)) { |
84 | 10 | pixelWidth_ = getULong(buf + 18, littleEndian); |
85 | 10 | pixelHeight_ = getULong(buf + 22, littleEndian); |
86 | 10 | } |
87 | 10 | } |
88 | | |
89 | 0 | void BmpImage::writeMetadata() { |
90 | | /// \todo implement me! |
91 | 0 | throw(Error(ErrorCode::kerWritingImageFormatUnsupported, "BMP")); |
92 | 0 | } |
93 | | |
94 | | // ************************************************************************* |
95 | | // free functions |
96 | 11 | Image::UniquePtr newBmpInstance(BasicIo::UniquePtr io, bool /*create*/) { |
97 | 11 | auto image = std::make_unique<BmpImage>(std::move(io)); |
98 | 11 | if (!image->good()) { |
99 | 1 | return nullptr; |
100 | 1 | } |
101 | 10 | return image; |
102 | 11 | } |
103 | | |
104 | 7.94k | bool isBmpType(BasicIo& iIo, bool advance) { |
105 | 7.94k | const int32_t len = 2; |
106 | 7.94k | const std::array<byte, len> BmpImageId{'B', 'M'}; |
107 | 7.94k | std::array<byte, len> buf; |
108 | 7.94k | iIo.read(buf.data(), len); |
109 | 7.94k | if (iIo.error() || iIo.eof()) { |
110 | 165 | return false; |
111 | 165 | } |
112 | 7.78k | bool matched = buf == BmpImageId; |
113 | 7.78k | if (!advance || !matched) { |
114 | 7.78k | iIo.seek(-len, BasicIo::cur); |
115 | 7.78k | } |
116 | 7.78k | return matched; |
117 | 7.94k | } |
118 | | } // namespace Exiv2 |