Skip to content

Commit

Permalink
Fixed color in RAW reader.
Browse files Browse the repository at this point in the history
Build fix.
  • Loading branch information
ggarra13 committed Sep 22, 2023
1 parent 2cf268b commit a7fada0
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 164 deletions.
2 changes: 1 addition & 1 deletion etc/SuperBuild/cmake/Modules/BuildLibRaw.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ExternalProject_Add(
)

if(APPLE)
set(CMAKE_CXX_FLAGS -Wno-register ${CMAKE_CXX_FLAGS})
set(CMAKE_CXX_FLAGS "-Wno-register ${CMAKE_CXX_FLAGS}")
endif()

set(LibRaw_ARGS
Expand Down
2 changes: 1 addition & 1 deletion lib/tlIO/RAW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace tl
{ ".srf", io::FileType::Sequence },
{ ".srw", io::FileType::Sequence },
{ ".sti", io::FileType::Sequence },
{ ".x3f", io::FileType::Sequence },
{ ".x3f", io::FileType::Sequence }
},
cache,
logSystem);
Expand Down
294 changes: 132 additions & 162 deletions lib/tlIO/RAWRead.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,50 @@

#include <tlIO/RAW.h>

#include <tlCore/String.h>
#include <tlCore/StringFormat.h>

#include <libraw/libraw.h>

#define LIBRAW_ERROR(function, ret) \
if (ret) \
{ \
throw std::runtime_error( \
string::Format("{0}: {1} - {2}") \
.arg(fileName) \
.arg(#function) \
.arg(libraw_strerror(ret))); \
}



namespace {
const char*
libraw_filter_to_str(unsigned int filters)
{
// Convert the libraw filter pattern description
// into a slightly more human readable string
// LibRaw/internal/defines.h:166
switch (filters) {
// CYGM
case 0xe1e4e1e4: return "GMYC";
case 0x1b4e4b1e: return "CYGM";
case 0x1e4b4e1b: return "YCGM";
case 0xb4b4b4b4: return "GMCY";
case 0x1e4e1e4e: return "CYMG";

// RGB
case 0x16161616: return "BGRG";
case 0x61616161: return "GRGB";
case 0x49494949: return "GBGR";
case 0x94949494: return "RGBG";
default: break;
}
return "";
}
} // namespace


namespace tl
{
namespace raw
Expand All @@ -23,43 +63,15 @@ namespace tl
{
int ret;
{

// LibRaw is not thread safe. We use a static mutex
// so only one threads constructs a LibRaw at a time.
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
iProcessor.reset(new LibRaw());
}
_memory = memory;
if (memory)
{
ret = iProcessor->open_buffer(memory->p, memory->size);
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("open_buffer failed")
.arg(libraw_strerror(ret)));
}
}
else
{
// Open the file and read the metadata
#ifdef _WIN32
ret = iProcessor->open_file(fileName.c_str());
#else
ret = iProcessor->open_file(fileName.c_str());
#endif
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("open_file failed")
.arg(libraw_strerror(ret)));
}
}

_openFile(fileName);

_info.video.resize(1);
auto& info = _info.video[0];
Expand All @@ -84,14 +96,11 @@ namespace tl
info.size.h = sizes.height;
break;
}
info.size.pixelAspectRatio = sizes.pixel_aspect;

// Save Tags
auto& tags = _info.tags;
{
std::stringstream ss;
ss << sizes.flip;
tags["Orientation"] = ss.str();
}

if (idata.make[0])
tags["Camera Manufacturer"] = idata.make;
if (idata.model[0])
Expand All @@ -102,36 +111,16 @@ namespace tl
tags["Software"] = idata.software;
else if(color.model2[0])
tags["Software"] = color.model2;
{
std::stringstream ss;
ss << other.iso_speed;
tags["Exif:ISOSpeedRatings"] = ss.str();
}
{
std::stringstream ss;
ss << other.shutter;
tags["ExposureTime"] = ss.str();
}
{
std::stringstream ss;
ss << -std::log2(other.shutter);
tags["Exif:ShutterSpeedValue"] = ss.str();
}
{
std::stringstream ss;
ss << other.aperture;
tags["FNumber"] = ss.str();
}
{
std::stringstream ss;
ss << 2.0f * std::log2(other.aperture);
tags["Exif:ApertureValue"] = ss.str();
}
{
std::stringstream ss;
ss << other.focal_len;
tags["Exif:FocalLength"] = ss.str();
}

_getTag("Orientation", sizes.flip);
_getTag("Exif:ISOSpeedRatings", other.iso_speed);
_getTag("ExposureTime", other.shutter);
_getTag("Exif:ShutterSpeedValue",
-std::log2(other.shutter));
_getTag("FNumber", other.aperture);
_getTag("Exif:ApertureValue",
2.0f * std::log2(other.aperture));
_getTag("Exif:FocalLength", other.focal_len);

info.pixelType = image::PixelType::RGB_U16;
info.layout.endian = memory::Endian::LSB;
Expand All @@ -153,129 +142,78 @@ namespace tl
const auto& info = _info.video[0];
out.image = image::Image::create(info);

auto& params(iProcessor->imgdata.params);

// Output 16-bit images
iProcessor->imgdata.params.output_bps = 16;
params.output_bps = 16;

