Skip to content

Commit 5dd4f6e

Browse files
authored
feat(raw): add raw:ForceLoad hint (#4704)
The raw input plugin populates the attributes in the ImageSpec from the libraw structures in the RawInput::open_raw() method. That is done before the actual image data being decompressed on demand in RawInput::read_native_scanline(). Libraw re-calculates some values after the pixels get available, it is impossible to access those, as the ImageBuf's spec does not get updated, and the updated ImageSpec is not available from outside of RawInput when/after the pixels are being processed. An example: the initial values for the white balancing weights get populated from the image file metadata, those get copied into the ImageSpec. If the libraw was configured to white balance by averaging the pixels of the whole image or a region, the white balancing weights would get re-calculated by libraw after processing the pixels, but the updated numbers are impossible to access from outside of the RawInput plugin. This change adds a hint "raw:ForceLoad", which, if set to 1, forces libraw to decompress and process the image in RawInput::open_raw(), so the image attributes returned from that method would contain the final values. I am not certain if this is the best way to achieve what I needed. I have also looked into making the ImageBuf retain the ImageInput object instead of spawning multiple transient objects, but that seemed too complicated. I have not added any unit tests, not sure how to approach that. I have tested that the image does not get decompressed multiple times in a bunch of scenarios. Signed-off-by: Anton Dukhovnikov <antond@wetafx.co.nz>
1 parent e43fada commit 5dd4f6e

2 files changed

Lines changed: 36 additions & 26 deletions

File tree

src/doc/builtinplugins.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2228,7 +2228,12 @@ options are supported:
22282228
- Maximum memory allocation for processing of raw images. Stop processing if
22292229
raw buffer size grows larger than that value (in megabytes).
22302230
(Default: 2048)
2231-
2231+
* - ``raw:ForceLoad``
2232+
- int
2233+
- If 1, forces libraw to decompress and process the image during
2234+
initialization. This populates the image attributes which depend on the
2235+
pixel values.
2236+
(Default: 0)
22322237

22332238
|
22342239

src/raw.imageio/rawinput.cpp

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ class RawInput final : public ImageInput {
7272
void* data) override;
7373

7474
private:
75-
bool process();
7675
bool m_process = true;
7776
bool m_unpacked = false;
7877
std::unique_ptr<LibRaw> m_processor;
@@ -87,9 +86,10 @@ class RawInput final : public ImageInput {
8786
std::string m_make;
8887

8988
bool do_unpack();
89+
bool do_process();
9090

9191
// Do the actual open. It expects m_filename and m_config to be set.
92-
bool open_raw(bool unpack, const std::string& name,
92+
bool open_raw(bool unpack, bool process, const std::string& name,
9393
const ImageSpec& config);
9494
void get_makernotes();
9595
void get_makernotes_canon();
@@ -374,12 +374,14 @@ RawInput::open(const std::string& name, ImageSpec& newspec,
374374
m_filename = name;
375375
m_config = config;
376376

377+
bool force_load = config.get_int_attribute("raw:ForceLoad");
378+
377379
// For a fresh open, we are concerned with just reading all the
378380
// metadata quickly, because maybe that's all that will be needed. So
379381
// call open_raw passing unpack=false. This will not read the pixels! We
380382
// will need to close and re-open with unpack=true if and when we need
381383
// the actual pixel values.
382-
bool ok = open_raw(false, m_filename, m_config);
384+
bool ok = open_raw(force_load, force_load, m_filename, m_config);
383385
if (ok)
384386
newspec = m_spec;
385387
return ok;
@@ -388,7 +390,7 @@ RawInput::open(const std::string& name, ImageSpec& newspec,
388390

389391

390392
bool
391-
RawInput::open_raw(bool unpack, const std::string& name,
393+
RawInput::open_raw(bool unpack, bool process, const std::string& name,
392394
const ImageSpec& config)
393395
{
394396
// std::cout << "open_raw " << name << " unpack=" << unpack << "\n";
@@ -517,31 +519,31 @@ RawInput::open_raw(bool unpack, const std::string& name,
517519
} else {
518520
if (config.get_int_attribute("raw:use_auto_wb", 0) == 1) {
519521
m_processor->imgdata.params.use_auto_wb = 1;
520-
} else {
522+
// White balancing to a box requires use_auto_wb = 1
521523
auto p = config.find_attribute("raw:greybox");
522524
if (p && p->type() == TypeDesc(TypeDesc::INT, 4)) {
523525
// p->get<int>() didn't work for me here
524526
m_processor->imgdata.params.greybox[0] = p->get_int_indexed(0);
525527
m_processor->imgdata.params.greybox[1] = p->get_int_indexed(1);
526528
m_processor->imgdata.params.greybox[2] = p->get_int_indexed(2);
527529
m_processor->imgdata.params.greybox[3] = p->get_int_indexed(3);
528-
} else {
529-
// Set user white balance coefficients.
530-
// Only has effect if "raw:use_camera_wb" is equal to 0,
531-
// i.e. we are not using the camera white balance
532-
auto p = config.find_attribute("raw:user_mul");
533-
if (p && p->type() == TypeDesc(TypeDesc::FLOAT, 4)) {
534-
m_processor->imgdata.params.user_mul[0] = p->get<float>(0);
535-
m_processor->imgdata.params.user_mul[1] = p->get<float>(1);
536-
m_processor->imgdata.params.user_mul[2] = p->get<float>(2);
537-
m_processor->imgdata.params.user_mul[3] = p->get<float>(3);
538-
}
539-
if (p && p->type() == TypeDesc(TypeDesc::DOUBLE, 4)) {
540-
m_processor->imgdata.params.user_mul[0] = p->get<double>(0);
541-
m_processor->imgdata.params.user_mul[1] = p->get<double>(1);
542-
m_processor->imgdata.params.user_mul[2] = p->get<double>(2);
543-
m_processor->imgdata.params.user_mul[3] = p->get<double>(3);
544-
}
530+
}
531+
} else {
532+
// Set user white balance coefficients.
533+
// Only has effect if "raw:use_camera_wb" is equal to 0,
534+
// i.e. we are not using the camera white balance
535+
auto p = config.find_attribute("raw:user_mul");
536+
if (p && p->type() == TypeDesc(TypeDesc::FLOAT, 4)) {
537+
m_processor->imgdata.params.user_mul[0] = p->get<float>(0);
538+
m_processor->imgdata.params.user_mul[1] = p->get<float>(1);
539+
m_processor->imgdata.params.user_mul[2] = p->get<float>(2);
540+
m_processor->imgdata.params.user_mul[3] = p->get<float>(3);
541+
}
542+
if (p && p->type() == TypeDesc(TypeDesc::DOUBLE, 4)) {
543+
m_processor->imgdata.params.user_mul[0] = p->get<double>(0);
544+
m_processor->imgdata.params.user_mul[1] = p->get<double>(1);
545+
m_processor->imgdata.params.user_mul[2] = p->get<double>(2);
546+
m_processor->imgdata.params.user_mul[3] = p->get<double>(3);
545547
}
546548
}
547549
}
@@ -938,6 +940,9 @@ RawInput::open_raw(bool unpack, const std::string& name,
938940
}
939941
}
940942

943+
if (process) {
944+
do_process();
945+
}
941946

942947
// Metadata
943948

@@ -1517,15 +1522,15 @@ RawInput::do_unpack()
15171522
// We need to unpack but we didn't when we opened the file. Close and
15181523
// re-open with unpack.
15191524
close();
1520-
bool ok = open_raw(true, m_filename, m_config);
1525+
bool ok = open_raw(true, false, m_filename, m_config);
15211526
m_unpacked = true;
15221527
return ok;
15231528
}
15241529

15251530

15261531

15271532
bool
1528-
RawInput::process()
1533+
RawInput::do_process()
15291534
{
15301535
if (!m_image) {
15311536
int ret = m_processor->dcraw_process();
@@ -1624,7 +1629,7 @@ RawInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/,
16241629
// Check the state of the internal RAW reader.
16251630
// Have to load the entire image at once, so only do this once
16261631
if (!m_image) {
1627-
if (!process()) {
1632+
if (!do_process()) {
16281633
return false;
16291634
}
16301635
}

0 commit comments

Comments
 (0)