Coverage Report

Created: 2026-05-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/exiv2/src/rw2image.cpp
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
3
// included header files
4
#include "rw2image.hpp"
5
#include "basicio.hpp"
6
#include "config.h"
7
#include "error.hpp"
8
#include "futils.hpp"
9
#include "image.hpp"
10
#include "preview.hpp"
11
#include "rw2image_int.hpp"
12
#include "tags.hpp"
13
#include "tiffcomposite_int.hpp"
14
#include "tiffimage_int.hpp"
15
16
// + standard includes
17
#include <array>
18
19
#ifdef EXIV2_DEBUG_MESSAGES
20
#include <iostream>
21
#include "value.hpp"
22
#endif
23
24
// *****************************************************************************
25
// class member definitions
26
namespace Exiv2 {
27
using namespace Internal;
28
29
194
Rw2Image::Rw2Image(BasicIo::UniquePtr io) : Image(ImageType::rw2, mdExif | mdIptc | mdXmp, std::move(io)) {
30
194
}  // Rw2Image::Rw2Image
31
32
726
std::string Rw2Image::mimeType() const {
33
726
  return "image/x-panasonic-rw2";
34
726
}
35
36
180
uint32_t Rw2Image::pixelWidth() const {
37
180
  auto imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorWidth"));
38
180
  if (imageWidth == exifData_.end() || imageWidth->count() == 0)
39
168
    return 0;
40
12
  return imageWidth->toUint32();
41
180
}
42
43
180
uint32_t Rw2Image::pixelHeight() const {
44
180
  auto imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorHeight"));
45
180
  if (imageHeight == exifData_.end() || imageHeight->count() == 0)
46
164
    return 0;
47
16
  return imageHeight->toUint32();
48
180
}
49
50
0
void Rw2Image::setExifData(const ExifData& /*exifData*/) {
51
  // Todo: implement me!
52
0
  throw(Error(ErrorCode::kerInvalidSettingForImage, "Exif metadata", "RW2"));
53
0
}
54
55
0
void Rw2Image::setIptcData(const IptcData& /*iptcData*/) {
56
  // Todo: implement me!
57
0
  throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "RW2"));
58
0
}
59
60
0
void Rw2Image::setComment(const std::string&) {
61
  // not supported
62
0
  throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "RW2"));
63
0
}
64
65
0
void Rw2Image::printStructure(std::ostream& out, PrintStructureOption option, size_t depth) {
66
0
  out << "RW2 IMAGE" << '\n';
67
0
  if (io_->open() != 0)
68
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
69
  // Ensure that this is the correct image type
70
0
  if (imageType() == ImageType::none && !isRw2Type(*io_, false)) {
71
0
    if (io_->error() || io_->eof())
72
0
      throw Error(ErrorCode::kerFailedToReadImageData);
73
0
    throw Error(ErrorCode::kerNotAJpeg);
74
0
  }
75
76
0
  io_->seek(0, BasicIo::beg);
77
78
0
  printTiffStructure(io(), out, option, depth);
79
0
}  // Rw2Image::printStructure
80
81
194
void Rw2Image::readMetadata() {
82
#ifdef EXIV2_DEBUG_MESSAGES
83
  std::cerr << "Reading RW2 file " << io_->path() << "\n";
84
#endif
85
194
  if (io_->open() != 0) {
86
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
87
0
  }
88
194
  IoCloser closer(*io_);
89
  // Ensure that this is the correct image type
90
194
  if (!isRw2Type(*io_, false)) {
91
0
    if (io_->error() || io_->eof())
92
0
      throw Error(ErrorCode::kerFailedToReadImageData);
93
0
    throw Error(ErrorCode::kerNotAnImage, "RW2");
94
0
  }
95
194
  clearMetadata();
96
194
  ByteOrder bo = Rw2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size());
97
194
  setByteOrder(bo);
98
99
  // A lot more metadata is hidden in the embedded preview image
100
  // Todo: This should go into the Rw2Parser, but for that it needs the Image
101
194
  PreviewManager loader(*this);
102
194
  PreviewPropertiesList list = loader.getPreviewProperties();
103
  // Todo: What if there are more preview images?
104
194
  if (list.size() > 1) {
105
0
#ifndef SUPPRESS_WARNINGS
106
0
    EXV_WARNING << "RW2 image contains more than one preview. None used.\n";
107
0
#endif
108
0
  }
109
194
  if (list.size() != 1)
110
182
    return;
111
12
  ExifData exifData;
112
12
  PreviewImage preview = loader.getPreviewImage(*list.begin());
113
12
  auto image = ImageFactory::open(preview.pData(), preview.size());
114
12
  if (!image) {
115
0
#ifndef SUPPRESS_WARNINGS
116
0
    EXV_WARNING << "Failed to open RW2 preview image.\n";
117
0
#endif
118
0
    return;
119
0
  }