// Some default parameters
iProcessor->imgdata.params.no_auto_bright = 1;
iProcessor->imgdata.params.adjust_maximum_thr = 0.0f;
iProcessor->imgdata.params.user_sat = 0;
iProcessor->imgdata.params.use_camera_wb = 0;
iProcessor->imgdata.params.use_camera_matrix = 1;
params.no_auto_bright = 1;
params.adjust_maximum_thr = 0.0f;
params.user_sat = 0;
params.use_camera_wb = 1;

// Handle white balance
auto& color = iProcessor->imgdata.color;
auto& idata = iProcessor->imgdata.idata;

auto is_rgbg_or_bgrg = [&](unsigned int filters) {
std::string filter(libraw_filter_to_str(filters));
return filter == "RGBG" || filter == "BGRG";
};
float norm[4] = { color.cam_mul[0], color.cam_mul[1], color.cam_mul[2],
color.cam_mul[3] };

if (is_rgbg_or_bgrg(idata.filters)) {
// normalize white balance around green
norm[0] /= norm[1];
norm[1] /= norm[1];
norm[2] /= norm[3] > 0 ? norm[3] : norm[1];
norm[3] /= norm[3] > 0 ? norm[3] : norm[1];
}
params.user_mul[0] = norm[0];
params.user_mul[1] = norm[1];
params.user_mul[2] = norm[2];
params.user_mul[3] = norm[3];

// Handle camera matrix
iProcessor->imgdata.params.use_camera_matrix = 1;
params.use_camera_matrix = 1;

// Handle LCMS color correction with sRGB as output
iProcessor->imgdata.params.output_color = 1;
iProcessor->imgdata.params.gamm[0] = 1.0 / 2.4;
iProcessor->imgdata.params.gamm[1] = 12.92;

if (_memory)
{
ret = iProcessor->open_buffer(_memory->p, _memory->size);
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("open_buffer failed")
.arg(libraw_strerror(ret)));
}
}
else
{
// Open the file and read the metadata
#ifdef _WIN32
ret = iProcessor->open_file(fileName.c_str());
#else
ret = iProcessor->open_file(fileName.c_str());
#endif
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("open_file failed")
.arg(libraw_strerror(ret)));
}
}

if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("open_file failed")
.arg(libraw_strerror(ret)));
}
params.output_color = 1;
params.gamm[0] = 1.0 / 2.4;
params.gamm[1] = 12.92;

_openFile(fileName);

const libraw_image_sizes_t& sizes(iProcessor->imgdata.sizes);

// Let us unpack the image
ret = iProcessor->unpack();
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("unpack failed")
.arg(libraw_strerror(ret)));
}
LIBRAW_ERROR(unpack, ret);

ret = iProcessor->raw2image_ex(/*substract_black=*/true);
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("raw2image_ex failed")
.arg(libraw_strerror(ret)));
}

LIBRAW_ERROR(raw2image_ex, ret);

ret = iProcessor->adjust_maximum();
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("adjust_maximum failed")
.arg(libraw_strerror(ret)));
}
LIBRAW_ERROR(adjust_maximum, ret);

iProcessor->imgdata.params.adjust_maximum_thr = 1.0;

ret = iProcessor->adjust_maximum();
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("adjust_maximum failed")
.arg(libraw_strerror(ret)));
}
LIBRAW_ERROR(adjust_maximum, ret);

ret = iProcessor->dcraw_process();
if (ret)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
.arg(fileName)
.arg("dcraw_process failed")
.arg(libraw_strerror(ret)));
}
LIBRAW_ERROR(dcraw_process, ret);

const int channels = image::getChannelCount(info.pixelType);
const size_t bytes = image::getBitDepth(info.pixelType) / 8;

image = iProcessor->dcraw_make_mem_image(&ret);
if (ret || !image)
LIBRAW_ERROR(dcraw_make_mem_image, ret);
if (!image)
{
throw std::runtime_error(
string::Format("{0}: {1} - Error {2}")
string::Format("{0}: {1}")
.arg(fileName)
.arg("dcraw_make_mem_image")
.arg(libraw_strerror(ret)));
.arg("dcraw_make_mem_image returne null"));
}

if (image->type != LIBRAW_IMAGE_BITMAP)
Expand Down Expand Up @@ -315,6 +253,38 @@ namespace tl
return out;
}

protected:
void _openFile(const std::string& fileName) const
{
int ret;
if (_memory)
{
ret = iProcessor->open_buffer(_memory->p,
_memory->size);
LIBRAW_ERROR(open_buffer, ret);
}
else
{
// Open the file and read the metadata
#ifdef _WIN32
const std::wstring wideFileName =
string::toWide(fileName);
ret = iProcessor->open_file(wideFileName.c_str());
#else
ret = iProcessor->open_file(fileName.c_str());
#endif
LIBRAW_ERROR(open_file, ret);
}
}

template<typename T>
void _getTag(const char* tag, const T& value)
{
std::stringstream ss;
ss << value;
_info.tags[tag] = ss.str();
}

private:
std::unique_ptr<LibRaw> iProcessor;
libraw_processed_image_t* image = nullptr;
Expand Down

0 comments on commit a7fada0

Please sign in to comment.