Refactor: Modify colorspace handling for image buffer reading

The file formats now fill in ImColorSpaceInfo with the metadata colorspace
and a boolean saying if the pixels have HDR colors. And then the actual
colorspace is decided in imb_handle_colorspace_and_alpha.

This centralizes the logic in one place to make it possible to add
OpenColorIO file rules.

Pull Request: https://projects.blender.org/blender/blender/pulls/136516
This commit is contained in:
Brecht Van Lommel
2025-03-25 14:52:31 +01:00
parent c225772735
commit ccd7bc2078
23 changed files with 152 additions and 177 deletions

View File

@@ -107,7 +107,5 @@ ColorManagedLook *colormanage_look_add(const char *name, const char *process_spa
ColorManagedLook *colormanage_look_get_named(const char *name);
ColorManagedLook *colormanage_look_get_indexed(int index);
void colorspace_set_default_role(char *colorspace, int size, int role);
void colormanage_imbuf_set_default_spaces(ImBuf *ibuf);
void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace);

View File

@@ -10,12 +10,13 @@
#include "IMB_imbuf.hh"
struct ImBuf;
struct ImFileColorSpace;
/* -------------------------------------------------------------------- */
/** \name Generic File Type
* \{ */
struct ImBuf;
#define IM_FTYPE_FLOAT 1
struct ImFileType {
@@ -32,9 +33,9 @@ struct ImFileType {
bool (*is_a)(const unsigned char *buf, size_t size);
/** Load an image from memory. */
ImBuf *(*load)(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
ImBuf *(*load)(const unsigned char *mem, size_t size, int flags, ImFileColorSpace &r_colorspace);
/** Load an image from a file. */
ImBuf *(*load_filepath)(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
ImBuf *(*load_filepath)(const char *filepath, int flags, ImFileColorSpace &r_colorspace);
/**
* Load/Create a thumbnail image from a filepath. `max_thumb_size` is maximum size of either
* dimension, so can return less on either or both. Should, if possible and performant, return
@@ -43,7 +44,7 @@ struct ImFileType {
ImBuf *(*load_filepath_thumbnail)(const char *filepath,
int flags,
size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height);
/** Save to a file (or memory if #IB_mem is set in `flags` and the format supports it). */
@@ -57,6 +58,14 @@ struct ImFileType {
int default_save_role;
};
/* Color space information provided by the file. */
struct ImFileColorSpace {
/* Color space from metadata. */
char metadata_colorspace[IM_MAX_SPACE] = "";
/* Is image HDR with range potentially outside 0..1? */
bool is_hdr_float = false;
};
extern const ImFileType IMB_FILE_TYPES[];
extern const ImFileType *IMB_FILE_TYPES_LAST;
@@ -78,7 +87,7 @@ bool imb_is_a_png(const unsigned char *mem, size_t size);
ImBuf *imb_load_png(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
bool imb_save_png(ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@@ -91,7 +100,7 @@ bool imb_is_a_tga(const unsigned char *mem, size_t size);
ImBuf *imb_load_tga(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
bool imb_save_tga(ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@@ -107,7 +116,7 @@ bool imb_is_a_iris(const unsigned char *mem, size_t size);
ImBuf *imb_loadiris(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
bool imb_saveiris(ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@@ -120,8 +129,8 @@ bool imb_is_a_jp2(const unsigned char *buf, size_t size);
ImBuf *imb_load_jp2(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, ImFileColorSpace &r_colorspace);
bool imb_save_jp2(ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@@ -135,11 +144,11 @@ bool imb_savejpeg(ImBuf *ibuf, const char *filepath, int flags);
ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
ImBuf *imb_thumbnail_jpeg(const char *filepath,
int flags,
size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height);
@@ -153,7 +162,7 @@ bool imb_is_a_bmp(const unsigned char *mem, size_t size);
ImBuf *imb_load_bmp(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_save_bmp(ImBuf *ibuf, const char *filepath, int flags);
@@ -168,7 +177,7 @@ bool imb_save_cineon(ImBuf *buf, const char *filepath, int flags);
ImBuf *imb_load_cineon(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
/** \} */
@@ -181,7 +190,7 @@ bool imb_save_dpx(ImBuf *ibuf, const char *filepath, int flags);
ImBuf *imb_load_dpx(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
/** \} */
@@ -193,7 +202,7 @@ bool imb_is_a_hdr(const unsigned char *mem, size_t size);
ImBuf *imb_load_hdr(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
bool imb_save_hdr(ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@@ -215,7 +224,7 @@ bool imb_is_a_tiff(const unsigned char *mem, size_t size);
ImBuf *imb_load_tiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
/**
* Saves a TIFF file.
*
@@ -242,11 +251,11 @@ bool imb_is_a_webp(const unsigned char *mem, size_t size);
ImBuf *imb_loadwebp(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath,
const int flags,
const size_t max_thumb_size,
char colorspace[],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height);
bool imb_savewebp(ImBuf *ibuf, const char *filepath, int flags);
@@ -264,7 +273,7 @@ bool imb_is_a_dds(const unsigned char *mem, size_t size);
ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
/** \} */
@@ -277,7 +286,7 @@ bool imb_is_a_psd(const unsigned char *mem, size_t size);
ImBuf *imb_load_psd(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
/** \} */
@@ -288,7 +297,7 @@ ImBuf *imb_load_psd(const unsigned char *mem,
ImBuf *imb_load_filepath_thumbnail_svg(const char *filepath,
const int flags,
const size_t max_thumb_size,
char colorspace[],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height);

View File

@@ -20,14 +20,12 @@
#include "MEM_guardedalloc.h"
static ImBuf *imb_load_dpx_cineon(
const uchar *mem, size_t size, int use_cineon, int flags, char colorspace[IM_MAX_SPACE])
const uchar *mem, size_t size, int use_cineon, int flags, ImFileColorSpace &r_colorspace)
{
ImBuf *ibuf;
LogImageFile *image;
int width, height, depth;
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
logImageSetVerbose((G.debug & G_DEBUG) ? 1 : 0);
image = logImageOpenFromMemory(mem, size);
@@ -61,6 +59,8 @@ static ImBuf *imb_load_dpx_cineon(
ibuf->flags |= IB_alphamode_premul;
}
r_colorspace.is_hdr_float = true;
return ibuf;
}
@@ -173,10 +173,10 @@ bool imb_is_a_cineon(const uchar *mem, size_t size)
return logImageIsCineon(mem, size);
}
ImBuf *imb_load_cineon(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_cineon(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
if (!imb_is_a_cineon(mem, size)) {
return nullptr;
}
return imb_load_dpx_cineon(mem, size, 1, flags, colorspace);
return imb_load_dpx_cineon(mem, size, 1, flags, r_colorspace);
}

View File

@@ -1110,17 +1110,6 @@ static void curve_mapping_apply_pixel(const CurveMapping *curve_mapping,
}
}
void colorspace_set_default_role(char *colorspace, int size, int role)
{
if (colorspace && colorspace[0] == '\0') {
const char *role_colorspace;
role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
BLI_strncpy(colorspace, role_colorspace, size);
}
}
void colormanage_imbuf_set_default_spaces(ImBuf *ibuf)
{
ibuf->byte_buffer.colorspace = colormanage_colorspace_get_named(global_role_default_byte);

View File

@@ -19,7 +19,7 @@ bool imb_is_a_bmp(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "bmp");
}
ImBuf *imb_load_bmp(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_bmp(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
@@ -27,7 +27,7 @@ ImBuf *imb_load_bmp(const uchar *mem, size_t size, int flags, char colorspace[IM
config.attribute("bmp:monochrome_detect", 0);
ReadContext ctx{mem, size, "bmp", IMB_FTYPE_BMP, flags};
return imb_oiio_read(ctx, config, colorspace, spec);
return imb_oiio_read(ctx, config, r_colorspace, spec);
}
bool imb_save_bmp(ImBuf *ibuf, const char *filepath, int flags)

View File

@@ -48,12 +48,12 @@ bool imb_is_a_dds(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "dds");
}
ImBuf *imb_load_dds(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_dds(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
ReadContext ctx{mem, size, "dds", IMB_FTYPE_DDS, flags};
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
ImBuf *ibuf = imb_oiio_read(ctx, config, r_colorspace, spec);
/* Load compressed DDS information if available. */
if (ibuf && (flags & IB_test) == 0) {

View File

@@ -20,21 +20,21 @@ bool imb_is_a_dpx(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "dpx");
}
ImBuf *imb_load_dpx(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_dpx(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
ReadContext ctx{mem, size, "dpx", IMB_FTYPE_DPX, flags};
ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_FLOAT;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
ImBuf *ibuf = imb_oiio_read(ctx, config, r_colorspace, spec);
if (ibuf) {
if (flags & IB_alphamode_detect) {
ibuf->flags |= IB_alphamode_premul;
}
}
r_colorspace.is_hdr_float = true;
return ibuf;
}

View File

@@ -19,7 +19,7 @@ bool imb_is_a_hdr(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "hdr");
}
ImBuf *imb_load_hdr(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_hdr(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
@@ -28,7 +28,7 @@ ImBuf *imb_load_hdr(const uchar *mem, size_t size, int flags, char colorspace[IM
/* Always create ImBufs with a 4th alpha channel despite the format only supporting 3. */
ctx.use_all_planes = true;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
ImBuf *ibuf = imb_oiio_read(ctx, config, r_colorspace, spec);
if (ibuf) {
if (flags & IB_alphamode_detect) {
ibuf->flags |= IB_alphamode_premul;

View File

@@ -20,23 +20,23 @@ bool imb_is_a_png(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "png");
}
ImBuf *imb_load_png(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_png(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
ReadContext ctx{mem, size, "png", IMB_FTYPE_PNG, flags};
/* Both 8 and 16 bit PNGs should be in default byte colorspace. */
ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_BYTE;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
ImBuf *ibuf = imb_oiio_read(ctx, config, r_colorspace, spec);
if (ibuf) {
if (spec.format == TypeDesc::UINT16) {
ibuf->flags |= PNG_16BIT;
}
}
/* Both 8 and 16 bit PNGs should be in default byte colorspace. */
r_colorspace.is_hdr_float = false;
return ibuf;
}

View File

@@ -20,7 +20,7 @@ bool imb_is_a_psd(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "psd");
}
ImBuf *imb_load_psd(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_psd(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
@@ -28,7 +28,7 @@ ImBuf *imb_load_psd(const uchar *mem, size_t size, int flags, char colorspace[IM
ReadContext ctx{mem, size, "psd", IMB_FTYPE_PSD, flags};
/* PSD should obey color space information embedded in the file. */
ctx.use_embedded_colorspace = true;
ctx.use_metadata_colorspace = true;
return imb_oiio_read(ctx, config, colorspace, spec);
return imb_oiio_read(ctx, config, r_colorspace, spec);
}

View File

@@ -19,7 +19,7 @@
ImBuf *imb_load_filepath_thumbnail_svg(const char *filepath,
const int /*flags*/,
const size_t max_thumb_size,
char colorspace[],
ImFileColorSpace & /*r_colorspace*/,
size_t *r_width,
size_t *r_height)
{
@@ -47,8 +47,6 @@ ImBuf *imb_load_filepath_thumbnail_svg(const char *filepath,
return nullptr;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
const float scale = float(max_thumb_size) / std::max(w, h);
const int dest_w = std::max(int(w * scale), 1);
const int dest_h = std::max(int(h * scale), 1);

View File

@@ -19,13 +19,13 @@ bool imb_is_a_tga(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "tga");
}
ImBuf *imb_load_tga(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_tga(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
ReadContext ctx{mem, size, "tga", IMB_FTYPE_TGA, flags};
return imb_oiio_read(ctx, config, colorspace, spec);
return imb_oiio_read(ctx, config, r_colorspace, spec);
}
bool imb_save_tga(ImBuf *ibuf, const char *filepath, int flags)

View File

@@ -20,17 +20,14 @@ bool imb_is_a_tiff(const uchar *mem, size_t size)
return imb_oiio_check(mem, size, "tif");
}
ImBuf *imb_load_tiff(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_tiff(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
ReadContext ctx{mem, size, "tif", IMB_FTYPE_TIF, flags};
/* All TIFFs should be in default byte colorspace. */
ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_BYTE;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
ImBuf *ibuf = imb_oiio_read(ctx, config, r_colorspace, spec);
if (ibuf) {
if (flags & IB_alphamode_detect) {
if (spec.nchannels == 4 && spec.format == TypeDesc::UINT16) {
@@ -39,6 +36,9 @@ ImBuf *imb_load_tiff(const uchar *mem, size_t size, int flags, char colorspace[I
}
}
/* All TIFFs should be in default byte colorspace. */
r_colorspace.is_hdr_float = false;
return ibuf;
}

View File

@@ -213,7 +213,7 @@ bool imb_is_a_iris(const uchar *mem, size_t size)
return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
}
ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, ImFileColorSpace & /*r_colorspace*/)
{
uint *base, *lptr = nullptr;
float *fbase, *fptr = nullptr;
@@ -235,9 +235,6 @@ ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM
return nullptr;
}
/* OCIO_TODO: only tested with 1 byte per pixel, not sure how to test with other settings */
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
readheader(inf, &image);
if (image.imagic != IMAGIC) {
fprintf(stderr, "longimagedata: bad magic number in image file\n");

View File

@@ -298,9 +298,9 @@ static opj_stream_t *opj_stream_create_from_file(const char *filepath,
static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
OPJ_CODEC_FORMAT p_format,
int flags,
char colorspace[IM_MAX_SPACE]);
ImFileColorSpace &r_colorspace);
ImBuf *imb_load_jp2(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_jp2(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
const OPJ_CODEC_FORMAT format = (size > JP2_FILEHEADER_SIZE) ? format_from_header(mem, size) :
OPJ_CODEC_UNKNOWN;
@@ -310,12 +310,12 @@ ImBuf *imb_load_jp2(const uchar *mem, size_t size, int flags, char colorspace[IM
buf_wrapper.len = OPJ_OFF_T(size);
opj_stream_t *stream = opj_stream_create_from_buffer(
&buf_wrapper, OPJ_J2K_STREAM_CHUNK_SIZE, true);
ImBuf *ibuf = imb_load_jp2_stream(stream, format, flags, colorspace);
ImBuf *ibuf = imb_load_jp2_stream(stream, format, flags, r_colorspace);
opj_stream_destroy(stream);
return ibuf;
}
ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, ImFileColorSpace &r_colorspace)
{
FILE *p_file = nullptr;
uchar mem[JP2_FILEHEADER_SIZE];
@@ -333,7 +333,7 @@ ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, char colorspace[IM
fseek(p_file, 0, SEEK_SET);
const OPJ_CODEC_FORMAT format = format_from_header(mem, sizeof(mem));
ImBuf *ibuf = imb_load_jp2_stream(stream, format, flags, colorspace);
ImBuf *ibuf = imb_load_jp2_stream(stream, format, flags, r_colorspace);
opj_stream_destroy(stream);
return ibuf;
}
@@ -341,7 +341,7 @@ ImBuf *imb_load_jp2_filepath(const char *filepath, int flags, char colorspace[IM
static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
const OPJ_CODEC_FORMAT format,
int flags,
char colorspace[IM_MAX_SPACE])
ImFileColorSpace & /*r_colorspace*/)
{
if (format == OPJ_CODEC_UNKNOWN) {
return nullptr;
@@ -363,9 +363,6 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
opj_image_t *image = nullptr;
opj_codec_t *codec = nullptr; /* handle to a decompressor */
/* both 8, 12 and 16 bit JP2Ks are default to standard byte colorspace */
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
/* set decoding parameters to default values */
opj_set_default_decoder_parameters(&parameters);

View File

@@ -438,7 +438,10 @@ static ImBuf *ibJpegImageFromCinfo(
return ibuf;
}
ImBuf *imb_load_jpeg(const uchar *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_jpeg(const uchar *buffer,
size_t size,
int flags,
ImFileColorSpace & /*r_colorspace*/)
{
jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
my_error_mgr jerr;
@@ -448,8 +451,6 @@ ImBuf *imb_load_jpeg(const uchar *buffer, size_t size, int flags, char colorspac
return nullptr;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
@@ -479,7 +480,7 @@ ImBuf *imb_load_jpeg(const uchar *buffer, size_t size, int flags, char colorspac
ImBuf *imb_thumbnail_jpeg(const char *filepath,
const int flags,
const size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height)
{
@@ -487,8 +488,6 @@ ImBuf *imb_thumbnail_jpeg(const char *filepath,
my_error_mgr jerr;
FILE *infile = nullptr;
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
@@ -526,7 +525,7 @@ ImBuf *imb_thumbnail_jpeg(const char *filepath,
buffer[0] = JPEG_MARKER_MSB;
buffer[1] = JPEG_MARKER_SOI;
if (fread(buffer + 2, JPEG_APP1_MAX - 2, 1, infile) == 1) {
ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, colorspace);
ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, r_colorspace);
}
MEM_SAFE_FREE(buffer);
if (ibuf) {

View File

@@ -16,6 +16,7 @@
#include "DNA_ID.h"
#include "IMB_allocimbuf.hh"
#include "IMB_colormanagement.hh"
#include "IMB_filetype.hh"
#include "IMB_metadata.hh"
OIIO_NAMESPACE_USING
@@ -139,44 +140,25 @@ static ImBuf *load_pixels(
return ibuf;
}
static void set_colorspace_name(char colorspace[IM_MAX_SPACE],
static void set_file_colorspace(ImFileColorSpace &r_colorspace,
const ReadContext &ctx,
const ImageSpec &spec,
bool is_float)
{
const bool is_colorspace_set = (colorspace[0] != '\0');
if (is_colorspace_set) {
return;
}
/* Use a default role unless otherwise specified. */
if (ctx.use_colorspace_role >= 0) {
colorspace_set_default_role(colorspace, IM_MAX_SPACE, ctx.use_colorspace_role);
}
else if (is_float) {
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
}
else {
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
}
/* Guess float data types means HDR colors. File formats can override this later. */
r_colorspace.is_hdr_float = is_float;
/* Override if necessary. */
if (ctx.use_embedded_colorspace) {
if (ctx.use_metadata_colorspace) {
string ics = spec.get_string_attribute("oiio:ColorSpace");
char file_colorspace[IM_MAX_SPACE];
STRNCPY(file_colorspace, ics.c_str());
/* Only use color-spaces that exist. */
if (colormanage_colorspace_get_named(file_colorspace)) {
BLI_strncpy(colorspace, file_colorspace, IM_MAX_SPACE);
}
STRNCPY(r_colorspace.metadata_colorspace, ics.c_str());
}
}
/**
* Get an #ImBuf filled in with pixel data and associated metadata using the provided ImageInput.
*/
static ImBuf *get_oiio_ibuf(ImageInput *in, const ReadContext &ctx, char colorspace[IM_MAX_SPACE])
static ImBuf *get_oiio_ibuf(ImageInput *in, const ReadContext &ctx, ImFileColorSpace &r_colorspace)
{
const ImageSpec &spec = in->spec();
const int width = spec.width;
@@ -205,7 +187,7 @@ static ImBuf *get_oiio_ibuf(ImageInput *in, const ReadContext &ctx, char colorsp
ibuf->ftype = ctx.file_type;
ibuf->foptions.flag |= (spec.format == TypeDesc::HALF) ? OPENEXR_HALF : 0;
set_colorspace_name(colorspace, ctx, spec, is_float);
set_file_colorspace(r_colorspace, ctx, spec, is_float);
float x_res = spec.get_float_attribute("XResolution", 0.0f);
float y_res = spec.get_float_attribute("YResolution", 0.0f);
@@ -277,7 +259,7 @@ bool imb_oiio_check(const uchar *mem, size_t mem_size, const char *file_format)
ImBuf *imb_oiio_read(const ReadContext &ctx,
const ImageSpec &config,
char colorspace[IM_MAX_SPACE],
ImFileColorSpace &r_colorspace,
ImageSpec &r_newspec)
{
/* This memory proxy must remain alive for the full duration of the read. */
@@ -287,7 +269,7 @@ ImBuf *imb_oiio_read(const ReadContext &ctx,
return nullptr;
}
return get_oiio_ibuf(in.get(), ctx, colorspace);
return get_oiio_ibuf(in.get(), ctx, r_colorspace);
}
bool imb_oiio_write(const WriteContext &ctx, const char *filepath, const ImageSpec &file_spec)

View File

@@ -15,6 +15,8 @@
#include "IMB_imbuf.hh"
#include "IMB_imbuf_types.hh"
struct ImFileColorSpace;
namespace blender::imbuf {
/**
@@ -27,14 +29,11 @@ struct ReadContext {
const eImbFileType file_type;
const int flags;
/** Override the automatic color-role choice with the value specified here. */
int use_colorspace_role = -1;
/** Allocate and use all #ImBuf image planes even if the image has fewer. */
bool use_all_planes = false;
/** Use the `colorspace` provided in the image metadata when available. */
bool use_embedded_colorspace = false;
bool use_metadata_colorspace = false;
};
/**
@@ -67,7 +66,7 @@ bool imb_oiio_check(const uchar *mem, size_t mem_size, const char *file_format);
*/
ImBuf *imb_oiio_read(const ReadContext &ctx,
const OIIO::ImageSpec &config,
char colorspace[IM_MAX_SPACE],
ImFileColorSpace &r_colorspace,
OIIO::ImageSpec &r_newspec);
/**

View File

@@ -6,6 +6,7 @@
* \ingroup openexr
*/
#include "IMB_filetype.hh"
#include <algorithm>
#include <cctype>
#include <cerrno>
@@ -2174,11 +2175,9 @@ static bool imb_check_chromaticity_matches(const Imf::Chromaticities &a,
imb_check_chromaticity_val(a.white.y, b.white.y);
}
static void imb_exr_set_known_colorspace(const Header &header, char colorspace[IMA_MAX_SPACE])
static void imb_exr_set_known_colorspace(const Header &header, ImFileColorSpace &r_colorspace)
{
if (colorspace == nullptr || colorspace[0] != '\0') {
return;
}
r_colorspace.is_hdr_float = true;
/* Read ACES container format metadata. */
const IntAttribute *header_aces_container = header.findTypedAttribute<IntAttribute>(
@@ -2193,25 +2192,18 @@ static void imb_exr_set_known_colorspace(const Header &header, char colorspace[I
const char *known_colorspace = IMB_colormanagement_role_colorspace_name_get(
COLOR_ROLE_ACES_INTERCHANGE);
if (known_colorspace) {
BLI_strncpy(colorspace, known_colorspace, IMA_MAX_SPACE);
return;
STRNCPY(r_colorspace.metadata_colorspace, known_colorspace);
}
}
else if (header_chromaticities &&
(imb_check_chromaticity_matches(header_chromaticities->value(), CHROMATICITIES_XYZ_E)))
{
/* Only works for the Blender default configuration due to fixed name. */
const char *known_colorspace = "Linear CIE-XYZ E";
if (IMB_colormanagement_space_get_named(known_colorspace)) {
BLI_strncpy(colorspace, known_colorspace, IMA_MAX_SPACE);
return;
}
STRNCPY(r_colorspace.metadata_colorspace, "Linear CIE-XYZ E");
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
}
ImBuf *imb_load_openexr(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_load_openexr(const uchar *mem, size_t size, int flags, ImFileColorSpace &r_colorspace)
{
ImBuf *ibuf = nullptr;
IMemStream *membuf = nullptr;
@@ -2258,7 +2250,7 @@ ImBuf *imb_load_openexr(const uchar *mem, size_t size, int flags, char colorspac
ibuf->ppm[1] = ibuf->ppm[0] * double(file_header.pixelAspectRatio());
}
imb_exr_set_known_colorspace(file_header, colorspace);
imb_exr_set_known_colorspace(file_header, r_colorspace);
ibuf->ftype = IMB_FTYPE_OPENEXR;
@@ -2416,7 +2408,7 @@ ImBuf *imb_load_openexr(const uchar *mem, size_t size, int flags, char colorspac
ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
const int /*flags*/,
const size_t max_thumb_size,
char colorspace[],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height)
{
@@ -2465,7 +2457,7 @@ ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
}
/* No effect yet for thumbnails, but will work once it is supported. */
imb_exr_set_known_colorspace(file_header, colorspace);
imb_exr_set_known_colorspace(file_header, r_colorspace);
/* Create a new thumbnail. */
float scale_factor = std::min(float(max_thumb_size) / float(source_w),

View File

@@ -10,8 +10,10 @@
#include <cstdio>
void imb_initopenexr(void);
void imb_exitopenexr(void);
struct ImFileColorSpace;
void imb_initopenexr();
void imb_exitopenexr();
/**
* Test presence of OpenEXR file.
@@ -21,11 +23,14 @@ bool imb_is_a_openexr(const unsigned char *mem, size_t size);
bool imb_save_openexr(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char *colorspace);
struct ImBuf *imb_load_openexr(const unsigned char *mem,
size_t size,
int flags,
ImFileColorSpace &r_colorspace);
struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
int flags,
size_t max_thumb_size,
char colorspace[],
ImFileColorSpace &r_colorspace,
size_t *r_width,
size_t *r_height);

View File

@@ -29,23 +29,40 @@
#include "IMB_colormanagement.hh"
#include "IMB_colormanagement_intern.hh"
static void imb_handle_alpha(ImBuf *ibuf,
int flags,
char colorspace[IM_MAX_SPACE],
const char effective_colorspace[IM_MAX_SPACE])
static void imb_handle_colorspace_and_alpha(ImBuf *ibuf,
int flags,
const ImFileColorSpace &file_colorspace,
char r_colorspace[IM_MAX_SPACE])
{
if (colorspace) {
char new_colorspace[IM_MAX_SPACE];
if (r_colorspace && r_colorspace[0]) {
/* Existing configured colorspace has priority. */
STRNCPY(new_colorspace, r_colorspace);
}
else if (file_colorspace.metadata_colorspace[0] &&
colormanage_colorspace_get_named(file_colorspace.metadata_colorspace))
{
/* Use colorspace from file metadata if provided. */
STRNCPY(new_colorspace, file_colorspace.metadata_colorspace);
}
else {
/* Use float colorspace if the image may contain HDR colors, byte otherwise. */
const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(
file_colorspace.is_hdr_float ? COLOR_ROLE_DEFAULT_FLOAT : COLOR_ROLE_DEFAULT_BYTE);
STRNCPY(new_colorspace, role_colorspace);
}
if (r_colorspace) {
if (ibuf->byte_buffer.data != nullptr && ibuf->float_buffer.data == nullptr) {
/* byte buffer is never internally converted to some standard space,
* store pointer to its color space descriptor instead
*/
ibuf->byte_buffer.colorspace = colormanage_colorspace_get_named(effective_colorspace);
ibuf->byte_buffer.colorspace = colormanage_colorspace_get_named(new_colorspace);
}
BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE);
}
bool is_data = (colorspace && IMB_colormanagement_space_name_is_data(colorspace));
bool is_data = (r_colorspace && IMB_colormanagement_space_name_is_data(new_colorspace));
int alpha_flags = (flags & IB_alphamode_detect) ? ibuf->flags : flags;
if (is_data || (flags & IB_alphamode_channel_packed)) {
@@ -76,7 +93,10 @@ static void imb_handle_alpha(ImBuf *ibuf,
}
}
colormanage_imbuf_make_linear(ibuf, effective_colorspace);
colormanage_imbuf_make_linear(ibuf, new_colorspace);
if (r_colorspace) {
BLI_strncpy(r_colorspace, new_colorspace, IM_MAX_SPACE);
}
}
ImBuf *IMB_ibImageFromMemory(
@@ -84,22 +104,19 @@ ImBuf *IMB_ibImageFromMemory(
{
ImBuf *ibuf;
const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (mem == nullptr) {
fprintf(stderr, "%s: nullptr pointer\n", __func__);
return nullptr;
}
if (colorspace) {
STRNCPY(effective_colorspace, colorspace);
}
ImFileColorSpace file_colorspace;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->load) {
ibuf = type->load(mem, size, flags, effective_colorspace);
ibuf = type->load(mem, size, flags, file_colorspace);
if (ibuf) {
imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
imb_handle_colorspace_and_alpha(ibuf, flags, file_colorspace, colorspace);
return ibuf;
}
}
@@ -179,14 +196,13 @@ ImBuf *IMB_thumb_load_image(const char *filepath,
size_t width = 0;
size_t height = 0;
char effective_colorspace[IM_MAX_SPACE] = "";
if (colorspace) {
STRNCPY(effective_colorspace, colorspace);
}
if (type->load_filepath_thumbnail) {
ImFileColorSpace file_colorspace;
ibuf = type->load_filepath_thumbnail(
filepath, flags, max_thumb_size, colorspace, &width, &height);
filepath, flags, max_thumb_size, file_colorspace, &width, &height);
if (ibuf) {
imb_handle_colorspace_and_alpha(ibuf, flags, file_colorspace, colorspace);
}
}
else {
/* Skip images of other types if over 100MB. */
@@ -204,8 +220,6 @@ ImBuf *IMB_thumb_load_image(const char *filepath,
}
if (ibuf) {
imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
if (width > 0 && height > 0) {
/* Save dimensions of original image into the thumbnail metadata. */
char cwidth[40];

View File

@@ -37,14 +37,12 @@ bool imb_is_a_webp(const uchar *mem, size_t size)
return false;
}
ImBuf *imb_loadwebp(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
ImBuf *imb_loadwebp(const uchar *mem, size_t size, int flags, ImFileColorSpace & /*r_colorspace*/)
{
if (!imb_is_a_webp(mem, size)) {
return nullptr;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
WebPBitstreamFeatures features;
if (WebPGetFeatures(mem, size, &features) != VP8_STATUS_OK) {
fprintf(stderr, "WebP: Failed to parse features\n");
@@ -77,7 +75,7 @@ ImBuf *imb_loadwebp(const uchar *mem, size_t size, int flags, char colorspace[IM
ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath,
const int /*flags*/,
const size_t max_thumb_size,
char colorspace[],
ImFileColorSpace & /*r_colorspace*/,
size_t *r_width,
size_t *r_height)
{
@@ -116,7 +114,6 @@ ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath,
const int dest_w = std::max(int(config.input.width * scale), 1);
const int dest_h = std::max(int(config.input.height * scale), 1);
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_byte_data);
if (ibuf == nullptr) {
fprintf(stderr, "WebP: Failed to allocate image memory\n");

View File

@@ -108,13 +108,12 @@ MovieReader *MOV_open_file(const char *filepath,
anim = MEM_new<MovieReader>("anim struct");
if (anim != nullptr) {
const char *byte_colorspace = IMB_colormanagement_role_colorspace_name_get(
COLOR_ROLE_DEFAULT_BYTE);
STRNCPY(anim->colorspace, byte_colorspace);
if (colorspace) {
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
STRNCPY(anim->colorspace, colorspace);
}
else {
colorspace_set_default_role(
anim->colorspace, sizeof(anim->colorspace), COLOR_ROLE_DEFAULT_BYTE);
BLI_strncpy(colorspace, anim->colorspace, IM_MAX_SPACE);
}
STRNCPY(anim->filepath, filepath);