Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2012-12-31 17:52:13 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2012-12-31 17:52:13 +0400
commit08cea96ab08026ae9a3351b3e5830eda93f3106f (patch)
tree5fdcc1f2dc6ccf6388ba8bbe5792c18ddeddb424 /source/blender/imbuf
parent97c6a55c39e1a1949e04cf491946f8b275e2efb5 (diff)
Alpha premul pipeline cleanup
This assumptions are now made: - Internally float buffers are always linear alpha-premul colors - Readers should worry about delivering float buffers with that assumptions. - There's an input image setting to say whether it's stored with straight/premul alpha on the disk. - Byte buffers are now assumed have straight alpha, readers should deliver straight alpha. Some implementation details: - Removed scene's color unpremultiply setting, which was very much confusing and was wrong for default settings. Now all renderers assumes to deliver premultiplied alpha. - IMB_buffer_byte_from_float will now linearize alpha when converting from buffer. - Sequencer's effects were changed to assume bytes have got straight alpha. Most of effects will work with bytes still, however for glow it was more tricky to avoid data loss, so there's a commented out glow implementation which converts byte buffer to floats first, operates on floats and returns bytes back. It's slower and not sure if it should actually be used -- who're using glow on alpha anyway? - Sequencer modifiers should also be working nice with straight bytes now. - GLSL preview will predivide float textures to make nice shading, shading with byte textures worked nice (GLSL was assuming straight alpha). - Blender Internal will set alpha=1 to the whole sky. The same happens in Cycles and there's no way to avoid this -- sky is neither straight nor premul and doesn't fit color pipeline well. - Straight alpha mode for render result was also eliminated. - Conversion to correct alpha need to be done before linearizing float buffer. - TIFF will now load and save files with proper alpha mode setting in file meta data header. - Remove Use Alpha from texture mapping and replaced with image datablock setting. Behaves much more predictable and clear from code point of view and solves possible regressions when non-premultiplied images were used as textures with ignoring alpha channel.
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h1
-rw-r--r--source/blender/imbuf/IMB_imbuf.h4
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h5
-rw-r--r--source/blender/imbuf/intern/IMB_filter.h3
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c3
-rw-r--r--source/blender/imbuf/intern/colormanagement.c63
-rw-r--r--source/blender/imbuf/intern/divers.c81
-rw-r--r--source/blender/imbuf/intern/filter.c64
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp3
-rw-r--r--source/blender/imbuf/intern/png.c21
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c3
-rw-r--r--source/blender/imbuf/intern/readimage.c24
-rw-r--r--source/blender/imbuf/intern/scaling.c35
-rw-r--r--source/blender/imbuf/intern/tiff.c52
14 files changed, 262 insertions, 100 deletions
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 0653956e113..1e33f8da363 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -138,6 +138,7 @@ struct ColormanageProcessor *IMB_colormanagement_display_processor_new(const str
const struct ColorManagedDisplaySettings *display_settings);
struct ColormanageProcessor *IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace);
void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_processor, float pixel[4]);
+void IMB_colormanagement_processor_apply_v4_predivide(struct ColormanageProcessor *cm_processor, float pixel[4]);
void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_processor, float pixel[3]);
void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height,
int channels, int predivide);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index db1404813b1..850060ef4d5 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -373,7 +373,6 @@ void IMB_rect_from_float(struct ImBuf *ibuf);
* Changed part will be stored in buffer. This is expected to be used for texture painting updates */
void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y, int w, int h, int is_data);
void IMB_float_from_rect(struct ImBuf *ibuf);
-void IMB_float_from_rect_simple(struct ImBuf *ibuf); /* no profile conversion */
/* note, check that the conversion exists, only some are supported */
float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc);
void IMB_color_to_bw(struct ImBuf *ibuf);
@@ -393,6 +392,8 @@ void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect
int profile_to, int profile_from, int predivide,
int width, int height, int stride_to, int stride_from);
void IMB_buffer_float_clamp(float *buf, int width, int height);
+void IMB_buffer_float_unpremultiply(float *buf, int width, int height);
+void IMB_buffer_float_premultiply(float *buf, int width, int height);
/**
* Change the ordering of the color bytes pointed to by rect from
@@ -467,6 +468,7 @@ void IMB_flipy(struct ImBuf *ibuf);
/* Premultiply alpha */
void IMB_premultiply_alpha(struct ImBuf *ibuf);
+void IMB_unpremultiply_alpha(struct ImBuf *ibuf);
/**
*
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 9fe66b562d1..49e2e7fc80d 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -167,8 +167,9 @@ typedef struct ImBuf {
#define IB_animdeinterlace (1 << 9)
#define IB_tiles (1 << 10)
#define IB_tilecache (1 << 11)
-#define IB_premul (1 << 12)
-#define IB_cm_predivide (1 << 13)
+#define IB_alphamode_premul (1 << 12) /* indicates whether image on disk have premul alpha */
+#define IB_alphamode_detect (1 << 13) /* if this flag is set, alpha mode would be guessed from file */
+#define IB_ignore_alpha (1 << 14) /* ignore alpha on load and substitude it with 1.0f */
/*
* The bit flag is stored in the ImBuf.ftype variable.
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);