Coverage Report

Created: 2026-04-29 07:00

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
93
Rw2Image::Rw2Image(BasicIo::UniquePtr io) : Image(ImageType::rw2, mdExif | mdIptc | mdXmp, std::move(io)) {
30
93
}  // Rw2Image::Rw2Image
31
32
366
std::string Rw2Image::mimeType() const {
33
366
  return "image/x-panasonic-rw2";
34
366
}
35
36
90
uint32_t Rw2Image::pixelWidth() const {
37
90
  auto imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorWidth"));
38
90
  if (imageWidth == exifData_.end() || imageWidth->count() == 0)
39
86
    return 0;
40
4
  return imageWidth->toUint32();
41
90
}
42
43
90
uint32_t Rw2Image::pixelHeight() const {
44
90
  auto imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorHeight"));
45
90
  if (imageHeight == exifData_.end() || imageHeight->count() == 0)
46
80
    return 0;
47
10
  return imageHeight->toUint32();
48
90
}
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
93
void Rw2Image::readMetadata() {
82
#ifdef EXIV2_DEBUG_MESSAGES
83
  std::cerr << "Reading RW2 file " << io_->path() << "\n";
84
#endif
85
93
  if (io_->open() != 0) {
86
0
    throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
87
0
  }
88
93
  IoCloser closer(*io_);
89
  // Ensure that this is the correct image type
90
93
  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
93
  clearMetadata();
96
93
  ByteOrder bo = Rw2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size());
97
93
  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
93
  PreviewManager loader(*this);
102
93
  PreviewPropertiesList list = loader.getPreviewProperties();
103
  // Todo: What if there are more preview images?
104
93
  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
93
  if (list.size() != 1)
110
92
    return;
111
1
  ExifData exifData;
112
1
  PreviewImage preview = loader.getPreviewImage(*list.begin());
113
1
  auto image = ImageFactory::open(preview.pData(), preview.size());
114
1
  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
1
  image->readMetadata();
121
1
  ExifData& prevData = image->exifData();
122
1
  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
1
  static constexpr auto filteredTags = std::array{
139
1
      "Exif.Photo.ComponentsConfiguration",
140
1
      "Exif.Photo.CompressedBitsPerPixel",
141
1
      "Exif.Panasonic.ColorEffect",
142
1
      "Exif.Panasonic.Contrast",
143
1
      "Exif.Panasonic.NoiseReduction",
144
1
      "Exif.Panasonic.ColorMode",
145
1
      "Exif.Panasonic.OpticalZoomMode",
146
1
      "Exif.Panasonic.Contrast",
147
1
      "Exif.Panasonic.Saturation",
148
1
      "Exif.Panasonic.Sharpness",
149
1
      "Exif.Panasonic.FilmMode",
150
1
      "Exif.Panasonic.SceneMode",
151
1
      "Exif.Panasonic.WBRedLevel",
152
1
      "Exif.Panasonic.WBGreenLevel",
153
1
      "Exif.Panasonic.WBBlueLevel",
154
1
      "Exif.Photo.ColorSpace",
155
1
      "Exif.Photo.PixelXDimension",
156
1
      "Exif.Photo.PixelYDimension",
157
1
      "Exif.Photo.SceneType",
158
1
      "Exif.Photo.CustomRendered",
159
1
      "Exif.Photo.DigitalZoomRatio",
160
1
      "Exif.Photo.SceneCaptureType",
161
1
      "Exif.Photo.GainControl",
162
1
      "Exif.Photo.Contrast",
163
1
      "Exif.Photo.Saturation",
164
1
      "Exif.Photo.Sharpness",
165
1
      "Exif.Image.PrintImageMatching",
166
1
      "Exif.Image.YCbCrPositioning",
167
1
  };
168
1
  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
1
  for (const auto& pos : prevData) {
180
0
    exifData_.add(pos);
181
0
  }
182
183
1
}  // 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
93
ByteOrder Rw2Parser::decode(ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, size_t size) {
191
93
  Rw2Header rw2Header;
192
93
  return TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Tag::pana, TiffMapping::findDecoder,
193
93
                                  &rw2Header);
194
93
}
195
196
// *************************************************************************
197
// free functions
198
93
Image::UniquePtr newRw2Instance(BasicIo::UniquePtr io, bool /*create*/) {
199
93
  auto image = std::make_unique<Rw2Image>(std::move(io));
200
93
  if (!image->good()) {
201
0
    return nullptr;
202
0
  }
203
93
  return image;
204
93
}
205
206
8.31k
bool isRw2Type(BasicIo& iIo, bool advance) {
207
8.31k
  const int32_t len = 24;
208
8.31k
  byte buf[len];
209
8.31k
  iIo.read(buf, len);
210
8.31k
  if (iIo.error() || iIo.eof()) {
211
9
    return false;
212
9
  }
213
8.30k
  Rw2Header header;
214
8.30k
  bool rc = header.read(buf, len);
215
8.30k
  if (!advance || !rc) {
216
8.30k
    iIo.seek(-len, BasicIo::cur);
217
8.30k
  }
218
8.30k
  return rc;
219
8.31k
}
220
221
}  // namespace Exiv2