1- use tiny_skia:: { Pixmap , PixmapPaint } ;
1+ use anyhow:: anyhow;
2+ use tiny_skia:: { FillRule , FilterQuality , Mask , Path , PathBuilder , Pixmap , PixmapPaint , Transform } ;
23
34use crate :: components:: interface:: {
45 component:: { Component , ComponentContext , RenderParams } ,
@@ -31,9 +32,10 @@ impl Component for Image {
3132 _style : & ComponentStyle ,
3233 _parent_style : & Style < f32 > ,
3334 ) -> render_error:: Result < ( ) > {
34- let transform =
35- tiny_skia:: Transform :: from_scale ( context. scale_factor , context. scale_factor ) ;
36- let paint = PixmapPaint :: default ( ) ;
35+ let transform = Transform :: from_scale ( context. scale_factor , context. scale_factor ) ;
36+ let mut paint = PixmapPaint :: default ( ) ;
37+
38+ paint. quality = FilterQuality :: Bilinear ;
3739
3840 pixmap. draw_pixmap (
3941 render_params. x as i32 ,
@@ -49,12 +51,55 @@ impl Component for Image {
4951}
5052
5153impl Image {
52- pub fn new ( image_data : Vec < u8 > ) -> anyhow:: Result < Self > {
53- let image_pixmap = Pixmap :: decode_png ( & image_data) ?;
54+ pub fn new ( radius : f32 , image_data : Vec < u8 > ) -> anyhow:: Result < Self > {
55+ let mut image_pixmap = Pixmap :: decode_png ( & image_data) ?;
56+ let rounded_mask = Self :: build_round_mask ( & image_pixmap, radius) ?;
57+ image_pixmap. apply_mask ( & rounded_mask) ;
5458
5559 Ok ( Self {
5660 image_pixmap,
5761 children : vec ! [ ] ,
5862 } )
5963 }
64+
65+ fn build_round_mask ( pixmap : & Pixmap , radius : f32 ) -> anyhow:: Result < Mask > {
66+ let width = pixmap. width ( ) ;
67+ let height = pixmap. height ( ) ;
68+
69+ if width == 0 || height == 0 {
70+ return Err ( anyhow ! ( "image pixmap must have non-zero dimensions" ) ) ;
71+ }
72+
73+ let path = Self :: rounded_rect_path ( width as f32 , height as f32 , radius) ?;
74+ let mut mask = Mask :: new ( width, height) . ok_or_else ( || anyhow ! ( "failed to create mask" ) ) ?;
75+ mask. fill_path ( & path, FillRule :: Winding , true , Transform :: identity ( ) ) ;
76+
77+ Ok ( mask)
78+ }
79+
80+ fn rounded_rect_path ( width : f32 , height : f32 , radius : f32 ) -> anyhow:: Result < Path > {
81+ if width <= 0.0 || height <= 0.0 {
82+ return Err ( anyhow ! ( "rounded rect requires positive size" ) ) ;
83+ }
84+
85+ let mut builder = PathBuilder :: new ( ) ;
86+ let radius = radius. max ( 0.0 ) . min ( width / 2.0 ) . min ( height / 2.0 ) ;
87+ let right = width;
88+ let bottom = height;
89+
90+ builder. move_to ( radius, 0.0 ) ;
91+ builder. line_to ( right - radius, 0.0 ) ;
92+ builder. quad_to ( right, 0.0 , right, radius) ;
93+ builder. line_to ( right, bottom - radius) ;
94+ builder. quad_to ( right, bottom, right - radius, bottom) ;
95+ builder. line_to ( radius, bottom) ;
96+ builder. quad_to ( 0.0 , bottom, 0.0 , bottom - radius) ;
97+ builder. line_to ( 0.0 , radius) ;
98+ builder. quad_to ( 0.0 , 0.0 , radius, 0.0 ) ;
99+ builder. close ( ) ;
100+
101+ builder
102+ . finish ( )
103+ . ok_or_else ( || anyhow ! ( "failed to create rounded rectangle path" ) )
104+ }
60105}
0 commit comments