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/intern')
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h7
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h8
-rw-r--r--source/blender/imbuf/intern/IMB_metadata.h10
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c6
-rw-r--r--source/blender/imbuf/intern/anim_movie.c25
-rw-r--r--source/blender/imbuf/intern/bmp.c2
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c2
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c104
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h24
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h3
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp6
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h12
-rw-r--r--source/blender/imbuf/intern/dds/Stream.h3
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp2
-rw-r--r--source/blender/imbuf/intern/divers.c86
-rw-r--r--source/blender/imbuf/intern/filetype.c12
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/imageprocess.c63
-rw-r--r--source/blender/imbuf/intern/indexer.c31
-rw-r--r--source/blender/imbuf/intern/metadata.c7
-rw-r--r--source/blender/imbuf/intern/moviecache.c4
-rw-r--r--source/blender/imbuf/intern/oiio/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp1148
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h45
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp56
-rw-r--r--source/blender/imbuf/intern/png.c19
-rw-r--r--source/blender/imbuf/intern/readimage.c10
-rw-r--r--source/blender/imbuf/intern/rectop.c18
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c1292
-rw-r--r--source/blender/imbuf/intern/targa.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c244
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c4
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c100
-rw-r--r--source/blender/imbuf/intern/tiff.c4
-rw-r--r--source/blender/imbuf/intern/util.c24
-rw-r--r--source/blender/imbuf/intern/writeimage.c40
40 files changed, 2883 insertions, 555 deletions
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index ed349e8f7eb..690ec813407 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -79,11 +79,7 @@
#endif
#ifdef WITH_REDCODE
-# ifdef _WIN32 /* on windows we use the one in extern instead */
-# include "libredcode/format.h"
-# else
-# include "libredcode/format.h"
-# endif
+# include "libredcode/format.h"
#endif
#include "IMB_imbuf_types.h"
@@ -194,6 +190,7 @@ struct anim {
struct anim_index *curr_idx[IMB_TC_MAX_SLOT];
char colorspace[64];
+ char suffix[64]; /* MAX_NAME - multiview */
};
#endif
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 9327c15c415..332878b6067 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -40,7 +40,7 @@ typedef struct ImFileType {
int (*is_a)(unsigned char *buf);
int (*is_a_filepath)(const char *name);
- int (*ftype)(struct ImFileType *type, struct ImBuf *ibuf);
+ int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf);
struct ImBuf *(*load)(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
struct ImBuf *(*load_filepath)(const char *name, int flags, char colorspace[IM_MAX_SPACE]);
int (*save)(struct ImBuf *ibuf, const char *name, int flags);
@@ -51,8 +51,8 @@ typedef struct ImFileType {
int default_save_role;
} ImFileType;
-extern ImFileType IMB_FILE_TYPES[];
-extern ImFileType *IMB_FILE_TYPES_LAST;
+extern const ImFileType IMB_FILE_TYPES[];
+extern const ImFileType *IMB_FILE_TYPES_LAST;
void imb_filetypes_init(void);
void imb_filetypes_exit(void);
@@ -88,7 +88,7 @@ int imb_savejp2(struct ImBuf *ibuf, const char *name, int flags);
/* jpeg */
int imb_is_a_jpeg(unsigned char *mem);
int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags);
-struct ImBuf *imb_load_jpeg (unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_load_jpeg(unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
/* bmp */
int imb_is_a_bmp(unsigned char *buf);
diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h
index 5d4a0028ee1..bc0b2c70ecb 100644
--- a/source/blender/imbuf/intern/IMB_metadata.h
+++ b/source/blender/imbuf/intern/IMB_metadata.h
@@ -47,16 +47,6 @@ struct ImBuf;
/* free blender ImMetaData struct */
void IMB_metadata_free(struct ImBuf *img);
-/** read the field from the image info into the field
- * \param img - the ImBuf that contains the image data
- * \param key - the key of the field
- * \param value - the data in the field, first one found with key is returned,
- * memory has to be allocated by user.
- * \param len - length of value buffer allocated by user.
- * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
- */
-bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len);
-
/** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create
* before calling this function.
* \param img - the ImBuf that contains the image data
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index b28d19e3e15..79f869968d3 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -210,6 +210,8 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf)
rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
+
IMB_freeImBuf(ibuf);
return rval;
@@ -465,10 +467,10 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
if (ibuf2 == NULL) return NULL;
if (flags & IB_rect)
- memcpy(ibuf2->rect, ibuf1->rect, x * y * sizeof(int));
+ memcpy(ibuf2->rect, ibuf1->rect, ((size_t)x) * y * sizeof(int));
if (flags & IB_rectfloat)
- memcpy(ibuf2->rect_float, ibuf1->rect_float, ibuf1->channels * x * y * sizeof(float));
+ memcpy(ibuf2->rect_float, ibuf1->rect_float, ((size_t)ibuf1->channels) * x * y * sizeof(float));
if (ibuf1->encodedbuffer) {
ibuf2->encodedbuffersize = ibuf1->encodedbuffersize;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index ffdecb793aa..e2d56d29726 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -99,13 +99,8 @@
#endif //WITH_FFMPEG
#ifdef WITH_REDCODE
-#ifdef _WIN32 /* on windows we use the ones in extern instead */
-#include "libredcode/format.h"
-#include "libredcode/codec.h"
-#else
-#include "libredcode/format.h"
-#include "libredcode/codec.h"
-#endif
+# include "libredcode/format.h"
+# include "libredcode/codec.h"
#endif
#include "IMB_colormanagement.h"
@@ -271,6 +266,8 @@ struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char
{
struct anim *anim;
+ BLI_assert(!BLI_path_is_rel(name));
+
anim = (struct anim *)MEM_callocN(sizeof(struct anim), "anim struct");
if (anim != NULL) {
if (colorspace) {
@@ -288,6 +285,11 @@ struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char
return(anim);
}
+void IMB_suffix_anim(struct anim *anim, const char *suffix)
+{
+ BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
+}
+
#ifdef WITH_AVI
static int startavi(struct anim *anim)
{
@@ -1422,11 +1424,18 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
}
bool IMB_anim_get_fps(struct anim *anim,
- short *frs_sec, float *frs_sec_base)
+ short *frs_sec, float *frs_sec_base, bool no_av_base)
{
if (anim->frs_sec) {
*frs_sec = anim->frs_sec;
*frs_sec_base = anim->frs_sec_base;
+#ifdef WITH_FFMPEG
+ if (no_av_base) {
+ *frs_sec_base /= AV_TIME_BASE;
+ }
+#else
+ UNUSED_VARS(no_av_base);
+#endif
return true;
}
return false;
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 19e655a0b3d..298e2da965f 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -136,7 +136,7 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
- bmp = mem + LITTLE_LONG(*(int*)(mem + 10));
+ bmp = mem + LITTLE_LONG(*(int *)(mem + 10));
if (CHECK_HEADER_FIELD_BMP(mem)) {
/* skip fileheader */
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 0e71206517e..fbce508af17 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -307,7 +307,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
printf(" Transfer characteristics: %d\n", cineon->element[i].transfer);
printf(" Packing: %d\n", cineon->element[i].packing);
printf(" Descriptor: %d\n", cineon->element[i].descriptor);
- printf(" Data offset: %u\n", cineon->element[i].dataOffset);
+ printf(" Data offset: %d\n", cineon->element[i].dataOffset);
printf(" Reference low data: %u\n", cineon->element[i].refLowData);
printf(" Reference low quantity: %f\n", cineon->element[i].refLowQuantity);
printf(" Reference high data: %u\n", cineon->element[i].refHighData);
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 23e5517bb09..562bdecb842 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -366,7 +366,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
printf(" Transfer characteristics: %d\n", dpx->element[i].transfer);
printf(" Packing: %d\n", dpx->element[i].packing);
printf(" Descriptor: %d\n", dpx->element[i].descriptor);
- printf(" Data offset: %u\n", dpx->element[i].dataOffset);
+ printf(" Data offset: %d\n", dpx->element[i].dataOffset);
printf(" Reference low data: %u\n", dpx->element[i].refLowData);
printf(" Reference low quantity: %f\n", dpx->element[i].refLowQuantity);
printf(" Reference high data: %u\n", dpx->element[i].refHighData);
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 1500f4282e5..5ec0a87890c 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -623,7 +623,7 @@ static int logImageElementGetData8(LogImageFile *logImage, LogImageElement logEl
for (y = 0; y < logImage->height; y++) {
/* 8 bits are 32-bits padded so we need to seek at each row */
if (logimage_fseek(logImage, logElement.dataOffset + y * rowLength, SEEK_SET) != 0) {
- if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset + y * rowLength);
+ if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset + y * (int)rowLength);
return 1;
}
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index 6b1435817d2..389e88a24de 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -52,8 +52,7 @@ enum format {
format_Cineon
};
-typedef struct LogImageElement
-{
+typedef struct LogImageElement {
int depth;
int bitsPerSample;
int dataOffset;
@@ -67,8 +66,7 @@ typedef struct LogImageElement
float maxValue; /* = 2^bitsPerSample - 1 (used internally, doesn't come from the file header) */
} LogImageElement;
-typedef struct LogImageFile
-{
+typedef struct LogImageFile {
/* specified in header */
int width;
int height;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 95e166b2f8b..a61204ea850 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -90,6 +90,11 @@ static int global_tot_display = 0;
static int global_tot_view = 0;
static int global_tot_looks = 0;
+/* Set to ITU-BT.709 / sRGB primaries weight. Brute force stupid, but only
+ * option with no colormanagement in place.
+ */
+static float luma_coefficients[3] = { 0.2126f, 0.7152f, 0.0722f };
+
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
* LOCK_COLORMANAGE can not be used since this mutex could be needed to
@@ -545,6 +550,9 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
colormanage_look_add(name, process_space, false);
}
+
+ /* Load luminance coefficients. */
+ OCIO_configGetDefaultLumaCoefs(config, luma_coefficients);
}
static void colormanage_free_config(void)
@@ -1222,6 +1230,34 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
return ibuf->rect_colorspace->name;
}
+/* Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
+
+float IMB_colormanagement_get_luminance(const float rgb[3])
+{
+ return dot_v3v3(luma_coefficients, rgb);
+}
+
+/* Byte equivalent of IMB_colormanagement_get_luminance(). */
+unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
+{
+ float rgbf[3];
+ float val;
+
+ rgb_uchar_to_float(rgbf, rgb);
+ val = dot_v3v3(luma_coefficients, rgbf);
+
+ return FTOCHAR(val);
+}
+
/*********************** Threaded display buffer transform routines *************************/
typedef struct DisplayBufferThread {
@@ -1270,8 +1306,8 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
float dither = ibuf->dither;
bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
- int offset = channels * start_line * ibuf->x;
- int display_buffer_byte_offset = DISPLAY_BUFFER_CHANNELS * start_line * ibuf->x;
+ size_t offset = ((size_t)channels) * start_line * ibuf->x;
+ size_t display_buffer_byte_offset = ((size_t)DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
memset(handle, 0, sizeof(DisplayBufferThread));
@@ -1308,7 +1344,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
int channels = handle->channels;
int width = handle->width;
- int buffer_size = channels * width * height;
+ size_t buffer_size = ((size_t)channels) * width * height;
bool is_data = handle->is_data;
bool is_data_display = handle->cm_processor->is_data_result;
@@ -1321,11 +1357,12 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
float *fp;
unsigned char *cp;
- int i;
+ const size_t i_last = ((size_t)width) * height;
+ size_t i;
/* first convert byte buffer to float, keep in image space */
for (i = 0, fp = linear_buffer, cp = byte_buffer;
- i < width * height;
+ i != i_last;
i++, fp += channels, cp += channels)
{
if (channels == 3) {
@@ -1404,7 +1441,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
else {
bool is_straight_alpha, predivide;
- float *linear_buffer = MEM_mallocN(channels * width * height * sizeof(float),
+ float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float),
"color conversion linear buffer");
display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
@@ -1431,14 +1468,15 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
if (display_buffer) {
- memcpy(display_buffer, linear_buffer, width * height * channels * sizeof(float));
+ memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float));
if (is_straight_alpha && channels == 4) {
- int i;
+ const size_t i_last = ((size_t)width) * height;
+ size_t i;
float *fp;
for (i = 0, fp = display_buffer;
- i < width * height;
+ i != i_last;
i++, fp += channels)
{
straight_to_premul_v4(fp);
@@ -1566,7 +1604,7 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
int width = init_data->width;
bool predivide = init_data->predivide;
- int offset = channels * start_line * width;
+ size_t offset = ((size_t)channels) * start_line * width;
memset(handle, 0, sizeof(ProcessorTransformThread));
@@ -1751,8 +1789,10 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in
if (processor) {
OCIO_PackedImageDesc *img;
- img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
- channels * sizeof(float), channels * sizeof(float) * width);
+ img = OCIO_createOCIO_PackedImageDesc(
+ buffer, width, height, channels, sizeof(float),
+ (size_t)channels * sizeof(float),
+ (size_t)channels * sizeof(float) * width);
if (predivide)
OCIO_processorApply_predivide(processor, img);
@@ -1912,7 +1952,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
if (do_colormanagement) {
bool make_byte = false;
- ImFileType *type;
+ const ImFileType *type;
/* 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
@@ -1954,7 +1994,7 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char
const ColorManagedDisplaySettings *display_settings)
{
ColormanageProcessor *cm_processor;
- size_t float_buffer_size = width * height * channels * sizeof(float);
+ size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
memcpy(display_buffer_float, buffer, float_buffer_size);
@@ -1979,7 +2019,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
const ColorManagedDisplaySettings *display_settings, void **cache_handle)
{
unsigned char *display_buffer;
- int buffer_size;
+ size_t buffer_size;
ColormanageCacheViewSettings cache_view_settings;
ColormanageCacheDisplaySettings cache_display_settings;
ColorManagedViewSettings default_view_settings;
@@ -2047,7 +2087,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
return display_buffer;
}
- buffer_size = DISPLAY_BUFFER_CHANNELS * ibuf->x * ibuf->y * sizeof(char);
+ buffer_size = DISPLAY_BUFFER_CHANNELS * ((size_t)ibuf->x) * ibuf->y * sizeof(char);
display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
colormanage_display_buffer_process(ibuf, display_buffer, applied_view_settings, display_settings);
@@ -2077,8 +2117,8 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *li
float *buffer;
ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
- buffer = MEM_callocN(channels * width * height * sizeof(float), "display transform temp buffer");
- memcpy(buffer, linear_buffer, channels * width * height * sizeof(float));
+ buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float), "display transform temp buffer");
+ memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float));
IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
@@ -2421,7 +2461,7 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->save && type->ftype(type, ibuf)) {
@@ -2622,14 +2662,14 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
if (!cm_processor)
channels = 4;
- display_buffer_float = MEM_callocN(channels * width * height * sizeof(float), "display buffer for dither");
+ display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float), "display buffer for dither");
}
if (cm_processor) {
for (y = ymin; y < ymax; y++) {
for (x = xmin; x < xmax; x++) {
- int display_index = (y * display_stride + x) * 4;
- int linear_index = ((y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
+ size_t display_index = ((size_t)y * display_stride + x) * 4;
+ size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
float pixel[4];
if (linear_buffer) {
@@ -2658,7 +2698,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
if (display_buffer_float) {
- int index = ((y - ymin) * width + (x - xmin)) * channels;
+ size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels;
if (channels == 4) {
copy_v4_v4(display_buffer_float + index, pixel);
@@ -2701,8 +2741,8 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
int i;
for (i = ymin; i < ymax; i++) {
- int byte_offset = (linear_stride * i + xmin) * 4;
- int display_offset = (display_stride * i + xmin) * 4;
+ size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4;
+ size_t display_offset = ((size_t)display_stride * i + xmin) * 4;
memcpy(display_buffer + display_offset, byte_buffer + byte_offset, 4 * sizeof(char) * width);
}
@@ -2710,7 +2750,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
if (display_buffer_float) {
- int display_index = (ymin * display_stride + xmin) * channels;
+ size_t display_index = ((size_t)ymin * display_stride + xmin) * channels;
IMB_buffer_byte_from_float(display_buffer + display_index, display_buffer_float, channels, dither,
IB_PROFILE_SRGB, IB_PROFILE_SRGB, true, width, height, display_stride, width);
@@ -2797,8 +2837,8 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
if (copy_display_to_byte_buffer && (unsigned char *) ibuf->rect != display_buffer) {
int y;
for (y = ymin; y < ymax; y++) {
- int index = y * buffer_width * 4;
- memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (xmax - xmin) * 4);
+ size_t index = (size_t)y * buffer_width * 4;
+ memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (size_t)(xmax - xmin) * 4);
}
}
}
@@ -2923,7 +2963,7 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- float *pixel = buffer + channels * (y * width + x);
+ float *pixel = buffer + channels * (((size_t)y) * width + x);
curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
}
@@ -2934,8 +2974,10 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
OCIO_PackedImageDesc *img;
/* apply OCIO processor */
- img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
- channels * sizeof(float), channels * sizeof(float) * width);
+ img = OCIO_createOCIO_PackedImageDesc(
+ buffer, width, height, channels, sizeof(float),
+ (size_t)channels * sizeof(float),
+ (size_t)channels * sizeof(float) * width);
if (predivide)
OCIO_processorApply_predivide(cm_processor->processor, img);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 7e5a1e504b8..6aae9c9817c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -64,8 +64,7 @@
#include <Stream.h>
/// DXT1 block.
-struct BlockDXT1
-{
+struct BlockDXT1 {
Color16 col0;
Color16 col1;
union {
@@ -98,8 +97,7 @@ inline bool BlockDXT1::isFourColorMode() const
/// DXT3 alpha block with explicit alpha.
-struct AlphaBlockDXT3
-{
+struct AlphaBlockDXT3 {
union {
struct {
uint alpha0 : 4;
@@ -130,8 +128,7 @@ struct AlphaBlockDXT3
/// DXT3 block.
-struct BlockDXT3
-{
+struct BlockDXT3 {
AlphaBlockDXT3 alpha;
BlockDXT1 color;
@@ -144,8 +141,7 @@ struct BlockDXT3
/// DXT5 alpha block.
-struct AlphaBlockDXT5
-{
+struct AlphaBlockDXT5 {
// uint64 unions do not compile on all platforms
#if 0
union {
@@ -208,8 +204,7 @@ struct AlphaBlockDXT5
/// DXT5 block.
-struct BlockDXT5
-{
+struct BlockDXT5 {
AlphaBlockDXT5 alpha;
BlockDXT1 color;
@@ -221,8 +216,7 @@ struct BlockDXT5
};
/// ATI1 block.
-struct BlockATI1
-{
+struct BlockATI1 {
AlphaBlockDXT5 alpha;
void decodeBlock(ColorBlock * block) const;
@@ -232,8 +226,7 @@ struct BlockATI1
};
/// ATI2 block.
-struct BlockATI2
-{
+struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
@@ -244,8 +237,7 @@ struct BlockATI2
};
/// CTX1 block.
-struct BlockCTX1
-{
+struct BlockCTX1 {
uint8 col0[2];
uint8 col1[2];
union {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 730a19d84fd..8d5031aa603 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -41,8 +41,7 @@
#include <Image.h>
/// Uncompressed 4x4 color block.
-struct ColorBlock
-{
+struct ColorBlock {
ColorBlock();
ColorBlock(const uint * linearImage);
ColorBlock(const ColorBlock & block);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index 028026527dc..6bf82776afe 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -60,6 +60,7 @@
#include <PixelFormat.h>
#include <stdio.h> // printf
+#include <stdlib.h> // malloc
#include <math.h> // sqrt
#include <sys/types.h>
@@ -496,8 +497,7 @@ void mem_read(Stream & mem, DDSHeader & header)
namespace
{
-struct FormatDescriptor
-{
+struct FormatDescriptor {
uint format;
uint bitcount;
uint rmask;
@@ -1148,7 +1148,7 @@ void* DirectDrawSurface::readData(uint &rsize)
uint size = stream.size - header_size;
rsize = size;
- unsigned char *data = new unsigned char[size];
+ unsigned char *data = (unsigned char *)malloc(sizeof(*data) * size);
stream.seek(header_size);
mem_read(stream, data, size);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 3d308ba1ff1..44c27a98c1d 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -63,8 +63,7 @@
#include <ColorBlock.h>
#include <Image.h>
-struct DDSPixelFormat
-{
+struct DDSPixelFormat {
uint size;
uint flags;
uint fourcc;
@@ -75,8 +74,7 @@ struct DDSPixelFormat
uint amask;
};
-struct DDSCaps
-{
+struct DDSCaps {
uint caps1;
uint caps2;
uint caps3;
@@ -84,8 +82,7 @@ struct DDSCaps
};
/// DDS file header for DX10.
-struct DDSHeader10
-{
+struct DDSHeader10 {
uint dxgiFormat;
uint resourceDimension;
uint miscFlag;
@@ -94,8 +91,7 @@ struct DDSHeader10
};
/// DDS file header.
-struct DDSHeader
-{
+struct DDSHeader {
uint fourcc;
uint size;
uint flags;
diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h
index a1ac49b58da..6557fb4f063 100644
--- a/source/blender/imbuf/intern/dds/Stream.h
+++ b/source/blender/imbuf/intern/dds/Stream.h
@@ -30,8 +30,7 @@
#ifndef __STREAM_H__
#define __STREAM_H__
-struct Stream
-{
+struct Stream {
unsigned char *mem; // location in memory
unsigned int size; // size
unsigned int pos; // current position
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index a6d53ffac96..45d9fa2ac59 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -47,7 +47,7 @@ extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-int imb_save_dds(struct ImBuf *ibuf, const char *name, int flags)
+int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
{
return(0); /* todo: finish this function */
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 65abf22ff2c..455b78bce4d 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -184,16 +184,16 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
- const float *from = rect_from + stride_from * y;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]);
}
else if (channels_from == 3) {
/* RGB input */
- const float *from = rect_from + stride_from * y * 3;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -221,8 +221,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 4) {
/* RGBA input */
- const float *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
float straight[4];
@@ -334,8 +334,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
- const float *from = rect_from + stride_from * y;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -343,8 +343,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 3) {
/* RGB input */
- const float *from = rect_from + stride_from * y * 3;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 3, to += 4) {
if (*mask++ == FILTER_MASK_USED) {
@@ -355,8 +355,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 4) {
/* RGBA input */
- const float *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
float straight[4];
@@ -408,7 +408,7 @@ void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from,
/* RGBA input */
for (y = 0; y < height; y++) {
const uchar *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -460,8 +460,8 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
to[0] = to[1] = to[2] = to[3] = from[0];
@@ -470,8 +470,8 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
else if (channels_from == 3) {
/* RGB input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 3;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -499,12 +499,12 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
else if (channels_from == 4) {
/* RGBA input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* same profile, copy */
- memcpy(to, from, sizeof(float) * 4 * width);
+ memcpy(to, from, sizeof(float) * ((size_t)4) * width);
}
else if (profile_to == IB_PROFILE_LINEAR_RGB) {
/* convert to sRGB to linear */
@@ -541,8 +541,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
if (channels_from == 1) {
/* single channel input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -552,8 +552,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
else if (channels_from == 3) {
/* RGB input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 3;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 3, to += 4) {
if (*mask++ == FILTER_MASK_USED) {
@@ -566,8 +566,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
else if (channels_from == 4) {
/* RGBA input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 4, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -590,8 +590,8 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
/* always RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* same profile, copy */
@@ -690,8 +690,8 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
imb_addrectImBuf(ibuf);
/* do conversion */
- rect_float = ibuf->rect_float + (x + y * ibuf->x) * ibuf->channels;
- rect_byte = (uchar *)ibuf->rect + (x + y * ibuf->x) * 4;
+ rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
+ rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
if (is_data) {
/* exception for non-color data, just copy float */
@@ -734,9 +734,9 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- int size;
+ size_t size;
- size = ibuf->x * ibuf->y;
+ size = ((size_t)ibuf->x) * ibuf->y;
size = size * 4 * sizeof(float);
ibuf->channels = 4;
@@ -771,22 +771,22 @@ void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
uchar *rct = (uchar *)ibuf->rect;
- int i;
+ size_t i;
if (rct_fl) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4)
- rct_fl[0] = rct_fl[1] = rct_fl[2] = rgb_to_grayscale(rct_fl);
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4)
+ rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
if (rct) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4)
- rct[0] = rct[1] = rct[2] = rgb_to_grayscale_byte(rct);
+ for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4)
+ rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
void IMB_buffer_float_clamp(float *buf, int width, int height)
{
- int i, total = width * height * 4;
+ size_t i, total = ((size_t)width) * height * 4;
for (i = 0; i < total; i++) {
buf[i] = min_ff(1.0, buf[i]);
}
@@ -794,7 +794,7 @@ void IMB_buffer_float_clamp(float *buf, int width, int height)
void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
{
- int total = width * height;
+ size_t total = ((size_t)width) * height;
float *fp = buf;
while (total--) {
premul_to_straight_v4(fp);
@@ -804,7 +804,7 @@ void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
void IMB_buffer_float_premultiply(float *buf, int width, int height)
{
- int total = width * height;
+ size_t total = ((size_t)width) * height;
float *fp = buf;
while (total--) {
straight_to_premul_v4(fp);
@@ -816,14 +816,14 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height)
void IMB_saturation(ImBuf *ibuf, float sat)
{
- int i;
+ size_t i;
unsigned char *rct = (unsigned char *)ibuf->rect;
float *rct_fl = ibuf->rect_float;
float hsv[3];
if (rct) {
float rgb[3];
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -832,7 +832,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index c6e358dd3d2..e58cda07ecf 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -51,17 +51,17 @@
#include "quicktime_import.h"
#endif
-static int imb_ftype_default(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
{
return (ibuf->ftype & type->filetype);
}
-static int imb_ftype_iris(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf)
{
(void)type;
return (ibuf->ftype == IMAGIC);
}
-ImFileType IMB_FILE_TYPES[] = {
+const ImFileType IMB_FILE_TYPES[] = {
{NULL, NULL, imb_is_a_jpeg, NULL, imb_ftype_default, imb_load_jpeg, NULL, imb_savejpeg, NULL, 0, JPG, COLOR_ROLE_DEFAULT_BYTE},
{NULL, NULL, imb_is_a_png, NULL, imb_ftype_default, imb_loadpng, NULL, imb_savepng, NULL, 0, PNG, COLOR_ROLE_DEFAULT_BYTE},
{NULL, NULL, imb_is_a_bmp, NULL, imb_ftype_default, imb_bmp_decode, NULL, imb_savebmp, NULL, 0, BMP, COLOR_ROLE_DEFAULT_BYTE},
@@ -92,11 +92,11 @@ ImFileType IMB_FILE_TYPES[] = {
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}
};
-ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES) / sizeof(ImFileType) - 1];
+const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES) / sizeof(ImFileType) - 1];
void imb_filetypes_init(void)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->init)
@@ -109,7 +109,7 @@ void imb_filetypes_init(void)
void imb_filetypes_exit(void)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->exit)
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 352e230068b..7adb2c7cc1d 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -526,7 +526,7 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
hbuf = ibuf->mipmap[curmap];
hbuf->miplevel = curmap + 1;
- if (hbuf->x <= 2 && hbuf->y <= 2)
+ if (hbuf->x < 2 && hbuf->y < 2)
break;
curmap++;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 8234b01992b..d44f0dc86f4 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -51,7 +51,7 @@
/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
- int size;
+ size_t size;
unsigned char rt, *cp = (unsigned char *)ibuf->rect;
float rtf, *cpf = ibuf->rect_float;
@@ -86,7 +86,7 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
- int offset = ibuf->x * y * 4 + 4 * x;
+ size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
if (ibuf->rect)
*outI = (unsigned char *)ibuf->rect + offset;
@@ -172,10 +172,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
if (outF) {
/* sample including outside of edges of image */
- row1 = in->rect_float + in->x * y1 * 4 + 4 * x1;
- row2 = in->rect_float + in->x * y2 * 4 + 4 * x1;
- row3 = in->rect_float + in->x * y1 * 4 + 4 * x2;
- row4 = in->rect_float + in->x * y2 * 4 + 4 * x2;
+ row1 = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
+ row2 = in->rect_float + ((size_t)in->x) * y2 * 4 + 4 * x1;
+ row3 = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x2;
+ row4 = in->rect_float + ((size_t)in->x) * y2 * 4 + 4 * x2;
outF[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
outF[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
@@ -190,10 +190,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
}
if (outI) {
/* sample including outside of edges of image */
- row1I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1;
- row2I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x1;
- row3I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x2;
- row4I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x2;
+ row1I = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
+ row2I = (unsigned char *)in->rect + ((size_t)in->x) * y2 * 4 + 4 * x1;
+ row3I = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x2;
+ row4I = (unsigned char *)in->rect + ((size_t)in->x) * y2 * 4 + 4 * x2;
/* need to add 0.5 to avoid rounding down (causes darken with the smear brush)
* tested with white images and this should not wrap back to zero */
@@ -256,14 +256,14 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
}
}
else {
- dataI = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1;
+ dataI = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
if (outI) {
outI[0] = dataI[0];
outI[1] = dataI[1];
outI[2] = dataI[2];
outI[3] = dataI[3];
}
- dataF = in->rect_float + in->x * y1 * 4 + 4 * x1;
+ dataF = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
if (outF) {
outF[0] = dataF[0];
outF[1] = dataF[1];
@@ -273,6 +273,41 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
}
}
+
+void nearest_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+{
+ const float *dataF;
+ unsigned char *dataI;
+ int y, x;
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+
+ x = (int) floor(u);
+ y = (int) floor(v);
+
+ x = x % in->x;
+ y = y % in->y;
+
+ /* wrap interpolation pixels - main difference from nearest_interpolation_color */
+ if (x < 0) x += in->x;
+ if (y < 0) y += in->y;
+
+ dataI = (unsigned char *)in->rect + ((size_t)in->x) * y * 4 + 4 * x;
+ if (outI) {
+ outI[0] = dataI[0];
+ outI[1] = dataI[1];
+ outI[2] = dataI[2];
+ outI[3] = dataI[3];
+ }
+ dataF = in->rect_float + ((size_t)in->x) * y * 4 + 4 * x;
+ if (outF) {
+ outF[0] = dataF[0];
+ outF[1] = dataF[1];
+ outF[2] = dataF[2];
+ outF[3] = dataF[3];
+ }
+}
+
void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout)
{
unsigned char *outI = NULL;
@@ -343,7 +378,7 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
{
- int a = x * y;
+ size_t a = ((size_t)x) * y;
float *fp = rect_float;
while (a--) {
@@ -366,7 +401,7 @@ void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3])
{
- int a = x * y;
+ size_t a = ((size_t)x) * y;
unsigned char *cp = rect;
while (a--) {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index d0281744830..ac57b095800 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -41,7 +41,6 @@
#include "IMB_anim.h"
#include "imbuf.h"
-#include "MEM_guardedalloc.h"
#include "BKE_global.h"
#ifdef WITH_AVI
@@ -374,6 +373,13 @@ 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);
+}
+
static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
char *fname, bool temp)
{
@@ -381,8 +387,8 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
int i = IMB_proxy_size_to_array_index(preview_size);
char proxy_name[256];
- char proxy_temp_name[256];
char stream_suffix[20];
+ const char *name = (temp) ? "proxy_%d%s_part.avi" : "proxy_%d%s.avi";
stream_suffix[0] = 0;
@@ -390,15 +396,12 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
BLI_snprintf(stream_suffix, sizeof(stream_suffix), "_st%d", anim->streamindex);
}
- BLI_snprintf(proxy_name, sizeof(proxy_name), "proxy_%d%s.avi",
- (int) (proxy_fac[i] * 100), stream_suffix);
- BLI_snprintf(proxy_temp_name, sizeof(proxy_temp_name), "proxy_%d%s_part.avi",
- (int) (proxy_fac[i] * 100), stream_suffix);
+ BLI_snprintf(proxy_name, sizeof(proxy_name), name,
+ (int) (proxy_fac[i] * 100), stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir,
- temp ? proxy_temp_name : proxy_name);
+ BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
}
static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
@@ -407,10 +410,10 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
const char *index_names[] = {
- "record_run%s.blen_tc",
- "free_run%s.blen_tc",
- "interp_free_run%s.blen_tc",
- "record_run_no_gaps%s.blen_tc"
+ "record_run%s%s.blen_tc",
+ "free_run%s%s.blen_tc",
+ "interp_free_run%s%s.blen_tc",
+ "record_run_no_gaps%s%s.blen_tc"
};
char stream_suffix[20];
@@ -422,7 +425,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
}
- BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
+ BLI_snprintf(index_name, 256, index_names[i], stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
@@ -1002,7 +1005,7 @@ static AviMovie *alloc_proxy_output_avi(
* but sane defaults help anyways...*/
float frs_sec_base = 1.0;
- IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
+ IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base, false);
x = width;
y = height;
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 8cb5070dd62..134bbe88f15 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -79,6 +79,13 @@ bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, con
return retval;
}
+void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
+{
+ if (simb->metadata) {
+ dimb->metadata = IDP_CopyProperty(simb->metadata);
+ }
+}
+
bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value)
{
IDProperty *prop;
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 29bb35986e8..4b49076dcd6 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -147,8 +147,8 @@ static void check_unused_keys(MovieCache *cache)
BLI_ghashIterator_init(&gh_iter, cache->hash);
while (!BLI_ghashIterator_done(&gh_iter)) {
- MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
- MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
+ const MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ const MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
bool remove;
BLI_ghashIterator_step(&gh_iter);
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
index 5fb8f11602e..c873fa3f32d 100644
--- a/source/blender/imbuf/intern/oiio/CMakeLists.txt
+++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
if(WITH_OPENIMAGEIO)
list(APPEND INC_SYS
${OPENIMAGEIO_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
)
add_definitions(-DWITH_OPENIMAGEIO)
endif()
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 6e3f97a4902..7728183d3b6 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -182,7 +182,7 @@ int imb_is_a_photoshop(const char *filename)
return BLI_testextensie_array(filename, photoshop_extension);
}
-int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags)
+int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags)
{
if (flags & IB_mem) {
std::cerr << __func__ << ": Photoshop PSD-save: Create PSD in memory"
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 45eae89ad9d..44b7fbf6315 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -63,6 +63,7 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "BLI_threads.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -92,9 +93,32 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include <ImfStringAttribute.h>
#include <ImfStandardAttributes.h>
+/* multiview/multipart */
+#include <ImfMultiView.h>
+#include <ImfMultiPartInputFile.h>
+#include <ImfInputPart.h>
+#include <ImfOutputPart.h>
+#include <ImfMultiPartOutputFile.h>
+#include <ImfTiledOutputPart.h>
+#include <ImfPartType.h>
+#include <ImfPartHelper.h>
+
using namespace Imf;
using namespace Imath;
+extern "C"
+{
+/* prototype */
+static struct ExrPass *imb_exr_get_pass(ListBase *lb, char *passname);
+static bool exr_has_multiview(MultiPartInputFile& file);
+static bool exr_has_multipart_file(MultiPartInputFile& file);
+static bool exr_has_alpha(MultiPartInputFile& file);
+static bool exr_has_zbuffer(MultiPartInputFile& file);
+static void exr_printf(const char *__restrict format, ...);
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview);
+}
+
/* Memory Input Stream */
class Mem_IStream : public Imf::IStream
@@ -340,13 +364,28 @@ static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
}
-static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags)
+static void openexr_header_metadata_callback(void *data, const char *propname, const char *prop)
+{
+ Header *header = (Header *)data;
+ header->insert(propname, StringAttribute(prop));
+}
+
+
+static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
- const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
- const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
+ const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
+ const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -355,13 +394,22 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(HALF));
- header.channels().insert("G", Channel(HALF));
- header.channels().insert("B", Channel(HALF));
- if (is_alpha)
- header.channels().insert("A", Channel(HALF));
- if (is_zbuf) // z we do as float always
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(HALF));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(HALF));
+ if (is_zbuf) // z we do as float always
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -370,75 +418,91 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
OutputFile file(file_stream, header);
/* we store first everything in half array */
- RGBAZ *pixels = new RGBAZ[height * width];
- RGBAZ *to = pixels;
+ RGBAZ *pixels = new RGBAZ[height * width * totviews];
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
- /* indicate used buffers */
- frameBuffer.insert("R", Slice(HALF, (char *) &pixels[0].r, xstride, ystride));
- frameBuffer.insert("G", Slice(HALF, (char *) &pixels[0].g, xstride, ystride));
- frameBuffer.insert("B", Slice(HALF, (char *) &pixels[0].b, xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(HALF, (char *) &pixels[0].a, xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)(ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
- if (ibuf->rect_float) {
- float *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = ibuf->rect_float + channels * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = from[0];
- to->g = (channels >= 2) ? from[1] : from[0];
- to->b = (channels >= 3) ? from[2] : from[0];
- to->a = (channels >= 4) ? from[3] : 1.0f;
- to++; from += channels;
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+ const size_t offset = view_id * width * height;
+ RGBAZ *to = pixels + offset;
+
+ /* indicate used buffers */
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF, (char *) &pixels[offset].r, xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF, (char *) &pixels[offset].g, xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF, (char *) &pixels[offset].b, xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+ if (view_ibuf->rect_float) {
+ float *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = view_ibuf->rect_float + channels * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = from[0];
+ to->g = (channels >= 2) ? from[1] : from[0];
+ to->b = (channels >= 3) ? from[2] : from[0];
+ to->a = (channels >= 4) ? from[3] : 1.0f;
+ to++; from += channels;
+ }
}
}
- }
- else {
- unsigned char *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = (unsigned char *)ibuf->rect + 4 * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
- to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
- to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
- to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
- to++; from += 4;
+ else {
+ unsigned char *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = (unsigned char *)view_ibuf->rect + 4 * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
+ to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
+ to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
+ to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
+ to++; from += 4;
+ }
}
}
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
}
-// printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
+ exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
delete[] pixels;
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
- return (0);
+ return false;
}
- return (1);
+ return true;
}
-static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flags)
+static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
- const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
- const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
+ const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
+ const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -447,13 +511,22 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(Imf::FLOAT));
- header.channels().insert("G", Channel(Imf::FLOAT));
- header.channels().insert("B", Channel(Imf::FLOAT));
- if (is_alpha)
- header.channels().insert("A", Channel(Imf::FLOAT));
- if (is_zbuf)
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT));
+ if (is_zbuf)
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -463,37 +536,41 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
int xstride = sizeof(float) * channels;
int ystride = -xstride * width;
- float *rect[4] = {NULL, NULL, NULL, NULL};
- /* last scanline, stride negative */
- rect[0] = ibuf->rect_float + channels * (height - 1) * width;
- rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
- rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
- rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
-
- frameBuffer.insert("R", Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
- frameBuffer.insert("G", Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
- frameBuffer.insert("B", Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ float *rect[4] = {NULL, NULL, NULL, NULL};
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+
+ /* last scanline, stride negative */
+ rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
+ rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
+ rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
+ rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
+
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
+ }
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
-
- return (0);
+ return false;
}
- return (1);
- // printf("OpenEXR-save: Done.\n");
+ return true;
}
-
int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
{
if (flags & IB_mem) {
@@ -504,16 +581,48 @@ int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
}
if (ibuf->ftype & OPENEXR_HALF)
- return imb_save_openexr_half(ibuf, name, flags);
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else {
+ /* when no float rect, we save as half (16 bits is sufficient) */
+ if (ibuf->rect_float == NULL)
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else
+ return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL);
+ }
+}
+
+static bool imb_save_openexr_multiview(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ if (flags & IB_mem) {
+ printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
+ imb_addencodedbufferImBuf(ibuf);
+ ibuf->encodedsize = 0;
+ return false;
+ }
+
+ if (ibuf->ftype & OPENEXR_HALF)
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else {
/* when no float rect, we save as half (16 bits is sufficient) */
if (ibuf->rect_float == NULL)
- return imb_save_openexr_half(ibuf, name, flags);
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else
- return imb_save_openexr_float(ibuf, name, flags);
+ return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer);
}
}
+/* Save single-layer multiview OpenEXR
+ * If we have more multiview formats in the future, the function below could be incorporated
+ * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
+bool IMB_exr_multiview_save(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
+}
+
/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
/* naming rules:
@@ -527,30 +636,39 @@ static ListBase exrhandles = {NULL, NULL};
typedef struct ExrHandle {
struct ExrHandle *next, *prev;
+ char name[FILE_MAX];
- IFileStream *ifile_stream;
- InputFile *ifile;
+ IStream *ifile_stream;
+ MultiPartInputFile *ifile;
OFileStream *ofile_stream;
- TiledOutputFile *tofile;
+ MultiPartOutputFile *mpofile;
OutputFile *ofile;
int tilex, tiley;
int width, height;
int mipmap;
+ StringVector *multiView; /* it needs to be a pointer due to Windows release builds of EXR2.0 segfault when opening EXR bug */
+ int parts;
+
ListBase channels; /* flattened out, ExrChannel */
ListBase layers; /* hierarchical, pointing in end to ExrChannel */
+
+ int num_half_channels; /* used during filr save, allows faster temporary buffers allocation */
} ExrHandle;
/* flattened out channel */
typedef struct ExrChannel {
struct ExrChannel *next, *prev;
- char name[EXR_TOT_MAXNAME + 1]; /* full name of layer+pass */
+ char name[EXR_TOT_MAXNAME + 1]; /* full name with everything */
+ struct MultiViewChannelName *m; /* struct to store all multipart channel info */
int xstride, ystride; /* step to next pixel, to next scanline */
float *rect; /* first pointer to write in */
char chan_id; /* quick lookup of channel char */
+ int view_id; /* quick lookup of channel view */
+ bool use_half_float; /* when saving use half float for file storage */
} ExrChannel;
@@ -562,6 +680,10 @@ typedef struct ExrPass {
float *rect;
struct ExrChannel *chan[EXR_PASS_MAXCHAN];
char chan_id[EXR_PASS_MAXCHAN];
+
+ char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
+ char view[EXR_VIEW_MAXNAME];
+ int view_id;
} ExrPass;
typedef struct ExrLayer {
@@ -575,40 +697,153 @@ typedef struct ExrLayer {
void *IMB_exr_get_handle(void)
{
ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ data->multiView = new StringVector();
+
BLI_addtail(&exrhandles, data);
return data;
}
+void *IMB_exr_get_handle_name(const char *name)
+{
+ ExrHandle *data = (ExrHandle *) BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
+
+ if (data == NULL) {
+ data = (ExrHandle *)IMB_exr_get_handle();
+ BLI_strncpy(data->name, name, strlen(name) + 1);
+ }
+ return data;
+}
+
+/* multiview functions */
+} // extern "C"
+
+extern "C"
+{
+
+void IMB_exr_add_view(void *handle, const char *name)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ data->multiView->push_back(name);
+}
+
+static int imb_exr_get_multiView_id(StringVector& views, const std::string& name)
+{
+ int count = 0;
+ for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
+ if (name == *i)
+ return count;
+ else
+ count ++;
+ }
+
+ /* no views or wrong name */
+ return -1;
+}
+
+static void imb_exr_get_views(MultiPartInputFile& file, StringVector& views)
+{
+ if (exr_has_multipart_file(file) == false) {
+ if (exr_has_multiview(file)) {
+ StringVector sv = multiView(file.header(0));
+ for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
+ views.push_back(*i);
+ }
+ }
+
+ else {
+ for (int p = 0; p < file.parts(); p++) {
+ std::string view = "";
+ if (file.header(p).hasView())
+ view = file.header(p).view();
+
+ if (imb_exr_get_multiView_id(views, view) == -1)
+ views.push_back(view);
+ }
+ }
+}
+
+/* Multilayer Blender files have the view name in all the passes (even the default view one) */
+static const char *imb_exr_insert_view_name(const char *passname, const char *viewname)
+{
+ if (viewname == NULL || viewname[0] == '\0')
+ return passname;
+
+ static char retstr[EXR_PASS_MAXNAME];
+ const char delims[] = {'.', '\0'};
+ const char *sep;
+ const char *token;
+ size_t len;
+
+ len = BLI_str_rpartition(passname, delims, &sep, &token);
+
+ if (sep) {
+ BLI_snprintf(retstr, sizeof(retstr), "%.*s.%s.%s", (int)len, passname, viewname, token);
+ }
+ else {
+ BLI_snprintf(retstr, sizeof(retstr), "%s.%s", passname, viewname);
+ }
+
+ return retstr;
+}
+
/* adds flattened ExrChannels */
/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
+/* passname does not include view */
+void IMB_exr_add_channel(void *handle,
+ const char *layname, const char *passname, const char *viewname,
+ int xstride, int ystride, float *rect,
+ bool use_half_float)
{
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
+ echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan->m = new MultiViewChannelName ();
- if (layname) {
- char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
- BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
- BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
+ if (layname && layname[0] != '\0') {
+ echan->m->name = layname;
+ echan->m->name.append(".");
+ echan->m->name.append(passname);
+ }
+ else {
+ echan->m->name.assign(passname);
+ }
+
+ echan->m->internal_name = echan->m->name;
+
+ echan->m->view.assign(viewname ? viewname : "");
+
+ /* quick look up */
+ echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
- BLI_snprintf(echan->name, sizeof(echan->name), "%s.%s", lay, pass);
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(echan->m->name.c_str(), echan->m->view.c_str());
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
+ }
+ else if (data->multiView->size() > 1) {
+ std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
}
else {
- BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME - 1);
+ BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
}
echan->xstride = xstride;
echan->ystride = ystride;
echan->rect = rect;
+ echan->use_half_float = use_half_float;
+
+ if (echan->use_half_float) {
+ data->num_half_channels++;
+ }
- // printf("added channel %s\n", echan->name);
+ exr_printf("added channel %s\n", echan->name);
BLI_addtail(&data->channels, echan);
}
-/* only used for writing temp. render results (not image files) */
-int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress)
+/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
+int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const StampData *stamp)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
@@ -617,14 +852,24 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->width = width;
data->height = height;
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
- header.channels().insert(echan->name, Channel(Imf::FLOAT));
+ bool is_singlelayer, is_multilayer, is_multiview;
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ header.channels().insert(echan->name,
+ Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
+ }
openexr_header_compression(&header, compress);
- // openexr_header_metadata(&header, ibuf); // no imbuf. cant write
+ BKE_stamp_info_callback(&header, stamp, openexr_header_metadata_callback);
/* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
- header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+ imb_exr_type_by_channels(header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
+
+ if (is_multilayer)
+ header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+
+ if (is_multiview)
+ addMultiView(header, *data->multiView);
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
@@ -632,7 +877,7 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->ofile_stream = new OFileStream(filename);
data->ofile = new OutputFile(*(data->ofile_stream), header);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
delete data->ofile;
@@ -645,10 +890,13 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
return (data->ofile != NULL);
}
+/* only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
+ std::vector<Header> headers;
ExrChannel *echan;
data->tilex = tilex;
@@ -657,26 +905,49 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
data->height = height;
data->mipmap = mipmap;
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
- header.channels().insert(echan->name, Channel(Imf::FLOAT));
-
header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
- header.lineOrder() = RANDOM_Y;
header.compression() = RLE_COMPRESSION;
+ header.setType(TILEDIMAGE);
header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
+ int numparts = data->multiView->size();
+
+ /* copy header from all parts of input to our header array
+ * those temporary files have one part per view */
+ for (int i = 0; i < numparts; i++) {
+ headers.push_back (header);
+ headers[headers.size() - 1].setView((*(data->multiView))[i]);
+ headers[headers.size() - 1].setName((*(data->multiView))[i]);
+ }
+
+ exr_printf("\nIMB_exrtile_begin_write\n");
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------\n");
+
+ /* assign channels */
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ /* Tiles are expected to be saved with full float currently. */
+ BLI_assert(echan->use_half_float == 0);
+
+ echan->m->internal_name = echan->m->name;
+ echan->m->part_number = echan->view_id;
+
+ headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
+ }
+
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filename);
- data->tofile = new TiledOutputFile(*(data->ofile_stream), header);
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
}
catch (const std::exception &) {
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
}
}
@@ -685,12 +956,13 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
{
ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
if (BLI_exists(filename) && BLI_file_size(filename) > 32) { /* 32 is arbitrary, but zero length files crashes exr */
/* avoid crash/abort when we don't have permission to write here */
try {
data->ifile_stream = new IFileStream(filename);
- data->ifile = new InputFile(*(data->ifile_stream));
+ data->ifile = new MultiPartInputFile(*(data->ifile_stream));
}
catch (const std::exception &) {
delete data->ifile;
@@ -701,14 +973,24 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
if (data->ifile) {
- Box2i dw = data->ifile->header().dataWindow();
+ Box2i dw = data->ifile->header(0).dataWindow();
data->width = *width = dw.max.x - dw.min.x + 1;
data->height = *height = dw.max.y - dw.min.y + 1;
- const ChannelList &channels = data->ifile->header().channels();
+ imb_exr_get_views(*data->ifile, *data->multiView);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
+
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
return 1;
}
@@ -717,6 +999,7 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
/* still clumsy name handling, layers/channels can be ordered as list in list later */
+/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
ExrHandle *data = (ExrHandle *)handle;
@@ -741,37 +1024,53 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
echan->rect = rect;
}
else
- printf("IMB_exrtile_set_channel error %s\n", name);
+ printf("IMB_exr_set_channel error %s\n", name);
}
-void IMB_exrtile_clear_channels(void *handle)
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
- BLI_freelistN(&data->channels);
-}
-
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
-{
- ExrHandle *data = (ExrHandle *)handle;
- FrameBuffer frameBuffer;
ExrChannel *echan;
+ char name[EXR_TOT_MAXNAME + 1];
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ if (layname) {
+ char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
+ BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
+ BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
- echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
+ BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
}
+ else
+ BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
- data->tofile->setFrameBuffer(frameBuffer);
-
- try {
- // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
- data->tofile->writeTile(partx / data->tilex, party / data->tiley, level);
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(name, viewname);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
- catch (const std::exception &exc) {
- std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ else if (data->multiView->size() > 1) {
+ size_t view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
+ std::string raw_name = insertViewName(name, *data->multiView, view_id);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
+
+ echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
+
+ if (echan)
+ return echan->rect;
+
+ return NULL;
+}
+
+void IMB_exr_clear_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *chan;
+
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
+ delete chan->m;
+
+ BLI_freelistN(&data->channels);
}
void IMB_exr_write_channels(void *handle)
@@ -781,70 +1080,223 @@ void IMB_exr_write_channels(void *handle)
ExrChannel *echan;
if (data->channels.first) {
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- /* last scanline, stride negative */
- float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ const size_t num_pixels = ((size_t)data->width) * data->height;
+ half *rect_half = NULL, *current_rect_half;
+
+ /* We allocate teporary storage for half pixels for all the channels at once. */
+ if (data->num_half_channels != 0) {
+ rect_half = (half *)MEM_mallocN(sizeof(half) * data->num_half_channels * num_pixels, __func__);
+ current_rect_half = rect_half;
+ }
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
- echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ /* Writting starts from last scanline, stride negative. */
+ if (echan->use_half_float) {
+ float *rect = echan->rect;
+ half *cur = current_rect_half;
+ for (size_t i = 0; i < num_pixels; ++i, ++cur) {
+ *cur = rect[i * echan->xstride];
+ }
+ half *rect_to_write = current_rect_half + (data->height - 1) * data->width;
+ frameBuffer.insert(echan->name, Slice(Imf::HALF, (char *)rect_to_write,
+ sizeof(half), -data->width * sizeof(half)));
+ current_rect_half += num_pixels;
+ }
+ else {
+ float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
+ echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
+ }
}
data->ofile->setFrameBuffer(frameBuffer);
try {
data->ofile->writePixels(data->height);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
}
+ /* Free temporary buffers. */
+ if (rect_half != NULL) {
+ MEM_freeN(rect_half);
+ }
}
else {
printf("Error: attempt to save MultiLayer without layers.\n");
}
}
-void IMB_exr_read_channels(void *handle)
+/* temporary function, used for FSA and Save Buffers */
+/* called once per tile * view */
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
FrameBuffer frameBuffer;
ExrChannel *echan;
+ std::string view(viewname);
+ const size_t view_id = imb_exr_get_multiView_id(*data->multiView, view);
+
+ exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------------\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ /* eventually we can make the parts' channels to include
+ only the current view TODO */
+ if (strcmp(viewname, echan->m->view.c_str()) != 0)
+ continue;
+
+ exr_printf("%d %-6s %-22s \"%s\"\n",
+ echan->m->part_number,
+ echan->m->view.c_str(),
+ echan->m->name.c_str(),
+ echan->m->internal_name.c_str()
+ );
+
+ float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ frameBuffer.insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ echan->ystride * sizeof(float)
+ )
+ );
+ }
+
+ TiledOutputPart out (*data->mpofile, view_id);
+ out.setFrameBuffer(frameBuffer);
+
+ try {
+ // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
+ out.writeTile(partx / data->tilex, party / data->tiley, level);
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+/* called only when handle has all views */
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ const size_t view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
+ int numparts = (view_id == -1 ? data->parts : view_id + 1);
+ std::vector <FrameBuffer> frameBuffers(numparts);
+ std::vector <OutputPart> outputParts;
+ ExrChannel *echan;
+ int i, part;
+
+ if (data->channels.first == NULL)
+ return;
+
+ exr_printf("\nIMB_exrmultiview_write_channels()\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ if (view_id != -1 && echan->view_id != view_id)
+ continue;
+
+ part = (view_id == -1 ? echan->m->part_number : echan->view_id);
+
+ /* last scanline, stride negative */
+ float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ frameBuffers[part].insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ -echan->ystride * sizeof(float))
+ );
+ }
+
+ for (i = 0; i < numparts; i++) {
+ OutputPart out(*data->mpofile, i);
+ out.setFrameBuffer(frameBuffers[i]);
+ outputParts.push_back(out);
+ }
+
+ try {
+ for (i = 0; i < numparts; i++) {
+ if (view_id != -1 && i != view_id)
+ continue;
+
+ outputParts[i].writePixels(data->height);
+ }
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+void IMB_exr_read_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
+ int numparts = data->ifile->parts();
+ std::vector<FrameBuffer> frameBuffers(numparts);
+ std::vector<InputPart> inputParts;
/* check if exr was saved with previous versions of blender which flipped images */
- const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
+ const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
+ exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name");
+
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
if (echan->rect) {
if (flip)
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)echan->rect,
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)echan->rect,
echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
else
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
}
else
- printf("warning, channel with no rect set %s\n", echan->name);
+ printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
}
- data->ifile->setFrameBuffer(frameBuffer);
+ for (int i = 0; i < numparts; i++) {
+ InputPart in (*data->ifile, i);
+ in.setFrameBuffer(frameBuffers[i]);
+ inputParts.push_back(in);
+ }
try {
- data->ifile->readPixels(0, data->height - 1);
+ for (int i = 0; i < numparts; i++) {
+ Header header = inputParts[i].header();
+ exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(0, data->height - 1);
+ }
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
}
}
void IMB_exr_multilayer_convert(void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
void * (*addlayer)(void *base, const char *str),
void (*addpass)(void *base, void *lay, const char *str,
- float *rect, int totchan, const char *chan_id))
+ float *rect, int totchan, const char *chan_id,
+ const char *view))
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ /* RenderResult needs at least one RenderView */
+ if (data->multiView->size() == 0) {
+ addview(base, "");
+ }
+ else {
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+ }
+
if (BLI_listbase_is_empty(&data->layers)) {
printf("cannot convert multilayer, no layers in handle\n");
return;
@@ -854,32 +1306,99 @@ void IMB_exr_multilayer_convert(void *handle, void *base,
void *laybase = addlayer(base, lay->name);
if (laybase) {
for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
- addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
+ addpass(base, laybase, pass->internal_name, pass->rect, pass->totchan, pass->chan_id, pass->view);
pass->rect = NULL;
}
}
}
}
+void IMB_exr_multiview_convert(void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame),
+ const int frame)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ ExrLayer *lay;
+ ExrPass *pass;
+ ImBuf *ibuf = NULL;
+ const bool is_alpha = exr_has_alpha(*file);
+ Box2i dw = file->header(0).dataWindow();
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
+ const bool is_depth = exr_has_zbuffer(*file);
+
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+
+ if (BLI_listbase_is_empty(&data->layers)) {
+ printf("cannot convert multiviews, no views in handle\n");
+ return;
+ }
+
+ /* there is one float/pass per layer (layer here is a view) */
+ BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1);
+ lay = (ExrLayer *)data->layers.first;
+ for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
+ if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) {
+ ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat);
+
+ if (!ibuf) {
+ printf("error creating multiview buffer\n");
+ return;
+ }
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, pass->rect, pass->totchan,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
+ }
+
+ if (is_depth) {
+ ExrPass *zpass;
+ for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) {
+ if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) {
+ addzbuffloatImBuf(ibuf);
+ memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y);
+ }
+ }
+ }
+
+ addbuffer(base, pass->view, ibuf, frame);
+ }
+ }
+}
void IMB_exr_close(void *handle)
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ ExrChannel *chan;
delete data->ifile;
delete data->ifile_stream;
delete data->ofile;
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
+ delete data->multiView;
data->ifile = NULL;
data->ifile_stream = NULL;
data->ofile = NULL;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
+ delete chan->m;
+ }
BLI_freelistN(&data->channels);
for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
@@ -899,19 +1418,21 @@ void IMB_exr_close(void *handle)
/* get a substring from the end of the name, separated by '.' */
static int imb_exr_split_token(const char *str, const char *end, const char **token)
{
- ptrdiff_t maxlen = end - str;
- int len = 0;
- while (len < maxlen && *(end - len - 1) != '.') {
- len++;
+ const char delims[] = {'.', '\0'};
+ const char *sep;
+
+ BLI_str_partition_ex(str, end, delims, &sep, token, true);
+
+ if (!sep) {
+ *token = str;
}
- *token = end - len;
- return len;
+ return (int)(end - *token);
}
static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
{
- const char *name = echan->name;
+ const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
char tokenbuf[EXR_TOT_MAXNAME];
@@ -1020,7 +1541,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
}
/* creates channels, makes a hierarchy and assigns memory to channels */
-static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
+static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height)
{
ExrLayer *lay;
ExrPass *pass;
@@ -1029,30 +1550,59 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
int a;
char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
- data->ifile = file;
+ data->ifile_stream = &file_stream;
+ data->ifile = &file;
+
data->width = width;
data->height = height;
- const ChannelList &channels = data->ifile->header().channels();
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ data->multiView = new StringVector();
+ imb_exr_get_views(*data->ifile, *data->multiView);
+
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
/* now try to sort out how to assign memory to the channels */
/* first build hierarchical layer list */
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- if (imb_exr_split_channel_name(echan, layname, passname) ) {
+ if (imb_exr_split_channel_name(echan, layname, passname)) {
+
+ const char *view = echan->m->view.c_str();
+ char internal_name[EXR_PASS_MAXNAME];
+
+ BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
+
+ if (view[0] != '\0') {
+ char tmp_pass[EXR_PASS_MAXNAME];
+ BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
+ BLI_strncpy(passname, tmp_pass, sizeof(passname));
+ }
+
ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
pass->chan[pass->totchan] = echan;
pass->totchan++;
+ pass->view_id = echan->view_id;
+ BLI_strncpy(pass->view, view, sizeof(pass->view));
+ BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
+
if (pass->totchan >= EXR_PASS_MAXCHAN)
break;
}
}
if (echan) {
- printf("error, too many channels in one pass: %s\n", echan->name);
+ printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
IMB_exr_close(data);
return NULL;
}
@@ -1122,20 +1672,52 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
/* ********************************************************* */
/* debug only */
-static void exr_print_filecontents(InputFile *file)
+static void exr_printf(const char *fmt, ...)
{
- const ChannelList &channels = file->header().channels();
+#if 0
+ char output[1024];
+ va_list args;
+ va_start(args, fmt);
+ std::vsprintf(output, fmt, args);
+ va_end(args);
+ printf("%s", output);
+#else
+ (void)fmt;
+#endif
+}
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
- const Channel &channel = i.channel();
- printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+static void exr_print_filecontents(MultiPartInputFile& file)
+{
+ int numparts = file.parts();
+ if (numparts == 1 && hasMultiView(file.header(0))) {
+ const StringVector views = multiView(file.header(0));
+ printf("OpenEXR-load: MultiView file\n");
+ printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
+ for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
+ printf("OpenEXR-load: Found view %s\n", (*i).c_str());
+ }
+ }
+ else if (numparts > 1) {
+ printf("OpenEXR-load: MultiPart file\n");
+ for (int i = 0; i < numparts; i++) {
+ if (file.header(i).hasView())
+ printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
+ }
+ }
+
+ for (int j = 0; j < numparts; j++) {
+ const ChannelList& channels = file.header(j).channels();
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
+ const Channel& channel = i.channel();
+ printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+ }
}
}
/* for non-multilayer, map R G B A channel names to something that's in this file */
-static const char *exr_rgba_channelname(InputFile *file, const char *chan)
+static const char *exr_rgba_channelname(MultiPartInputFile& file, const char *chan)
{
- const ChannelList &channels = file->header().channels();
+ const ChannelList& channels = file.header(0).channels();
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
/* const Channel &channel = i.channel(); */ /* Not used yet */
@@ -1150,48 +1732,48 @@ static const char *exr_rgba_channelname(InputFile *file, const char *chan)
return chan;
}
-static bool exr_has_rgb(InputFile *file)
+static bool exr_has_rgb(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("R") != NULL &&
- file->header().channels().findChannel("G") != NULL &&
- file->header().channels().findChannel("B") != NULL;
+ return file.header(0).channels().findChannel("R") != NULL &&
+ file.header(0).channels().findChannel("G") != NULL &&
+ file.header(0).channels().findChannel("B") != NULL;
}
-static bool exr_has_luma(InputFile *file)
+static bool exr_has_luma(MultiPartInputFile& file)
{
/* Y channel is the luma and should always present fir luma space images,
* optionally it could be also channels for chromas called BY and RY.
*/
- return file->header().channels().findChannel("Y") != NULL;
+ return file.header(0).channels().findChannel("Y") != NULL;
}
-static bool exr_has_chroma(InputFile *file)
+static bool exr_has_chroma(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("BY") != NULL &&
- file->header().channels().findChannel("RY") != NULL;
+ return file.header(0).channels().findChannel("BY") != NULL &&
+ file.header(0).channels().findChannel("RY") != NULL;
}
-static int exr_has_zbuffer(InputFile *file)
+static bool exr_has_zbuffer(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("Z") == NULL);
+ return !(file.header(0).channels().findChannel("Z") == NULL);
}
-static int exr_has_alpha(InputFile *file)
+static bool exr_has_alpha(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("A") == NULL);
+ return !(file.header(0).channels().findChannel("A") == NULL);
}
-static bool exr_is_multilayer(InputFile *file)
+static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
{
- const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
- const ChannelList &channels = file->header().channels();
+ const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+ const ChannelList& channels = file.header(0).channels();
std::set <std::string> layerNames;
/* will not include empty layer names */
channels.layers(layerNames);
if (comments || layerNames.size() > 1)
- return 1;
+ return true;
if (layerNames.size()) {
/* if layerNames is not empty, it means at least one layer is non-empty,
@@ -1206,17 +1788,123 @@ static bool exr_is_multilayer(InputFile *file)
size_t pos = layerName.rfind ('.');
if (pos == std::string::npos)
- return 1;
+ return true;
}
}
- return 0;
+ return false;
+}
+
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
+{
+ std::set <std::string> layerNames;
+
+ *r_singlelayer = true;
+ *r_multilayer = *r_multiview = false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ if (views.size() && views[0] != "")
+ *r_multiview = true;
+
+ if (layerNames.size()) {
+ /* if layerNames is not empty, it means at least one layer is non-empty,
+ * but it also could be layers without names in the file and such case
+ * shall be considered a multilayer exr
+ *
+ * that's what we do here: test whether there're empty layer names together
+ * with non-empty ones in the file
+ */
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ /* see if any layername differs from a viewname */
+ if (imb_exr_get_multiView_id(views, *i) == -1) {
+ std::string layerName = *i;
+ size_t pos = layerName.rfind ('.');
+
+ if (pos != std::string::npos) {
+ *r_multilayer = true;
+ *r_singlelayer = false;
+ return;
+ }
+ }
+ }
+ else {
+ *r_singlelayer = true;
+ *r_multilayer = false;
+ *r_multiview = false;
+ }
+
+ BLI_assert(r_singlelayer != r_multilayer);
+}
+
+bool IMB_exr_has_singlelayer_multiview(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ std::set <std::string> layerNames;
+ const ChannelList& channels = file->header(0).channels();
+ const StringAttribute *comments;
+
+ if (exr_has_multiview(*file) == false)
+ return false;
+
+ comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+
+ if (comments)
+ return false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ /* returns false if any layer differs from views list */
+ if (layerNames.size())
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ if (imb_exr_get_multiView_id(*data->multiView, *i) == -1)
+ return false;
+
+ return true;
+}
+
+bool IMB_exr_has_multilayer(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ return imb_exr_is_multilayer_file(*data->ifile);
+}
+
+static bool exr_has_multiview(MultiPartInputFile& file)
+{
+ return hasMultiView(file.header(0));
+}
+
+static bool exr_has_multipart_file(MultiPartInputFile& file)
+{
+ return file.parts() > 1;
+}
+
+/* it returns true if the file is multilayer or multiview */
+static bool imb_exr_is_multi(MultiPartInputFile& file)
+{
+ /* multipart files are treated as multilayer in blender - even if they are single layer openexr with multiview */
+ if (exr_has_multipart_file(file))
+ return true;
+
+ if (exr_has_multiview(file))
+ return true;
+
+ if (imb_exr_is_multilayer_file(file))
+ return true;
+
+ return false;
}
struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = NULL;
- InputFile *file = NULL;
+ Mem_IStream *membuf = NULL;
+ MultiPartInputFile *file = NULL;
if (imb_is_a_openexr(mem) == 0) return(NULL);
@@ -1224,11 +1912,12 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
try
{
- Mem_IStream *membuf = new Mem_IStream(mem, size);
bool is_multi;
- file = new InputFile(*membuf);
- Box2i dw = file->header().dataWindow();
+ membuf = new Mem_IStream(mem, size);
+ file = new MultiPartInputFile(*membuf);
+
+ Box2i dw = file->header(0).dataWindow();
const int width = dw.max.x - dw.min.x + 1;
const int height = dw.max.y - dw.min.y + 1;
@@ -1236,38 +1925,54 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
if (0) // debug
- exr_print_filecontents(file);
+ exr_print_filecontents(*file);
- is_multi = exr_is_multilayer(file);
+ is_multi = imb_exr_is_multi(*file);
/* do not make an ibuf when */
if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
printf("Error: can't process EXR multilayer file\n");
}
else {
- const int is_alpha = exr_has_alpha(file);
+ const int is_alpha = exr_has_alpha(*file);
ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
- if (hasXDensity(file->header())) {
- ibuf->ppm[0] = xDensity(file->header()) * 39.3700787f;
- ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header().pixelAspectRatio();
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
}
ibuf->ftype = OPENEXR;
if (!(flags & IB_test)) {
- if (is_multi) { /* only enters with IB_multilayer flag set */
+
+ if (flags & IB_metadata) {
+ const Header & header = file->header(0);
+ Header::ConstIterator iter;
+
+ for (iter = header.begin(); iter != header.end(); iter++) {
+ const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name());
+
+ /* not all attributes are string attributes so we might get some NULLs here */
+ if (attrib) {
+ IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str());
+ ibuf->flags |= IB_metadata;
+ }
+ }
+ }
+
+ if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
/* constructs channels for reading, allocates memory in channels */
- ExrHandle *handle = imb_exr_begin_read_mem(file, width, height);
+ ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height);
if (handle) {
IMB_exr_read_channels(handle);
ibuf->userdata = handle; /* potential danger, the caller has to check for this! */
}
}
else {
- const bool has_rgb = exr_has_rgb(file);
- const bool has_luma = exr_has_luma(file);
+ const bool has_rgb = exr_has_rgb(*file);
+ const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
int xstride = sizeof(float) * 4;
@@ -1281,27 +1986,27 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
first += 4 * (height - 1) * width;
if (has_rgb) {
- frameBuffer.insert(exr_rgba_channelname(file, "R"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "R"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "G"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "G"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "B"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "B"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride));
}
else if (has_luma) {
- frameBuffer.insert(exr_rgba_channelname(file, "Y"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "BY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "BY"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride, 1, 1, 0.5f));
- frameBuffer.insert(exr_rgba_channelname(file, "RY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "RY"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride, 1, 1, 0.5f));
}
/* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
- frameBuffer.insert(exr_rgba_channelname(file, "A"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "A"),
Slice(Imf::FLOAT, (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
- if (exr_has_zbuffer(file)) {
+ if (exr_has_zbuffer(*file)) {
float *firstz;
addzbuffloatImBuf(ibuf);
@@ -1310,8 +2015,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)firstz, sizeof(float), -width * sizeof(float)));
}
- file->setFrameBuffer(frameBuffer);
- file->readPixels(dw.min.y, dw.max.y);
+ InputPart in (*file, 0);
+ in.setFrameBuffer(frameBuffer);
+ in.readPixels(dw.min.y, dw.max.y);
// XXX, ImBuf has no nice way to deal with this.
// ideally IM_rect would be used when the caller wants a rect BUT
@@ -1325,7 +2031,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
if (!has_rgb && has_luma) {
size_t a;
- if (exr_has_chroma(file)) {
+ if (exr_has_chroma(*file)) {
for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
float *color = ibuf->rect_float + a * 4;
ycc_to_rgb(color[0] * 255.0f, color[1] * 255.0f, color[2] * 255.0f,
@@ -1342,6 +2048,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
/* file is no longer needed */
+ delete membuf;
delete file;
}
}
@@ -1351,11 +2058,12 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
return(ibuf);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
std::cerr << exc.what() << std::endl;
if (ibuf) IMB_freeImBuf(ibuf);
delete file;
+ delete membuf;
return (0);
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 376d2401b1c..70ba4978124 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -39,34 +39,63 @@
/* This api also supports max 8 channels per pass now. easy to fix! */
#define EXR_LAY_MAXNAME 64
#define EXR_PASS_MAXNAME 64
+#define EXR_VIEW_MAXNAME 64
#define EXR_TOT_MAXNAME 64
-#define EXR_PASS_MAXCHAN 8
+#define EXR_PASS_MAXCHAN 24
#ifdef __cplusplus
extern "C" {
#endif
+struct StampData;
+
void *IMB_exr_get_handle(void);
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+void *IMB_exr_get_handle_name(const char *name);
+void IMB_exr_add_channel(void *handle,
+ const char *layname, const char *passname, const char *view,
+ int xstride, int ystride,
+ float *rect,
+ bool use_half_float);
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height);
-int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress);
+int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const struct StampData *stamp);
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *view);
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level);
-void IMB_exrtile_clear_channels(void *handle);
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname);
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname);
+void IMB_exr_clear_channels(void *handle);
+
+void IMB_exr_multilayer_convert(
+ void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
+ void * (*addlayer)(void *base, const char *str),
+ void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view));
+
+void IMB_exr_multiview_convert(
+ void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int frame);
-void IMB_exr_multilayer_convert(void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id));
+bool IMB_exr_multiview_save(
+ struct ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ struct ImBuf * (*getbuffer)(void *base, const size_t view_id));
void IMB_exr_close(void *handle);
+void IMB_exr_add_view(void *handle, const char *name);
+
+bool IMB_exr_has_multilayer(void *handle);
+bool IMB_exr_has_singlelayer_multiview(void *handle);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 21fa878c08a..c198cac6357 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -32,26 +32,52 @@
#include "openexr_api.h"
#include "openexr_multi.h"
-
void *IMB_exr_get_handle (void) {return NULL;}
-void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void *IMB_exr_get_handle_name (const char * /*name*/) { return NULL;}
+void IMB_exr_add_channel (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, const char * /*view*/,
+ int /*xstride*/, int /*ystride*/, float * /*rect*/,
+ bool /*use_half_float*/) { }
+
+int IMB_exr_begin_read (void * /*handle*/, const char * /*filename*/, int * /*width*/, int * /*height*/) { return 0;}
+int IMB_exr_begin_write (void * /*handle*/, const char * /*filename*/, int /*width*/, int /*height*/, int /*compress*/, const struct StampData * /*stamp*/) { return 0;}
+void IMB_exrtile_begin_write (void * /*handle*/, const char * /*filename*/, int /*mipmap*/, int /*width*/, int /*height*/, int /*tilex*/, int /*tiley*/) { }
-int IMB_exr_begin_read (void *handle, const char *filename, int *width, int *height) { (void)handle; (void)filename; (void)width; (void)height; return 0;}
-int IMB_exr_begin_write (void *handle, const char *filename, int width, int height, int compress) { (void)handle; (void)filename; (void)width; (void)height; (void)compress; return 0;}
-void IMB_exrtile_begin_write (void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley) { (void)handle; (void)filename; (void)mipmap; (void)width; (void)height; (void)tilex; (void)tiley; }
+void IMB_exr_set_channel (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, int /*xstride*/, int /*ystride*/, float * /*rect*/) { }
+float *IMB_exr_channel_rect (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, const char * /*view*/) { return NULL; }
-void IMB_exr_set_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void IMB_exr_read_channels (void * /*handle*/) { }
+void IMB_exr_write_channels (void * /*handle*/) { }
+void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/) { }
+void IMB_exrmultiview_write_channels(void * /*handle*/, const char * /*viewname*/) { }
+void IMB_exr_clear_channels (void * /*handle*/) { }
+
+void IMB_exr_multilayer_convert(
+ void * /*handle*/, void * /*base*/,
+ void * (* /*addview*/)(void *base, const char *str),
+ void * (* /*addlayer*/)(void *base, const char *str),
+ void (* /*addpass*/)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view))
+{
+}
-void IMB_exr_read_channels (void *handle) { (void)handle; }
-void IMB_exr_write_channels (void *handle) { (void)handle; }
-void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) { (void)handle; (void)partx; (void)party; (void)level; }
-void IMB_exrtile_clear_channels (void *handle) { (void)handle; }
+void IMB_exr_multiview_convert(
+ void * /*handle*/, void * /*base*/,
+ void (* /*addview*/)(void *base, const char *str),
+ void (* /*addbuffer*/)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int /*frame*/)
+{
+}
-void IMB_exr_multilayer_convert (void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id))
+bool IMB_exr_multiview_save(
+ struct ImBuf * /*ibuf*/, const char * /*name*/, const int /*flags*/, const size_t /*totviews*/,
+ const char * (* /*getview*/)(void *base, size_t view_id),
+ struct ImBuf * (* /*getbuffer*/)(void *base, const size_t view_id))
{
- (void)handle; (void)base; (void)addlayer; (void)addpass;
+ return false;
}
-void IMB_exr_close (void *handle) { (void)handle; }
+void IMB_exr_close (void * /*handle*/) { }
+
+void IMB_exr_add_view(void * /*handle*/, const char * /*name*/) { }
+bool IMB_exr_has_multilayer(void * /*handle*/) { return false; }
+bool IMB_exr_has_singlelayer_multiview(void * /*handle*/) { return false; }
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 683bdabcd6c..1b6b413838d 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -138,6 +138,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
int channels_in_float = ibuf->channels ? ibuf->channels : 4;
float (*chanel_colormanage_cb)(float);
+ size_t num_bytes;
/* use the jpeg quality setting for compression */
int compression;
@@ -184,11 +185,11 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
}
/* copy image data */
-
+ num_bytes = ((size_t)ibuf->x) * ibuf->y * bytesperpixel;
if (is_16bit)
- pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels");
+ pixels16 = MEM_mallocN(num_bytes * sizeof(unsigned short), "png 16bit pixels");
else
- pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels");
+ pixels = MEM_mallocN(num_bytes * sizeof(unsigned char), "png 8bit pixels");
if (pixels == NULL && pixels16 == NULL) {
png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -312,7 +313,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
rgb[0] = chanel_colormanage_cb(from_straight[0]);
rgb[1] = chanel_colormanage_cb(from_straight[1]);
rgb[2] = chanel_colormanage_cb(from_straight[2]);
- to16[0] = ftoshort(rgb_to_bw(rgb));
+ to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++; from_float += 4;
}
}
@@ -321,7 +322,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
rgb[0] = chanel_colormanage_cb(from_float[0]);
rgb[1] = chanel_colormanage_cb(from_float[1]);
rgb[2] = chanel_colormanage_cb(from_float[2]);
- to16[0] = ftoshort(rgb_to_bw(rgb));
+ to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++; from_float += 3;
}
}
@@ -454,13 +455,13 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
if (is_16bit) {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel);
+ ((unsigned short *)pixels16 + (((size_t)i) * ibuf->x) * bytesperpixel);
}
}
else {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
}
}
@@ -682,7 +683,7 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
else {
imb_addrectImBuf(ibuf);
- pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
+ pixels = MEM_mallocN(((size_t)ibuf->x) * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
if (pixels == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
@@ -698,7 +699,7 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
/* set the individual row-pointers to point at the correct offsets */
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
}
png_read_image(png_ptr, row_pointers);
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index bb09c57d1e5..38d54e64035 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -103,7 +103,7 @@ static void imb_handle_alpha(ImBuf *ibuf, int flags, char colorspace[IM_MAX_SPAC
ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
{
ImBuf *ibuf;
- ImFileType *type;
+ const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (mem == NULL) {
@@ -133,7 +133,7 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co
static ImBuf *IMB_ibImageFromFile(const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
{
ImBuf *ibuf;
- ImFileType *type;
+ const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (colorspace)
@@ -209,6 +209,8 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
int file, a;
char filepath_tx[IB_FILENAME_SIZE];
+ BLI_assert(!BLI_path_is_rel(filepath));
+
imb_cache_filename(filepath_tx, filepath, flags);
file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
@@ -237,6 +239,8 @@ ImBuf *IMB_testiffname(const char *filepath, int flags)
char filepath_tx[IB_FILENAME_SIZE];
char colorspace[IM_MAX_SPACE] = "\0";
+ BLI_assert(!BLI_path_is_rel(filepath));
+
imb_cache_filename(filepath_tx, filepath, flags);
file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
@@ -257,7 +261,7 @@ ImBuf *IMB_testiffname(const char *filepath, int flags)
static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int *rect)
{
- ImFileType *type;
+ const ImFileType *type;
unsigned char *mem;
size_t size;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4001b681ad9..c7b347cb20c 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -322,30 +322,30 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float);
if (do_char) {
- drect = dbuf->rect + desty * dbuf->x + destx;
- orect = obuf->rect + origy * obuf->x + origx;
+ drect = dbuf->rect + ((size_t)desty) * dbuf->x + destx;
+ orect = obuf->rect + ((size_t)origy) * obuf->x + origx;
}
if (do_float) {
- drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
- orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
+ drectf = dbuf->rect_float + (((size_t)desty) * dbuf->x + destx) * 4;
+ orectf = obuf->rect_float + (((size_t)origy) * obuf->x + origx) * 4;
}
if (dmaskrect)
- dmaskrect += origy * obuf->x + origx;
+ dmaskrect += ((size_t)origy) * obuf->x + origx;
destskip = dbuf->x;
origskip = obuf->x;
if (sbuf) {
- if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
- if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4;
+ if (do_char) srect = sbuf->rect + ((size_t)srcy) * sbuf->x + srcx;
+ if (do_float) srectf = sbuf->rect_float + (((size_t)srcy) * sbuf->x + srcx) * 4;
srcskip = sbuf->x;
if (cmaskrect)
- cmaskrect += srcy * sbuf->x + srcx;
+ cmaskrect += ((size_t)srcy) * sbuf->x + srcx;
if (texmaskrect)
- texmaskrect += srcy * sbuf->x + srcx;
+ texmaskrect += ((size_t)srcy) * sbuf->x + srcx;
}
else {
srect = drect;
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
new file mode 100644
index 00000000000..3b9da639a86
--- /dev/null
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -0,0 +1,1292 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/stereoimbuf.c
+ * \ingroup imbuf
+ */
+
+#include <stddef.h>
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_filetype.h"
+#include "IMB_metadata.h"
+#include "IMB_colormanagement_intern.h"
+
+#include "imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_math.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
+
+/* prototypes */
+struct Stereo3DData;
+static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+
+typedef struct Stereo3DData {
+ struct { float *left, *right, *stereo; } rectf;
+ struct { uchar *left, *right, *stereo; } rect;
+ size_t x, y, channels;
+ bool is_float;
+} Stereo3DData;
+
+static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][3], from[0][3]);
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][3], from[0][3]);
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(float) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ const float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(uchar) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width * 2;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/**************************** dimension utils ****************************************/
+
+void IMB_stereo3d_write_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width : width * 2;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height : height * 2;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+void IMB_stereo3d_read_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width / 2 : width;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height / 2 : height;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+/**************************** un/squeeze frame ****************************************/
+
+static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_squeeze_rectf(float *rectf, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rectfloat);
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, rectf, channels,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ memcpy(rectf, ibuf->rect_float, x * y * sizeof(float[4]));
+ IMB_freeImBuf(ibuf);
+}
+
+static void imb_stereo3d_squeeze_rect(int *rect, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rect);
+
+ IMB_buffer_byte_from_byte(
+ (unsigned char *)ibuf->rect, (unsigned char *)rect,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ memcpy(rect, ibuf->rect, x * y * sizeof(unsigned int));
+ IMB_freeImBuf(ibuf);
+}
+
+
+/*************************** preparing to call the write functions **************************/
+
+static void imb_stereo3d_data_initialize(
+ Stereo3DData *s3d_data, const bool is_float,
+ const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right, int *rect_stereo,
+ float *rectf_left, float *rectf_right, float *rectf_stereo)
+{
+ s3d_data->is_float = is_float;
+ s3d_data->x = x;
+ s3d_data->y = y;
+ s3d_data->channels = channels;
+ s3d_data->rect.left = (uchar *)rect_left;
+ s3d_data->rect.right = (uchar *)rect_right;
+ s3d_data->rect.stereo = (uchar *)rect_stereo;
+ s3d_data->rectf.left = rectf_left;
+ s3d_data->rectf.right = rectf_right;
+ s3d_data->rectf.stereo = rectf_stereo;
+}
+
+int *IMB_stereo3d_from_rect(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right)
+{
+ int *r_rect;
+ 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__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, 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);
+
+ return r_rect;
+}
+
+float *IMB_stereo3d_from_rectf(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ float *rectf_left, float *rectf_right)
+{
+ float *r_rectf;
+ 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__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rectf;
+}
+
+/* left/right are always float */
+ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
+{
+ ImBuf *ibuf_stereo = NULL;
+ 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, ibuf_left->x, ibuf_left->y, &width, &height);
+ ibuf_stereo = IMB_allocImBuf(width, height, ibuf_left->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_stereo->flags = ibuf_left->flags;
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo->rect_float);
+
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_ImBuf(ibuf_stereo, &im_format->stereo3d_format, ibuf_left->x, ibuf_left->y);
+
+ return ibuf_stereo;
+}
+
+static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_write_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_write_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_write_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_write_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************** reading stereo imbufs **********************/
+
+static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_from = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_from = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(float) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.right;
+ uchar *rect_right = s3d->rect.left;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(uchar) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width * 2;
+ const int stride_to = width;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(float) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ /* always RGBA input/output */
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(float) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+
+/*************************** preparing to call the read functions **************************/
+
+/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
+void IMB_ImBufFromStereo3d(
+ Stereo3dFormat *s3d, ImBuf *ibuf_stereo3d,
+ ImBuf **r_ibuf_left, ImBuf **r_ibuf_right)
+{
+ Stereo3DData s3d_data = {{NULL}};
+ ImBuf *ibuf_left, *ibuf_right;
+ size_t width, height;
+ const bool is_float = (ibuf_stereo3d->rect_float != NULL);
+
+ IMB_stereo3d_read_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+
+ ibuf_left = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+ ibuf_right = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_left->flags = ibuf_stereo3d->flags;
+ ibuf_right->flags = ibuf_stereo3d->flags;
+
+ /* we always work with unsqueezed formats */
+ IMB_stereo3d_write_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+ imb_stereo3d_unsqueeze_ImBuf(ibuf_stereo3d, s3d, width, height);
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo3d->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo3d->rect_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+
+ if (ibuf_stereo3d->flags & (IB_zbuf | IB_zbuffloat)) {
+ if (is_float) {
+ addzbuffloatImBuf(ibuf_left);
+ addzbuffloatImBuf(ibuf_right);
+ }
+ else {
+ addzbufImBuf(ibuf_left);
+ addzbufImBuf(ibuf_right);
+ }
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 1,
+ (int *)ibuf_left->zbuf, (int *)ibuf_right->zbuf, (int *)ibuf_stereo3d->zbuf,
+ ibuf_left->zbuf_float, ibuf_right->zbuf_float, ibuf_stereo3d->zbuf_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+ }
+
+ IMB_freeImBuf(ibuf_stereo3d);
+
+ *r_ibuf_left = ibuf_left;
+ *r_ibuf_right = ibuf_right;
+}
+
+static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_read_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_read_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_read_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_read_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
index 70b71ec4182..40dcdc9d24a 100644
--- a/source/blender/imbuf/intern/targa.c
+++ b/source/blender/imbuf/intern/targa.c
@@ -568,7 +568,7 @@ ImBuf *imb_loadtarga(unsigned char *mem, size_t mem_size, int flags, char colors
else ibuf = IMB_allocImBuf(tga.xsize, tga.ysize, (tga.pixsize + 0x7) & ~0x7, IB_rect);
if (ibuf == NULL) return NULL;
- ibuf->ftype = TGA;
+ ibuf->ftype = (tga.imgtyp < 4) ? RAWTGA : TGA;
mem = mem + 18 + tga.numid;
cp[0] = 0xff;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 118f0405303..7a949b7ffea 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -200,6 +200,17 @@ static void escape_uri_string(const char *string, char *escaped_string, int esca
/** ----- end of adapted code from glib --- */
+static bool thumbhash_from_path(const char *UNUSED(path), ThumbSource source, char *r_hash)
+{
+ switch (source) {
+ case THB_SOURCE_FONT:
+ return IMB_thumb_load_font_get_hash(r_hash);
+ default:
+ r_hash[0] = '\0';
+ return false;
+ }
+}
+
static int uri_from_filename(const char *path, char *uri)
{
char orig_uri[URI_MAX];
@@ -239,47 +250,68 @@ static int uri_from_filename(const char *path, char *uri)
return 1;
}
-static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len)
+static bool thumbpathname_from_uri(
+ const char *uri, char *r_path, const int path_len, char *r_name, int name_len, ThumbSize size)
{
- char hexdigest[33];
- unsigned char digest[16];
+ char name_buff[40];
+
+ if (r_path && !r_name) {
+ r_name = name_buff;
+ name_len = sizeof(name_buff);
+ }
- BLI_hash_md5_buffer(uri, strlen(uri), digest);
- hexdigest[0] = '\0';
- BLI_snprintf(thumb, thumb_len, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
+ if (r_name) {
+ char hexdigest[33];
+ unsigned char digest[16];
+ BLI_hash_md5_buffer(uri, strlen(uri), digest);
+ hexdigest[0] = '\0';
+ BLI_snprintf(r_name, name_len, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
+// printf("%s: '%s' --> '%s'\n", __func__, uri, r_name);
+ }
- // printf("%s: '%s' --> '%s'\n", __func__, uri, thumb);
+ if (r_path) {
+ char tmppath[FILE_MAX];
+
+ if (get_thumb_dir(tmppath, size)) {
+ BLI_snprintf(r_path, path_len, "%s%s", tmppath, r_name);
+// printf("%s: '%s' --> '%s'\n", __func__, uri, r_path);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len)
+{
+ thumbpathname_from_uri(uri, NULL, 0, thumb, thumb_len, THB_FAIL);
}
-static int thumbpath_from_uri(const char *uri, char *path, const int path_len, ThumbSize size)
+static bool thumbpath_from_uri(const char *uri, char *path, const int path_len, ThumbSize size)
{
- char tmppath[FILE_MAX];
- int rv = 0;
-
- if (get_thumb_dir(tmppath, size)) {
- char thumb[40];
- thumbname_from_uri(uri, thumb, sizeof(thumb));
- BLI_snprintf(path, path_len, "%s%s", tmppath, thumb);
- rv = 1;
- }
- return rv;
+ return thumbpathname_from_uri(uri, path, path_len, NULL, 0, size);
}
void IMB_thumb_makedirs(void)
{
char tpath[FILE_MAX];
+#if 0 /* UNUSED */
if (get_thumb_dir(tpath, THB_NORMAL)) {
BLI_dir_create_recursive(tpath);
}
+#endif
+ if (get_thumb_dir(tpath, THB_LARGE)) {
+ BLI_dir_create_recursive(tpath);
+ }
if (get_thumb_dir(tpath, THB_FAIL)) {
BLI_dir_create_recursive(tpath);
}
}
/* create thumbnail for file and returns new imbuf for thumbnail */
-ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+static ImBuf *thumb_create_ex(
+ const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash,
+ ThumbSize size, ThumbSource source, ImBuf *img)
{
- char uri[URI_MAX] = "";
char desc[URI_MAX + 22];
char tpath[FILE_MAX];
char tdir[FILE_MAX];
@@ -287,7 +319,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
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 thumb[40];
short tsize = 128;
short ex, ey;
float scaledx, scaledy;
@@ -295,10 +326,10 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
switch (size) {
case THB_NORMAL:
- tsize = 128;
+ tsize = PREVIEW_RENDER_DEFAULT_HEIGHT;
break;
case THB_LARGE:
- tsize = 256;
+ tsize = PREVIEW_RENDER_DEFAULT_HEIGHT * 2;
break;
case THB_FAIL:
tsize = 1;
@@ -309,20 +340,18 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
/* exception, skip images over 100mb */
if (source == THB_SOURCE_IMAGE) {
- const size_t file_size = BLI_file_size(path);
+ 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, path);
+ // printf("file too big: %d, skipping %s\n", (int)size, file_path);
return NULL;
}
}
- uri_from_filename(path, uri);
- thumbname_from_uri(uri, thumb, sizeof(thumb));
if (get_thumb_dir(tdir, size)) {
BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
- thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
+// thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb);
- if (BLI_path_ncmp(path, tdir, sizeof(tdir)) == 0) {
+ if (BLI_path_ncmp(file_path, tdir, sizeof(tdir)) == 0) {
return NULL;
}
if (size == THB_FAIL) {
@@ -330,20 +359,26 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
if (!img) return NULL;
}
else {
- if (THB_SOURCE_IMAGE == source || THB_SOURCE_BLEND == source) {
-
+ if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
/* only load if we didnt give an image */
if (img == NULL) {
- if (THB_SOURCE_BLEND == source) {
- img = IMB_loadblend_thumb(path);
- }
- else {
- img = IMB_loadiffname(path, IB_rect | IB_metadata, NULL);
+ switch (source) {
+ case THB_SOURCE_IMAGE:
+ img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL);
+ break;
+ case THB_SOURCE_BLEND:
+ img = IMB_thumb_load_blend(file_path);
+ break;
+ case THB_SOURCE_FONT:
+ img = IMB_thumb_load_font(file_path, tsize, tsize);
+ break;
+ default:
+ BLI_assert(0); /* This should never happen */
}
}
if (img != NULL) {
- if (BLI_stat(path, &info) != -1) {
+ 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);
@@ -352,11 +387,11 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
else if (THB_SOURCE_MOVIE == source) {
struct anim *anim = NULL;
- anim = IMB_open_anim(path, IB_rect | IB_metadata, 0, NULL);
+ anim = IMB_open_anim(file_path, IB_rect | IB_metadata, 0, NULL);
if (anim != NULL) {
img = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (img == NULL) {
- printf("not an anim; %s\n", path);
+ printf("not an anim; %s\n", file_path);
}
else {
IMB_freeImBuf(img);
@@ -364,7 +399,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
IMB_free_anim(anim);
}
- if (BLI_stat(path, &info) != -1) {
+ if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
}
@@ -380,7 +415,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
ex = (short)scaledx;
ey = (short)scaledy;
-
+
/* save some time by only scaling byte buf */
if (img->rect_float) {
if (img->rect == NULL) {
@@ -397,7 +432,10 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
IMB_metadata_change_field(img, "Software", "Blender");
IMB_metadata_change_field(img, "Thumb::URI", uri);
IMB_metadata_change_field(img, "Thumb::MTime", mtime);
- if (THB_SOURCE_IMAGE == source) {
+ if (use_hash) {
+ IMB_metadata_change_field(img, "X-Blender::Hash", hash);
+ }
+ if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth);
IMB_metadata_change_field(img, "Thumb::Image::Height", cheight);
}
@@ -412,12 +450,40 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
BLI_rename(temp, tpath);
}
+ }
+ return img;
+}
- return img;
+static ImBuf *thumb_create_or_fail(
+ const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash,
+ ThumbSize size, ThumbSource source)
+{
+ ImBuf *img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, size, source, NULL);
+
+ if (!img) {
+ /* thumb creation failed, write fail thumb */
+ img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, THB_FAIL, source, NULL);
+ if (img) {
+ /* we don't need failed thumb anymore */
+ IMB_freeImBuf(img);
+ img = NULL;
+ }
}
+
return img;
}
+ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+{
+ char uri[URI_MAX] = "";
+ char thumb_name[40];
+
+ uri_from_filename(path, uri);
+ thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
+
+ return thumb_create_ex(path, uri, thumb_name, false, THUMB_DEFAULT_HASH, size, source, img);
+}
+
/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
@@ -456,25 +522,30 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
/* create the thumb if necessary and manage failed and old thumbs */
-ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
- char thumb[FILE_MAX];
+ char thumb_path[FILE_MAX];
+ char thumb_name[40];
char uri[URI_MAX];
+ const char *file_path;
+ const char *path;
BLI_stat_t st;
ImBuf *img = NULL;
-
- if (BLI_stat(path, &st) == -1) {
+
+ path = file_path = org_path;
+
+ if (BLI_stat(file_path, &st) == -1) {
return NULL;
}
if (!uri_from_filename(path, uri)) {
return NULL;
}
- if (thumbpath_from_uri(uri, thumb, sizeof(thumb), THB_FAIL)) {
+ if (thumbpath_from_uri(uri, thumb_path, sizeof(thumb_path), THB_FAIL)) {
/* failure thumb exists, don't try recreating */
- if (BLI_exists(thumb)) {
+ if (BLI_exists(thumb_path)) {
/* clear out of date fail case */
- if (BLI_file_older(thumb, path)) {
- BLI_delete(thumb, false, false);
+ if (BLI_file_older(thumb_path, file_path)) {
+ BLI_delete(thumb_path, false, false);
}
else {
return NULL;
@@ -482,52 +553,53 @@ ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
}
}
- if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
- if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) {
+ if (thumbpathname_from_uri(uri, thumb_path, sizeof(thumb_path), thumb_name, sizeof(thumb_name), size)) {
+ if (BLI_path_ncmp(path, thumb_path, sizeof(thumb_path)) == 0) {
img = IMB_loadiffname(path, IB_rect, NULL);
}
else {
- img = IMB_loadiffname(thumb, IB_rect | IB_metadata, NULL);
+ img = IMB_loadiffname(thumb_path, IB_rect | IB_metadata, NULL);
if (img) {
+ bool regenerate = false;
+
char mtime[40];
- if (!IMB_metadata_get_field(img, "Thumb::MTime", mtime, 40)) {
- /* illegal thumb, forget it! */
- IMB_freeImBuf(img);
- img = NULL;
+ char thumb_hash[33];
+ char thumb_hash_curr[33];
+
+ const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
+
+ if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) {
+ regenerate = (st.st_mtime != atol(mtime));
}
else {
- time_t t = atol(mtime);
- if (st.st_mtime != t) {
- /* recreate all thumbs */
- IMB_freeImBuf(img);
- img = NULL;
- IMB_thumb_delete(path, THB_NORMAL);
- IMB_thumb_delete(path, THB_LARGE);
- IMB_thumb_delete(path, THB_FAIL);
- img = IMB_thumb_create(path, size, source, NULL);
- if (!img) {
- /* thumb creation failed, write fail thumb */
- img = IMB_thumb_create(path, THB_FAIL, source, NULL);
- if (img) {
- /* we don't need failed thumb anymore */
- IMB_freeImBuf(img);
- img = NULL;
- }
- }
+ /* illegal thumb, regenerate it! */
+ regenerate = true;
+ }
+
+ if (use_hash && !regenerate) {
+ if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) {
+ regenerate = !STREQ(thumb_hash, thumb_hash_curr);
+ }
+ else {
+ regenerate = true;
}
}
+
+ if (regenerate) {
+ /* recreate all thumbs */
+ IMB_freeImBuf(img);
+ img = NULL;
+ IMB_thumb_delete(path, THB_NORMAL);
+ IMB_thumb_delete(path, THB_LARGE);
+ IMB_thumb_delete(path, THB_FAIL);
+ img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source);
+ }
}
else {
- img = IMB_thumb_create(path, size, source, NULL);
- if (!img) {
- /* thumb creation failed, write fail thumb */
- img = IMB_thumb_create(path, THB_FAIL, source, NULL);
- if (img) {
- /* we don't need failed thumb anymore */
- IMB_freeImBuf(img);
- img = NULL;
- }
- }
+ char thumb_hash[33];
+ const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
+
+ img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source);
}
}
}
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index aee465c49cc..d7b9089c437 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -121,7 +121,7 @@ static ImBuf *loadblend_thumb(gzFile gzfile)
return NULL;
}
-ImBuf *IMB_loadblend_thumb(const char *path)
+ImBuf *IMB_thumb_load_blend(const char *path)
{
gzFile gzfile;
/* not necessarily a gzip */
@@ -143,7 +143,7 @@ ImBuf *IMB_loadblend_thumb(const char *path)
/* add a fake passepartout overlay to a byte buffer, use for blend file thumbnails */
#define MARGIN 2
-void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect)
+void IMB_thumb_overlay_blend(unsigned int *thumb, int width, int height, float aspect)
{
unsigned char *px = (unsigned char *)thumb;
int margin_l = MARGIN;
diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c
new file mode 100644
index 00000000000..4b024f3c51b
--- /dev/null
+++ b/source/blender/imbuf/intern/thumbs_font.c
@@ -0,0 +1,100 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Thomas Beck.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/thumbs_font.c
+ * \ingroup imbuf
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_fileops.h"
+#include "BLI_hash_md5.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_thumbs.h"
+
+
+/* XXX, bad level call */
+#include "../../blenfont/BLF_api.h"
+#include "../../blenfont/BLF_translation.h" /* 'N_' macro and BLF_lang_get()... */
+
+static const char *thumb_str[] = {
+ N_("AaBbCc"),
+
+ N_("The quick"),
+ N_("brown fox"),
+ N_("jumps over"),
+ N_("the lazy dog"),
+};
+
+struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y)
+{
+ const int font_size = y / 4;
+
+ struct ImBuf *ibuf;
+ float font_color[4];
+
+ /* create a white image (theme color is used for drawing) */
+ font_color[0] = font_color[1] = font_color[2] = 1.0f;
+
+ /* fill with zero alpha */
+ font_color[3] = 0.0f;
+
+ ibuf = IMB_allocImBuf(x, y, 32, IB_rect | IB_metadata);
+ IMB_rectfill(ibuf, font_color);
+
+ /* draw with full alpha */
+ font_color[3] = 1.0f;
+
+ BLF_thumb_preview(
+ filename, thumb_str, ARRAY_SIZE(thumb_str),
+ font_color, font_size,
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels);
+
+ return ibuf;
+}
+
+bool IMB_thumb_load_font_get_hash(char *r_hash)
+{
+ char buf[1024];
+ char *str = buf;
+ size_t len = 0;
+
+ int draw_str_lines = ARRAY_SIZE(thumb_str);
+ int i;
+
+ unsigned char digest[16];
+
+ len += BLI_strncpy_rlen(str + len, THUMB_DEFAULT_HASH, sizeof(buf) - len);
+
+ for (i = 0; (i < draw_str_lines) && (len < sizeof(buf)); i++) {
+ len += BLI_strncpy_rlen(str + len, BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, thumb_str[i]), sizeof(buf) - len);
+ }
+
+ BLI_hash_md5_buffer(str, len, digest);
+ r_hash[0] = '\0';
+ BLI_hash_md5_to_hexdigest(digest, r_hash);
+
+ return true;
+}
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 4d58642e9c4..62097635296 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -454,7 +454,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (bitspersample == 32) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
- fill_vn_fl(fbuf, ibuf->x, 1.0f);
+ copy_vn_fl(fbuf, ibuf->x, 1.0f);
else if (chan >= spp) /* for grayscale, duplicate first channel into G and B */
success |= TIFFReadScanline(image, fbuf, row, 0);
else
@@ -464,7 +464,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
}
else if (bitspersample == 16) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
- fill_vn_ushort(sbuf, ibuf->x, 65535);
+ copy_vn_ushort(sbuf, ibuf->x, 65535);
else if (chan >= spp) /* for grayscale, duplicate first channel into G and B */
success |= TIFFReadScanline(image, fbuf, row, 0);
else
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 32100aa2288..8b16e03aed2 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -186,11 +186,13 @@ int IMB_ispic_type(const char *name)
#define HEADER_SIZE 64
unsigned char buf[HEADER_SIZE];
- ImFileType *type;
+ const ImFileType *type;
BLI_stat_t st;
int fp;
- if (UTIL_DEBUG) printf("IMB_ispic_name: loading %s\n", name);
+ BLI_assert(!BLI_path_is_rel(name));
+
+ if (UTIL_DEBUG) printf("%s: loading %s\n", __func__, name);
if (BLI_stat(name, &st) == -1)
return false;
@@ -389,7 +391,9 @@ int imb_get_anim_type(const char *name)
int type;
BLI_stat_t st;
- if (UTIL_DEBUG) printf("in getanimtype: %s\n", name);
+ BLI_assert(!BLI_path_is_rel(name));
+
+ if (UTIL_DEBUG) printf("%s: %s\n", __func__, name);
#ifndef _WIN32
# ifdef WITH_QUICKTIME
@@ -434,8 +438,20 @@ int imb_get_anim_type(const char *name)
bool IMB_isanim(const char *filename)
{
int type;
-
+
type = imb_get_anim_type(filename);
return (type && type != ANIM_SEQUENCE);
}
+
+bool IMB_isfloat(ImBuf *ibuf)
+{
+ const ImFileType *type;
+
+ for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
+ if (type->ftype(type, ibuf)) {
+ return (type->flag & IM_FTYPE_FLOAT) != 0;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 087330d10d2..28710fba823 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -33,6 +33,10 @@
#include <stdio.h>
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -41,26 +45,16 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-static ImBuf *prepare_write_imbuf(ImFileType *type, ImBuf *ibuf)
+static ImBuf *prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
{
- ImBuf *write_ibuf = ibuf;
-
- if (type->flag & IM_FTYPE_FLOAT) {
- /* pass */
- }
- else {
- if (ibuf->rect == NULL && ibuf->rect_float) {
- ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
- IMB_rect_from_float(ibuf);
- }
- }
-
- return write_ibuf;
+ return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
}
short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
{
- ImFileType *type;
+ const ImFileType *type;
+
+ BLI_assert(!BLI_path_is_rel(name));
if (ibuf == NULL) return (false);
ibuf->flags = flags;
@@ -86,3 +80,19 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
return false;
}
+ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
+{
+ ImBuf *write_ibuf = ibuf;
+
+ if (isfloat) {
+ /* pass */
+ }
+ else {
+ if (ibuf->rect == NULL && ibuf->rect_float) {
+ ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
+ IMB_rect_from_float(ibuf);
+ }
+ }
+
+ return write_ibuf;
+}