Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-06-22 11:56:21 +0300
committerJacques Lucke <jacques@blender.org>2022-06-22 11:56:21 +0300
commit2d0dc88209e166159bd0b68dc54103280b09193c (patch)
tree3875e9554c810d14fa3a490cbdf003472bd7ee3c /source/blender/imbuf/intern
parentc57ed65cc88418e290401599e28d51f1acb5dfd9 (diff)
parenta3d0f77ded1c982da93d61fac6942cfc67c9e599 (diff)
Merge branch 'master' into deform-curves-with-surface
Diffstat (limited to 'source/blender/imbuf/intern')
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h8
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h17
-rw-r--r--source/blender/imbuf/intern/anim_movie.c2
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c10
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c22
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.h2
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c18
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.h2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c14
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h10
-rw-r--r--source/blender/imbuf/intern/colormanagement.c575
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c40
-rw-r--r--source/blender/imbuf/intern/dds/Color.h5
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp6
-rw-r--r--source/blender/imbuf/intern/filetype.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c96
-rw-r--r--source/blender/imbuf/intern/iris.c54
-rw-r--r--source/blender/imbuf/intern/jpeg.c8
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp222
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h7
-rw-r--r--source/blender/imbuf/intern/readimage.c10
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c31
-rw-r--r--source/blender/imbuf/intern/thumbs.c21
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c4
-rw-r--r--source/blender/imbuf/intern/tiff.c22
-rw-r--r--source/blender/imbuf/intern/transform.cc23
-rw-r--r--source/blender/imbuf/intern/util.c11
-rw-r--r--source/blender/imbuf/intern/util_gpu.c73
-rw-r--r--source/blender/imbuf/intern/writeimage.c37
29 files changed, 908 insertions, 444 deletions
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index c89b15480a2..23b3f0191b7 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -18,8 +18,12 @@ struct ImBuf;
struct OCIO_ConstCPUProcessorRcPtr;
extern float imbuf_luma_coefficients[3];
-extern float imbuf_xyz_to_rgb[3][3];
-extern float imbuf_rgb_to_xyz[3][3];
+extern float imbuf_scene_linear_to_xyz[3][3];
+extern float imbuf_xyz_to_scene_linear[3][3];
+extern float imbuf_scene_linear_to_aces[3][3];
+extern float imbuf_aces_to_scene_linear[3][3];
+extern float imbuf_scene_linear_to_rec709[3][3];
+extern float imbuf_rec709_to_scene_linear[3][3];
#define MAX_COLORSPACE_NAME 64
#define MAX_COLORSPACE_DESCRIPTION 512
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 67d1aefeacb..9a0a6998fab 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -42,8 +42,8 @@ typedef struct ImFileType {
* dimensions of the full-size image in r_width & r_height.
*/
struct ImBuf *(*load_filepath_thumbnail)(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
size_t *r_width,
size_t *r_height);
@@ -155,8 +155,8 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
int flags,
char colorspace[IM_MAX_SPACE]);
struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
size_t *r_width,
size_t *r_height);
@@ -240,11 +240,10 @@ void imb_loadtiletiff(
/**
* Saves a TIFF file.
*
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA respectively)
+ * are accepted, and interpreted correctly. Note that the TIFF convention is to use
+ * pre-multiplied alpha, which can be achieved within Blender by setting `premul` alpha handling.
+ * Other alpha conventions are not strictly correct, but are permitted anyhow.
*
* \param ibuf: Image buffer.
* \param filepath: Name of the TIFF file to create.
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 096089d4c41..0052ce19aa1 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -423,7 +423,7 @@ static int startavi(struct anim *anim)
anim->cur_position = 0;
# if 0
- printf("x:%d y:%d size:%d interl:%d dur:%d\n",
+ printf("x:%d y:%d size:%d interlace:%d dur:%d\n",
anim->x,
anim->y,
anim->framesize,
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
index d1cd30cfe84..1a99d2a34d9 100644
--- a/source/blender/imbuf/intern/cineon/cineon_dpx.c
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -69,7 +69,7 @@ static struct ImBuf *imb_load_dpx_cineon(const unsigned char *mem,
return ibuf;
}
-static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon, int flags)
+static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filepath, int use_cineon, int flags)
{
LogImageFile *logImage;
float *fbuf;
@@ -86,7 +86,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
depth = (ibuf->planes + 7) >> 3;
if (depth > 4 || depth < 3) {
- printf("DPX/Cineon: unsupported depth: %d for file: '%s'\n", depth, filename);
+ printf("DPX/Cineon: unsupported depth: %d for file: '%s'\n", depth, filepath);
return 0;
}
@@ -103,7 +103,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
bitspersample = 8;
}
- logImage = logImageCreate(filename,
+ logImage = logImageCreate(filepath,
use_cineon,
ibuf->x,
ibuf->y,
@@ -121,8 +121,8 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon
}
if (ibuf->rect_float != NULL && bitspersample != 8) {
- /* don't use the float buffer to save 8 bpp picture to prevent color banding
- * (there's no dithering algorithm behind the logImageSetDataRGBA function) */
+ /* Don't use the float buffer to save 8 BPP picture to prevent color banding
+ * (there's no dithering algorithm behind the #logImageSetDataRGBA function). */
fbuf = (float *)MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y,
"fbuf in imb_save_dpx_cineon");
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 3bdfcb60292..8312476bda0 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -35,7 +35,7 @@ void cineonSetVerbose(int verbosity)
static void fillCineonMainHeader(LogImageFile *cineon,
CineonMainHeader *header,
- const char *filename,
+ const char *filepath,
const char *creator)
{
time_t fileClock;
@@ -57,7 +57,7 @@ static void fillCineonMainHeader(LogImageFile *cineon,
getRowLength(cineon->width, cineon->element[0]),
cineon->isMSB);
strcpy(header->fileHeader.version, "v4.5");
- strncpy(header->fileHeader.file_name, filename, 99);
+ strncpy(header->fileHeader.file_name, filepath, 99);
header->fileHeader.file_name[99] = 0;
fileClock = time(NULL);
fileTime = localtime(&fileClock);
@@ -126,7 +126,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
{
CineonMainHeader header;
LogImageFile *cineon = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__);
- const char *filename = (const char *)byteStuff;
+ const char *filepath = (const char *)byteStuff;
int i;
unsigned int dataOffset;
@@ -144,11 +144,11 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
cineon->file = NULL;
if (fromMemory == 0) {
- /* byteStuff is then the filename */
- cineon->file = BLI_fopen(filename, "rb");
+ /* byteStuff is then the filepath */
+ cineon->file = BLI_fopen(filepath, "rb");
if (cineon->file == NULL) {
if (verbose) {
- printf("Cineon: Failed to open file \"%s\".\n", filename);
+ printf("Cineon: Failed to open file \"%s\".\n", filepath);
}
logImageClose(cineon);
return NULL;
@@ -350,7 +350,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
}
LogImageFile *cineonCreate(
- const char *filename, int width, int height, int bitsPerSample, const char *creator)
+ const char *filepath, int width, int height, int bitsPerSample, const char *creator)
{
CineonMainHeader header;
const char *shortFilename = NULL;
@@ -393,18 +393,18 @@ LogImageFile *cineonCreate(
cineon->referenceBlack = 95.0f;
cineon->gamma = 1.7f;
- shortFilename = strrchr(filename, '/');
+ shortFilename = strrchr(filepath, PATHSEP_CHAR);
if (shortFilename == NULL) {
- shortFilename = filename;
+ shortFilename = filepath;
}
else {
shortFilename++;
}
- cineon->file = BLI_fopen(filename, "wb");
+ cineon->file = BLI_fopen(filepath, "wb");
if (cineon->file == NULL) {
if (verbose) {
- printf("cineon: Couldn't open file %s\n", filename);
+ printf("cineon: Couldn't open file %s\n", filepath);
}
logImageClose(cineon);
return NULL;
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h
index 37b27d19539..13d40461728 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.h
+++ b/source/blender/imbuf/intern/cineon/cineonlib.h
@@ -114,7 +114,7 @@ typedef struct {
void cineonSetVerbose(int);
LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize);
LogImageFile *cineonCreate(
- const char *filename, int width, int height, int bitsPerSample, const char *creator);
+ const char *filepath, int width, int height, int bitsPerSample, const char *creator);
#ifdef __cplusplus
}
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 2d28a477c8a..28c19116361 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -124,7 +124,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
{
DpxMainHeader header;
LogImageFile *dpx = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__);
- const char *filename = (const char *)byteStuff;
+ const char *filepath = (const char *)byteStuff;
int i;
if (dpx == NULL) {
@@ -141,11 +141,11 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
dpx->file = NULL;
if (fromMemory == 0) {
- /* byteStuff is then the filename */
- dpx->file = BLI_fopen(filename, "rb");
+ /* byteStuff is then the filepath */
+ dpx->file = BLI_fopen(filepath, "rb");
if (dpx->file == NULL) {
if (verbose) {
- printf("DPX: Failed to open file \"%s\".\n", filename);
+ printf("DPX: Failed to open file \"%s\".\n", filepath);
}
logImageClose(dpx);
return NULL;
@@ -406,7 +406,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
return dpx;
}
-LogImageFile *dpxCreate(const char *filename,
+LogImageFile *dpxCreate(const char *filepath,
int width,
int height,
int bitsPerSample,
@@ -502,19 +502,19 @@ LogImageFile *dpxCreate(const char *filename,
dpx->gamma = 1.7f;
}
- shortFilename = strrchr(filename, '/');
+ shortFilename = strrchr(filepath, PATHSEP_CHAR);
if (shortFilename == NULL) {
- shortFilename = filename;
+ shortFilename = filepath;
}
else {
shortFilename++;
}
- dpx->file = BLI_fopen(filename, "wb");
+ dpx->file = BLI_fopen(filepath, "wb");
if (dpx->file == NULL) {
if (verbose) {
- printf("DPX: Couldn't open file %s\n", filename);
+ printf("DPX: Couldn't open file %s\n", filepath);
}
logImageClose(dpx);
return NULL;
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h
index d8ed5dc6f67..aac424d52d6 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.h
+++ b/source/blender/imbuf/intern/cineon/dpxlib.h
@@ -133,7 +133,7 @@ typedef struct {
void dpxSetVerbose(int verbosity);
LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize);
-LogImageFile *dpxCreate(const char *filename,
+LogImageFile *dpxCreate(const char *filepath,
int width,
int height,
int bitsPerSample,
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 36e12e07316..e693aa6f891 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -101,10 +101,10 @@ int logImageIsCineon(const void *buffer, const unsigned int size)
return (magicNum == CINEON_FILE_MAGIC || magicNum == swap_uint(CINEON_FILE_MAGIC, 1));
}
-LogImageFile *logImageOpenFromFile(const char *filename, int cineon)
+LogImageFile *logImageOpenFromFile(const char *filepath, int cineon)
{
unsigned int magicNum;
- FILE *f = BLI_fopen(filename, "rb");
+ FILE *f = BLI_fopen(filepath, "rb");
(void)cineon;
@@ -120,10 +120,10 @@ LogImageFile *logImageOpenFromFile(const char *filename, int cineon)
fclose(f);
if (logImageIsDpx(&magicNum, sizeof(magicNum))) {
- return dpxOpen((const unsigned char *)filename, 0, 0);
+ return dpxOpen((const unsigned char *)filepath, 0, 0);
}
if (logImageIsCineon(&magicNum, sizeof(magicNum))) {
- return cineonOpen((const unsigned char *)filename, 0, 0);
+ return cineonOpen((const unsigned char *)filepath, 0, 0);
}
return NULL;
@@ -141,7 +141,7 @@ LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int s
return NULL;
}
-LogImageFile *logImageCreate(const char *filename,
+LogImageFile *logImageCreate(const char *filepath,
int cineon,
int width,
int height,
@@ -155,10 +155,10 @@ LogImageFile *logImageCreate(const char *filename,
{
/* referenceWhite, referenceBlack and gamma values are only supported for DPX file */
if (cineon) {
- return cineonCreate(filename, width, height, bitsPerSample, creator);
+ return cineonCreate(filepath, width, height, bitsPerSample, creator);
}
- return dpxCreate(filename,
+ return dpxCreate(filepath,
width,
height,
bitsPerSample,
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index 6875dba3f87..35540497828 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -19,6 +19,12 @@
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
+#ifdef _WIN32
+# define PATHSEP_CHAR '\\'
+#else
+# define PATHSEP_CHAR '/'
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -169,9 +175,9 @@ void logImageSetVerbose(int verbosity);
int logImageIsDpx(const void *buffer, unsigned int size);
int logImageIsCineon(const void *buffer, unsigned int size);
LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int size);
-LogImageFile *logImageOpenFromFile(const char *filename, int cineon);
+LogImageFile *logImageOpenFromFile(const char *filepath, int cineon);
void logImageGetSize(LogImageFile *logImage, int *width, int *height, int *depth);
-LogImageFile *logImageCreate(const char *filename,
+LogImageFile *logImageCreate(const char *filepath,
int cineon,
int width,
int height,
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 53aa74edc61..33873b5daa7 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -73,10 +73,12 @@ static int global_tot_looks = 0;
/* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
float imbuf_luma_coefficients[3] = {0.0f};
-float imbuf_xyz_to_rgb[3][3] = {{0.0f}};
-float imbuf_rgb_to_xyz[3][3] = {{0.0f}};
-static float imbuf_xyz_to_linear_srgb[3][3] = {{0.0f}};
-static float imbuf_linear_srgb_to_xyz[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_xyz[3][3] = {{0.0f}};
+float imbuf_xyz_to_scene_linear[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_rec709[3][3] = {{0.0f}};
+float imbuf_rec709_to_scene_linear[3][3] = {{0.0f}};
+float imbuf_scene_linear_to_aces[3][3] = {{0.0f}};
+float imbuf_aces_to_scene_linear[3][3] = {{0.0f}};
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
@@ -573,10 +575,16 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
/* Load luminance coefficients. */
OCIO_configGetDefaultLumaCoefs(config, imbuf_luma_coefficients);
- OCIO_configGetXYZtoRGB(config, imbuf_xyz_to_rgb);
- invert_m3_m3(imbuf_rgb_to_xyz, imbuf_xyz_to_rgb);
- copy_m3_m3(imbuf_xyz_to_linear_srgb, OCIO_XYZ_TO_LINEAR_SRGB);
- invert_m3_m3(imbuf_linear_srgb_to_xyz, imbuf_xyz_to_linear_srgb);
+
+ /* Load standard color spaces. */
+ OCIO_configGetXYZtoSceneLinear(config, imbuf_xyz_to_scene_linear);
+ invert_m3_m3(imbuf_scene_linear_to_xyz, imbuf_xyz_to_scene_linear);
+
+ mul_m3_m3m3(imbuf_scene_linear_to_rec709, OCIO_XYZ_TO_REC709, imbuf_scene_linear_to_xyz);
+ invert_m3_m3(imbuf_rec709_to_scene_linear, imbuf_scene_linear_to_rec709);
+
+ mul_m3_m3m3(imbuf_aces_to_scene_linear, imbuf_xyz_to_scene_linear, OCIO_ACES_TO_XYZ);
+ invert_m3_m3(imbuf_scene_linear_to_aces, imbuf_aces_to_scene_linear);
}
static void colormanage_free_config(void)
@@ -589,7 +597,7 @@ static void colormanage_free_config(void)
while (colorspace) {
ColorSpace *colorspace_next = colorspace->next;
- /* free precomputer processors */
+ /* Free precomputed processors. */
if (colorspace->to_scene_linear) {
OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear);
}
@@ -665,7 +673,7 @@ void colormanagement_init(void)
#ifdef WIN32
{
- /* quite a hack to support loading configuration from path with non-acii symbols */
+ /* Quite a hack to support loading configuration from path with non-ACII symbols. */
char short_name[256];
BLI_get_short_name(short_name, configfile);
@@ -1412,9 +1420,15 @@ bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
}
-const float *IMB_colormanagement_get_xyz_to_rgb()
+bool IMB_colormanagement_space_name_is_srgb(const char *name)
{
- return &imbuf_xyz_to_rgb[0][0];
+ ColorSpace *colorspace = colormanage_colorspace_get_named(name);
+ return (colorspace && IMB_colormanagement_space_is_srgb(colorspace));
+}
+
+const float *IMB_colormanagement_get_xyz_to_scene_linear()
+{
+ return &imbuf_xyz_to_scene_linear[0][0];
}
/** \} */
@@ -2197,21 +2211,14 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const int width,
const int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
const bool store_premultiplied)
{
- /* Convert byte buffer for texture storage on the GPU. These have builtin
- * support for converting sRGB to linear, which allows us to store textures
- * without precision or performance loss at minimal memory usage. */
+ /* Byte buffer storage, only for sRGB and data texture since other
+ * color space conversions can't be done on the GPU. */
BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
+ BLI_assert(IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_data(ibuf->rect_colorspace));
- OCIO_ConstCPUProcessorRcPtr *processor = NULL;
- if (compress_as_srgb && ibuf->rect_colorspace &&
- !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
- processor = colorspace_to_scene_linear_cpu_processor(ibuf->rect_colorspace);
- }
-
- /* TODO(brecht): make this multi-threaded, or at least process in batches. */
const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
@@ -2221,20 +2228,7 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const unsigned char *in = in_buffer + in_offset * 4;
unsigned char *out = out_buffer + out_offset * 4;
- if (processor != NULL) {
- /* Convert to scene linear, to sRGB and premultiply. */
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- float pixel[4];
- rgba_uchar_to_float(pixel, in);
- OCIO_cpuProcessorApplyRGB(processor, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
- if (use_premultiply) {
- mul_v3_fl(pixel, pixel[3]);
- }
- rgba_float_to_uchar(out, pixel);
- }
- }
- else if (use_premultiply) {
+ if (use_premultiply) {
/* Premultiply only. */
for (int x = 0; x < width; x++, in += 4, out += 4) {
out[0] = (in[0] * in[3]) >> 8;
@@ -2265,49 +2259,87 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
{
/* Float texture are stored in scene linear color space, with premultiplied
* alpha depending on the image alpha mode. */
- const float *in_buffer = ibuf->rect_float;
- const int in_channels = ibuf->channels;
- const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
-
- for (int y = 0; y < height; y++) {
- const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
- const size_t out_offset = y * width;
- const float *in = in_buffer + in_offset * in_channels;
- float *out = out_buffer + out_offset * 4;
-
- if (in_channels == 1) {
- /* Copy single channel. */
- for (int x = 0; x < width; x++, in += 1, out += 4) {
- out[0] = in[0];
- out[1] = in[0];
- out[2] = in[0];
- out[3] = in[0];
+ if (ibuf->rect_float) {
+ /* Float source buffer. */
+ const float *in_buffer = ibuf->rect_float;
+ const int in_channels = ibuf->channels;
+ const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const float *in = in_buffer + in_offset * in_channels;
+ float *out = out_buffer + out_offset * 4;
+
+ if (in_channels == 1) {
+ /* Copy single channel. */
+ for (int x = 0; x < width; x++, in += 1, out += 4) {
+ out[0] = in[0];
+ out[1] = in[0];
+ out[2] = in[0];
+ out[3] = in[0];
+ }
}
- }
- else if (in_channels == 3) {
- /* Copy RGB. */
- for (int x = 0; x < width; x++, in += 3, out += 4) {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
- out[3] = 1.0f;
+ else if (in_channels == 3) {
+ /* Copy RGB. */
+ for (int x = 0; x < width; x++, in += 3, out += 4) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 1.0f;
+ }
}
- }
- else if (in_channels == 4) {
- /* Copy or convert RGBA. */
- if (use_unpremultiply) {
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- premul_to_straight_v4_v4(out, in);
+ else if (in_channels == 4) {
+ /* Copy or convert RGBA. */
+ if (use_unpremultiply) {
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ premul_to_straight_v4_v4(out, in);
+ }
+ }
+ else {
+ memcpy(out, in, sizeof(float[4]) * width);
}
}
- else {
- memcpy(out, in, sizeof(float[4]) * width);
+ }
+ }
+ else {
+ /* Byte source buffer. */
+ const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
+ const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
+
+ /* TODO(brecht): make this multi-threaded, or at least process in batches. */
+ OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ?
+ colorspace_to_scene_linear_cpu_processor(
+ ibuf->rect_colorspace) :
+ NULL;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const unsigned char *in = in_buffer + in_offset * 4;
+ float *out = out_buffer + out_offset * 4;
+
+ /* Convert to scene linear, to sRGB and premultiply. */
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ float pixel[4];
+ rgba_uchar_to_float(pixel, in);
+ if (processor) {
+ OCIO_cpuProcessorApplyRGB(processor, pixel);
+ }
+ else {
+ srgb_to_linearrgb_v3_v3(pixel, pixel);
+ }
+ if (use_premultiply) {
+ mul_v3_fl(pixel, pixel[3]);
+ }
+ copy_v4_v4(out, pixel);
}
}
}
}
-void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
+void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3],
+ const float scene_linear[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
/* Create processor if none exists. */
@@ -2329,12 +2361,15 @@ void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
BLI_mutex_unlock(&processor_lock);
}
+ copy_v3_v3(color_picking, scene_linear);
+
if (global_color_picking_state.cpu_processor_to) {
- OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_to, pixel);
+ OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_to, color_picking);
}
}
-void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
+void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3],
+ const float color_picking[3])
{
if (!global_color_picking_state.cpu_processor_from && !global_color_picking_state.failed) {
/* Create processor if none exists. */
@@ -2356,25 +2391,13 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
BLI_mutex_unlock(&processor_lock);
}
+ copy_v3_v3(scene_linear, color_picking);
+
if (global_color_picking_state.cpu_processor_from) {
- OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_from, pixel);
+ OCIO_cpuProcessorApplyRGB(global_color_picking_state.cpu_processor_from, scene_linear);
}
}
-void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
-{
- mul_m3_v3(imbuf_rgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_linear_srgb, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
-}
-
-void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
-{
- srgb_to_linearrgb_v3_v3(pixel, pixel);
- mul_m3_v3(imbuf_linear_srgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_rgb, pixel);
-}
-
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -2445,68 +2468,77 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
+static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* Is already an editable copy. */
+ return colormanaged_ibuf;
+ }
+
+ if (allocate_result) {
+ /* Copy full image buffer. */
+ colormanaged_ibuf = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ return colormanaged_ibuf;
+ }
+ else {
+ /* Render pipeline is constructing image buffer itself,
+ * but it's re-using byte and float buffers from render result make copy of this buffers
+ * here sine this buffers would be transformed to other color space here. */
+ if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
+ ibuf->rect = MEM_dupallocN(ibuf->rect);
+ ibuf->mall |= IB_rect;
+ }
+
+ if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
+ ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
+ ibuf->mall |= IB_rectfloat;
+ }
+
+ return ibuf;
+ }
+}
+
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
const ImageFormatData *image_format)
{
ImBuf *colormanaged_ibuf = ibuf;
- const bool is_movie = BKE_imtype_is_movie(image_format->imtype);
- const bool requires_linear_float = BKE_imtype_requires_linear_float(image_format->imtype);
- const bool do_alpha_under = image_format->planes != R_IMF_PLANES_RGBA;
+ /* Update byte buffer if exists but invalid. */
if (ibuf->rect_float && ibuf->rect &&
(ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) {
IMB_rect_from_float(ibuf);
ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
}
- const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float);
- const bool do_colormanagement_linear = save_as_render && requires_linear_float &&
- image_format->linear_colorspace_settings.name[0] &&
- !IMB_colormanagement_space_name_is_scene_linear(
- image_format->linear_colorspace_settings.name);
+ /* Detect if we are writing to a file format that needs a linear float buffer. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
- if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) {
- if (allocate_result) {
- colormanaged_ibuf = IMB_dupImBuf(ibuf);
- }
- else {
- /* Render pipeline is constructing image buffer itself,
- * but it's re-using byte and float buffers from render result make copy of this buffers
- * here sine this buffers would be transformed to other color space here.
- */
+ /* Detect if we are writing output a byte buffer, which we would need to create
+ * with color management conversions applied. This may be for either applying the
+ * display transform for renders, or a user specified color space for the file. */
+ const bool byte_output = BKE_image_format_is_byte(image_format);
- if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
- ibuf->rect = MEM_dupallocN(ibuf->rect);
- ibuf->mall |= IB_rect;
- }
-
- if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
- ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
- ibuf->mall |= IB_rectfloat;
- }
- }
- }
+ BLI_assert(!(byte_output && linear_float_output));
- /* If we're saving from RGBA to RGB buffer then it's not
- * so much useful to just ignore alpha -- it leads to bad
- * artifacts especially when saving byte images.
+ /* If we're saving from RGBA to RGB buffer then it's not so much useful to just ignore alpha --
+ * it leads to bad artifacts especially when saving byte images.
*
- * What we do here is we're overlaying our image on top of
- * background color (which is currently black).
+ * What we do here is we're overlaying our image on top of background color (which is currently
+ * black). This is quite much the same as what Gimp does and it seems to be what artists expects
+ * from saving.
*
- * This is quite much the same as what Gimp does and it
- * seems to be what artists expects from saving.
- *
- * Do a conversion here, so image format writers could
- * happily assume all the alpha tricks were made already.
- * helps keep things locally here, not spreading it to
- * all possible image writers we've got.
+ * Do a conversion here, so image format writers could happily assume all the alpha tricks were
+ * made already. helps keep things locally here, not spreading it to all possible image writers
+ * we've got.
*/
- if (do_alpha_under) {
+ if (image_format->planes != R_IMF_PLANES_RGBA) {
float color[3] = {0, 0, 0};
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
+
if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
IMB_alpha_under_color_float(
colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
@@ -2520,69 +2552,95 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
}
}
- if (do_colormanagement_display) {
- /* Color management with display and view transform. */
- bool make_byte = false;
+ if (save_as_render && !linear_float_output) {
+ /* Render output: perform conversion to display space using view transform. */
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
- /* for proper check whether byte buffer is required by a format or not
- * should be pretty safe since this image buffer is supposed to be used for
- * saving only and ftype would be overwritten a bit later by BKE_imbuf_write
- */
- colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format->imtype,
- &colormanaged_ibuf->foptions);
-
- /* if file format isn't able to handle float buffer itself,
- * we need to allocate byte buffer and store color managed
- * image there
- */
- const ImFileType *type = IMB_file_type_from_ibuf(colormanaged_ibuf);
- if (type != NULL) {
- if ((type->save != NULL) && (type->flag & IM_FTYPE_FLOAT) == 0) {
- make_byte = true;
- }
- }
-
- /* perform color space conversions */
colormanagement_imbuf_make_display_space(colormanaged_ibuf,
&image_format->view_settings,
&image_format->display_settings,
- make_byte);
+ byte_output);
if (colormanaged_ibuf->rect_float) {
- /* float buffer isn't linear anymore,
+ /* Float buffer isn't linear anymore,
* image format write callback should check for this flag and assume
- * no space conversion should happen if ibuf->float_colorspace != NULL
- */
+ * no space conversion should happen if ibuf->float_colorspace != NULL. */
colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(
&image_format->view_settings, &image_format->display_settings);
+ if (byte_output) {
+ colormanaged_ibuf->rect_colorspace = colormanaged_ibuf->float_colorspace;
+ }
}
}
- else if (do_colormanagement_linear) {
- /* Color management transform to another linear color space. */
- if (!colormanaged_ibuf->rect_float) {
- IMB_float_from_rect(colormanaged_ibuf);
- imb_freerectImBuf(colormanaged_ibuf);
+ else {
+ /* Linear render or regular file output: conversion between two color spaces. */
+
+ /* Detect which color space we need to convert between. */
+ const char *from_colorspace = (ibuf->rect_float && !(byte_output && ibuf->rect)) ?
+ /* From float buffer. */
+ (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
+ global_role_scene_linear :
+ /* From byte buffer. */
+ (ibuf->rect_colorspace) ? ibuf->rect_colorspace->name :
+ global_role_default_byte;
+
+ const char *to_colorspace = image_format->linear_colorspace_settings.name;
+
+ /* TODO: can we check with OCIO if color spaces are the same but have different names? */
+ if (to_colorspace[0] == '\0' || STREQ(from_colorspace, to_colorspace)) {
+ /* No conversion needed, but may still need to allocate byte buffer for output. */
+ if (byte_output && !ibuf->rect) {
+ ibuf->rect_colorspace = ibuf->float_colorspace;
+ IMB_rect_from_float(ibuf);
+ }
}
+ else {
+ /* Color space conversion needed. */
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
+
+ if (byte_output) {
+ colormanaged_ibuf->rect_colorspace = colormanage_colorspace_get_named(to_colorspace);
+
+ if (colormanaged_ibuf->rect) {
+ /* Byte to byte. */
+ IMB_colormanagement_transform_byte_threaded((unsigned char *)colormanaged_ibuf->rect,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ }
+ else {
+ /* Float to byte. */
+ IMB_rect_from_float(colormanaged_ibuf);
+ }
+ }
+ else {
+ if (!colormanaged_ibuf->rect_float) {
+ /* Byte to float. */
+ IMB_float_from_rect(colormanaged_ibuf);
+ imb_freerectImBuf(colormanaged_ibuf);
- if (colormanaged_ibuf->rect_float) {
- const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
- global_role_scene_linear;
- const char *to_colorspace = image_format->linear_colorspace_settings.name;
+ /* This conversion always goes to scene linear. */
+ from_colorspace = global_role_scene_linear;
+ }
- IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
- colormanaged_ibuf->x,
- colormanaged_ibuf->y,
- colormanaged_ibuf->channels,
- from_colorspace,
- to_colorspace,
- false);
+ if (colormanaged_ibuf->rect_float) {
+ /* Float to float. */
+ IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace,
+ false);
+
+ colormanaged_ibuf->float_colorspace = colormanage_colorspace_get_named(to_colorspace);
+ }
+ }
}
}
- if (colormanaged_ibuf != ibuf) {
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
- }
-
return colormanaged_ibuf;
}
@@ -4076,3 +4134,170 @@ void IMB_colormanagement_finish_glsl_draw(void)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rendering Tables
+ * \{ */
+
+/* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ *
+ * The result of this can be negative to support gamut wider than
+ * than rec.709, just needs to be clamped. */
+
+static const float blackbody_table_r[7][3] = {{1.61919106e+03f, -2.05010916e-03f, 5.02995757e+00f},
+ {2.48845471e+03f, -1.11330907e-03f, 3.22621544e+00f},
+ {3.34143193e+03f, -4.86551192e-04f, 1.76486769e+00f},
+ {4.09461742e+03f, -1.27446582e-04f, 7.25731635e-01f},
+ {4.67028036e+03f, 2.91258199e-05f, 1.26703442e-01f},
+ {4.59509185e+03f, 2.87495649e-05f, 1.50345020e-01f},
+ {3.78717450e+03f, 9.35907826e-06f, 3.99075871e-01f}};
+
+static const float blackbody_table_g[7][3] = {
+ {-4.88999748e+02f, 6.04330754e-04f, -7.55807526e-02f},
+ {-7.55994277e+02f, 3.16730098e-04f, 4.78306139e-01f},
+ {-1.02363977e+03f, 1.20223470e-04f, 9.36662319e-01f},
+ {-1.26571316e+03f, 4.87340896e-06f, 1.27054498e+00f},
+ {-1.42529332e+03f, -4.01150431e-05f, 1.43972784e+00f},
+ {-1.17554822e+03f, -2.16378048e-05f, 1.30408023e+00f},
+ {-5.00799571e+02f, -4.59832026e-06f, 1.09098763e+00f}};
+
+static const float blackbody_table_b[7][4] = {
+ {5.96945309e-11f, -4.85742887e-08f, -9.70622247e-05f, -4.07936148e-03f},
+ {2.40430366e-11f, 5.55021075e-08f, -1.98503712e-04f, 2.89312858e-02f},
+ {-1.40949732e-11f, 1.89878968e-07f, -3.56632824e-04f, 9.10767778e-02f},
+ {-3.61460868e-11f, 2.84822009e-07f, -4.93211319e-04f, 1.56723440e-01f},
+ {-1.97075738e-11f, 1.75359352e-07f, -2.50542825e-04f, -2.22783266e-02f},
+ {-1.61997957e-13f, -1.64216008e-08f, 3.86216271e-04f, -7.38077418e-01f},
+ {6.72650283e-13f, -2.73078809e-08f, 4.24098264e-04f, -7.52335691e-01f}};
+
+static void blackbody_temperature_to_rec709(float rec709[3], float t)
+{
+ if (t >= 12000.0f) {
+ rec709[0] = 0.8262954810464208f;
+ rec709[1] = 0.9945080501520986f;
+ rec709[2] = 1.566307710274283f;
+ }
+ else if (t < 800.0f) {
+ rec709[0] = 5.413294490189271f;
+ rec709[1] = -0.20319390035873933f;
+ rec709[2] = -0.0822535242887164f;
+ }
+ else {
+ int i = (t >= 6365.0f) ? 6 :
+ (t >= 3315.0f) ? 5 :
+ (t >= 1902.0f) ? 4 :
+ (t >= 1449.0f) ? 3 :
+ (t >= 1167.0f) ? 2 :
+ (t >= 965.0f) ? 1 :
+ 0;
+
+ const float *r = blackbody_table_r[i];
+ const float *g = blackbody_table_g[i];
+ const float *b = blackbody_table_b[i];
+
+ const float t_inv = 1.0f / t;
+ rec709[0] = r[0] * t_inv + r[1] * t + r[2];
+ rec709[1] = g[0] * t_inv + g[1] * t + g[2];
+ rec709[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
+ }
+}
+
+void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table,
+ const int width,
+ const float min,
+ const float max)
+{
+ for (int i = 0; i < width; i++) {
+ float temperature = min + (max - min) / (float)width * (float)i;
+
+ float rec709[3];
+ blackbody_temperature_to_rec709(rec709, temperature);
+
+ float rgb[3];
+ IMB_colormanagement_rec709_to_scene_linear(rgb, rec709);
+ clamp_v3(rgb, 0.0f, FLT_MAX);
+
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
+ }
+}
+
+/**
+ * CIE color matching functions `xBar`, `yBar`, and `zBar` for
+ * wavelengths from 380 through 780 nanometers, every 5 nanometers.
+ *
+ * For a wavelength lambda in this range:
+ * \code{.txt}
+ * cie_color_match[(lambda - 380) / 5][0] = xBar
+ * cie_color_match[(lambda - 380) / 5][1] = yBar
+ * cie_color_match[(lambda - 380) / 5][2] = zBar
+ * \endcode
+ */
+
+static float cie_colour_match[81][3] = {
+ {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
+ {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
+ {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
+ {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
+ {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
+ {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
+ {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
+ {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
+ {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
+ {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
+ {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
+ {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
+ {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
+ {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
+ {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
+ {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
+ {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
+ {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
+ {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
+ {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
+ {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
+ {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
+ {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
+ {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
+ {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
+ {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
+ {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
+
+static void wavelength_to_xyz(float xyz[3], float lambda_nm)
+{
+ float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
+ int i = (int)ii;
+
+ if (i < 0 || i >= 80) {
+ xyz[0] = 0.0f;
+ xyz[1] = 0.0f;
+ xyz[2] = 0.0f;
+ }
+ else {
+ ii -= (float)i;
+ const float *c = cie_colour_match[i];
+ xyz[0] = c[0] + ii * (c[3] - c[0]);
+ xyz[1] = c[1] + ii * (c[4] - c[1]);
+ xyz[2] = c[2] + ii * (c[5] - c[2]);
+ }
+}
+
+void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width)
+{
+ for (int i = 0; i < width; i++) {
+ float temperature = 380 + 400 / (float)width * (float)i;
+
+ float xyz[3];
+ wavelength_to_xyz(xyz, temperature);
+
+ float rgb[3];
+ IMB_colormanagement_xyz_to_scene_linear(rgb, xyz);
+ clamp_v3(rgb, 0.0f, FLT_MAX);
+
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index 411cf9af802..668307ec802 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,14 +27,46 @@ unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
return unit_float_to_uchar_clamp(val);
}
-void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3])
+void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3])
{
- mul_v3_m3v3(rgb, imbuf_xyz_to_rgb, xyz);
+ mul_v3_m3v3(scene_linear, imbuf_xyz_to_scene_linear, xyz);
}
-void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3])
+void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3])
{
- mul_v3_m3v3(xyz, imbuf_rgb_to_xyz, rgb);
+ mul_v3_m3v3(xyz, imbuf_scene_linear_to_xyz, scene_linear);
+}
+
+void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
+{
+ mul_v3_m3v3(scene_linear, imbuf_rec709_to_scene_linear, rec709);
+}
+
+void IMB_colormanagement_scene_linear_to_rec709(float rec709[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(rec709, imbuf_scene_linear_to_rec709, scene_linear);
+}
+
+void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(srgb, imbuf_scene_linear_to_rec709, scene_linear);
+ linearrgb_to_srgb_v3_v3(srgb, srgb);
+}
+
+void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
+{
+ srgb_to_linearrgb_v3_v3(scene_linear, srgb);
+ mul_m3_v3(imbuf_rec709_to_scene_linear, scene_linear);
+}
+
+void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3], const float aces[3])
+{
+ mul_v3_m3v3(scene_linear, imbuf_aces_to_scene_linear, aces);
+}
+
+void IMB_colormanagement_scene_linear_to_aces(float aces[3], const float scene_linear[3])
+{
+ mul_v3_m3v3(aces, imbuf_scene_linear_to_aces, scene_linear);
}
#endif /* __IMB_COLORMANAGEMENT_INLINE_H__ */
diff --git a/source/blender/imbuf/intern/dds/Color.h b/source/blender/imbuf/intern/dds/Color.h
index 3918ef31052..5b00333ad77 100644
--- a/source/blender/imbuf/intern/dds/Color.h
+++ b/source/blender/imbuf/intern/dds/Color.h
@@ -21,9 +21,8 @@ class Color32 {
Color32()
{
}
- Color32(const Color32 &c) : u(c.u)
- {
- }
+ Color32(const Color32 &) = default;
+
Color32(unsigned char R, unsigned char G, unsigned char B)
{
setRGBA(R, G, B, 0xFF);
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
index 34f3654aa3f..566891dac8b 100644
--- a/source/blender/imbuf/intern/dds/Stream.cpp
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -45,7 +45,7 @@ unsigned int mem_read(Stream &mem, unsigned long long &i)
mem.set_failed(msg_error_seek);
return 0;
}
- memcpy(&i, mem.mem + mem.pos, 8); /* @@ todo: make sure little endian */
+ memcpy(&i, mem.mem + mem.pos, 8); /* TODO: make sure little endian. */
mem.pos += 8;
return 8;
}
@@ -56,7 +56,7 @@ unsigned int mem_read(Stream &mem, unsigned int &i)
mem.set_failed(msg_error_read);
return 0;
}
- memcpy(&i, mem.mem + mem.pos, 4); /* @@ todo: make sure little endian */
+ memcpy(&i, mem.mem + mem.pos, 4); /* TODO: make sure little endian. */
mem.pos += 4;
return 4;
}
@@ -67,7 +67,7 @@ unsigned int mem_read(Stream &mem, unsigned short &i)
mem.set_failed(msg_error_read);
return 0;
}
- memcpy(&i, mem.mem + mem.pos, 2); /* @@ todo: make sure little endian */
+ memcpy(&i, mem.mem + mem.pos, 2); /* TODO: make sure little endian. */
mem.pos += 2;
return 2;
}
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 74042ef75be..92fa980cd7f 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -157,7 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_openexr,
.load = imb_load_openexr,
.load_filepath = NULL,
- .load_filepath_thumbnail = NULL,
+ .load_filepath_thumbnail = imb_load_filepath_thumbnail_openexr,
.save = imb_save_openexr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 1cc91d25d2a..cbc5d984755 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -376,10 +376,10 @@ int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_len)
{
if (!anim->index_dir[0]) {
- char fname[FILE_MAXFILE];
- BLI_split_dirfile(anim->name, index_dir, fname, index_dir_len, sizeof(fname));
+ char filename[FILE_MAXFILE];
+ BLI_split_dirfile(anim->name, index_dir, filename, index_dir_len, sizeof(filename));
BLI_path_append(index_dir, index_dir_len, "BL_proxy");
- BLI_path_append(index_dir, index_dir_len, fname);
+ BLI_path_append(index_dir, index_dir_len, filename);
}
else {
BLI_strncpy(index_dir, anim->index_dir, index_dir_len);
@@ -388,14 +388,14 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l
void IMB_anim_get_fname(struct anim *anim, char *file, int size)
{
- char fname[FILE_MAXFILE];
- BLI_split_dirfile(anim->name, file, fname, size, sizeof(fname));
- BLI_strncpy(file, fname, size);
+ char filename[FILE_MAXFILE];
+ BLI_split_dirfile(anim->name, file, filename, size, sizeof(filename));
+ BLI_strncpy(file, filename, size);
}
-static bool get_proxy_filename(struct anim *anim,
+static bool get_proxy_filepath(struct anim *anim,
IMB_Proxy_Size preview_size,
- char *fname,
+ char *filepath,
bool temp)
{
char index_dir[FILE_MAXDIR];
@@ -426,11 +426,11 @@ static bool get_proxy_filename(struct anim *anim,
return false;
}
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
+ BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
return true;
}
-static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname)
+static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *filepath)
{
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
@@ -457,7 +457,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname
get_index_dir(anim, index_dir, sizeof(index_dir));
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
+ BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
}
/* ----------------------------------------------------------------------
@@ -492,18 +492,18 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
{
struct proxy_output_ctx *rv = MEM_callocN(sizeof(struct proxy_output_ctx), "alloc_proxy_output");
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
rv->proxy_size = proxy_size;
rv->anim = anim;
- get_proxy_filename(rv->anim, rv->proxy_size, fname, true);
- BLI_make_existing_file(fname);
+ get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true);
+ BLI_make_existing_file(filepath);
rv->of = avformat_alloc_context();
rv->of->oformat = av_guess_format("avi", NULL, NULL);
- rv->of->url = av_strdup(fname);
+ rv->of->url = av_strdup(filepath);
fprintf(stderr, "Starting work on proxy: %s\n", rv->of->url);
@@ -577,7 +577,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
avcodec_parameters_from_context(rv->st->codecpar, rv->c);
- int ret = avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE);
+ int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr,
@@ -723,8 +723,8 @@ static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *fr
static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback)
{
- char fname[FILE_MAX];
- char fname_tmp[FILE_MAX];
+ char filepath[FILE_MAX];
+ char filepath_tmp[FILE_MAX];
if (!ctx) {
return;
@@ -755,15 +755,15 @@ static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback)
av_free(ctx->frame);
}
- get_proxy_filename(ctx->anim, ctx->proxy_size, fname_tmp, true);
+ get_proxy_filepath(ctx->anim, ctx->proxy_size, filepath_tmp, true);
if (rollback) {
- unlink(fname_tmp);
+ unlink(filepath_tmp);
}
else {
- get_proxy_filename(ctx->anim, ctx->proxy_size, fname, false);
- unlink(fname);
- BLI_rename(fname_tmp, fname);
+ get_proxy_filepath(ctx->anim, ctx->proxy_size, filepath, false);
+ unlink(filepath);
+ BLI_rename(filepath_tmp, filepath);
}
MEM_freeN(ctx);
@@ -907,11 +907,11 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
for (i = 0; i < num_indexers; i++) {
if (tcs_in_use & tc_types[i]) {
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
- get_tc_filename(anim, tc_types[i], fname);
+ get_tc_filename(anim, tc_types[i], filepath);
- context->indexer[i] = IMB_index_builder_create(fname);
+ context->indexer[i] = IMB_index_builder_create(filepath);
if (!context->indexer[i]) {
tcs_in_use &= ~tc_types[i];
}
@@ -1212,7 +1212,7 @@ typedef struct FallbackIndexBuilderContext {
} FallbackIndexBuilderContext;
static AviMovie *alloc_proxy_output_avi(
- struct anim *anim, char *filename, int width, int height, int quality)
+ struct anim *anim, char *filepath, int width, int height, int quality)
{
int x, y;
AviFormat format;
@@ -1233,7 +1233,7 @@ static AviMovie *alloc_proxy_output_avi(
format = AVI_FORMAT_MJPEG;
- if (AVI_open_compress(filename, avi, 1, format) != AVI_ERROR_NONE) {
+ if (AVI_open_compress(filepath, avi, 1, format) != AVI_ERROR_NONE) {
MEM_freeN(avi);
return NULL;
}
@@ -1275,13 +1275,13 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim,
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
if (context->proxy_sizes_in_use & proxy_sizes[i]) {
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
- get_proxy_filename(anim, proxy_sizes[i], fname, true);
- BLI_make_existing_file(fname);
+ get_proxy_filepath(anim, proxy_sizes[i], filepath, true);
+ BLI_make_existing_file(filepath);
context->proxy_ctx[i] = alloc_proxy_output_avi(
- anim, fname, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
+ anim, filepath, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
}
}
@@ -1291,8 +1291,8 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim,
static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, int stop)
{
struct anim *anim = context->anim;
- char fname[FILE_MAX];
- char fname_tmp[FILE_MAX];
+ char filepath[FILE_MAX];
+ char filepath_tmp[FILE_MAX];
int i;
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
@@ -1300,15 +1300,15 @@ static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context,
AVI_close_compress(context->proxy_ctx[i]);
MEM_freeN(context->proxy_ctx[i]);
- get_proxy_filename(anim, proxy_sizes[i], fname_tmp, true);
- get_proxy_filename(anim, proxy_sizes[i], fname, false);
+ get_proxy_filepath(anim, proxy_sizes[i], filepath_tmp, true);
+ get_proxy_filepath(anim, proxy_sizes[i], filepath, false);
if (stop) {
- unlink(fname_tmp);
+ unlink(filepath_tmp);
}
else {
- unlink(fname);
- rename(fname_tmp, fname);
+ unlink(filepath);
+ rename(filepath_tmp, filepath);
}
}
}
@@ -1388,7 +1388,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & proxy_sizes_to_build) {
char filename[FILE_MAX];
- if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
+ if (get_proxy_filepath(anim, proxy_size, filename, false) == false) {
return NULL;
}
void **filename_key_p;
@@ -1411,7 +1411,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & built_proxies) {
char filename[FILE_MAX];
- if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
+ if (get_proxy_filepath(anim, proxy_size, filename, false) == false) {
return NULL;
}
printf("Skipping proxy: %s\n", filename);
@@ -1532,7 +1532,7 @@ void IMB_anim_set_index_dir(struct anim *anim, const char *dir)
struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
{
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
int i = IMB_proxy_size_to_array_index(preview_size);
if (i < 0) {
@@ -1547,10 +1547,10 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
return NULL;
}
- get_proxy_filename(anim, preview_size, fname, false);
+ get_proxy_filepath(anim, preview_size, filepath, false);
/* proxies are generated in the same color space as animation itself */
- anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0, anim->colorspace);
+ anim->proxy_anim[i] = IMB_open_anim(filepath, 0, 0, anim->colorspace);
anim->proxies_tried |= preview_size;
@@ -1559,7 +1559,7 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc)
{
- char fname[FILE_MAX];
+ char filepath[FILE_MAX];
int i = IMB_timecode_to_array_index(tc);
if (i < 0) {
@@ -1574,9 +1574,9 @@ struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc)
return NULL;
}
- get_tc_filename(anim, tc, fname);
+ get_tc_filename(anim, tc, filepath);
- anim->curr_idx[i] = IMB_indexer_open(fname);
+ anim->curr_idx[i] = IMB_indexer_open(filepath);
anim->indices_tried |= tc;
@@ -1602,7 +1602,7 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim)
for (i = 0; i < num_proxy_sizes; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
char filename[FILE_MAX];
- get_proxy_filename(anim, proxy_size, filename, false);
+ get_proxy_filepath(anim, proxy_size, filename, false);
if (BLI_exists(filename)) {
existing |= proxy_size;
}
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index eb0a2c4a47f..a8150fd1648 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -105,7 +105,7 @@ static int expandrow2(
float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
-static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len);
+static int compressrow(const uchar *lbuf, uchar *rlebuf, int z, int row_len);
static void lumrow(const uchar *rgbptr, uchar *lumptr, int n);
/*
@@ -779,18 +779,24 @@ fail:
}
/**
- * Copy an array of ints to an iris image file.
- * Each int represents one pixel. xsize and ysize specify the dimensions of
- * the pixel array. zsize specifies what kind of image file to
- * write out. if zsize is 1, the luminance of the pixels are
- * calculated, and a single channel black and white image is saved.
- * If zsize is 3, an RGB image file is saved. If zsize is 4, an
- * RGBA image file is saved.
- *
- * Added: zbuf write
+ * \param filepath: The file path to write to.
+ * \param lptr: an array of integers to an iris image file (each int represents one pixel).
+ * \param zptr: depth-buffer (optional, may be NULL).
+ * \param xsize: with width of the pixel-array.
+ * \param ysize: height of the pixel-array.
+ * \param zsize: specifies what kind of image file to write out.
+ * - 1: the luminance of the pixels are calculated,
+ * and a single channel black and white image is saved.
+ * - 3: an RGB image file is saved.
+ * - 4: an RGBA image file is saved.
+ * - 8: an RGBA image and a Z-buffer (non-null `zptr`).
*/
-
-static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr)
+static bool output_iris(const char *filepath,
+ const uint *lptr,
+ const int *zptr,
+ const int xsize,
+ const int ysize,
+ const int zsize)
{
FILE *outf;
IMAGE *image;
@@ -801,7 +807,7 @@ static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char
int rlebuflen, goodwrite;
goodwrite = 1;
- outf = BLI_fopen(name, "wb");
+ outf = BLI_fopen(filepath, "wb");
if (!outf) {
return 0;
}
@@ -837,21 +843,20 @@ static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char
for (z = 0; z < zsize; z++) {
if (zsize == 1) {
- lumrow((uchar *)lptr, (uchar *)lumbuf, xsize);
- len = compressrow((uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize);
+ lumrow((const uchar *)lptr, (uchar *)lumbuf, xsize);
+ len = compressrow((const uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize);
}
else {
if (z < 4) {
- len = compressrow((uchar *)lptr, rlebuf, CHANOFFSET(z), xsize);
+ len = compressrow((const uchar *)lptr, rlebuf, CHANOFFSET(z), xsize);
}
else if (z < 8 && zptr) {
- len = compressrow((uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize);
+ len = compressrow((const uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize);
}
}
- if (len > rlebuflen) {
- fprintf(stderr, "output_iris: rlebuf is too small - bad poop\n");
- exit(1);
- }
+
+ BLI_assert_msg(len <= rlebuflen, "The length calculated for 'rlebuflen' was too small!");
+
goodwrite *= fwrite(rlebuf, len, 1, outf);
starttab[y + z * ysize] = pos;
lengthtab[y + z * ysize] = len;
@@ -892,9 +897,10 @@ static void lumrow(const uchar *rgbptr, uchar *lumptr, int n)
}
}
-static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len)
+static int compressrow(const uchar *lbuf, uchar *rlebuf, const int z, const int row_len)
{
- uchar *iptr, *ibufend, *sptr, *optr;
+ const uchar *iptr, *ibufend, *sptr;
+ uchar *optr;
short todo, cc;
int count;
@@ -964,7 +970,7 @@ bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags)
IMB_convert_rgba_to_abgr(ibuf);
test_endian_zbuf(ibuf);
- const bool ok = output_iris(ibuf->rect, ibuf->x, ibuf->y, zsize, filepath, ibuf->zbuf);
+ const bool ok = output_iris(filepath, ibuf->rect, ibuf->zbuf, ibuf->x, ibuf->y, zsize);
/* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */
IMB_convert_rgba_to_abgr(ibuf);
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 80fcceb0aa7..cffa61977f7 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -286,8 +286,8 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
}
if (max_size > 0) {
- /* libjpeg can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
- * while libjpeg-turbo can also do 3/8, 5/8, etc. But max is 1/8. */
+ /* `libjpeg` can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
+ * while `libjpeg-turbo` can also do 3/8, 5/8, etc. But max is 1/8. */
float scale = (float)max_size / MAX2(cinfo->image_width, cinfo->image_height);
cinfo->scale_denom = 8;
cinfo->scale_num = max_uu(1, min_uu(8, ceill(scale * (float)cinfo->scale_denom)));
@@ -520,9 +520,9 @@ struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
if ((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI) &&
(fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_APP1)) {
- /* This is a JPEG in Exif format (SOI + APP1), not JFIF (SOI + APP0). */
+ /* This is a JPEG in EXIF format (SOI + APP1), not JFIF (SOI + APP0). */
unsigned int i = JPEG_APP1_MAX;
- /* All Exif data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
+ /* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) &&
!feof(infile) && i--)
;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 9948aaac5da..0414fa1268d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -10,6 +10,7 @@
#include <cstddef>
#include <cstdio>
#include <cstdlib>
+#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <set>
@@ -43,6 +44,8 @@
#include <OpenEXR/ImfInputFile.h>
#include <OpenEXR/ImfOutputFile.h>
#include <OpenEXR/ImfPixelType.h>
+#include <OpenEXR/ImfPreviewImage.h>
+#include <OpenEXR/ImfRgbaFile.h>
#include <OpenEXR/ImfStandardAttributes.h>
#include <OpenEXR/ImfStringAttribute.h>
#include <OpenEXR/ImfVersion.h>
@@ -63,6 +66,9 @@
#if defined(WIN32)
# include "utfconv.h"
+# include <io.h>
+#else
+# include <unistd.h>
#endif
#include "MEM_guardedalloc.h"
@@ -77,7 +83,9 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#endif
}
#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
#include "BLI_math_color.h"
+#include "BLI_mmap.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -151,6 +159,66 @@ class IMemStream : public Imf::IStream {
unsigned char *_exrbuf;
};
+/* Memory-Mapped Input Stream */
+
+class IMMapStream : public Imf::IStream {
+ public:
+ IMMapStream(const char *filepath) : IStream(filepath)
+ {
+ int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
+ if (file < 0) {
+ throw IEX_NAMESPACE::InputExc("file not found");
+ }
+ _exrpos = 0;
+ _exrsize = BLI_file_descriptor_size(file);
+ imb_mmap_lock();
+ _mmap_file = BLI_mmap_open(file);
+ imb_mmap_unlock();
+ if (_mmap_file == nullptr) {
+ throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed");
+ }
+ close(file);
+ _exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file);
+ }
+
+ ~IMMapStream() override
+ {
+ imb_mmap_lock();
+ BLI_mmap_free(_mmap_file);
+ imb_mmap_unlock();
+ }
+
+ /* This is implementing regular `read`, not `readMemoryMapped`, because DWAA and DWAB
+ * decompressors load on unaligned offsets. Therefore we can't avoid the memory copy. */
+
+ bool read(char c[], int n) override
+ {
+ if (_exrpos + n > _exrsize) {
+ throw Iex::InputExc("Unexpected end of file.");
+ }
+ memcpy(c, _exrbuf + _exrpos, n);
+ _exrpos += n;
+
+ return _exrpos < _exrsize;
+ }
+
+ exr_file_offset_t tellg() override
+ {
+ return _exrpos;
+ }
+
+ void seekg(exr_file_offset_t pos) override
+ {
+ _exrpos = pos;
+ }
+
+ private:
+ BLI_mmap_file *_mmap_file;
+ exr_file_offset_t _exrpos;
+ exr_file_offset_t _exrsize;
+ unsigned char *_exrbuf;
+};
+
/* File Input Stream */
class IFileStream : public Imf::IStream {
@@ -363,7 +431,7 @@ static void openexr_header_compression(Header *header, int compression)
case R_IMF_EXR_CODEC_B44A:
header->compression() = B44A_COMPRESSION;
break;
-#if OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2
+#if OPENEXR_VERSION_MAJOR > 2 || (OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2)
case R_IMF_EXR_CODEC_DWAA:
header->compression() = DWAA_COMPRESSION;
break;
@@ -444,7 +512,7 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
/* we store first everything in half array */
std::vector<RGBAZ> pixels(height * width);
- RGBAZ *to = &pixels[0];
+ RGBAZ *to = pixels.data();
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
@@ -942,7 +1010,7 @@ void IMB_exrtile_begin_write(
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filepath);
- data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
}
catch (const std::exception &) {
delete data->mpofile;
@@ -1394,12 +1462,10 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
- char tokenbuf[EXR_TOT_MAXNAME];
- int len;
/* some multilayers have the combined buffer with names A B G R saved */
if (name[1] == 0) {
- echan->chan_id = name[0];
+ echan->chan_id = BLI_toupper_ascii(name[0]);
layname[0] = '\0';
if (ELEM(name[0], 'R', 'G', 'B', 'A')) {
@@ -1416,13 +1482,17 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is channel identifier */
- len = imb_exr_split_token(name, end, &token);
+ size_t len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
}
+
+ char channelname[EXR_TOT_MAXNAME];
+ BLI_strncpy(channelname, token, std::min(len + 1, sizeof(channelname)));
+
if (len == 1) {
- echan->chan_id = token[0];
+ echan->chan_id = BLI_toupper_ascii(channelname[0]);
}
else if (len > 1) {
bool ok = false;
@@ -1436,36 +1506,35 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
*
* Here we do some magic to distinguish such cases.
*/
- if (ELEM(token[1], 'X', 'Y', 'Z') || ELEM(token[1], 'R', 'G', 'B') ||
- ELEM(token[1], 'U', 'V', 'A')) {
- echan->chan_id = token[1];
+ const char chan_id = BLI_toupper_ascii(channelname[1]);
+ if (ELEM(chan_id, 'X', 'Y', 'Z', 'R', 'G', 'B', 'U', 'V', 'A')) {
+ echan->chan_id = chan_id;
ok = true;
}
}
- else if (BLI_strcaseeq(token, "red")) {
+ else if (BLI_strcaseeq(channelname, "red")) {
echan->chan_id = 'R';
ok = true;
}
- else if (BLI_strcaseeq(token, "green")) {
+ else if (BLI_strcaseeq(channelname, "green")) {
echan->chan_id = 'G';
ok = true;
}
- else if (BLI_strcaseeq(token, "blue")) {
+ else if (BLI_strcaseeq(channelname, "blue")) {
echan->chan_id = 'B';
ok = true;
}
- else if (BLI_strcaseeq(token, "alpha")) {
+ else if (BLI_strcaseeq(channelname, "alpha")) {
echan->chan_id = 'A';
ok = true;
}
- else if (BLI_strcaseeq(token, "depth")) {
+ else if (BLI_strcaseeq(channelname, "depth")) {
echan->chan_id = 'Z';
ok = true;
}
if (ok == false) {
- BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
- printf("multilayer read: unknown channel token: %s\n", tokenbuf);
+ printf("multilayer read: unknown channel token: %s\n", channelname);
return 0;
}
}
@@ -2098,19 +2167,122 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
}
}
-void imb_initopenexr(void)
+struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
+ const int UNUSED(flags),
+ const size_t max_thumb_size,
+ char colorspace[],
+ size_t *r_width,
+ size_t *r_height)
{
- int num_threads = BLI_system_thread_count();
+ IStream *stream = nullptr;
+ Imf::RgbaInputFile *file = nullptr;
+
+ /* OpenExr uses exceptions for error-handling. */
+ try {
- setGlobalThreadCount(num_threads);
+ /* The memory-mapped stream is faster, but don't use for huge files as it requires contiguous
+ * address space and we are processing multiple files at once (typically one per processor
+ * core). The 100 MB limit here is arbitrary, but seems reasonable and conservative. */
+ if (BLI_file_size(filepath) < 100 * 1024 * 1024) {
+ stream = new IMMapStream(filepath);
+ }
+ else {
+ stream = new IFileStream(filepath);
+ }
+
+ /* imb_initopenexr() creates a global pool of worker threads. But we thumbnail multiple images
+ * at once, and by default each file will attempt to use the entire pool for itself, stalling
+ * the others. So each thumbnail should use a single thread of the pool. */
+ file = new RgbaInputFile(*stream, 1);
+
+ if (!file->isComplete()) {
+ return nullptr;
+ }
+
+ Imath::Box2i dw = file->dataWindow();
+ int source_w = dw.max.x - dw.min.x + 1;
+ int source_h = dw.max.y - dw.min.y + 1;
+ *r_width = source_w;
+ *r_height = source_h;
+
+ /* If there is an embedded thumbnail, return that instead of making a new one. */
+ if (file->header().hasPreviewImage()) {
+ const Imf::PreviewImage &preview = file->header().previewImage();
+ ImBuf *ibuf = IMB_allocFromBuffer(
+ (unsigned int *)preview.pixels(), nullptr, preview.width(), preview.height(), 4);
+ delete file;
+ delete stream;
+ IMB_flipy(ibuf);
+ return ibuf;
+ }
+
+ /* Create a new thumbnail. */
+
+ if (colorspace && colorspace[0]) {
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
+ }
+
+ float scale_factor = MIN2((float)max_thumb_size / (float)source_w,
+ (float)max_thumb_size / (float)source_h);
+ int dest_w = (int)(source_w * scale_factor);
+ int dest_h = (int)(source_h * scale_factor);
+
+ struct ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rectfloat);
+
+ /* A single row of source pixels. */
+ Imf::Array<Imf::Rgba> pixels(source_w);
+
+ /* Loop through destination thumbnail rows. */
+ for (int h = 0; h < dest_h; h++) {
+
+ /* Load the single source row that corresponds with destination row. */
+ int source_y = (int)((float)h / scale_factor) + dw.min.y;
+ file->setFrameBuffer(&pixels[0] - dw.min.x - source_y * source_w, 1, source_w);
+ file->readPixels(source_y);
+
+ for (int w = 0; w < dest_w; w++) {
+ /* For each destination pixel find single corresponding source pixel. */
+ int source_x = (int)(MIN2((w / scale_factor), dw.max.x - 1));
+ float *dest_px = &ibuf->rect_float[(h * dest_w + w) * 4];
+ dest_px[0] = pixels[source_x].r;
+ dest_px[1] = pixels[source_x].g;
+ dest_px[2] = pixels[source_x].b;
+ dest_px[3] = pixels[source_x].a;
+ }
+ }
+
+ if (file->lineOrder() == INCREASING_Y) {
+ IMB_flipy(ibuf);
+ }
+
+ delete file;
+ delete stream;
+
+ return ibuf;
+ }
+
+ catch (const std::exception &exc) {
+ std::cerr << exc.what() << std::endl;
+ delete file;
+ delete stream;
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+void imb_initopenexr(void)
+{
+ /* In a multithreaded program, staticInitialize() must be called once during startup, before the
+ * program accesses any other functions or classes in the IlmImf library. */
+ Imf::staticInitialize();
+ Imf::setGlobalThreadCount(BLI_system_thread_count());
}
void imb_exitopenexr(void)
{
- /* Tells OpenEXR to free thread pool, also ensures there is no running
- * tasks.
- */
- setGlobalThreadCount(0);
+ /* Tells OpenEXR to free thread pool, also ensures there is no running tasks. */
+ Imf::setGlobalThreadCount(0);
}
} /* export "C" */
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index c02b03dbe6c..40a724c9f42 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -26,6 +26,13 @@ bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char *colorspace);
+struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
+ int flags,
+ size_t max_thumb_size,
+ char colorspace[],
+ size_t *r_width,
+ size_t *r_height);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index 805a7e8d687..4b433836767 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -189,21 +189,21 @@ ImBuf *IMB_loadifffile(
return ibuf;
}
-static void imb_cache_filename(char *filename, const char *name, int flags)
+static void imb_cache_filename(char *filepath, const char *name, int flags)
{
/* read .tx instead if it exists and is not older */
if (flags & IB_tilecache) {
- BLI_strncpy(filename, name, IMB_FILENAME_SIZE);
- if (!BLI_path_extension_replace(filename, IMB_FILENAME_SIZE, ".tx")) {
+ BLI_strncpy(filepath, name, IMB_FILENAME_SIZE);
+ if (!BLI_path_extension_replace(filepath, IMB_FILENAME_SIZE, ".tx")) {
return;
}
- if (BLI_file_older(name, filename)) {
+ if (BLI_file_older(name, filepath)) {
return;
}
}
- BLI_strncpy(filename, name, IMB_FILENAME_SIZE);
+ BLI_strncpy(filepath, name, IMB_FILENAME_SIZE);
}
ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 52756891f21..2a0baaf6172 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -702,21 +702,21 @@ int *IMB_stereo3d_from_rect(const ImageFormatData *im_format,
int *rect_left,
int *rect_right)
{
- int *r_rect;
+ int *rect_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+ rect_result = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ &s3d_data, is_float, x, y, channels, rect_left, rect_right, rect_result, NULL, NULL, NULL);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rect(rect_result, &im_format->stereo3d_format, x, y, channels);
- return r_rect;
+ return rect_result;
}
float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
@@ -726,21 +726,30 @@ float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
float *rectf_left,
float *rectf_right)
{
- float *r_rectf;
+ float *rectf_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+ rectf_result = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
- imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_data_init(&s3d_data,
+ is_float,
+ x,
+ y,
+ channels,
+ NULL,
+ NULL,
+ NULL,
+ rectf_left,
+ rectf_right,
+ rectf_result);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rectf(rectf_result, &im_format->stereo3d_format, x, y, channels);
- return r_rectf;
+ return rectf_result;
}
ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 51951aa9605..6f39009d38d 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -30,7 +30,6 @@
#include "IMB_thumbs.h"
#include <ctype.h>
-#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -466,27 +465,27 @@ static ImBuf *thumb_create_or_fail(const char *file_path,
return img;
}
-ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+ImBuf *IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, ImBuf *img)
{
char uri[URI_MAX] = "";
char thumb_name[40];
- if (!uri_from_filename(path, uri)) {
+ if (!uri_from_filename(filepath, uri)) {
return NULL;
}
thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
return thumb_create_ex(
- path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
+ filepath, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
}
-ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
+ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
ImBuf *img = NULL;
- if (!uri_from_filename(path, uri)) {
+ if (!uri_from_filename(filepath, uri)) {
return NULL;
}
if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
@@ -496,16 +495,16 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
return img;
}
-void IMB_thumb_delete(const char *path, ThumbSize size)
+void IMB_thumb_delete(const char *filepath, ThumbSize size)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
- if (!uri_from_filename(path, uri)) {
+ if (!uri_from_filename(filepath, uri)) {
return;
}
if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
- if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) {
+ if (BLI_path_ncmp(filepath, thumb, sizeof(thumb)) == 0) {
return;
}
if (BLI_exists(thumb)) {
@@ -514,7 +513,7 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
}
}
-ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
char thumb_name[40];
@@ -526,7 +525,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
ImBuf *img = NULL;
char *blen_group = NULL, *blen_id = NULL;
- path = file_path = org_path;
+ path = file_path = filepath;
if (source == THB_SOURCE_BLEND) {
if (BLO_library_path_explode(path, path_buff, &blen_group, &blen_id)) {
if (blen_group) {
diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c
index 7a1c4947c99..c0a33f608a5 100644
--- a/source/blender/imbuf/intern/thumbs_font.c
+++ b/source/blender/imbuf/intern/thumbs_font.c
@@ -41,7 +41,7 @@ void IMB_thumb_ensure_translations(void)
}
}
-struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y)
+struct ImBuf *IMB_thumb_load_font(const char *filepath, unsigned int x, unsigned int y)
{
const int font_size = y / 4;
@@ -60,7 +60,7 @@ struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned
/* draw with full alpha */
font_color[3] = 1.0f;
- BLF_thumb_preview(filename,
+ BLF_thumb_preview(filepath,
thumb_str,
i18n_thumb_str,
ARRAY_SIZE(thumb_str),
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 1372aa31713..2f13ef409e3 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -8,15 +8,15 @@
* Provides TIFF file loading and saving for Blender, via libtiff.
*
* The task of loading is complicated somewhat by the fact that Blender has
- * already loaded the file into a memory buffer. libtiff is not well
+ * already loaded the file into a memory buffer. libtiff is not well
* configured to handle files in memory, so a client wrapper is written to
- * surround the memory and turn it into a virtual file. Currently, reading
- * of TIFF files is done using libtiff's RGBAImage support. This is a
+ * surround the memory and turn it into a virtual file. Currently, reading
+ * of TIFF files is done using libtiff's RGBAImage support. This is a
* high-level routine that loads all images as 32-bit RGBA, handling all the
* required conversions between many different TIFF types internally.
*
* Saving supports RGB, RGBA and BW (gray-scale) images correctly, with
- * 8 bits per channel in all cases. The "deflate" compression algorithm is
+ * 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -151,8 +151,8 @@ static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
/**
* Writes data to an in-memory TIFF file.
*
- * NOTE: The current Blender implementation should not need this function. It
- * is simply a stub.
+ * NOTE: The current Blender implementation should not need this function.
+ * It is simply a stub.
*/
static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
{
@@ -176,7 +176,7 @@ static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
* error).
*
* \return Resulting offset location within the file, measured in bytes from
- * the beginning of the file. (-1) indicates an error.
+ * the beginning of the file. (-1) indicates an error.
*/
static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
{
@@ -215,8 +215,8 @@ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
* Closes (virtually) an in-memory TIFF file.
*
* NOTE: All this function actually does is sets the data pointer within the
- * TIFF file to NULL. That should trigger assertion errors if attempts
- * are made to access the file after that point. However, no such
+ * TIFF file to NULL. That should trigger assertion errors if attempts
+ * are made to access the file after that point. However, no such
* attempts should ever be made (in theory).
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
@@ -734,7 +734,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
int x, y, from_i, to_i, i;
int compress_mode = COMPRESSION_NONE;
- /* check for a valid number of bytes per pixel. Like the PNG writer,
+ /* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
* to gray, RGB, RGBA respectively. */
samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
@@ -838,7 +838,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
- /* copy pixel data. While copying, we flip the image vertically. */
+ /* copy pixel data. While copying, we flip the image vertically. */
const int channels_in_float = ibuf->channels ? ibuf->channels : 4;
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index edb47c8c7ce..1499c1071e3 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -293,30 +293,37 @@ class Sampler {
NumChannels == 4) {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
- bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
+ bilinear_interpolation_color_fl(source, nullptr, r_sample.data(), wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_NEAREST &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
- nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ nearest_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
- bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ bilinear_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) {
- BLI_bilinear_interpolation_wrap_fl(
- source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
+ BLI_bilinear_interpolation_wrap_fl(source->rect_float,
+ r_sample.data(),
+ source->x,
+ source->y,
+ NumChannels,
+ u,
+ v,
+ true,
+ true);
}
else {
const float wrapped_u = uv_wrapper.modify_u(source, u);
const float wrapped_v = uv_wrapper.modify_v(source, v);
BLI_bilinear_interpolation_fl(source->rect_float,
- &r_sample[0],
+ r_sample.data(),
source->x,
source->y,
NumChannels,
@@ -390,11 +397,11 @@ class ChannelConverter {
BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
- copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
DestinationNumChannels == 4) {
- copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
DestinationNumChannels == 4) {
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 45b50c866fe..ffa989a29b4 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -390,14 +390,3 @@ bool IMB_isanim(const char *filepath)
return (type && type != ANIM_SEQUENCE);
}
-
-bool IMB_isfloat(const ImBuf *ibuf)
-{
- const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
- if (type != NULL) {
- if (type->flag & IM_FTYPE_FLOAT) {
- return true;
- }
- }
- return false;
-}
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 5abbc84b0ea..5feb0ceb515 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -28,17 +28,30 @@ static void imb_gpu_get_format(const ImBuf *ibuf,
eGPUTextureFormat *r_texture_format)
{
const bool float_rect = (ibuf->rect_float != NULL);
- const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
- !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
-
- *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
if (float_rect) {
- *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+ /* Float. */
+ const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
}
else {
- *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* Non-color data or scene linear, just store buffer as is. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_RGBA8;
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ /* sRGB, store as byte texture that the GPU can decode directly. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_SRGB8_A8;
+ }
+ else {
+ /* Other colorspace, store as half float texture to avoid precision loss. */
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = GPU_RGBA16F;
+ }
}
}
@@ -74,7 +87,6 @@ static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *
static void *imb_gpu_get_data(const ImBuf *ibuf,
const bool do_rescale,
const int rescale_size[2],
- const bool compress_as_srgb,
const bool store_premultiplied,
bool *r_freedata)
{
@@ -99,14 +111,16 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
}
}
else {
- /* Byte image is in original colorspace from the file. If the file is sRGB
- * scene linear, or non-color data no conversion is needed. Otherwise we
- * compress as scene linear + sRGB transfer function to avoid precision loss
- * in common cases.
+ /* Byte image is in original colorspace from the file, and may need conversion.
*
* We must also convert to premultiplied for correct texture interpolation
* and consistency with float images. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__);
*r_freedata = freedata = true;
@@ -120,7 +134,24 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
* zero alpha areas, and appears generally closer to what game engines that we
* want to be compatible with do. */
IMB_colormanagement_imbuf_to_byte_texture(
- (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
+ (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
+ }
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
+ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+ *r_freedata = freedata = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ /* Texture storage of images is defined by the alpha mode of the image. The
+ * downside of this is that there can be artifacts near alpha edges. However,
+ * this allows us to use sRGB texture formats and preserves color values in
+ * zero alpha areas, and appears generally closer to what game engines that we
+ * want to be compatible with do. */
+ IMB_colormanagement_imbuf_to_float_texture(
+ (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
}
}
@@ -154,7 +185,7 @@ GPUTexture *IMB_touch_gpu_texture(
GPUTexture *tex;
if (layers > 0) {
- tex = GPU_texture_create_2d_array(name, w, h, layers, 1, tex_format, NULL);
+ tex = GPU_texture_create_2d_array(name, w, h, layers, 9999, tex_format, NULL);
}
else {
tex = GPU_texture_create_2d(name, w, h, 9999, tex_format, NULL);
@@ -181,10 +212,9 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
/* Update Texture. */
GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
@@ -197,12 +227,10 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
GPUTexture *IMB_create_gpu_texture(const char *name,
ImBuf *ibuf,
bool use_high_bitdepth,
- bool use_premult,
- bool limit_gl_texture_size)
+ bool use_premult)
{
GPUTexture *tex = NULL;
- int size[2] = {GPU_texture_size_with_limit(ibuf->x, limit_gl_texture_size),
- GPU_texture_size_with_limit(ibuf->y, limit_gl_texture_size)};
+ int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)};
bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
#ifdef WITH_DDS
@@ -240,7 +268,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
/* Create Texture. */
@@ -252,7 +279,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
do_rescale = true;
}
BLI_assert(tex != NULL);
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
GPU_texture_update(tex, data_format, data);
GPU_texture_anisotropic_filter(tex, true);
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 56c9384a330..d2c0b61c1c5 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -19,11 +19,6 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-static bool prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
-{
- return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
-}
-
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
{
errno = 0;
@@ -36,34 +31,22 @@ bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
ibuf->flags = flags;
const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
- if (type != NULL) {
- if (type->save != NULL) {
- prepare_write_imbuf(type, ibuf);
- return type->save(ibuf, filepath, flags);
- }
+ if (type == NULL || type->save == NULL) {
+ fprintf(stderr, "Couldn't save picture.\n");
+ return false;
}
- fprintf(stderr, "Couldn't save picture.\n");
-
- return false;
-}
-
-bool IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
-{
- bool changed = false;
-
- if (isfloat) {
- /* pass */
- }
- else {
+ /* If writing byte image from float buffer, create a byte buffer for writing.
+ *
+ * For color managed image writing, IMB_colormanagement_imbuf_for_write should
+ * have already created this byte buffer. This is a basic fallback for other
+ * cases where we do not have a specific desired output colorspace. */
+ if (!(type->flag & IM_FTYPE_FLOAT)) {
if (ibuf->rect == NULL && ibuf->rect_float) {
ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
IMB_rect_from_float(ibuf);
- if (ibuf->rect != NULL) {
- changed = true;
- }
}
}
- return changed;
+ return type->save(ibuf, filepath, flags);
}