Skip to content

Commit

Permalink
Decode CR3 via libraw, extract WB, crop, black/white level
Browse files Browse the repository at this point in the history
  • Loading branch information
cytrinox committed Nov 13, 2021
1 parent 3dbc717 commit e58084d
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 19 deletions.
18 changes: 14 additions & 4 deletions src/common/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "common/image_cache.h"
#include "common/imageio.h"
#include "common/imageio_rawspeed.h"
#include "common/imageio_libraw.h"
#include "common/mipmap_cache.h"
#include "common/ratings.h"
#include "common/tags.h"
Expand Down Expand Up @@ -1792,10 +1793,19 @@ void dt_image_refresh_makermodel(dt_image_t *img)
if(!img->camera_maker[0] || !img->camera_model[0] || !img->camera_alias[0])
{
// We need to use the exif values, so let's get rawspeed to munge them
dt_rawspeed_lookup_makermodel(img->exif_maker, img->exif_model,
img->camera_maker, sizeof(img->camera_maker),
img->camera_model, sizeof(img->camera_model),
img->camera_alias, sizeof(img->camera_alias));
int found = dt_rawspeed_lookup_makermodel(img->exif_maker, img->exif_model,
img->camera_maker, sizeof(img->camera_maker),
img->camera_model, sizeof(img->camera_model),
img->camera_alias, sizeof(img->camera_alias));

if(found == FALSE)
{
// Special handling for CR3 raw files via libraw
found = dt_libraw_lookup_makermodel(img->exif_maker, img->exif_model,
img->camera_maker, sizeof(img->camera_maker),
img->camera_model, sizeof(img->camera_model),
img->camera_alias, sizeof(img->camera_alias));
}
}

// Now we just create a makermodel by concatenation
Expand Down
136 changes: 123 additions & 13 deletions src/common/imageio_libraw.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,142 @@ static gboolean _supported_image(const gchar *filename)
}


dt_imageio_retval_t dt_imageio_open_libraw(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)

int dt_libraw_lookup_makermodel(const char *maker, const char *model,
char *mk, int mk_len, char *md, int md_len,
char *al, int al_len)
{
int err = DT_IMAGEIO_FILE_CORRUPTED;
int got_it_done = FALSE;

if(!_supported_image(filename)) return DT_IMAGEIO_FILE_CORRUPTED;
if(g_str_equal(maker, "Canon"))
{
g_strlcpy(mk, "Canon", mk_len);

if(!img->exif_inited) (void)dt_exif_read(img, filename);
if(g_str_equal(model, "Canon EOS RP"))
{
g_strlcpy(md, "EOS RP", md_len);
g_strlcpy(al, "EOS RP", al_len);
}
if(g_str_equal(model, "Canon EOS R"))
{
g_strlcpy(md, "EOS R", md_len);
g_strlcpy(al, "EOS R", al_len);
}
got_it_done = TRUE;
}

return got_it_done;
}

libraw_data_t *raw_data = libraw_init(0);

