/src/exiv2/src/crwimage.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | File: crwimage.cpp |
4 | | Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> |
5 | | History: 28-Aug-05, ahu: created |
6 | | */ |
7 | | // included header files |
8 | | #include "crwimage.hpp" |
9 | | #include "basicio.hpp" |
10 | | #include "config.h" |
11 | | #include "crwimage_int.hpp" |
12 | | #include "error.hpp" |
13 | | #include "futils.hpp" |
14 | | #include "tags.hpp" |
15 | | |
16 | | #include <cstring> |
17 | | |
18 | | #ifdef EXIV2_DEBUG_MESSAGES |
19 | | #include <iostream> |
20 | | #endif |
21 | | |
22 | | // ***************************************************************************** |
23 | | // class member definitions |
24 | | namespace Exiv2 { |
25 | | |
26 | 186 | CrwImage::CrwImage(BasicIo::UniquePtr io, bool /*create*/) : Image(ImageType::crw, mdExif | mdComment, std::move(io)) { |
27 | 186 | } // CrwImage::CrwImage |
28 | | |
29 | 0 | std::string CrwImage::mimeType() const { |
30 | 0 | return "image/x-canon-crw"; |
31 | 0 | } |
32 | | |
33 | 13 | uint32_t CrwImage::pixelWidth() const { |
34 | 13 | auto widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); |
35 | 13 | if (widthIter != exifData_.end() && widthIter->count() > 0) { |
36 | 0 | return widthIter->toUint32(); |
37 | 0 | } |
38 | 13 | return 0; |
39 | 13 | } |
40 | | |
41 | 13 | uint32_t CrwImage::pixelHeight() const { |
42 | 13 | auto heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); |
43 | 13 | if (heightIter != exifData_.end() && heightIter->count() > 0) { |
44 | 0 | return heightIter->toUint32(); |
45 | 0 | } |
46 | 13 | return 0; |
47 | 13 | } |
48 | | |
49 | 0 | void CrwImage::setIptcData(const IptcData& /*iptcData*/) { |
50 | | // not supported |
51 | 0 | throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "CRW")); |
52 | 0 | } |
53 | | |
54 | 186 | void CrwImage::readMetadata() { |
55 | | #ifdef EXIV2_DEBUG_MESSAGES |
56 | | std::cerr << "Reading CRW file " << io_->path() << "\n"; |
57 | | #endif |
58 | 186 | if (io_->open()) { |
59 | 0 | throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); |
60 | 0 | } |
61 | 186 | IoCloser closer(*io_); |
62 | | // Ensure that this is the correct image type |
63 | 186 | if (!isCrwType(*io_, false)) { |
64 | 0 | if (io_->error() || io_->eof()) |
65 | 0 | throw Error(ErrorCode::kerFailedToReadImageData); |
66 | 0 | throw Error(ErrorCode::kerNotACrwImage); |
67 | 0 | } |
68 | 186 | clearMetadata(); |
69 | 186 | DataBuf file(io().size()); |
70 | 186 | io_->read(file.data(), file.size()); |
71 | | |
72 | 186 | CrwParser::decode(this, io_->mmap(), io_->size()); |
73 | | |
74 | 186 | } // CrwImage::readMetadata |
75 | | |
76 | 0 | void CrwImage::writeMetadata() { |
77 | | #ifdef EXIV2_DEBUG_MESSAGES |
78 | | std::cerr << "Writing CRW file " << io_->path() << "\n"; |
79 | | #endif |
80 | | // Read existing image |
81 | 0 | DataBuf buf; |
82 | 0 | if (io_->open() == 0) { |
83 | 0 | IoCloser closer(*io_); |
84 | | // Ensure that this is the correct image type |
85 | 0 | if (isCrwType(*io_, false)) { |
86 | | // Read the image into a memory buffer |
87 | 0 | buf.alloc(io_->size()); |
88 | 0 | io_->read(buf.data(), buf.size()); |
89 | 0 | if (io_->error() || io_->eof()) { |
90 | 0 | buf.reset(); |
91 | 0 | } |
92 | 0 | } |
93 | 0 | } |
94 | |
|
95 | 0 | Blob blob; |
96 | 0 | CrwParser::encode(blob, buf.c_data(), buf.size(), this); |
97 | | |
98 | | // Write new buffer to file |
99 | 0 | MemIo tempIo; |
100 | 0 | tempIo.write((!blob.empty() ? blob.data() : nullptr), blob.size()); |
101 | 0 | io_->close(); |
102 | 0 | io_->transfer(tempIo); // may throw |
103 | |
|
104 | 0 | } // CrwImage::writeMetadata |
105 | | |
106 | 186 | void CrwParser::decode(CrwImage* pCrwImage, const byte* pData, size_t size) { |
107 | | // Parse the image, starting with a CIFF header component |
108 | 186 | Internal::CiffHeader header; |
109 | 186 | header.read(pData, size); |
110 | 186 | header.decode(*pCrwImage); |
111 | | |
112 | | // a hack to get absolute offset of preview image inside CRW structure |
113 | 186 | if (auto preview = header.findComponent(0x2007, 0x0000)) { |
114 | 0 | (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormat"] = static_cast<uint32_t>(preview->pData() - pData); |
115 | 0 | (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormatLength"] = static_cast<uint32_t>(preview->size()); |
116 | 0 | } |
117 | 186 | } // CrwParser::decode |
118 | | |
119 | 0 | void CrwParser::encode(Blob& blob, const byte* pData, size_t size, const CrwImage* pCrwImage) { |
120 | | // Parse image, starting with a CIFF header component |
121 | 0 | Internal::CiffHeader header; |
122 | 0 | if (size != 0) { |
123 | 0 | header.read(pData, size); |
124 | 0 | } |
125 | | |
126 | | // Encode Exif tags from image into the CRW parse tree and write the |
127 | | // structure to the binary image blob |
128 | 0 | Internal::CrwMap::encode(header, *pCrwImage); |
129 | 0 | header.write(blob); |
130 | 0 | } |
131 | | |
132 | | // ************************************************************************* |
133 | | // free functions |
134 | 186 | Image::UniquePtr newCrwInstance(BasicIo::UniquePtr io, bool create) { |
135 | 186 | auto image = std::make_unique<CrwImage>(std::move(io), create); |
136 | 186 | if (!image->good()) { |
137 | 0 | return nullptr; |
138 | 0 | } |
139 | 186 | return image; |
140 | 186 | } |
141 | | |
142 | 24.9k | bool isCrwType(BasicIo& iIo, bool advance) { |
143 | 24.9k | bool result = true; |
144 | 24.9k | byte tmpBuf[14]; |
145 | 24.9k | iIo.read(tmpBuf, 14); |
146 | 24.9k | if (iIo.error() || iIo.eof()) { |
147 | 69 | return false; |
148 | 69 | } |
149 | 24.8k | if (('I' != tmpBuf[0] || 'I' != tmpBuf[1]) && ('M' != tmpBuf[0] || 'M' != tmpBuf[1])) { |
150 | 11.0k | result = false; |
151 | 11.0k | } |
152 | 24.8k | if (result && std::memcmp(tmpBuf + 6, Internal::CiffHeader::signature(), 8) != 0) { |
153 | 13.1k | result = false; |
154 | 13.1k | } |
155 | 24.8k | if (!advance || !result) |
156 | 24.8k | iIo.seek(-14, BasicIo::cur); |
157 | 24.8k | return result; |
158 | 24.9k | } |
159 | | |
160 | | } // namespace Exiv2 |