diff options
Diffstat (limited to 'source/blender/imbuf')
23 files changed, 498 insertions, 310 deletions
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 0390df06052..7493fa3e4af 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -109,6 +109,14 @@ struct ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[I /** * + * \attention Defined in readimage.c + */ +struct ImBuf *IMB_thumb_load_image(const char *filepath, + const size_t max_thumb_size, + char colorspace[IM_MAX_SPACE]); + +/** + * * \attention Defined in allocimbuf.c */ void IMB_freeImBuf(struct ImBuf *ibuf); @@ -522,7 +530,6 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int * \attention Defined in writeimage.c */ bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags); -bool IMB_prepare_write_ImBuf(bool isfloat, struct ImBuf *ibuf); /** * @@ -546,12 +553,6 @@ bool IMB_isanim(const char *filepath); int imb_get_anim_type(const char *filepath); /** - * - * \attention Defined in util.c - */ -bool IMB_isfloat(const struct ImBuf *ibuf); - -/** * Test if color-space conversions of pixels in buffer need to take into account alpha. */ bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf); diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 934163846e4..16cf0e2125e 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -47,7 +47,7 @@ typedef struct DDSData { * Also; add new variables to the end to save pain! */ -/* Warning: Keep explicit value assignments here, +/* WARNING: Keep explicit value assignments here, * this file is included in areas where not all format defines are set * (e.g. intern/dds only get WITH_DDS, even if TIFF, HDR etc are also defined). * See T46524. */ diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h index 623a3b2b5f4..b55a6f653b8 100644 --- a/source/blender/imbuf/IMB_thumbs.h +++ b/source/blender/imbuf/IMB_thumbs.h @@ -50,7 +50,7 @@ typedef enum ThumbSource { /** * Create thumbnail for file and returns new imbuf for thumbnail. */ -struct ImBuf *IMB_thumb_create(const char *path, +struct ImBuf *IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, struct ImBuf *img); @@ -58,17 +58,17 @@ struct ImBuf *IMB_thumb_create(const char *path, /** * Read thumbnail for file and returns new imbuf for thumbnail. */ -struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size); +struct ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size); /** * Delete all thumbs for the file. */ -void IMB_thumb_delete(const char *path, ThumbSize size); +void IMB_thumb_delete(const char *filepath, ThumbSize size); /** * Create the thumb if necessary and manage failed and old thumbs. */ -struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source); +struct ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source); /** * Create the necessary directories to store the thumbnails. @@ -85,7 +85,7 @@ struct ImBuf *IMB_thumb_load_blend(const char *blen_path, /** * Special function for previewing fonts. */ -struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y); +struct ImBuf *IMB_thumb_load_font(const char *filepath, unsigned int x, unsigned int y); bool IMB_thumb_load_font_get_hash(char *r_hash); void IMB_thumb_clear_translations(void); void IMB_thumb_ensure_translations(void); diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 31f8b3a9505..67d1aefeacb 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -36,6 +36,17 @@ typedef struct ImFileType { char colorspace[IM_MAX_SPACE]); /** Load an image from a file. */ struct ImBuf *(*load_filepath)(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]); + /** + * Load/Create a thumbnail image from a filepath. `max_thumb_size` is maximum size of either + * dimension, so can return less on either or both. Should, if possible and performant, return + * dimensions of the full-size image in r_width & r_height. + */ + struct ImBuf *(*load_filepath_thumbnail)(const char *filepath, + const int flags, + const size_t max_thumb_size, + char colorspace[IM_MAX_SPACE], + size_t *r_width, + size_t *r_height); /** Save to a file (or memory if #IB_mem is set in `flags` and the format supports it). */ bool (*save)(struct ImBuf *ibuf, const char *filepath, int flags); void (*load_tile)(struct ImBuf *ibuf, @@ -143,6 +154,12 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]); +struct ImBuf *imb_thumbnail_jpeg(const char *filepath, + const int flags, + const size_t max_thumb_size, + char colorspace[IM_MAX_SPACE], + size_t *r_width, + size_t *r_height); /** \} */ diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 096089d4c41..0052ce19aa1 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -423,7 +423,7 @@ static int startavi(struct anim *anim) anim->cur_position = 0; # if 0 - printf("x:%d y:%d size:%d interl:%d dur:%d\n", + printf("x:%d y:%d size:%d interlace:%d dur:%d\n", anim->x, anim->y, anim->framesize, diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index d1cd30cfe84..6448d6cd76a 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -69,7 +69,7 @@ static struct ImBuf *imb_load_dpx_cineon(const unsigned char *mem, return ibuf; } -static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon, int flags) +static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filepath, int use_cineon, int flags) { LogImageFile *logImage; float *fbuf; @@ -86,7 +86,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon depth = (ibuf->planes + 7) >> 3; if (depth > 4 || depth < 3) { - printf("DPX/Cineon: unsupported depth: %d for file: '%s'\n", depth, filename); + printf("DPX/Cineon: unsupported depth: %d for file: '%s'\n", depth, filepath); return 0; } @@ -103,7 +103,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon bitspersample = 8; } - logImage = logImageCreate(filename, + logImage = logImageCreate(filepath, use_cineon, ibuf->x, ibuf->y, diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index 3bdfcb60292..8312476bda0 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -35,7 +35,7 @@ void cineonSetVerbose(int verbosity) static void fillCineonMainHeader(LogImageFile *cineon, CineonMainHeader *header, - const char *filename, + const char *filepath, const char *creator) { time_t fileClock; @@ -57,7 +57,7 @@ static void fillCineonMainHeader(LogImageFile *cineon, getRowLength(cineon->width, cineon->element[0]), cineon->isMSB); strcpy(header->fileHeader.version, "v4.5"); - strncpy(header->fileHeader.file_name, filename, 99); + strncpy(header->fileHeader.file_name, filepath, 99); header->fileHeader.file_name[99] = 0; fileClock = time(NULL); fileTime = localtime(&fileClock); @@ -126,7 +126,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t { CineonMainHeader header; LogImageFile *cineon = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__); - const char *filename = (const char *)byteStuff; + const char *filepath = (const char *)byteStuff; int i; unsigned int dataOffset; @@ -144,11 +144,11 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t cineon->file = NULL; if (fromMemory == 0) { - /* byteStuff is then the filename */ - cineon->file = BLI_fopen(filename, "rb"); + /* byteStuff is then the filepath */ + cineon->file = BLI_fopen(filepath, "rb"); if (cineon->file == NULL) { if (verbose) { - printf("Cineon: Failed to open file \"%s\".\n", filename); + printf("Cineon: Failed to open file \"%s\".\n", filepath); } logImageClose(cineon); return NULL; @@ -350,7 +350,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t } LogImageFile *cineonCreate( - const char *filename, int width, int height, int bitsPerSample, const char *creator) + const char *filepath, int width, int height, int bitsPerSample, const char *creator) { CineonMainHeader header; const char *shortFilename = NULL; @@ -393,18 +393,18 @@ LogImageFile *cineonCreate( cineon->referenceBlack = 95.0f; cineon->gamma = 1.7f; - shortFilename = strrchr(filename, '/'); + shortFilename = strrchr(filepath, PATHSEP_CHAR); if (shortFilename == NULL) { - shortFilename = filename; + shortFilename = filepath; } else { shortFilename++; } - cineon->file = BLI_fopen(filename, "wb"); + cineon->file = BLI_fopen(filepath, "wb"); if (cineon->file == NULL) { if (verbose) { - printf("cineon: Couldn't open file %s\n", filename); + printf("cineon: Couldn't open file %s\n", filepath); } logImageClose(cineon); return NULL; diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h index 37b27d19539..13d40461728 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.h +++ b/source/blender/imbuf/intern/cineon/cineonlib.h @@ -114,7 +114,7 @@ typedef struct { void cineonSetVerbose(int); LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize); LogImageFile *cineonCreate( - const char *filename, int width, int height, int bitsPerSample, const char *creator); + const char *filepath, int width, int height, int bitsPerSample, const char *creator); #ifdef __cplusplus } diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 2d28a477c8a..28c19116361 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -124,7 +124,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf { DpxMainHeader header; LogImageFile *dpx = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__); - const char *filename = (const char *)byteStuff; + const char *filepath = (const char *)byteStuff; int i; if (dpx == NULL) { @@ -141,11 +141,11 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf dpx->file = NULL; if (fromMemory == 0) { - /* byteStuff is then the filename */ - dpx->file = BLI_fopen(filename, "rb"); + /* byteStuff is then the filepath */ + dpx->file = BLI_fopen(filepath, "rb"); if (dpx->file == NULL) { if (verbose) { - printf("DPX: Failed to open file \"%s\".\n", filename); + printf("DPX: Failed to open file \"%s\".\n", filepath); } logImageClose(dpx); return NULL; @@ -406,7 +406,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf return dpx; } -LogImageFile *dpxCreate(const char *filename, +LogImageFile *dpxCreate(const char *filepath, int width, int height, int bitsPerSample, @@ -502,19 +502,19 @@ LogImageFile *dpxCreate(const char *filename, dpx->gamma = 1.7f; } - shortFilename = strrchr(filename, '/'); + shortFilename = strrchr(filepath, PATHSEP_CHAR); if (shortFilename == NULL) { - shortFilename = filename; + shortFilename = filepath; } else { shortFilename++; } - dpx->file = BLI_fopen(filename, "wb"); + dpx->file = BLI_fopen(filepath, "wb"); if (dpx->file == NULL) { if (verbose) { - printf("DPX: Couldn't open file %s\n", filename); + printf("DPX: Couldn't open file %s\n", filepath); } logImageClose(dpx); return NULL; diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h index d8ed5dc6f67..aac424d52d6 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.h +++ b/source/blender/imbuf/intern/cineon/dpxlib.h @@ -133,7 +133,7 @@ typedef struct { void dpxSetVerbose(int verbosity); LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize); -LogImageFile *dpxCreate(const char *filename, +LogImageFile *dpxCreate(const char *filepath, int width, int height, int bitsPerSample, diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c index 36e12e07316..e693aa6f891 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.c +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -101,10 +101,10 @@ int logImageIsCineon(const void *buffer, const unsigned int size) return (magicNum == CINEON_FILE_MAGIC || magicNum == swap_uint(CINEON_FILE_MAGIC, 1)); } -LogImageFile *logImageOpenFromFile(const char *filename, int cineon) +LogImageFile *logImageOpenFromFile(const char *filepath, int cineon) { unsigned int magicNum; - FILE *f = BLI_fopen(filename, "rb"); + FILE *f = BLI_fopen(filepath, "rb"); (void)cineon; @@ -120,10 +120,10 @@ LogImageFile *logImageOpenFromFile(const char *filename, int cineon) fclose(f); if (logImageIsDpx(&magicNum, sizeof(magicNum))) { - return dpxOpen((const unsigned char *)filename, 0, 0); + return dpxOpen((const unsigned char *)filepath, 0, 0); } if (logImageIsCineon(&magicNum, sizeof(magicNum))) { - return cineonOpen((const unsigned char *)filename, 0, 0); + return cineonOpen((const unsigned char *)filepath, 0, 0); } return NULL; @@ -141,7 +141,7 @@ LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int s return NULL; } -LogImageFile *logImageCreate(const char *filename, +LogImageFile *logImageCreate(const char *filepath, int cineon, int width, int height, @@ -155,10 +155,10 @@ LogImageFile *logImageCreate(const char *filename, { /* referenceWhite, referenceBlack and gamma values are only supported for DPX file */ if (cineon) { - return cineonCreate(filename, width, height, bitsPerSample, creator); + return cineonCreate(filepath, width, height, bitsPerSample, creator); } - return dpxCreate(filename, + return dpxCreate(filepath, width, height, bitsPerSample, diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h index 6875dba3f87..35540497828 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.h +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -19,6 +19,12 @@ #include "BLI_sys_types.h" #include "BLI_utildefines.h" +#ifdef _WIN32 +# define PATHSEP_CHAR '\\' +#else +# define PATHSEP_CHAR '/' +#endif + #ifdef __cplusplus extern "C" { #endif @@ -169,9 +175,9 @@ void logImageSetVerbose(int verbosity); int logImageIsDpx(const void *buffer, unsigned int size); int logImageIsCineon(const void *buffer, unsigned int size); LogImageFile *logImageOpenFromMemory(const unsigned char *buffer, unsigned int size); -LogImageFile *logImageOpenFromFile(const char *filename, int cineon); +LogImageFile *logImageOpenFromFile(const char *filepath, int cineon); void logImageGetSize(LogImageFile *logImage, int *width, int *height, int *depth); -LogImageFile *logImageCreate(const char *filename, +LogImageFile *logImageCreate(const char *filepath, int cineon, int width, int height, diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 53aa74edc61..1613595148b 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -2445,68 +2445,77 @@ void IMB_colormanagement_imbuf_make_display_space( colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false); } +static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result) +{ + if (colormanaged_ibuf != ibuf) { + /* Is already an editable copy. */ + return colormanaged_ibuf; + } + + if (allocate_result) { + /* Copy full image buffer. */ + colormanaged_ibuf = IMB_dupImBuf(ibuf); + IMB_metadata_copy(colormanaged_ibuf, ibuf); + return colormanaged_ibuf; + } + else { + /* Render pipeline is constructing image buffer itself, + * but it's re-using byte and float buffers from render result make copy of this buffers + * here sine this buffers would be transformed to other color space here. */ + if (ibuf->rect && (ibuf->mall & IB_rect) == 0) { + ibuf->rect = MEM_dupallocN(ibuf->rect); + ibuf->mall |= IB_rect; + } + + if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) { + ibuf->rect_float = MEM_dupallocN(ibuf->rect_float); + ibuf->mall |= IB_rectfloat; + } + + return ibuf; + } +} + ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format) { ImBuf *colormanaged_ibuf = ibuf; - const bool is_movie = BKE_imtype_is_movie(image_format->imtype); - const bool requires_linear_float = BKE_imtype_requires_linear_float(image_format->imtype); - const bool do_alpha_under = image_format->planes != R_IMF_PLANES_RGBA; + /* Update byte buffer if exists but invalid. */ if (ibuf->rect_float && ibuf->rect && (ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) { IMB_rect_from_float(ibuf); ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID); } - const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float); - const bool do_colormanagement_linear = save_as_render && requires_linear_float && - image_format->linear_colorspace_settings.name[0] && - !IMB_colormanagement_space_name_is_scene_linear( - image_format->linear_colorspace_settings.name); - - if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) { - if (allocate_result) { - colormanaged_ibuf = IMB_dupImBuf(ibuf); - } - else { - /* Render pipeline is constructing image buffer itself, - * but it's re-using byte and float buffers from render result make copy of this buffers - * here sine this buffers would be transformed to other color space here. - */ + /* Detect if we are writing to a file format that needs a linear float buffer. */ + const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype); - if (ibuf->rect && (ibuf->mall & IB_rect) == 0) { - ibuf->rect = MEM_dupallocN(ibuf->rect); - ibuf->mall |= IB_rect; - } + /* Detect if we are writing output a byte buffer, which we would need to create + * with color management conversions applied. This may be for either applying the + * display transform for renders, or a user specified color space for the file. */ + const bool byte_output = BKE_image_format_is_byte(image_format); - if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) { - ibuf->rect_float = MEM_dupallocN(ibuf->rect_float); - ibuf->mall |= IB_rectfloat; - } - } - } + BLI_assert(!(byte_output && linear_float_output)); - /* If we're saving from RGBA to RGB buffer then it's not - * so much useful to just ignore alpha -- it leads to bad - * artifacts especially when saving byte images. - * - * What we do here is we're overlaying our image on top of - * background color (which is currently black). + /* If we're saving from RGBA to RGB buffer then it's not so much useful to just ignore alpha -- + * it leads to bad artifacts especially when saving byte images. * - * This is quite much the same as what Gimp does and it - * seems to be what artists expects from saving. + * What we do here is we're overlaying our image on top of background color (which is currently + * black). This is quite much the same as what Gimp does and it seems to be what artists expects + * from saving. * - * Do a conversion here, so image format writers could - * happily assume all the alpha tricks were made already. - * helps keep things locally here, not spreading it to - * all possible image writers we've got. + * Do a conversion here, so image format writers could happily assume all the alpha tricks were + * made already. helps keep things locally here, not spreading it to all possible image writers + * we've got. */ - if (do_alpha_under) { + if (image_format->planes != R_IMF_PLANES_RGBA) { float color[3] = {0, 0, 0}; + colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result); + if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) { IMB_alpha_under_color_float( colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color); @@ -2520,69 +2529,95 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, } } - if (do_colormanagement_display) { - /* Color management with display and view transform. */ - bool make_byte = false; + if (save_as_render && !linear_float_output) { + /* Render output: perform conversion to display space using view transform. */ + colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result); - /* for proper check whether byte buffer is required by a format or not - * should be pretty safe since this image buffer is supposed to be used for - * saving only and ftype would be overwritten a bit later by BKE_imbuf_write - */ - colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format->imtype, - &colormanaged_ibuf->foptions); - - /* if file format isn't able to handle float buffer itself, - * we need to allocate byte buffer and store color managed - * image there - */ - const ImFileType *type = IMB_file_type_from_ibuf(colormanaged_ibuf); - if (type != NULL) { - if ((type->save != NULL) && (type->flag & IM_FTYPE_FLOAT) == 0) { - make_byte = true; - } - } - - /* perform color space conversions */ colormanagement_imbuf_make_display_space(colormanaged_ibuf, &image_format->view_settings, &image_format->display_settings, - make_byte); + byte_output); if (colormanaged_ibuf->rect_float) { - /* float buffer isn't linear anymore, + /* Float buffer isn't linear anymore, * image format write callback should check for this flag and assume - * no space conversion should happen if ibuf->float_colorspace != NULL - */ + * no space conversion should happen if ibuf->float_colorspace != NULL. */ colormanaged_ibuf->float_colorspace = display_transform_get_colorspace( &image_format->view_settings, &image_format->display_settings); + if (byte_output) { + colormanaged_ibuf->rect_colorspace = colormanaged_ibuf->float_colorspace; + } } } - else if (do_colormanagement_linear) { - /* Color management transform to another linear color space. */ - if (!colormanaged_ibuf->rect_float) { - IMB_float_from_rect(colormanaged_ibuf); - imb_freerectImBuf(colormanaged_ibuf); + else { + /* Linear render or regular file output: conversion between two color spaces. */ + + /* Detect which color space we need to convert between. */ + const char *from_colorspace = (ibuf->rect_float && !(byte_output && ibuf->rect)) ? + /* From float buffer. */ + (ibuf->float_colorspace) ? ibuf->float_colorspace->name : + global_role_scene_linear : + /* From byte buffer. */ + (ibuf->rect_colorspace) ? ibuf->rect_colorspace->name : + global_role_default_byte; + + const char *to_colorspace = image_format->linear_colorspace_settings.name; + + /* TODO: can we check with OCIO if color spaces are the same but have different names? */ + if (to_colorspace[0] == '\0' || STREQ(from_colorspace, to_colorspace)) { + /* No conversion needed, but may still need to allocate byte buffer for output. */ + if (byte_output && !ibuf->rect) { + ibuf->rect_colorspace = ibuf->float_colorspace; + IMB_rect_from_float(ibuf); + } } + else { + /* Color space conversion needed. */ + colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result); + + if (byte_output) { + colormanaged_ibuf->rect_colorspace = colormanage_colorspace_get_named(to_colorspace); + + if (colormanaged_ibuf->rect) { + /* Byte to byte. */ + IMB_colormanagement_transform_byte_threaded((unsigned char *)colormanaged_ibuf->rect, + colormanaged_ibuf->x, + colormanaged_ibuf->y, + colormanaged_ibuf->channels, + from_colorspace, + to_colorspace); + } + else { + /* Float to byte. */ + IMB_rect_from_float(colormanaged_ibuf); + } + } + else { + if (!colormanaged_ibuf->rect_float) { + /* Byte to float. */ + IMB_float_from_rect(colormanaged_ibuf); + imb_freerectImBuf(colormanaged_ibuf); - if (colormanaged_ibuf->rect_float) { - const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name : - global_role_scene_linear; - const char *to_colorspace = image_format->linear_colorspace_settings.name; + /* This conversion always goes to scene linear. */ + from_colorspace = global_role_scene_linear; + } - IMB_colormanagement_transform(colormanaged_ibuf->rect_float, - colormanaged_ibuf->x, - colormanaged_ibuf->y, - colormanaged_ibuf->channels, - from_colorspace, - to_colorspace, - false); + if (colormanaged_ibuf->rect_float) { + /* Float to float. */ + IMB_colormanagement_transform(colormanaged_ibuf->rect_float, + colormanaged_ibuf->x, + colormanaged_ibuf->y, + colormanaged_ibuf->channels, + from_colorspace, + to_colorspace, + false); + + colormanaged_ibuf->float_colorspace = colormanage_colorspace_get_named(to_colorspace); + } + } } } - if (colormanaged_ibuf != ibuf) { - IMB_metadata_copy(colormanaged_ibuf, ibuf); - } - return colormanaged_ibuf; } diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp index 34f3654aa3f..566891dac8b 100644 --- a/source/blender/imbuf/intern/dds/Stream.cpp +++ b/source/blender/imbuf/intern/dds/Stream.cpp @@ -45,7 +45,7 @@ unsigned int mem_read(Stream &mem, unsigned long long &i) mem.set_failed(msg_error_seek); return 0; } - memcpy(&i, mem.mem + mem.pos, 8); /* @@ todo: make sure little endian */ + memcpy(&i, mem.mem + mem.pos, 8); /* TODO: make sure little endian. */ mem.pos += 8; return 8; } @@ -56,7 +56,7 @@ unsigned int mem_read(Stream &mem, unsigned int &i) mem.set_failed(msg_error_read); return 0; } - memcpy(&i, mem.mem + mem.pos, 4); /* @@ todo: make sure little endian */ + memcpy(&i, mem.mem + mem.pos, 4); /* TODO: make sure little endian. */ mem.pos += 4; return 4; } @@ -67,7 +67,7 @@ unsigned int mem_read(Stream &mem, unsigned short &i) mem.set_failed(msg_error_read); return 0; } - memcpy(&i, mem.mem + mem.pos, 2); /* @@ todo: make sure little endian */ + memcpy(&i, mem.mem + mem.pos, 2); /* TODO: make sure little endian. */ mem.pos += 2; return 2; } diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index 548bc9e120c..74042ef75be 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -33,6 +33,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_jpeg, .load = imb_load_jpeg, .load_filepath = NULL, + .load_filepath_thumbnail = imb_thumbnail_jpeg, .save = imb_savejpeg, .load_tile = NULL, .flag = 0, @@ -45,6 +46,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_png, .load = imb_loadpng, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_savepng, .load_tile = NULL, .flag = 0, @@ -57,6 +59,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_bmp, .load = imb_bmp_decode, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_savebmp, .load_tile = NULL, .flag = 0, @@ -69,6 +72,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_targa, .load = imb_loadtarga, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_savetarga, .load_tile = NULL, .flag = 0, @@ -81,6 +85,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_iris, .load = imb_loadiris, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_saveiris, .load_tile = NULL, .flag = 0, @@ -94,6 +99,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_dpx, .load = imb_load_dpx, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_save_dpx, .load_tile = NULL, .flag = IM_FTYPE_FLOAT, @@ -106,6 +112,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_cineon, .load = imb_load_cineon, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_save_cineon, .load_tile = NULL, .flag = IM_FTYPE_FLOAT, @@ -120,6 +127,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_tiff, .load = imb_loadtiff, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_savetiff, .load_tile = imb_loadtiletiff, .flag = 0, @@ -134,6 +142,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_hdr, .load = imb_loadhdr, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_savehdr, .load_tile = NULL, .flag = IM_FTYPE_FLOAT, @@ -148,6 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_openexr, .load = imb_load_openexr, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_save_openexr, .load_tile = NULL, .flag = IM_FTYPE_FLOAT, @@ -162,6 +172,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_jp2, .load = imb_load_jp2, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_save_jp2, .load_tile = NULL, .flag = IM_FTYPE_FLOAT, @@ -176,6 +187,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_dds, .load = imb_load_dds, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = NULL, .load_tile = NULL, .flag = 0, @@ -190,6 +202,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_photoshop, .load = NULL, .load_filepath = imb_load_photoshop, + .load_filepath_thumbnail = NULL, .save = NULL, .load_tile = NULL, .flag = IM_FTYPE_FLOAT, @@ -204,6 +217,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_webp, .load = imb_loadwebp, .load_filepath = NULL, + .load_filepath_thumbnail = NULL, .save = imb_savewebp, .load_tile = NULL, .flag = 0, @@ -211,7 +225,7 @@ const ImFileType IMB_FILE_TYPES[] = { .default_save_role = COLOR_ROLE_DEFAULT_BYTE, }, #endif - {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0}, }; const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[ARRAY_SIZE(IMB_FILE_TYPES) - 1]; diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 1cc91d25d2a..cbc5d984755 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -376,10 +376,10 @@ int IMB_timecode_to_array_index(IMB_Timecode_Type tc) static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_len) { if (!anim->index_dir[0]) { - char fname[FILE_MAXFILE]; - BLI_split_dirfile(anim->name, index_dir, fname, index_dir_len, sizeof(fname)); + char filename[FILE_MAXFILE]; + BLI_split_dirfile(anim->name, index_dir, filename, index_dir_len, sizeof(filename)); BLI_path_append(index_dir, index_dir_len, "BL_proxy"); - BLI_path_append(index_dir, index_dir_len, fname); + BLI_path_append(index_dir, index_dir_len, filename); } else { BLI_strncpy(index_dir, anim->index_dir, index_dir_len); @@ -388,14 +388,14 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l void IMB_anim_get_fname(struct anim *anim, char *file, int size) { - char fname[FILE_MAXFILE]; - BLI_split_dirfile(anim->name, file, fname, size, sizeof(fname)); - BLI_strncpy(file, fname, size); + char filename[FILE_MAXFILE]; + BLI_split_dirfile(anim->name, file, filename, size, sizeof(filename)); + BLI_strncpy(file, filename, size); } -static bool get_proxy_filename(struct anim *anim, +static bool get_proxy_filepath(struct anim *anim, IMB_Proxy_Size preview_size, - char *fname, + char *filepath, bool temp) { char index_dir[FILE_MAXDIR]; @@ -426,11 +426,11 @@ static bool get_proxy_filename(struct anim *anim, return false; } - BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name); + BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name); return true; } -static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname) +static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *filepath) { char index_dir[FILE_MAXDIR]; int i = IMB_timecode_to_array_index(tc); @@ -457,7 +457,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname get_index_dir(anim, index_dir, sizeof(index_dir)); - BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name); + BLI_join_dirfile(filepath, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name); } /* ---------------------------------------------------------------------- @@ -492,18 +492,18 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( { struct proxy_output_ctx *rv = MEM_callocN(sizeof(struct proxy_output_ctx), "alloc_proxy_output"); - char fname[FILE_MAX]; + char filepath[FILE_MAX]; rv->proxy_size = proxy_size; rv->anim = anim; - get_proxy_filename(rv->anim, rv->proxy_size, fname, true); - BLI_make_existing_file(fname); + get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true); + BLI_make_existing_file(filepath); rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); - rv->of->url = av_strdup(fname); + rv->of->url = av_strdup(filepath); fprintf(stderr, "Starting work on proxy: %s\n", rv->of->url); @@ -577,7 +577,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( avcodec_parameters_from_context(rv->st->codecpar, rv->c); - int ret = avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE); + int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE); if (ret < 0) { fprintf(stderr, @@ -723,8 +723,8 @@ static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *fr static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback) { - char fname[FILE_MAX]; - char fname_tmp[FILE_MAX]; + char filepath[FILE_MAX]; + char filepath_tmp[FILE_MAX]; if (!ctx) { return; @@ -755,15 +755,15 @@ static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback) av_free(ctx->frame); } - get_proxy_filename(ctx->anim, ctx->proxy_size, fname_tmp, true); + get_proxy_filepath(ctx->anim, ctx->proxy_size, filepath_tmp, true); if (rollback) { - unlink(fname_tmp); + unlink(filepath_tmp); } else { - get_proxy_filename(ctx->anim, ctx->proxy_size, fname, false); - unlink(fname); - BLI_rename(fname_tmp, fname); + get_proxy_filepath(ctx->anim, ctx->proxy_size, filepath, false); + unlink(filepath); + BLI_rename(filepath_tmp, filepath); } MEM_freeN(ctx); @@ -907,11 +907,11 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { - char fname[FILE_MAX]; + char filepath[FILE_MAX]; - get_tc_filename(anim, tc_types[i], fname); + get_tc_filename(anim, tc_types[i], filepath); - context->indexer[i] = IMB_index_builder_create(fname); + context->indexer[i] = IMB_index_builder_create(filepath); if (!context->indexer[i]) { tcs_in_use &= ~tc_types[i]; } @@ -1212,7 +1212,7 @@ typedef struct FallbackIndexBuilderContext { } FallbackIndexBuilderContext; static AviMovie *alloc_proxy_output_avi( - struct anim *anim, char *filename, int width, int height, int quality) + struct anim *anim, char *filepath, int width, int height, int quality) { int x, y; AviFormat format; @@ -1233,7 +1233,7 @@ static AviMovie *alloc_proxy_output_avi( format = AVI_FORMAT_MJPEG; - if (AVI_open_compress(filename, avi, 1, format) != AVI_ERROR_NONE) { + if (AVI_open_compress(filepath, avi, 1, format) != AVI_ERROR_NONE) { MEM_freeN(avi); return NULL; } @@ -1275,13 +1275,13 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim, for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) { if (context->proxy_sizes_in_use & proxy_sizes[i]) { - char fname[FILE_MAX]; + char filepath[FILE_MAX]; - get_proxy_filename(anim, proxy_sizes[i], fname, true); - BLI_make_existing_file(fname); + get_proxy_filepath(anim, proxy_sizes[i], filepath, true); + BLI_make_existing_file(filepath); context->proxy_ctx[i] = alloc_proxy_output_avi( - anim, fname, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality); + anim, filepath, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality); } } @@ -1291,8 +1291,8 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim, static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, int stop) { struct anim *anim = context->anim; - char fname[FILE_MAX]; - char fname_tmp[FILE_MAX]; + char filepath[FILE_MAX]; + char filepath_tmp[FILE_MAX]; int i; for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) { @@ -1300,15 +1300,15 @@ static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, AVI_close_compress(context->proxy_ctx[i]); MEM_freeN(context->proxy_ctx[i]); - get_proxy_filename(anim, proxy_sizes[i], fname_tmp, true); - get_proxy_filename(anim, proxy_sizes[i], fname, false); + get_proxy_filepath(anim, proxy_sizes[i], filepath_tmp, true); + get_proxy_filepath(anim, proxy_sizes[i], filepath, false); if (stop) { - unlink(fname_tmp); + unlink(filepath_tmp); } else { - unlink(fname); - rename(fname_tmp, fname); + unlink(filepath); + rename(filepath_tmp, filepath); } } } @@ -1388,7 +1388,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Proxy_Size proxy_size = proxy_sizes[i]; if (proxy_size & proxy_sizes_to_build) { char filename[FILE_MAX]; - if (get_proxy_filename(anim, proxy_size, filename, false) == false) { + if (get_proxy_filepath(anim, proxy_size, filename, false) == false) { return NULL; } void **filename_key_p; @@ -1411,7 +1411,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Proxy_Size proxy_size = proxy_sizes[i]; if (proxy_size & built_proxies) { char filename[FILE_MAX]; - if (get_proxy_filename(anim, proxy_size, filename, false) == false) { + if (get_proxy_filepath(anim, proxy_size, filename, false) == false) { return NULL; } printf("Skipping proxy: %s\n", filename); @@ -1532,7 +1532,7 @@ void IMB_anim_set_index_dir(struct anim *anim, const char *dir) struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size) { - char fname[FILE_MAX]; + char filepath[FILE_MAX]; int i = IMB_proxy_size_to_array_index(preview_size); if (i < 0) { @@ -1547,10 +1547,10 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size) return NULL; } - get_proxy_filename(anim, preview_size, fname, false); + get_proxy_filepath(anim, preview_size, filepath, false); /* proxies are generated in the same color space as animation itself */ - anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0, anim->colorspace); + anim->proxy_anim[i] = IMB_open_anim(filepath, 0, 0, anim->colorspace); anim->proxies_tried |= preview_size; @@ -1559,7 +1559,7 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size) struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc) { - char fname[FILE_MAX]; + char filepath[FILE_MAX]; int i = IMB_timecode_to_array_index(tc); if (i < 0) { @@ -1574,9 +1574,9 @@ struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc) return NULL; } - get_tc_filename(anim, tc, fname); + get_tc_filename(anim, tc, filepath); - anim->curr_idx[i] = IMB_indexer_open(fname); + anim->curr_idx[i] = IMB_indexer_open(filepath); anim->indices_tried |= tc; @@ -1602,7 +1602,7 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim) for (i = 0; i < num_proxy_sizes; i++) { IMB_Proxy_Size proxy_size = proxy_sizes[i]; char filename[FILE_MAX]; - get_proxy_filename(anim, proxy_size, filename, false); + get_proxy_filepath(anim, proxy_size, filename, false); if (BLI_exists(filename)) { existing |= proxy_size; } diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index eb0a2c4a47f..a8150fd1648 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -105,7 +105,7 @@ static int expandrow2( float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z); static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n); static void interleaverow2(float *lptr, const uchar *cptr, int z, int n); -static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len); +static int compressrow(const uchar *lbuf, uchar *rlebuf, int z, int row_len); static void lumrow(const uchar *rgbptr, uchar *lumptr, int n); /* @@ -779,18 +779,24 @@ fail: } /** - * Copy an array of ints to an iris image file. - * Each int represents one pixel. xsize and ysize specify the dimensions of - * the pixel array. zsize specifies what kind of image file to - * write out. if zsize is 1, the luminance of the pixels are - * calculated, and a single channel black and white image is saved. - * If zsize is 3, an RGB image file is saved. If zsize is 4, an - * RGBA image file is saved. - * - * Added: zbuf write + * \param filepath: The file path to write to. + * \param lptr: an array of integers to an iris image file (each int represents one pixel). + * \param zptr: depth-buffer (optional, may be NULL). + * \param xsize: with width of the pixel-array. + * \param ysize: height of the pixel-array. + * \param zsize: specifies what kind of image file to write out. + * - 1: the luminance of the pixels are calculated, + * and a single channel black and white image is saved. + * - 3: an RGB image file is saved. + * - 4: an RGBA image file is saved. + * - 8: an RGBA image and a Z-buffer (non-null `zptr`). */ - -static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr) +static bool output_iris(const char *filepath, + const uint *lptr, + const int *zptr, + const int xsize, + const int ysize, + const int zsize) { FILE *outf; IMAGE *image; @@ -801,7 +807,7 @@ static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char int rlebuflen, goodwrite; goodwrite = 1; - outf = BLI_fopen(name, "wb"); + outf = BLI_fopen(filepath, "wb"); if (!outf) { return 0; } @@ -837,21 +843,20 @@ static bool output_iris(uint *lptr, int xsize, int ysize, int zsize, const char for (z = 0; z < zsize; z++) { if (zsize == 1) { - lumrow((uchar *)lptr, (uchar *)lumbuf, xsize); - len = compressrow((uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize); + lumrow((const uchar *)lptr, (uchar *)lumbuf, xsize); + len = compressrow((const uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize); } else { if (z < 4) { - len = compressrow((uchar *)lptr, rlebuf, CHANOFFSET(z), xsize); + len = compressrow((const uchar *)lptr, rlebuf, CHANOFFSET(z), xsize); } else if (z < 8 && zptr) { - len = compressrow((uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize); + len = compressrow((const uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize); } } - if (len > rlebuflen) { - fprintf(stderr, "output_iris: rlebuf is too small - bad poop\n"); - exit(1); - } + + BLI_assert_msg(len <= rlebuflen, "The length calculated for 'rlebuflen' was too small!"); + goodwrite *= fwrite(rlebuf, len, 1, outf); starttab[y + z * ysize] = pos; lengthtab[y + z * ysize] = len; @@ -892,9 +897,10 @@ static void lumrow(const uchar *rgbptr, uchar *lumptr, int n) } } -static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len) +static int compressrow(const uchar *lbuf, uchar *rlebuf, const int z, const int row_len) { - uchar *iptr, *ibufend, *sptr, *optr; + const uchar *iptr, *ibufend, *sptr; + uchar *optr; short todo, cc; int count; @@ -964,7 +970,7 @@ bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags) IMB_convert_rgba_to_abgr(ibuf); test_endian_zbuf(ibuf); - const bool ok = output_iris(ibuf->rect, ibuf->x, ibuf->y, zsize, filepath, ibuf->zbuf); + const bool ok = output_iris(filepath, ibuf->rect, ibuf->zbuf, ibuf->x, ibuf->y, zsize); /* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */ IMB_convert_rgba_to_abgr(ibuf); diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 6fb1fb52153..cffa61977f7 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -39,7 +39,11 @@ static void skip_input_data(j_decompress_ptr cinfo, long num_bytes); static void term_source(j_decompress_ptr cinfo); static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, size_t size); static boolean handle_app1(j_decompress_ptr cinfo); -static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags); +static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, + int flags, + int max_size, + size_t *r_width, + size_t *r_height); static const uchar jpeg_default_quality = 75; static uchar ibuf_quality; @@ -246,7 +250,11 @@ static boolean handle_app1(j_decompress_ptr cinfo) return true; } -static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags) +static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, + int flags, + int max_size, + size_t *r_width, + size_t *r_height) { JSAMPARRAY row_pointer; JSAMPLE *buffer = NULL; @@ -264,16 +272,34 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla jpeg_save_markers(cinfo, JPEG_COM, 0xffff); if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) { - x = cinfo->image_width; - y = cinfo->image_height; depth = cinfo->num_components; if (cinfo->jpeg_color_space == JCS_YCCK) { cinfo->out_color_space = JCS_CMYK; } + if (r_width) { + *r_width = cinfo->image_width; + } + if (r_height) { + *r_height = cinfo->image_height; + } + + if (max_size > 0) { + /* `libjpeg` can more quickly decompress while scaling down to 1/2, 1/4, 1/8, + * while `libjpeg-turbo` can also do 3/8, 5/8, etc. But max is 1/8. */ + float scale = (float)max_size / MAX2(cinfo->image_width, cinfo->image_height); + cinfo->scale_denom = 8; + cinfo->scale_num = max_uu(1, min_uu(8, ceill(scale * (float)cinfo->scale_denom))); + cinfo->dct_method = JDCT_FASTEST; + cinfo->dither_mode = JDITHER_ORDERED; + } + jpeg_start_decompress(cinfo); + x = cinfo->output_width; + y = cinfo->output_height; + if (flags & IB_test) { jpeg_abort_decompress(cinfo); ibuf = IMB_allocImBuf(x, y, 8 * depth, 0); @@ -449,11 +475,92 @@ ImBuf *imb_load_jpeg(const unsigned char *buffer, jpeg_create_decompress(cinfo); memory_source(cinfo, buffer, size); - ibuf = ibJpegImageFromCinfo(cinfo, flags); + ibuf = ibJpegImageFromCinfo(cinfo, flags, -1, NULL, NULL); + + return ibuf; +} + +/* Defines for JPEG Header markers and segment size. */ +#define JPEG_MARKER_MSB (0xFF) +#define JPEG_MARKER_SOI (0xD8) +#define JPEG_MARKER_APP1 (0xE1) +#define JPEG_APP1_MAX (1 << 16) + +struct ImBuf *imb_thumbnail_jpeg(const char *filepath, + const int flags, + const size_t max_thumb_size, + char colorspace[IM_MAX_SPACE], + size_t *r_width, + size_t *r_height) +{ + struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo; + struct my_error_mgr jerr; + FILE *infile = NULL; + + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); + + cinfo->err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = jpeg_error; + + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(cinfo); + return NULL; + } + + if ((infile = BLI_fopen(filepath, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filepath); + return NULL; + } + + /* If file contains an embedded thumbnail, let's return that instead. */ + + if ((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI) && + (fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_APP1)) { + /* This is a JPEG in EXIF format (SOI + APP1), not JFIF (SOI + APP0). */ + unsigned int i = JPEG_APP1_MAX; + /* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */ + while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) && + !feof(infile) && i--) + ; + if (i > 0 && !feof(infile)) { + /* We found a JPEG thumbnail inside this image. */ + ImBuf *ibuf = NULL; + uchar *buffer = MEM_callocN(JPEG_APP1_MAX, "thumbbuffer"); + /* Just put SOI directly in buffer rather than seeking back 2 bytes. */ + buffer[0] = JPEG_MARKER_MSB; + buffer[1] = JPEG_MARKER_SOI; + if (fread(buffer + 2, JPEG_APP1_MAX - 2, 1, infile) == 1) { + ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, colorspace); + } + MEM_SAFE_FREE(buffer); + if (ibuf) { + fclose(infile); + return ibuf; + } + } + } + + /* No embedded thumbnail found, so let's create a new one. */ + + fseek(infile, 0, SEEK_SET); + jpeg_create_decompress(cinfo); + + jpeg_stdio_src(cinfo, infile); + ImBuf *ibuf = ibJpegImageFromCinfo(cinfo, flags, max_thumb_size, r_width, r_height); + fclose(infile); return ibuf; } +#undef JPEG_MARKER_MSB +#undef JPEG_MARKER_SOI +#undef JPEG_MARKER_APP1 +#undef JPEG_APP1_MAX + static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf) { JSAMPLE *buffer = NULL; diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index df41c0ca757..4b433836767 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -22,6 +22,8 @@ #include "IMB_filetype.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_metadata.h" +#include "IMB_thumbs.h" #include "imbuf.h" #include "IMB_colormanagement.h" @@ -187,21 +189,21 @@ ImBuf *IMB_loadifffile( return ibuf; } -static void imb_cache_filename(char *filename, const char *name, int flags) +static void imb_cache_filename(char *filepath, const char *name, int flags) { /* read .tx instead if it exists and is not older */ if (flags & IB_tilecache) { - BLI_strncpy(filename, name, IMB_FILENAME_SIZE); - if (!BLI_path_extension_replace(filename, IMB_FILENAME_SIZE, ".tx")) { + BLI_strncpy(filepath, name, IMB_FILENAME_SIZE); + if (!BLI_path_extension_replace(filepath, IMB_FILENAME_SIZE, ".tx")) { return; } - if (BLI_file_older(name, filename)) { + if (BLI_file_older(name, filepath)) { return; } } - BLI_strncpy(filename, name, IMB_FILENAME_SIZE); + BLI_strncpy(filepath, name, IMB_FILENAME_SIZE); } ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]) @@ -234,6 +236,61 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S return ibuf; } +struct ImBuf *IMB_thumb_load_image(const char *filepath, + size_t max_thumb_size, + char colorspace[IM_MAX_SPACE]) +{ + const ImFileType *type = IMB_file_type_from_ftype(IMB_ispic_type(filepath)); + if (type == NULL) { + return NULL; + } + + ImBuf *ibuf = NULL; + int flags = IB_rect | IB_metadata; + /* Size of the original image. */ + size_t width = 0; + size_t height = 0; + + char effective_colorspace[IM_MAX_SPACE] = ""; + if (colorspace) { + BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace)); + } + + if (type->load_filepath_thumbnail) { + ibuf = type->load_filepath_thumbnail( + filepath, flags, max_thumb_size, colorspace, &width, &height); + } + else { + /* Skip images of other types if over 100MB. */ + const size_t file_size = BLI_file_size(filepath); + if (file_size != -1 && file_size > THUMB_SIZE_MAX) { + return NULL; + } + ibuf = IMB_loadiffname(filepath, flags, colorspace); + if (ibuf) { + width = ibuf->x; + height = ibuf->y; + } + } + + if (ibuf) { + imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace); + + if (width > 0 && height > 0) { + /* Save dimensions of original image into the thumbnail metadata. */ + char cwidth[40]; + char cheight[40]; + SNPRINTF(cwidth, "%zu", width); + SNPRINTF(cheight, "%zu", height); + IMB_metadata_ensure(&ibuf->metadata); + IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Width", cwidth); + IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Height", cheight); + } + } + + return ibuf; +} + ImBuf *IMB_testiffname(const char *filepath, int flags) { ImBuf *ibuf; diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 37734ebacb2..f2c9c82fa66 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -318,12 +318,8 @@ static ImBuf *thumb_create_ex(const char *file_path, char tpath[FILE_MAX]; char tdir[FILE_MAX]; char temp[FILE_MAX]; - char mtime[40] = "0"; /* in case we can't stat the file */ - char cwidth[40] = "0"; /* in case images have no data */ - char cheight[40] = "0"; + char mtime[40] = "0"; /* in case we can't stat the file */ short tsize = 128; - short ex, ey; - float scaledx, scaledy; BLI_stat_t info; switch (size) { @@ -340,15 +336,6 @@ static ImBuf *thumb_create_ex(const char *file_path, return NULL; /* unknown size */ } - /* exception, skip images over 100mb */ - if (source == THB_SOURCE_IMAGE) { - const size_t file_size = BLI_file_size(file_path); - if (file_size != -1 && file_size > THUMB_SIZE_MAX) { - // printf("file too big: %d, skipping %s\n", (int)size, file_path); - return NULL; - } - } - if (get_thumb_dir(tdir, size)) { BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb); // thumb[8] = '\0'; /* shorten for tempname, not needed anymore */ @@ -368,7 +355,7 @@ static ImBuf *thumb_create_ex(const char *file_path, if (img == NULL) { switch (source) { case THB_SOURCE_IMAGE: - img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL); + img = IMB_thumb_load_image(file_path, tsize, NULL); break; case THB_SOURCE_BLEND: img = IMB_thumb_load_blend(file_path, blen_group, blen_id); @@ -385,8 +372,6 @@ static ImBuf *thumb_create_ex(const char *file_path, if (BLI_stat(file_path, &info) != -1) { BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime); } - BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x); - BLI_snprintf(cheight, sizeof(cheight), "%d", img->y); } } else if (THB_SOURCE_MOVIE == source) { @@ -411,28 +396,20 @@ static ImBuf *thumb_create_ex(const char *file_path, return NULL; } - if (img->x > img->y) { - scaledx = (float)tsize; - scaledy = ((float)img->y / (float)img->x) * tsize; - } - else { - scaledy = (float)tsize; - scaledx = ((float)img->x / (float)img->y) * tsize; - } - /* Scaling down must never assign zero width/height, see: T89868. */ - ex = MAX2(1, (short)scaledx); - ey = MAX2(1, (short)scaledy); - - /* save some time by only scaling byte buf */ - if (img->rect_float) { - if (img->rect == NULL) { - IMB_rect_from_float(img); + if (img->x > tsize || img->y > tsize) { + float scale = MIN2((float)tsize / (float)img->x, (float)tsize / (float)img->y); + /* Scaling down must never assign zero width/height, see: T89868. */ + short ex = MAX2(1, (short)(img->x * scale)); + short ey = MAX2(1, (short)(img->y * scale)); + /* Save some time by only scaling byte buf */ + if (img->rect_float) { + if (img->rect == NULL) { + IMB_rect_from_float(img); + } + imb_freerectfloatImBuf(img); } - - imb_freerectfloatImBuf(img); + IMB_scaleImBuf(img, ex, ey); } - - IMB_scaleImBuf(img, ex, ey); } BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri); IMB_metadata_ensure(&img->metadata); @@ -443,10 +420,6 @@ static ImBuf *thumb_create_ex(const char *file_path, if (use_hash) { IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash); } - if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) { - IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth); - IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight); - } img->ftype = IMB_FTYPE_PNG; img->planes = 32; @@ -493,27 +466,27 @@ static ImBuf *thumb_create_or_fail(const char *file_path, return img; } -ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img) +ImBuf *IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, ImBuf *img) { char uri[URI_MAX] = ""; char thumb_name[40]; - if (!uri_from_filename(path, uri)) { + if (!uri_from_filename(filepath, uri)) { return NULL; } thumbname_from_uri(uri, thumb_name, sizeof(thumb_name)); return thumb_create_ex( - path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img); + filepath, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img); } -ImBuf *IMB_thumb_read(const char *path, ThumbSize size) +ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size) { char thumb[FILE_MAX]; char uri[URI_MAX]; ImBuf *img = NULL; - if (!uri_from_filename(path, uri)) { + if (!uri_from_filename(filepath, uri)) { return NULL; } if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) { @@ -523,16 +496,16 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size) return img; } -void IMB_thumb_delete(const char *path, ThumbSize size) +void IMB_thumb_delete(const char *filepath, ThumbSize size) { char thumb[FILE_MAX]; char uri[URI_MAX]; - if (!uri_from_filename(path, uri)) { + if (!uri_from_filename(filepath, uri)) { return; } if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) { - if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) { + if (BLI_path_ncmp(filepath, thumb, sizeof(thumb)) == 0) { return; } if (BLI_exists(thumb)) { diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c index 7a1c4947c99..c0a33f608a5 100644 --- a/source/blender/imbuf/intern/thumbs_font.c +++ b/source/blender/imbuf/intern/thumbs_font.c @@ -41,7 +41,7 @@ void IMB_thumb_ensure_translations(void) } } -struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y) +struct ImBuf *IMB_thumb_load_font(const char *filepath, unsigned int x, unsigned int y) { const int font_size = y / 4; @@ -60,7 +60,7 @@ struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned /* draw with full alpha */ font_color[3] = 1.0f; - BLF_thumb_preview(filename, + BLF_thumb_preview(filepath, thumb_str, i18n_thumb_str, ARRAY_SIZE(thumb_str), diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 45b50c866fe..ffa989a29b4 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -390,14 +390,3 @@ bool IMB_isanim(const char *filepath) return (type && type != ANIM_SEQUENCE); } - -bool IMB_isfloat(const ImBuf *ibuf) -{ - const ImFileType *type = IMB_file_type_from_ibuf(ibuf); - if (type != NULL) { - if (type->flag & IM_FTYPE_FLOAT) { - return true; - } - } - return false; -} diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c index 56c9384a330..d2c0b61c1c5 100644 --- a/source/blender/imbuf/intern/writeimage.c +++ b/source/blender/imbuf/intern/writeimage.c @@ -19,11 +19,6 @@ #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" -static bool prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf) -{ - return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf); -} - bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags) { errno = 0; @@ -36,34 +31,22 @@ bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags) ibuf->flags = flags; const ImFileType *type = IMB_file_type_from_ibuf(ibuf); - if (type != NULL) { - if (type->save != NULL) { - prepare_write_imbuf(type, ibuf); - return type->save(ibuf, filepath, flags); - } + if (type == NULL || type->save == NULL) { + fprintf(stderr, "Couldn't save picture.\n"); + return false; } - fprintf(stderr, "Couldn't save picture.\n"); - - return false; -} - -bool IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf) -{ - bool changed = false; - - if (isfloat) { - /* pass */ - } - else { + /* If writing byte image from float buffer, create a byte buffer for writing. + * + * For color managed image writing, IMB_colormanagement_imbuf_for_write should + * have already created this byte buffer. This is a basic fallback for other + * cases where we do not have a specific desired output colorspace. */ + if (!(type->flag & IM_FTYPE_FLOAT)) { if (ibuf->rect == NULL && ibuf->rect_float) { ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE); IMB_rect_from_float(ibuf); - if (ibuf->rect != NULL) { - changed = true; - } } } - return changed; + return type->save(ibuf, filepath, flags); } |