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:
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r--source/blender/imbuf/IMB_imbuf.h15
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h2
-rw-r--r--source/blender/imbuf/IMB_thumbs.h10
-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.c6
-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.c211
-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.c16
-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.c117
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp185
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h7
-rw-r--r--source/blender/imbuf/intern/readimage.c67
-rw-r--r--source/blender/imbuf/intern/thumbs.c71
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c4
-rw-r--r--source/blender/imbuf/intern/util.c11
-rw-r--r--source/blender/imbuf/intern/writeimage.c37
26 files changed, 686 insertions, 321 deletions
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 0390df06052..7493fa3e4af 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -109,6 +109,14 @@ struct ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[I
/**
*
+ * \attention Defined in readimage.c
+ */
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE]);
+
+/**
+ *
* \attention Defined in allocimbuf.c
*/
void IMB_freeImBuf(struct ImBuf *ibuf);
@@ -522,7 +530,6 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
-bool IMB_prepare_write_ImBuf(bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -546,12 +553,6 @@ bool IMB_isanim(const char *filepath);
int imb_get_anim_type(const char *filepath);
/**
- *
- * \attention Defined in util.c
- */
-bool IMB_isfloat(const struct ImBuf *ibuf);
-
-/**
* Test if color-space conversions of pixels in buffer need to take into account alpha.
*/
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 934163846e4..16cf0e2125e 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -47,7 +47,7 @@ typedef struct DDSData {
* Also; add new variables to the end to save pain!
*/
-/* Warning: Keep explicit value assignments here,
+/* WARNING: Keep explicit value assignments here,
* this file is included in areas where not all format defines are set
* (e.g. intern/dds only get WITH_DDS, even if TIFF, HDR etc are also defined).
* See T46524. */
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index 623a3b2b5f4..b55a6f653b8 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -50,7 +50,7 @@ typedef enum ThumbSource {
/**
* Create thumbnail for file and returns new imbuf for thumbnail.
*/
-struct ImBuf *IMB_thumb_create(const char *path,
+struct ImBuf *IMB_thumb_create(const char *filepath,
ThumbSize size,
ThumbSource source,
struct ImBuf *img);
@@ -58,17 +58,17 @@ struct ImBuf *IMB_thumb_create(const char *path,
/**
* Read thumbnail for file and returns new imbuf for thumbnail.
*/
-struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size);
+struct ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size);
/**
* Delete all thumbs for the file.
*/
-void IMB_thumb_delete(const char *path, ThumbSize size);
+void IMB_thumb_delete(const char *filepath, ThumbSize size);
/**
* Create the thumb if necessary and manage failed and old thumbs.
*/
-struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
+struct ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source);
/**
* Create the necessary directories to store the thumbnails.
@@ -85,7 +85,7 @@ struct ImBuf *IMB_thumb_load_blend(const char *blen_path,
/**
* Special function for previewing fonts.
*/
-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);
bool IMB_thumb_load_font_get_hash(char *r_hash);
void IMB_thumb_clear_translations(void);
void IMB_thumb_ensure_translations(void);
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 31f8b3a9505..67d1aefeacb 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -36,6 +36,17 @@ typedef struct ImFileType {
char colorspace[IM_MAX_SPACE]);
/** Load an image from a file. */
struct ImBuf *(*load_filepath)(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
+ /**
+ * Load/Create a thumbnail image from a filepath. `max_thumb_size` is maximum size of either
+ * dimension, so can return less on either or both. Should, if possible and performant, return
+ * 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,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height);
/** Save to a file (or memory if #IB_mem is set in `flags` and the format supports it). */
bool (*save)(struct ImBuf *ibuf, const char *filepath, int flags);
void (*load_tile)(struct ImBuf *ibuf,
@@ -143,6 +154,12 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height);
/** \} */
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..6448d6cd76a 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,
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 670394e1a1a..d4c9e78a299 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -2451,68 +2451,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);
-
- 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 to a file format that needs a linear float buffer. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
- if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
- ibuf->rect = MEM_dupallocN(ibuf->rect);
- ibuf->mall |= IB_rect;
- }
+ /* 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_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);
@@ -2526,67 +2535,93 @@ 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;
-
- IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
- colormanaged_ibuf->x,
- colormanaged_ibuf->y,
- colormanaged_ibuf->channels,
- from_colorspace,
- to_colorspace,
- false);
- }
- }
+ /* This conversion always goes to scene linear. */
+ from_colorspace = global_role_scene_linear;
+ }
- if (colormanaged_ibuf != ibuf) {
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ 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);
+ }
+ }
+ }
}
return colormanaged_ibuf;
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 548bc9e120c..92fa980cd7f 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -33,6 +33,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_jpeg,
.load = imb_load_jpeg,
.load_filepath = NULL,
+ .load_filepath_thumbnail = imb_thumbnail_jpeg,
.save = imb_savejpeg,
.load_tile = NULL,
.flag = 0,
@@ -45,6 +46,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_png,
.load = imb_loadpng,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savepng,
.load_tile = NULL,
.flag = 0,
@@ -57,6 +59,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_bmp,
.load = imb_bmp_decode,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savebmp,
.load_tile = NULL,
.flag = 0,
@@ -69,6 +72,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_targa,
.load = imb_loadtarga,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savetarga,
.load_tile = NULL,
.flag = 0,
@@ -81,6 +85,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_iris,
.load = imb_loadiris,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_saveiris,
.load_tile = NULL,
.flag = 0,
@@ -94,6 +99,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_dpx,
.load = imb_load_dpx,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_dpx,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -106,6 +112,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_cineon,
.load = imb_load_cineon,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_cineon,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -120,6 +127,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_tiff,
.load = imb_loadtiff,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savetiff,
.load_tile = imb_loadtiletiff,
.flag = 0,
@@ -134,6 +142,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_hdr,
.load = imb_loadhdr,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savehdr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -148,6 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_openexr,
.load = imb_load_openexr,
.load_filepath = NULL,
+ .load_filepath_thumbnail = imb_load_filepath_thumbnail_openexr,
.save = imb_save_openexr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -162,6 +172,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_jp2,
.load = imb_load_jp2,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_jp2,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -176,6 +187,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_dds,
.load = imb_load_dds,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = NULL,
.load_tile = NULL,
.flag = 0,
@@ -190,6 +202,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_photoshop,
.load = NULL,
.load_filepath = imb_load_photoshop,
+ .load_filepath_thumbnail = NULL,
.save = NULL,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -204,6 +217,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_webp,
.load = imb_loadwebp,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savewebp,
.load_tile = NULL,
.flag = 0,
@@ -211,7 +225,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
},
#endif
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0},
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
};
const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[ARRAY_SIZE(IMB_FILE_TYPES) - 1];
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 6fb1fb52153..cffa61977f7 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -39,7 +39,11 @@ static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
static void term_source(j_decompress_ptr cinfo);
static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, size_t size);
static boolean handle_app1(j_decompress_ptr cinfo);
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+ int flags,
+ int max_size,
+ size_t *r_width,
+ size_t *r_height);
static const uchar jpeg_default_quality = 75;
static uchar ibuf_quality;
@@ -246,7 +250,11 @@ static boolean handle_app1(j_decompress_ptr cinfo)
return true;
}
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags)
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+ int flags,
+ int max_size,
+ size_t *r_width,
+ size_t *r_height)
{
JSAMPARRAY row_pointer;
JSAMPLE *buffer = NULL;
@@ -264,16 +272,34 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) {
- x = cinfo->image_width;
- y = cinfo->image_height;
depth = cinfo->num_components;
if (cinfo->jpeg_color_space == JCS_YCCK) {
cinfo->out_color_space = JCS_CMYK;
}
+ if (r_width) {
+ *r_width = cinfo->image_width;
+ }
+ if (r_height) {
+ *r_height = cinfo->image_height;
+ }
+
+ 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. */
+ 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)));
+ cinfo->dct_method = JDCT_FASTEST;
+ cinfo->dither_mode = JDITHER_ORDERED;
+ }
+
jpeg_start_decompress(cinfo);
+ x = cinfo->output_width;
+ y = cinfo->output_height;
+
if (flags & IB_test) {
jpeg_abort_decompress(cinfo);
ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
@@ -449,11 +475,92 @@ ImBuf *imb_load_jpeg(const unsigned char *buffer,
jpeg_create_decompress(cinfo);
memory_source(cinfo, buffer, size);
- ibuf = ibJpegImageFromCinfo(cinfo, flags);
+ ibuf = ibJpegImageFromCinfo(cinfo, flags, -1, NULL, NULL);
+
+ return ibuf;
+}
+
+/* Defines for JPEG Header markers and segment size. */
+#define JPEG_MARKER_MSB (0xFF)
+#define JPEG_MARKER_SOI (0xD8)
+#define JPEG_MARKER_APP1 (0xE1)
+#define JPEG_APP1_MAX (1 << 16)
+
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height)
+{
+ struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
+ struct my_error_mgr jerr;
+ FILE *infile = NULL;
+
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+
+ cinfo->err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = jpeg_error;
+
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(cinfo);
+ return NULL;
+ }
+
+ if ((infile = BLI_fopen(filepath, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filepath);
+ return NULL;
+ }
+
+ /* If file contains an embedded thumbnail, let's return that instead. */
+
+ 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). */
+ unsigned int i = JPEG_APP1_MAX;
+ /* 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--)
+ ;
+ if (i > 0 && !feof(infile)) {
+ /* We found a JPEG thumbnail inside this image. */
+ ImBuf *ibuf = NULL;
+ uchar *buffer = MEM_callocN(JPEG_APP1_MAX, "thumbbuffer");
+ /* Just put SOI directly in buffer rather than seeking back 2 bytes. */
+ buffer[0] = JPEG_MARKER_MSB;
+ buffer[1] = JPEG_MARKER_SOI;
+ if (fread(buffer + 2, JPEG_APP1_MAX - 2, 1, infile) == 1) {
+ ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, colorspace);
+ }
+ MEM_SAFE_FREE(buffer);
+ if (ibuf) {
+ fclose(infile);
+ return ibuf;
+ }
+ }
+ }
+
+ /* No embedded thumbnail found, so let's create a new one. */
+
+ fseek(infile, 0, SEEK_SET);
+ jpeg_create_decompress(cinfo);
+
+ jpeg_stdio_src(cinfo, infile);
+ ImBuf *ibuf = ibJpegImageFromCinfo(cinfo, flags, max_thumb_size, r_width, r_height);
+ fclose(infile);
return ibuf;
}
+#undef JPEG_MARKER_MSB
+#undef JPEG_MARKER_SOI
+#undef JPEG_MARKER_APP1
+#undef JPEG_APP1_MAX
+
static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
{
JSAMPLE *buffer = NULL;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 66ee3cf2c26..54ef5438c23 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 == NULL) {
+ throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed");
+ }
+ close(file);
+ _exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file);
+ }
+
+ ~IMMapStream()
+ {
+ 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 {
@@ -2099,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 {
+
+ /* 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(), NULL, 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;
+ }
+ }
- setGlobalThreadCount(num_threads);
+ 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..a62c87428b6 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,
+ const int flags,
+ const 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 df41c0ca757..4b433836767 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -22,6 +22,8 @@
#include "IMB_filetype.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
+#include "IMB_thumbs.h"
#include "imbuf.h"
#include "IMB_colormanagement.h"
@@ -187,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])
@@ -234,6 +236,61 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
return ibuf;
}
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+ size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE])
+{
+ const ImFileType *type = IMB_file_type_from_ftype(IMB_ispic_type(filepath));
+ if (type == NULL) {
+ return NULL;
+ }
+
+ ImBuf *ibuf = NULL;
+ int flags = IB_rect | IB_metadata;
+ /* Size of the original image. */
+ size_t width = 0;
+ size_t height = 0;
+
+ char effective_colorspace[IM_MAX_SPACE] = "";
+ if (colorspace) {
+ BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
+ }
+
+ if (type->load_filepath_thumbnail) {
+ ibuf = type->load_filepath_thumbnail(
+ filepath, flags, max_thumb_size, colorspace, &width, &height);
+ }
+ else {
+ /* Skip images of other types if over 100MB. */
+ const size_t file_size = BLI_file_size(filepath);
+ if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
+ return NULL;
+ }
+ ibuf = IMB_loadiffname(filepath, flags, colorspace);
+ if (ibuf) {
+ width = ibuf->x;
+ height = ibuf->y;
+ }
+ }
+
+ if (ibuf) {
+ imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
+
+ if (width > 0 && height > 0) {
+ /* Save dimensions of original image into the thumbnail metadata. */
+ char cwidth[40];
+ char cheight[40];
+ SNPRINTF(cwidth, "%zu", width);
+ SNPRINTF(cheight, "%zu", height);
+ IMB_metadata_ensure(&ibuf->metadata);
+ IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Width", cwidth);
+ IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Height", cheight);
+ }
+ }
+
+ return ibuf;
+}
+
ImBuf *IMB_testiffname(const char *filepath, int flags)
{
ImBuf *ibuf;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 37734ebacb2..f2c9c82fa66 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -318,12 +318,8 @@ static ImBuf *thumb_create_ex(const char *file_path,
char tpath[FILE_MAX];
char tdir[FILE_MAX];
char temp[FILE_MAX];
- char mtime[40] = "0"; /* in case we can't stat the file */
- char cwidth[40] = "0"; /* in case images have no data */
- char cheight[40] = "0";
+ char mtime[40] = "0"; /* in case we can't stat the file */
short tsize = 128;
- short ex, ey;
- float scaledx, scaledy;
BLI_stat_t info;
switch (size) {
@@ -340,15 +336,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
return NULL; /* unknown size */
}
- /* exception, skip images over 100mb */
- if (source == THB_SOURCE_IMAGE) {
- const size_t file_size = BLI_file_size(file_path);
- if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
- // printf("file too big: %d, skipping %s\n", (int)size, file_path);
- return NULL;
- }
- }
-
if (get_thumb_dir(tdir, size)) {
BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
// thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
@@ -368,7 +355,7 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (img == NULL) {
switch (source) {
case THB_SOURCE_IMAGE:
- img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL);
+ img = IMB_thumb_load_image(file_path, tsize, NULL);
break;
case THB_SOURCE_BLEND:
img = IMB_thumb_load_blend(file_path, blen_group, blen_id);
@@ -385,8 +372,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
- BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x);
- BLI_snprintf(cheight, sizeof(cheight), "%d", img->y);
}
}
else if (THB_SOURCE_MOVIE == source) {
@@ -411,28 +396,20 @@ static ImBuf *thumb_create_ex(const char *file_path,
return NULL;
}
- if (img->x > img->y) {
- scaledx = (float)tsize;
- scaledy = ((float)img->y / (float)img->x) * tsize;
- }
- else {
- scaledy = (float)tsize;
- scaledx = ((float)img->x / (float)img->y) * tsize;
- }
- /* Scaling down must never assign zero width/height, see: T89868. */
- ex = MAX2(1, (short)scaledx);
- ey = MAX2(1, (short)scaledy);
-
- /* save some time by only scaling byte buf */
- if (img->rect_float) {
- if (img->rect == NULL) {
- IMB_rect_from_float(img);
+ if (img->x > tsize || img->y > tsize) {
+ float scale = MIN2((float)tsize / (float)img->x, (float)tsize / (float)img->y);
+ /* Scaling down must never assign zero width/height, see: T89868. */
+ short ex = MAX2(1, (short)(img->x * scale));
+ short ey = MAX2(1, (short)(img->y * scale));
+ /* Save some time by only scaling byte buf */
+ if (img->rect_float) {
+ if (img->rect == NULL) {
+ IMB_rect_from_float(img);
+ }
+ imb_freerectfloatImBuf(img);
}
-
- imb_freerectfloatImBuf(img);
+ IMB_scaleImBuf(img, ex, ey);
}
-
- IMB_scaleImBuf(img, ex, ey);
}
BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri);
IMB_metadata_ensure(&img->metadata);
@@ -443,10 +420,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (use_hash) {
IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash);
}
- if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
- IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth);
- IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight);
- }
img->ftype = IMB_FTYPE_PNG;
img->planes = 32;
@@ -493,27 +466,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)) {
@@ -523,16 +496,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)) {
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/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/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);
}