diff options
Diffstat (limited to 'source/blender/imbuf/intern')
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; +} |