Skip to content

Commit 29e80ca

Browse files
committed
better 0 detection in unpremultiply
We were avoiding /0 by testing for alpha==0, however, this will still allow very small values of alpha to generate +/- Inf. Instead, check for abs(alpha)<epsilon. Fixes some artifacts after unpremul.
1 parent 2c4c039 commit 29e80ca

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- add a summary table at the end of configure in meson
44
- fix libpng fallback when spng is disabled in meson
55
- add "unlimited" to jpegload
6+
- better 0 detection in unpremultiply
67

78
21/11/21 started 8.13
89
- configure fails for requested but unmet dependencies [remicollet]

libvips/conversion/unpremultiply.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* - match normalised alpha to output type
1010
* 27/2/21 jjonesrs
1111
* - revise range clipping and 1/x, again
12+
* 8/8/22
13+
* - look for alpha near 0, not just exactly 0
1214
*/
1315

1416
/*
@@ -123,6 +125,55 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION );
123125
} \
124126
}
125127

128+
/* For float-style images, we need to check for alpha near zero, or we'll get
129+
* +/- Inf in the output.
130+
*/
131+
#define FUNPRE_MANY( IN, OUT ) { \
132+
IN * restrict p = (IN *) in; \
133+
OUT * restrict q = (OUT *) out; \
134+
\
135+
for( x = 0; x < width; x++ ) { \
136+
IN alpha = p[alpha_band]; \
137+
OUT factor = VIPS_ABS( alpha ) < 0.01 ? 0 : max_alpha / alpha; \
138+
\
139+
for( i = 0; i < alpha_band; i++ ) \
140+
q[i] = factor * p[i]; \
141+
q[alpha_band] = VIPS_CLIP( 0, alpha, max_alpha ); \
142+
for( i = alpha_band + 1; i < bands; i++ ) \
143+
q[i] = p[i]; \
144+
\
145+
p += bands; \
146+
q += bands; \
147+
} \
148+
}
149+
150+
#define FUNPRE_RGBA( IN, OUT ) { \
151+
IN * restrict p = (IN *) in; \
152+
OUT * restrict q = (OUT *) out; \
153+
\
154+
for( x = 0; x < width; x++ ) { \
155+
IN alpha = p[3]; \
156+
OUT factor = VIPS_ABS( alpha ) < 0.01 ? 0 : max_alpha / alpha; \
157+
\
158+
q[0] = factor * p[0]; \
159+
q[1] = factor * p[1]; \
160+
q[2] = factor * p[2]; \
161+
q[3] = VIPS_CLIP( 0, alpha, max_alpha ); \
162+
\
163+
p += 4; \
164+
q += 4; \
165+
} \
166+
}
167+
168+
#define FUNPRE( IN, OUT ) { \
169+
if( bands == 4 ) { \
170+
FUNPRE_RGBA( IN, OUT ); \
171+
} \
172+
else { \
173+
FUNPRE_MANY( IN, OUT ); \
174+
} \
175+
}
176+
126177
static int
127178
vips_unpremultiply_gen( VipsRegion *or, void *vseq, void *a, void *b,
128179
gboolean *stop )
@@ -171,11 +222,11 @@ vips_unpremultiply_gen( VipsRegion *or, void *vseq, void *a, void *b,
171222
break;
172223

173224
case VIPS_FORMAT_FLOAT:
174-
UNPRE( float, float );
225+
FUNPRE( float, float );
175226
break;
176227

177228
case VIPS_FORMAT_DOUBLE:
178-
UNPRE( double, double );
229+
FUNPRE( double, double );
179230
break;
180231

181232
case VIPS_FORMAT_COMPLEX:

0 commit comments

Comments
 (0)