Skip to content

Commit 48ca77f

Browse files
committed
Fix alpha bleeding when smooth-scaling images
After loading for example PNGs with an alpha, prefer passing it to renderers as pre-multiplied alpha, so that nearby transparent pixels (r=g=b=a=0) don't contribute anything as pre-multiplication will zero out their r/g/b. Fixes #10469 For the screenshot tests, smooth scaling is disabled because it results in different rendering between macOS and Linux on Skia with pre-multiplied alpha.
1 parent ec83b67 commit 48ca77f

File tree

9 files changed

+30
-6
lines changed

9 files changed

+30
-6
lines changed

internal/core/graphics/image/cache.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,21 @@ impl ImageCache {
156156
}
157157

158158
fn dynamic_image_to_shared_image_buffer(dynamic_image: image::DynamicImage) -> SharedImageBuffer {
159+
use rgb::AsPixels;
160+
159161
if dynamic_image.color().has_alpha() {
160162
let rgba8image = dynamic_image.to_rgba8();
161-
SharedImageBuffer::RGBA8(SharedPixelBuffer::clone_from_slice(
162-
rgba8image.as_raw(),
163-
rgba8image.width(),
164-
rgba8image.height(),
165-
))
163+
// Prefer pre-multiplied alpha so that smooth-scaling won't bleed the alpha when blending
164+
// in the renderers.
165+
SharedImageBuffer::RGBA8Premultiplied(SharedPixelBuffer {
166+
width: rgba8image.width(),
167+
height: rgba8image.height(),
168+
data: rgba8image
169+
.as_pixels()
170+
.into_iter()
171+
.map(|pixel| Image::rgba_to_premultiplied_rgba(*pixel))
172+
.collect(),
173+
})
166174
} else {
167175
let rgb8image = dynamic_image.to_rgb8();
168176
SharedImageBuffer::RGB8(SharedPixelBuffer::clone_from_slice(

tests/screenshots/cases/image/border-image-repeat.slint

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ export component TestCase inherits Window {
1313
vertical-alignment: bottom;
1414
horizontal-tiling: repeat;
1515
horizontal-alignment: center;
16+
image-rendering: pixelated;
1617
}
1718
Image {
1819
source: @image-url("border-image.png", nine-slice(6 5));
1920
vertical-tiling: round;
2021
vertical-alignment: bottom;
2122
horizontal-tiling: round;
2223
horizontal-alignment: center;
24+
image-rendering: pixelated;
2325
}
2426
}
2527
}

tests/screenshots/cases/image/border-image.slint

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@ export component TestCase inherits Window {
88
height: 64px;
99
GridLayout {
1010
Image {
11-
source: @image-url("border-image.png", nine-slice(6));
11+
source: @image-url("border-image.png", nine-slice(6));
1212
colspan: 2;
13+
image-rendering: pixelated;
1314
}
1415
Image {
1516
source: @image-url("border-image.png", nine-slice(6 0));
1617
row: 1;
1718
width: 50%;
1819
height: 50%;
20+
image-rendering: pixelated;
1921
}
2022
Image {
2123
source: @image-url("border-image.png", nine-slice(5 6 2 0));
24+
image-rendering: pixelated;
2225
}
2326
}
2427
}

tests/screenshots/cases/image/border-image2.slint

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ export component TestCase inherits Window {
1616
Image {
1717
// The border is bigger than the image
1818
source: @image-url("border-image-rect.png", nine-slice(50 2));
19+
image-rendering: pixelated;
1920
}
2021
Image {
2122
source: @image-url("border-image-rect.png", nine-slice(1 0));
23+
image-rendering: pixelated;
2224
}
2325
}
2426
}

tests/screenshots/cases/image/image-repeat.slint

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export component TestCase inherits Window {
1515
vertical-alignment: top;
1616
horizontal-alignment: center;
1717
vertical-tiling: repeat;
18+
image-rendering: pixelated;
1819
}
1920

2021
Image {
@@ -24,6 +25,7 @@ export component TestCase inherits Window {
2425
horizontal-alignment: left;
2526
vertical-tiling: repeat;
2627
horizontal-tiling: repeat;
28+
image-rendering: pixelated;
2729
}
2830

2931
Image {
@@ -33,6 +35,7 @@ export component TestCase inherits Window {
3335
horizontal-alignment: right;
3436
opacity: 0.5;
3537
horizontal-tiling: repeat;
38+
image-rendering: pixelated;
3639
}
3740

3841
Image {
@@ -42,6 +45,7 @@ export component TestCase inherits Window {
4245
horizontal-alignment: right;
4346
vertical-tiling: round;
4447
horizontal-tiling: round;
48+
image-rendering: pixelated;
4549
}
4650
}
4751

@@ -54,6 +58,7 @@ export component TestCase inherits Window {
5458
horizontal-alignment: right;
5559
vertical-tiling: repeat;
5660
horizontal-tiling: round;
61+
image-rendering: pixelated;
5762
}
5863

5964
Image {
@@ -63,6 +68,7 @@ export component TestCase inherits Window {
6368
horizontal-alignment: left;
6469
vertical-tiling: round;
6570
width: 15%;
71+
image-rendering: pixelated;
6672
}
6773

6874
Image {
@@ -71,6 +77,7 @@ export component TestCase inherits Window {
7177
vertical-alignment: center;
7278
horizontal-alignment: left;
7379
horizontal-tiling: round;
80+
image-rendering: pixelated;
7481
}
7582

7683
Image {
@@ -87,6 +94,8 @@ export component TestCase inherits Window {
8794

8895
vertical-tiling: repeat;
8996
horizontal-tiling: round;
97+
98+
image-rendering: pixelated;
9099
}
91100
}
92101
}
7.29 KB
Loading
-2.92 KB
Loading
-351 Bytes
Loading
887 Bytes
Loading

0 commit comments

Comments
 (0)