if(!libraw_open_file(raw_data, filename))
goto error;
dt_imageio_retval_t dt_imageio_open_libraw(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
{
int err;
int libraw_err = 0;
if(!_supported_image(filename)) return DT_IMAGEIO_FILE_CORRUPTED;
if(!img->exif_inited) (void)dt_exif_read(img, filename);

libraw_data_t *raw = libraw_init(0);
if(!raw) return DT_IMAGEIO_FILE_CORRUPTED;

libraw_err = libraw_open_file(raw, filename);
if(libraw_err != LIBRAW_SUCCESS) goto error;

libraw_err = libraw_unpack(raw);
if(libraw_err != LIBRAW_SUCCESS) goto error;

// Bad method to detect if camera is fully supported by libraw.
// But seems to be the best available. libraw crx decoder can actually
// decode the raw data, but internal metadata like wb_coeffs, crops etc.
// are not populated into libraw structure.
if(raw->color.cam_mul[0] == 0.0)
{
libraw_close(raw);
return DT_IMAGEIO_FILE_CORRUPTED;
}

libraw_err = libraw_dcraw_process(raw);
if(libraw_err != LIBRAW_SUCCESS) goto error;

// Copy white level
img->raw_white_point = raw->color.maximum;

// Copy black level, specific for Canon as the regular black level
// info in libraw is set to 0. We need to look into makernotes!
img->raw_black_level_separate[0] = raw->makernotes.canon.ChannelBlackLevel[0];
img->raw_black_level_separate[1] = raw->makernotes.canon.ChannelBlackLevel[1];
img->raw_black_level_separate[2] = raw->makernotes.canon.ChannelBlackLevel[2];
img->raw_black_level_separate[3] = raw->makernotes.canon.ChannelBlackLevel[3];

// AsShot WB coeffs, caution: different ordering!
img->wb_coeffs[0] = raw->color.cam_mul[2];
img->wb_coeffs[1] = raw->color.cam_mul[1];
img->wb_coeffs[2] = raw->color.cam_mul[0];
img->wb_coeffs[3] = raw->color.cam_mul[3];

// Raw dimensions. This is the full sensor range.
img->width = raw->sizes.raw_width;
img->height = raw->sizes.raw_height;

// Apply crop parameters
img->crop_x = raw->sizes.raw_inset_crop.cleft;
img->crop_y = raw->sizes.raw_inset_crop.ctop;
img->crop_width = raw->sizes.raw_width - raw->sizes.raw_inset_crop.cwidth - raw->sizes.raw_inset_crop.cleft;
img->crop_height = raw->sizes.raw_height - raw->sizes.raw_inset_crop.cheight - raw->sizes.raw_inset_crop.ctop;

// We can reuse the libraw filters property, it's already well-handled in dt.
// It contains the BAYER filter pattern.
img->buf_dsc.filters = raw->idata.filters;

// For CR3, we only have BAYER data and a single channel
img->buf_dsc.channels = 1;

img->buf_dsc.datatype = TYPE_UINT16;
img->buf_dsc.cst = iop_cs_RAW;
img->flags |= DT_IMAGE_4BAYER;
img->flags &= ~DT_IMAGE_LDR;
img->flags |= DT_IMAGE_RAW;
img->loader = LOADER_LIBRAW;

libraw_close(raw_data);
// Allocate and copy image from libraw buffer to dt
void *buf = dt_mipmap_cache_alloc(mbuf, img);
if(!buf)
{
err = DT_IMAGEIO_CACHE_FULL;
goto error;
}
dt_imageio_flip_buffers((char *)buf, (char *)raw->rawdata.raw_image, sizeof(uint16_t), raw->sizes.raw_width,
raw->sizes.raw_height, raw->sizes.raw_width, raw->sizes.raw_height, raw->sizes.raw_pitch, ORIENTATION_NONE);


// Checks not really required for CR3 support, but it's taken from the old dt libraw integration.
if(FILTERS_ARE_4BAYER(img->buf_dsc.filters))
{
img->flags |= DT_IMAGE_4BAYER;
}
else
{
img->flags &= ~DT_IMAGE_4BAYER;
}

if(img->buf_dsc.filters)
{
img->flags &= ~DT_IMAGE_LDR;
img->flags &= ~DT_IMAGE_HDR;
img->flags |= DT_IMAGE_RAW;
}
else
{
// ldr dng. it exists :(
img->flags &= ~DT_IMAGE_RAW;
img->flags &= ~DT_IMAGE_HDR;
img->flags |= DT_IMAGE_LDR;
}

img->loader = LOADER_LIBRAW;
libraw_close(raw);

return DT_IMAGEIO_OK;

error:
libraw_close(raw_data);
printf("libraw error: %s\n", libraw_strerror(libraw_err));
libraw_close(raw);
return err;
}
#endif
Expand Down
12 changes: 12 additions & 0 deletions src/common/imageio_libraw.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,25 @@
#include "common/mipmap_cache.h"

#ifdef HAVE_LIBRAW
int dt_libraw_lookup_makermodel(const char *maker, const char *model,
char *mk, int mk_len, char *md, int md_len,
char *al, int al_len);

dt_imageio_retval_t dt_imageio_open_libraw(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf);
#else
inline int dt_libraw_lookup_makermodel(const char *maker, const char *model,
char *mk, int mk_len, char *md, int md_len,
char *al, int al_len)
{
return FALSE;
}

inline dt_imageio_retval_t dt_imageio_open_libraw(dt_image_t *img, const char *filename,
dt_mipmap_buffer_t *buf)
{
return DT_IMAGEIO_FILE_NOT_FOUND;
}

#endif

#endif
Expand Down
3 changes: 2 additions & 1 deletion src/common/imageio_rawspeed.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static void dt_rawspeed_load_meta() {
}
}

void dt_rawspeed_lookup_makermodel(const char *maker, const char *model,
int dt_rawspeed_lookup_makermodel(const char *maker, const char *model,
char *mk, int mk_len, char *md, int md_len,
char *al, int al_len)
{
Expand Down Expand Up @@ -105,6 +105,7 @@ void dt_rawspeed_lookup_makermodel(const char *maker, const char *model,
g_strlcpy(md, model, md_len);
g_strlcpy(al, model, al_len);
}
return got_it_done;
}

uint32_t dt_rawspeed_crop_dcraw_filters(uint32_t filters, uint32_t crop_x, uint32_t crop_y)
Expand Down
2 changes: 1 addition & 1 deletion src/common/imageio_rawspeed.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern "C" {
#include "common/image.h"
#include "common/mipmap_cache.h"

void dt_rawspeed_lookup_makermodel(const char *maker, const char *model,
int dt_rawspeed_lookup_makermodel(const char *maker, const char *model,
char *mk, int mk_len, char *md, int md_len,
char *al, int al_len);

Expand Down

0 comments on commit e58084d

Please sign in to comment.