diff options
Diffstat (limited to 'source/blender/imbuf/intern')
-rw-r--r-- | source/blender/imbuf/intern/IMB_filter.h | 3 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cineon_dpx.c | 3 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 63 | ||||
-rw-r--r-- | source/blender/imbuf/intern/divers.c | 81 | ||||
-rw-r--r-- | source/blender/imbuf/intern/filter.c | 64 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_api.cpp | 3 | ||||
-rw-r--r-- | source/blender/imbuf/intern/png.c | 21 | ||||
-rw-r--r-- | source/blender/imbuf/intern/radiance_hdr.c | 3 | ||||
-rw-r--r-- | source/blender/imbuf/intern/readimage.c | 24 | ||||
-rw-r--r-- | source/blender/imbuf/intern/scaling.c | 35 | ||||
-rw-r--r-- | source/blender/imbuf/intern/tiff.c | 52 |
11 files changed, 255 insertions, 97 deletions
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h index eaedb160c94..6bd5f44307f 100644 --- a/source/blender/imbuf/intern/IMB_filter.h +++ b/source/blender/imbuf/intern/IMB_filter.h @@ -41,6 +41,9 @@ void imb_filterx(struct ImBuf *ibuf); void IMB_premultiply_rect(unsigned int *rect, char planes, int w, int h); void IMB_premultiply_rect_float(float *rect_float, char planes, int w, int h); +void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h); +void IMB_unpremultiply_rect_float(float *rect_float, char planes, int w, int h); + void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1); #endif diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index c8bc3f8ebb8..ba84063f317 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -95,6 +95,9 @@ static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, size_t size, int us if (flags & IB_rect) IMB_rect_from_float(ibuf); + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; + return ibuf; } diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 1c68a466ade..bcfddfe425a 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -189,7 +189,6 @@ typedef struct ColormnaageCacheData { int flag; /* view flags of cached buffer */ float exposure; /* exposure value cached buffer is calculated with */ float gamma; /* gamma value cached buffer is calculated with */ - int predivide; /* predivide flag of cached buffer */ CurveMapping *curve_mapping; /* curve mapping used for cached buffer */ int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */ } ColormnaageCacheData; @@ -323,7 +322,6 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV ColormanageCacheKey key; ImBuf *cache_ibuf; int view_flag = 1 << (view_settings->view - 1); - int predivide = ibuf->flags & IB_cm_predivide; CurveMapping *curve_mapping = view_settings->curve_mapping; int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0; @@ -353,7 +351,6 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV if (cache_data->exposure != view_settings->exposure || cache_data->gamma != view_settings->gamma || - cache_data->predivide != predivide || cache_data->flag != view_settings->flag || cache_data->curve_mapping != curve_mapping || cache_data->curve_mapping_timestamp != curve_mapping_timestamp) @@ -379,7 +376,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting ImBuf *cache_ibuf; ColormnaageCacheData *cache_data; int view_flag = 1 << (view_settings->view - 1); - int predivide = ibuf->flags & IB_cm_predivide; struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf); CurveMapping *curve_mapping = view_settings->curve_mapping; int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0; @@ -400,7 +396,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data"); cache_data->exposure = view_settings->exposure; cache_data->gamma = view_settings->gamma; - cache_data->predivide = predivide; cache_data->flag = view_settings->flag; cache_data->curve_mapping = curve_mapping; cache_data->curve_mapping_timestamp = curve_mapping_timestamp; @@ -897,13 +892,12 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) if (ibuf->rect_float) { const char *to_colorspace = global_role_scene_linear; - int predivide = ibuf->flags & IB_cm_predivide; if (ibuf->rect) imb_freerectImBuf(ibuf); IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } @@ -1130,7 +1124,6 @@ typedef struct DisplayBufferThread { int channels; float dither; - int predivide; int is_data; const char *byte_colorspace; @@ -1158,7 +1151,6 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l DisplayBufferInitData *init_data = (DisplayBufferInitData *) init_data_v; ImBuf *ibuf = init_data->ibuf; - int predivide = ibuf->flags & IB_cm_predivide; int channels = ibuf->channels; float dither = ibuf->dither; int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA; @@ -1189,7 +1181,6 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l handle->channels = channels; handle->dither = dither; - handle->predivide = predivide; handle->is_data = is_data; handle->byte_colorspace = init_data->byte_colorspace; @@ -1206,7 +1197,6 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle) int buffer_size = channels * width * height; - int predivide = handle->predivide; int is_data = handle->is_data; int is_data_display = handle->cm_processor->is_data_result; @@ -1224,16 +1214,25 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle) /* first convert byte buffer to float, keep in image space */ for (i = 0, fp = linear_buffer, cp = byte_buffer; - i < channels * width * height; - i++, fp++, cp++) + i < width * height; + i++, fp += channels, cp += channels) { - *fp = (float)(*cp) / 255.0f; + if (channels == 3) { + rgb_uchar_to_float(fp, cp); + } + else if (channels == 4) { + rgba_uchar_to_float(fp, cp); + straight_to_premul_v4(fp, fp); + } + else { + BLI_assert(!"Buffers of 3 or 4 channels are only supported here"); + } } if (!is_data && !is_data_display) { /* convert float buffer to scene linear space */ IMB_colormanagement_transform(linear_buffer, width, height, channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } else if (handle->float_colorspace) { @@ -1249,7 +1248,7 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle) memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float)); IMB_colormanagement_transform(linear_buffer, width, height, channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } else { /* some processors would want to modify float original buffer @@ -1277,13 +1276,12 @@ static void *do_display_buffer_apply_thread(void *handle_v) int width = handle->width; int height = handle->tot_line; float dither = handle->dither; - int predivide = handle->predivide; int is_data = handle->is_data; if (cm_processor == NULL) { if (display_buffer_byte) { IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - FALSE, width, height, width, width); + FALSE, width, height, width, width); } if (display_buffer) { @@ -1301,7 +1299,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) } else { /* apply processor */ - IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, predivide); + IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, TRUE); } /* copy result to output buffers */ @@ -1309,7 +1307,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) /* do conversion */ IMB_buffer_byte_from_float(display_buffer_byte, linear_buffer, channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, - predivide, width, height, width, width); + TRUE, width, height, width, width); } if (display_buffer) @@ -1663,7 +1661,7 @@ static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorMan if (global_tot_display == 0 || global_tot_view == 0) { IMB_buffer_float_from_float(ibuf->rect_float, ibuf->rect_float, ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, - ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { colormanage_display_buffer_process_ex(ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect, @@ -2326,7 +2324,6 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe { int x, y; int channels = ibuf->channels; - int predivide = ibuf->flags & IB_cm_predivide; float dither = ibuf->dither; ColorSpace *rect_colorspace = ibuf->rect_colorspace; float *display_buffer_float = NULL; @@ -2350,13 +2347,11 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe else if (byte_buffer) { rgba_uchar_to_float(pixel, byte_buffer + linear_index); IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace); + straight_to_premul_v4(pixel, pixel); } if (!is_data) { - if (predivide) - IMB_colormanagement_processor_apply_v4(cm_processor, pixel); - else - IMB_colormanagement_processor_apply_v4(cm_processor, pixel); + IMB_colormanagement_processor_apply_v4_predivide(cm_processor, pixel); } if (display_buffer_float) { @@ -2365,7 +2360,9 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe copy_v4_v4(display_buffer_float + index, pixel); } else { - rgba_float_to_uchar(display_buffer + display_index, pixel); + float pixel_straight[4]; + premul_to_straight_v4(pixel_straight, pixel); + rgba_float_to_uchar(display_buffer + display_index, pixel_straight); } } } @@ -2389,7 +2386,6 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, /* update byte buffer created by legacy color management */ unsigned char *rect = (unsigned char *) ibuf->rect; - int predivide = ibuf->flags & IB_cm_predivide; int channels = ibuf->channels; int width = xmax - xmin; int height = ymax - ymin; @@ -2397,7 +2393,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, int linear_index = ((ymin - offset_y) * stride + (xmin - offset_x)) * channels; IMB_buffer_byte_from_float(rect + rect_index, linear_buffer + linear_index, channels, ibuf->dither, - IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide, width, height, ibuf->x, stride); + IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, width, height, ibuf->x, stride); } if (ibuf->display_buffer_flags) { @@ -2503,6 +2499,15 @@ void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, OCIO_processorApplyRGBA(cm_processor->processor, pixel); } +void IMB_colormanagement_processor_apply_v4_predivide(ColormanageProcessor *cm_processor, float pixel[4]) +{ + if (cm_processor->curve_mapping) + curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel); + + if (cm_processor->processor) + OCIO_processorApplyRGBA_predivide(cm_processor->processor, pixel); +} + void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, float pixel[3]) { if (cm_processor->curve_mapping) diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index f049c404e2d..f0d8b7cac72 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -39,6 +39,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_allocimbuf.h" +#include "IMB_filter.h" #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" @@ -249,11 +250,25 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, uchar *to = rect_to + stride_to * y * 4; if (profile_to == profile_from) { + float straight[4]; + /* no color space conversion */ - if (dither) { + if (dither && predivide) { + for (x = 0; x < width; x++, from += 4, to += 4) { + premul_to_straight_v4(straight, from); + float_to_byte_dither_v4(to, straight, di); + } + } + else if (dither) { for (x = 0; x < width; x++, from += 4, to += 4) float_to_byte_dither_v4(to, from, di); } + else if (predivide) { + for (x = 0; x < width; x++, from += 4, to += 4) { + premul_to_straight_v4(straight, from); + rgba_float_to_uchar(to, straight); + } + } else { for (x = 0; x < width; x++, from += 4, to += 4) rgba_float_to_uchar(to, from); @@ -262,10 +277,12 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, else if (profile_to == IB_PROFILE_SRGB) { /* convert from linear to sRGB */ unsigned short us[4]; + float straight[4]; if (dither && predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { - linearrgb_to_srgb_ushort4_predivide(us, from); + premul_to_straight_v4(straight, from); + linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_dither_v4(to, us, di); } } @@ -277,7 +294,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, } else if (predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { - linearrgb_to_srgb_ushort4_predivide(us, from); + premul_to_straight_v4(straight, from); + linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_v4(to, us); } } @@ -526,7 +544,6 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from, void IMB_rect_from_float(ImBuf *ibuf) { - int predivide = (ibuf->flags & IB_cm_predivide); float *buffer; const char *from_colorspace; @@ -548,7 +565,10 @@ void IMB_rect_from_float(ImBuf *ibuf) buffer = MEM_dupallocN(ibuf->rect_float); /* first make float buffer in byte space */ - IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, predivide); + IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, TRUE); + + /* convert from float's premul alpha to byte's straight alpha */ + IMB_unpremultiply_rect_float(buffer, ibuf->planes, ibuf->x, ibuf->y); /* convert float to byte */ IMB_buffer_byte_from_float((unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, @@ -565,7 +585,6 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w { float *rect_float; uchar *rect_byte; - int predivide = (ibuf->flags & IB_cm_predivide); int profile_from = IB_PROFILE_LINEAR_RGB; /* verify we have a float buffer */ @@ -588,12 +607,12 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w /* and do color space conversion to byte */ IMB_buffer_byte_from_float(rect_byte, rect_float, - 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, + 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, TRUE, w, h, ibuf->x, w); } else { IMB_buffer_float_from_float(buffer, rect_float, - ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide, + ibuf->channels, IB_PROFILE_SRGB, profile_from, TRUE, w, h, w, ibuf->x); /* XXX: need to convert to image buffer's rect space */ @@ -608,8 +627,6 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w void IMB_float_from_rect(ImBuf *ibuf) { - int predivide = (ibuf->flags & IB_cm_predivide); - /* verify if we byte and float buffers */ if (ibuf->rect == NULL) return; @@ -634,22 +651,12 @@ void IMB_float_from_rect(ImBuf *ibuf) /* then make float be in linear space */ IMB_colormanagement_colorspace_to_scene_linear(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - ibuf->rect_colorspace, predivide); - - BLI_unlock_thread(LOCK_COLORMANAGE); -} - -/* no profile conversion */ -void IMB_float_from_rect_simple(ImBuf *ibuf) -{ - int predivide = (ibuf->flags & IB_cm_predivide); + ibuf->rect_colorspace, FALSE); - if (ibuf->rect_float == NULL) - imb_addrectfloatImBuf(ibuf); + /* byte buffer is straight alpha, float should always be premul */ + IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); - IMB_buffer_float_from_byte(ibuf->rect_float, (uchar *)ibuf->rect, - IB_PROFILE_SRGB, IB_PROFILE_SRGB, predivide, - ibuf->x, ibuf->y, ibuf->x, ibuf->x); + BLI_unlock_thread(LOCK_COLORMANAGE); } /* use when you need to get a buffer with a certain profile @@ -660,7 +667,6 @@ void IMB_float_from_rect_simple(ImBuf *ibuf) */ float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc) { - int predivide = (ibuf->flags & IB_cm_predivide); int profile_from = IB_PROFILE_LINEAR_RGB; int profile_to; @@ -686,12 +692,13 @@ float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc) if (ibuf->rect_float == NULL) { IMB_buffer_float_from_byte(fbuf, (uchar *)ibuf->rect, - profile_to, profile_from, predivide, + profile_to, profile_from, FALSE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); } else { IMB_buffer_float_from_float(fbuf, ibuf->rect_float, - 4, profile_to, profile_from, predivide, + 4, profile_to, profile_from, TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } @@ -727,6 +734,26 @@ 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; + float *cp = buf; + while (total--) { + premul_to_straight_v4(cp, cp); + cp += 4; + } +} + +void IMB_buffer_float_premultiply(float *buf, int width, int height) +{ + int total = width * height; + float *cp = buf; + while (total--) { + straight_to_premul_v4(cp, cp); + cp += 4; + } +} + /**************************** alter saturation *****************************/ void IMB_saturation(ImBuf *ibuf, float sat) diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index 678b2908b96..51fee232034 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -599,3 +599,67 @@ void IMB_premultiply_alpha(ImBuf *ibuf) IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); } +void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h) +{ + char *cp; + int x, y; + float val; + + if (planes == 24) { /* put alpha at 255 */ + cp = (char *)(rect); + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++, cp += 4) + cp[3] = 255; + } + else { + cp = (char *)(rect); + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++, cp += 4) { + val = cp[3] != 0 ? 1.0f / (float)cp[3] : 1.0f; + cp[0] = FTOCHAR(cp[0] * val); + cp[1] = FTOCHAR(cp[1] * val); + cp[2] = FTOCHAR(cp[2] * val); + } + } + } +} + +void IMB_unpremultiply_rect_float(float *rect_float, char planes, int w, int h) +{ + float val, *fp; + int x, y; + + if (planes == 24) { /* put alpha at 1.0 */ + fp = rect_float; + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++, fp += 4) + fp[3] = 1.0; + } + else { + fp = rect_float; + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++, fp += 4) { + val = fp[3] != 0.0f ? 1.0f / fp[3] : 1.0f; + fp[0] = fp[0] * val; + fp[1] = fp[1] * val; + fp[2] = fp[2] * val; + } + } + } + +} + +void IMB_unpremultiply_alpha(ImBuf *ibuf) +{ + if (ibuf == NULL) + return; + + if (ibuf->rect) + IMB_unpremultiply_rect(ibuf->rect, ibuf->planes, ibuf->x, ibuf->y); + + if (ibuf->rect_float) + IMB_unpremultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y); +} diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index da7b31cc2ba..18b08c9b59b 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1197,6 +1197,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char delete file; } } + + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; } return(ibuf); } diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index c0737fadffa..bbe43132051 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -110,7 +110,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) unsigned char *pixels = NULL; unsigned char *from, *to; unsigned short *pixels16 = NULL, *to16; - float *from_float; + float *from_float, from_straight[4]; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; @@ -175,10 +175,11 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) color_type = PNG_COLOR_TYPE_RGBA; if (is_16bit) { for (i = ibuf->x * ibuf->y; i > 0; i--) { - to16[0] = FTOUSHORT(from_float[0]); - to16[1] = FTOUSHORT(from_float[1]); - to16[2] = FTOUSHORT(from_float[2]); - to16[3] = FTOUSHORT(from_float[3]); + premul_to_straight_v4(from_straight, from_float); + to16[0] = FTOUSHORT(from_straight[0]); + to16[1] = FTOUSHORT(from_straight[1]); + to16[2] = FTOUSHORT(from_straight[2]); + to16[3] = FTOUSHORT(from_straight[3]); to16 += 4; from_float += 4; } } @@ -196,9 +197,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) color_type = PNG_COLOR_TYPE_RGB; if (is_16bit) { for (i = ibuf->x * ibuf->y; i > 0; i--) { - to16[0] = FTOUSHORT(from_float[0]); - to16[1] = FTOUSHORT(from_float[1]); - to16[2] = FTOUSHORT(from_float[2]); + premul_to_straight_v4(from_straight, from_float); + to16[0] = FTOUSHORT(from_straight[0]); + to16[1] = FTOUSHORT(from_straight[1]); + to16[2] = FTOUSHORT(from_straight[2]); to16 += 3; from_float += 4; } } @@ -215,7 +217,8 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) color_type = PNG_COLOR_TYPE_GRAY; if (is_16bit) { for (i = ibuf->x * ibuf->y; i > 0; i--) { - to16[0] = FTOUSHORT(from_float[0]); + premul_to_straight_v4(from_straight, from_float); + to16[0] = FTOUSHORT(from_straight[0]); to16++; from_float += 4; } } diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 03ed1bb8008..d09adeb09b5 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -212,6 +212,9 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color if (ibuf == NULL) return NULL; ibuf->ftype = RADHDR; + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; + if (flags & IB_test) return ibuf; /* read in and decode the actual data */ diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index be20c80bdec..8e0709e3670 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -86,15 +86,28 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE); } + if (flags & IB_ignore_alpha) { + IMB_rectfill_alpha(ibuf, 1.0f); + } + else { + if (flags & IB_alphamode_premul) { + if (ibuf->rect) + IMB_unpremultiply_alpha(ibuf); + else + /* pass, floats are expected to be premul */ ; + } + else { + if (ibuf->rect_float) + IMB_premultiply_alpha(ibuf); + else + /* pass, bytes are expected to be straight */ ; + } + } + /* OCIO_TODO: in some cases it's faster to do threaded conversion, * but how to distinguish such cases */ colormanage_imbuf_make_linear(ibuf, effective_colorspace); - if (flags & IB_premul) { - IMB_premultiply_alpha(ibuf); - ibuf->flags |= IB_premul; - } - return ibuf; } } @@ -230,4 +243,3 @@ void imb_loadtile(ImBuf *ibuf, int tx, int ty, unsigned int *rect) close(file); } - diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 1e701b8d615..75d1f4c412d 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" +#include "BLI_math_color.h" #include "MEM_guardedalloc.h" #include "imbuf.h" @@ -303,23 +304,33 @@ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) } if (do_rect) { - char *p1, *p2, *dest; + unsigned char *cp1, *cp2, *dest; - p1 = (char *) ibuf1->rect; - dest = (char *) ibuf2->rect; + cp1 = (unsigned char *) ibuf1->rect; + dest = (unsigned char *) ibuf2->rect; for (y = ibuf2->y; y > 0; y--) { - p2 = p1 + (ibuf1->x << 2); + cp2 = cp1 + (ibuf1->x << 2); for (x = ibuf2->x; x > 0; x--) { - dest[0] = (p1[0] + p2[0] + p1[4] + p2[4]) >> 2; - dest[1] = (p1[1] + p2[1] + p1[5] + p2[5]) >> 2; - dest[2] = (p1[2] + p2[2] + p1[6] + p2[6]) >> 2; - dest[3] = (p1[3] + p2[3] + p1[7] + p2[7]) >> 2; - p1 += 8; - p2 += 8; + float p1f[8], p2f[8], destf[4]; + + straight_uchar_to_premul_float(p1f, cp1); + straight_uchar_to_premul_float(p2f, cp2); + straight_uchar_to_premul_float(p1f + 4, cp1 + 4); + straight_uchar_to_premul_float(p2f + 4, cp2 + 4); + + destf[0] = 0.25f * (p1f[0] + p2f[0] + p1f[4] + p2f[4]); + destf[1] = 0.25f * (p1f[1] + p2f[1] + p1f[5] + p2f[5]); + destf[2] = 0.25f * (p1f[2] + p2f[2] + p1f[6] + p2f[6]); + destf[3] = 0.25f * (p1f[3] + p2f[3] + p1f[7] + p2f[7]); + + premul_float_to_straight_uchar(dest, destf); + + cp1 += 8; + cp2 += 8; dest += 4; } - p1 = p2; - if (ibuf1->x & 1) p1 += 4; + cp1 = cp2; + if (ibuf1->x & 1) cp1 += 4; } } diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 83830f260e1..2630aebef3b 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -376,7 +376,7 @@ static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image) * This method is most flexible and can handle multiple different bit depths * and RGB channel orderings. */ -static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) +static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) { ImBuf *tmpibuf; int success = 0; @@ -390,6 +390,23 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); /* number of 'channels' */ TIFFGetField(image, TIFFTAG_PLANARCONFIG, &config); + if (spp == 4) { + /* HACK: this is really tricky hack, which is only needed to force libtiff + * do not touch RGB channels when there's alpha channel present + * The thing is: libtiff will premul RGB if alpha mode is set to + * unassociated, which really conflicts with blender's assumptions + * + * Alternative would be to unpremul after load, but it'll be really + * lossy and unwanted behavior + * + * So let's keep this thing here for until proper solution is found (sergey) + */ + + unsigned short extraSampleTypes[1]; + extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA; + TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); + } + imb_read_tiff_resolution(ibuf, image); scanline = TIFFScanlineSize(image); @@ -471,10 +488,6 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul) if (bitspersample < 16) if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(tmpibuf); - if (premul) { - IMB_premultiply_alpha(tmpibuf); - ibuf->flags |= IB_premul; - } /* assign rect last */ if (tmpibuf->rect_float) @@ -557,6 +570,18 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[ return NULL; } + /* get alpha mode from file header */ + if (flags & IB_alphamode_detect) { + if (spp == 4) { + unsigned short extra, *extraSampleTypes; + + TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes); + + if (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA) + ibuf->flags |= IB_alphamode_premul; + } + } + /* if testing, we're done */ if (flags & IB_test) { TIFFClose(image); @@ -585,9 +610,6 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[ hbuf->miplevel = level; hbuf->ftype = ibuf->ftype; ibuf->mipmap[level - 1] = hbuf; - - if (flags & IB_premul) - hbuf->flags |= IB_premul; } else hbuf = ibuf; @@ -608,7 +630,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[ } /* read pixels */ - if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image, 0)) { + if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image)) { fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n"); TIFFClose(image); return NULL; @@ -644,9 +666,6 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int if (TIFFReadRGBATile(image, tx * ibuf->tilex, (ibuf->ytiles - 1 - ty) * ibuf->tiley, rect) == 1) { if (ibuf->tiley > ibuf->y) memmove(rect, rect + ibuf->tilex * (ibuf->tiley - ibuf->y), sizeof(int) * ibuf->tilex * ibuf->y); - - if (ibuf->flags & IB_premul) - IMB_premultiply_rect(rect, 32, ibuf->tilex, ibuf->tiley); } else printf("imb_loadtiff: failed to read tiff tile at mipmap level %d\n", ibuf->miplevel); @@ -689,8 +708,6 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) float *fromf = NULL; float xres, yres; int x, y, from_i, to_i, i; - int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA }; - /* check for a valid number of bytes per pixel. Like the PNG writer, * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding @@ -763,6 +780,13 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags) TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); if (samplesperpixel == 4) { + unsigned short extraSampleTypes[1]; + + if (bitspersample == 16) + extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA; + else + extraSampleTypes[0] = EXTRASAMPLE_UNASSALPHA; + /* RGBA images */ TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); |