120
12
  image->readMetadata();
121
12
  ExifData& prevData = image->exifData();
122
12
  if (!prevData.empty()) {
123
    // Filter duplicate tags
124
0
    for (const auto& pos : exifData_) {
125
0
      if (pos.ifdId() == IfdId::panaRawId)
126
0
        continue;
127
0
      auto dup = prevData.findKey(ExifKey(pos.key()));
128
0
      if (dup != prevData.end()) {
129
#ifdef EXIV2_DEBUG_MESSAGES
130
        std::cerr << "Filtering duplicate tag " << pos.key() << " (values '" << pos.value() << "' and '" << dup->value()
131
                  << "')\n";
132
#endif
133
0
        prevData.erase(dup);
134
0
      }
135
0
    }
136
0
  }
137
  // Remove tags not applicable for raw images
138
12
  static constexpr auto filteredTags = std::array{
139
12
      "Exif.Photo.ComponentsConfiguration",
140
12
      "Exif.Photo.CompressedBitsPerPixel",
141
12
      "Exif.Panasonic.ColorEffect",
142
12
      "Exif.Panasonic.Contrast",
143
12
      "Exif.Panasonic.NoiseReduction",
144
12
      "Exif.Panasonic.ColorMode",
145
12
      "Exif.Panasonic.OpticalZoomMode",
146
12
      "Exif.Panasonic.Contrast",
147
12
      "Exif.Panasonic.Saturation",
148
12
      "Exif.Panasonic.Sharpness",
149
12
      "Exif.Panasonic.FilmMode",
150
12
      "Exif.Panasonic.SceneMode",
151
12
      "Exif.Panasonic.WBRedLevel",
152
12
      "Exif.Panasonic.WBGreenLevel",
153
12
      "Exif.Panasonic.WBBlueLevel",
154
12
      "Exif.Photo.ColorSpace",
155
12
      "Exif.Photo.PixelXDimension",
156
12
      "Exif.Photo.PixelYDimension",
157
12
      "Exif.Photo.SceneType",
158
12
      "Exif.Photo.CustomRendered",
159
12
      "Exif.Photo.DigitalZoomRatio",
160
12
      "Exif.Photo.SceneCaptureType",
161
12
      "Exif.Photo.GainControl",
162
12
      "Exif.Photo.Contrast",
163
12
      "Exif.Photo.Saturation",
164
12
      "Exif.Photo.Sharpness",
165
12
      "Exif.Image.PrintImageMatching",
166
12
      "Exif.Image.YCbCrPositioning",
167
12
  };
168
12
  for (auto&& filteredTag : filteredTags) {
169
0
    auto pos = prevData.findKey(ExifKey(filteredTag));
170
0
    if (pos != prevData.end()) {
171
#ifdef EXIV2_DEBUG_MESSAGES
172
      std::cerr << "Exif tag " << pos->key() << " removed\n";
173
#endif
174
0
      prevData.erase(pos);
175
0
    }
176
0
  }
177
178
  // Add the remaining tags
179
12
  for (const auto& pos : prevData) {
180
0
    exifData_.add(pos);
181
0
  }
182
183
12
}  // Rw2Image::readMetadata
184
185
0
void Rw2Image::writeMetadata() {
186
  // Todo: implement me!
187
0
  throw(Error(ErrorCode::kerWritingImageFormatUnsupported, "RW2"));
188
0
}  // Rw2Image::writeMetadata
189
190
194
ByteOrder Rw2Parser::decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size) {
191
194
  Rw2Header rw2Header;
192
194
  return TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Tag::pana, TiffMapping::findDecoder,
193
194
                                  &rw2Header);
194
194
}
195
196
// *************************************************************************
197
// free functions
198
194
Image::UniquePtr newRw2Instance(BasicIo::UniquePtr io, bool /*create*/) {
199
194
  auto image = std::make_unique<Rw2Image>(std::move(io));
200
194
  if (!image->good()) {
201
0
    return nullptr;
202
0
  }
203
194
  return image;
204
194
}
205
206
17.8k
bool isRw2Type(BasicIo& iIo, bool advance) {
207
17.8k
  const int32_t len = 24;
208
17.8k
  byte buf[len];
209
17.8k
  iIo.read(buf, len);
210
17.8k
  if (iIo.error() || iIo.eof()) {
211
284
    return false;
212
284
  }
213
17.5k
  Rw2Header header;
214
17.5k
  bool rc = header.read(buf, len);
215
17.5k
  if (!advance || !rc) {
216
17.5k
    iIo.seek(-len, BasicIo::cur);
217
17.5k
  }
218
17.5k
  return rc;
219
17.8k
}
220
221
}  // namespace Exiv2