@@ -117,66 +117,69 @@ impl DrawRectangleFilter {
117117 * pixel = Rgba ( [ r, g, b, a] ) ;
118118 }
119119
120- fn sdf_rounded_rect (
121- px : f32 ,
122- py : f32 ,
123- rect_x : f32 ,
124- rect_y : f32 ,
125- width : f32 ,
126- height : f32 ,
127- r : f32 ,
128- ) -> f32 {
129- // Translate point relative to rectangle top-left
130- let p_x = px - rect_x;
131- let p_y = py - rect_y;
132-
133- // Calculate distance from each edge
134- let d_left = p_x;
135- let d_right = width - p_x;
136- let d_top = p_y;
137- let d_bottom = height - p_y;
138-
139- // Find minimum distance to any edge
140- let d_x = d_left. min ( d_right) ;
141- let d_y = d_top. min ( d_bottom) ;
142-
143- // Check if we're in a corner region (both d_x and d_y are small)
144- if d_x < r && d_y < r && d_x >= 0.0 && d_y >= 0.0 {
145- // In corner region: calculate distance to the corner's arc
146- // Determine which corner
147- let corner_cx = if p_x < width / 2.0 { r } else { width - r } ;
148- let corner_cy = if p_y < height / 2.0 { r } else { height - r } ;
149-
150- let dx = p_x - corner_cx;
151- let dy = p_y - corner_cy;
152- let dist_to_center = ( dx * dx + dy * dy) . sqrt ( ) ;
153- r - dist_to_center
120+ /// 判断点是否在圆角矩形内部
121+ fn inside_rounded_rect ( x : f64 , y : f64 , w : f64 , h : f64 , r : f64 ) -> bool {
122+ // 检查是否在圆角区域
123+ let near_left = x < r;
124+ let near_right = x > w - r;
125+ let near_top = y < r;
126+ let near_bottom = y > h - r;
127+
128+ let in_corner = ( near_left || near_right) && ( near_top || near_bottom) ;
129+
130+ if in_corner {
131+ // 圆角区域:检查是否在圆内
132+ let cx = if near_left { r } else { w - r } ;
133+ let cy = if near_top { r } else { h - r } ;
134+ let dx = x - cx;
135+ let dy = y - cy;
136+ dx * dx + dy * dy <= r * r
154137 } else {
155- // In edge or interior region
156- let min_dist = d_x. min ( d_y) ;
157- if min_dist >= 0.0 {
158- // Inside: return distance to nearest edge
159- min_dist. min ( r)
160- } else {
161- // Outside: negative distance
162- min_dist
163- }
138+ // 直线区域
139+ x >= 0.0 && x <= w && y >= 0.0 && y <= h
164140 }
165141 }
166142
167- #[ inline]
168- fn aa_smoothstep ( edge0 : f32 , edge1 : f32 , x : f32 ) -> f32 {
169- let t = ( ( x - edge0) / ( edge1 - edge0) ) . clamp ( 0.0 , 1.0 ) ;
170- t * t * ( 3.0 - 2.0 * t)
143+ /// 计算点到圆角矩形边缘的距离(正值表示在内部)
144+ fn distance_to_edge ( x : f64 , y : f64 , w : f64 , h : f64 , r : f64 ) -> f64 {
145+ let near_left = x < r;
146+ let near_right = x > w - r;
147+ let near_top = y < r;
148+ let near_bottom = y > h - r;
149+
150+ let in_corner = ( near_left || near_right) && ( near_top || near_bottom) ;
151+
152+ if in_corner {
153+ // 圆角区域:到圆弧的距离
154+ let cx = if near_left { r } else { w - r } ;
155+ let cy = if near_top { r } else { h - r } ;
156+ let dx = x - cx;
157+ let dy = y - cy;
158+ let dist = ( dx * dx + dy * dy) . sqrt ( ) ;
159+ r - dist
160+ } else if near_left {
161+ x
162+ } else if near_right {
163+ w - x
164+ } else if near_top {
165+ y
166+ } else if near_bottom {
167+ h - y
168+ } else {
169+ // 内部区域:到最近边的距离
170+ x. min ( w - x) . min ( y) . min ( h - y)
171+ }
171172 }
172173
173- #[ inline]
174- fn aa_alpha ( sdf : f32 ) -> f32 {
175- // 1 pixel smooth transition range
176- const AA_RANGE : f32 = 1.0 ;
177- // SDF positive = inside, negative = outside
178- // Smooth transition from 0 to 1 across AA_RANGE
179- Self :: aa_smoothstep ( -AA_RANGE , AA_RANGE , sdf)
174+ /// 颜色混合
175+ fn blend_colors ( c1 : Rgba < u8 > , c2 : Rgba < u8 > , t : f64 ) -> Rgba < u8 > {
176+ let t = t. clamp ( 0.0 , 1.0 ) ;
177+ Rgba ( [
178+ ( c1[ 0 ] as f64 * ( 1.0 - t) + c2[ 0 ] as f64 * t) . round ( ) as u8 ,
179+ ( c1[ 1 ] as f64 * ( 1.0 - t) + c2[ 1 ] as f64 * t) . round ( ) as u8 ,
180+ ( c1[ 2 ] as f64 * ( 1.0 - t) + c2[ 2 ] as f64 * t) . round ( ) as u8 ,
181+ ( c1[ 3 ] as f64 * ( 1.0 - t) + c2[ 3 ] as f64 * t) . round ( ) as u8 ,
182+ ] )
180183 }
181184
182185 fn draw_filled_rounded_rect (
@@ -186,32 +189,148 @@ impl DrawRectangleFilter {
186189 width : u32 ,
187190 height : u32 ,
188191 corner_radius : u32 ,
189- color : & Rgba < u8 > ,
192+ fill_color : & Rgba < u8 > ,
190193 ) {
191- let rx = rect_x as f32 ;
192- let ry = rect_y as f32 ;
193- let w = width as f32 ;
194- let h = height as f32 ;
195- let r = corner_radius as f32 ;
196-
197- for dy in 0 ..height as i32 {
198- for dx in 0 ..width as i32 {
199- let px = rect_x + dx;
200- let py = rect_y + dy;
201-
202- if px < 0 || py < 0 || px >= buffer. width ( ) as i32 || py >= buffer. height ( ) as i32 {
194+ let x = rect_x as u32 ;
195+ let y = rect_y as u32 ;
196+ let ( img_width, img_height) = buffer. dimensions ( ) ;
197+
198+ // 限制圆角半径
199+ let max_radius = ( width / 2 ) . min ( height / 2 ) ;
200+ let radius = corner_radius. min ( max_radius) ;
201+
202+ // 遍历绘制区域
203+ for dy in 0 ..height {
204+ for dx in 0 ..width {
205+ let px = x + dx;
206+ let py = y + dy;
207+
208+ if px >= img_width || py >= img_height {
203209 continue ;
204210 }
205211
206- // Calculate signed distance field value
207- let sdf = Self :: sdf_rounded_rect ( px as f32 , py as f32 , rx, ry, w, h, r) ;
212+ // 使用浮点数计算像素中心
213+ let fx = dx as f64 + 0.5 ;
214+ let fy = dy as f64 + 0.5 ;
215+ let fw = width as f64 ;
216+ let fh = height as f64 ;
217+ let fr = radius as f64 ;
218+
219+ // 判断是否在圆角矩形内
220+ let in_rect = Self :: inside_rounded_rect ( fx, fy, fw, fh, fr) ;
221+ if !in_rect {
222+ continue ;
223+ }
224+
225+ // 计算抗锯齿
226+ let dist = Self :: distance_to_edge ( fx, fy, fw, fh, fr) ;
227+ let aa_range = 1.5 ;
228+
229+ let final_color = if dist < aa_range && dist >= 0.0 {
230+ let alpha = dist / aa_range;
231+ Self :: blend_colors ( Rgba ( [ 0 , 0 , 0 , 0 ] ) , * fill_color, alpha)
232+ } else {
233+ * fill_color
234+ } ;
235+
236+ Self :: draw_pixel_aa ( buffer, px, py, & final_color, 1.0 ) ;
237+ }
238+ }
239+ }
208240
209- // Apply anti-aliasing based on SDF
210- let alpha = Self :: aa_alpha ( sdf) ;
241+ /// 绘制带边框的圆角矩形
242+ fn draw_rounded_rectangle_with_border (
243+ buffer : & mut RgbaImage ,
244+ x : u32 ,
245+ y : u32 ,
246+ width : u32 ,
247+ height : u32 ,
248+ corner_radius : u32 ,
249+ fill_color : & Rgba < u8 > ,
250+ border_width : u32 ,
251+ border_color : & Rgba < u8 > ,
252+ ) {
253+ let ( img_width, img_height) = buffer. dimensions ( ) ;
211254
212- if alpha > 0.01 {
213- Self :: draw_pixel_aa ( buffer, px as u32 , py as u32 , color, alpha) ;
255+ // 限制圆角半径
256+ let max_radius = ( width / 2 ) . min ( height / 2 ) ;
257+ let radius = corner_radius. min ( max_radius) ;
258+
259+ // 遍历绘制区域
260+ for dy in 0 ..height {
261+ for dx in 0 ..width {
262+ let px = x + dx;
263+ let py = y + dy;
264+
265+ if px >= img_width || py >= img_height {
266+ continue ;
267+ }
268+
269+ // 使用浮点数计算像素中心
270+ let fx = dx as f64 + 0.5 ;
271+ let fy = dy as f64 + 0.5 ;
272+ let fw = width as f64 ;
273+ let fh = height as f64 ;
274+ let fr = radius as f64 ;
275+
276+ // 判断是否在外部圆角矩形内
277+ let in_outer = Self :: inside_rounded_rect ( fx, fy, fw, fh, fr) ;
278+ if !in_outer {
279+ continue ;
214280 }
281+
282+ // 计算颜色和抗锯齿
283+ let final_color = {
284+ let bw = border_width as f64 ;
285+ let inner_w = ( fw - 2.0 * bw) . max ( 0.0 ) ;
286+ let inner_h = ( fh - 2.0 * bw) . max ( 0.0 ) ;
287+ let inner_r = ( fr - bw) . max ( 0.0 ) ;
288+
289+ // 计算到外边界的距离
290+ let outer_dist = Self :: distance_to_edge ( fx, fy, fw, fh, fr) ;
291+
292+ // 计算到内边界的距离(边框与填充的交界)
293+ let inner_dist = if inner_w > 0.0 && inner_h > 0.0 {
294+ Self :: distance_to_edge ( fx - bw, fy - bw, inner_w, inner_h, inner_r)
295+ } else {
296+ f64:: INFINITY
297+ } ;
298+
299+ let aa_range = 1.5 ;
300+
301+ // 判断是在填充区还是边框区
302+ let in_fill = inner_w > 0.0 && inner_h > 0.0 &&
303+ Self :: inside_rounded_rect ( fx - bw, fy - bw, inner_w, inner_h, inner_r) ;
304+
305+ if in_fill {
306+ // 填充区:检查是否靠近内边界
307+ if inner_dist < aa_range && inner_dist >= 0.0 {
308+ let alpha = inner_dist / aa_range;
309+ Self :: blend_colors ( * border_color, * fill_color, alpha)
310+ } else {
311+ * fill_color
312+ }
313+ } else {
314+ // 边框区:需要检查外边界和内边界
315+ let mut color = * border_color;
316+
317+ // 外边界抗锯齿(与背景混合)
318+ if outer_dist < aa_range && outer_dist >= 0.0 {
319+ let alpha = outer_dist / aa_range;
320+ color = Self :: blend_colors ( Rgba ( [ 0 , 0 , 0 , 0 ] ) , color, alpha) ;
321+ }
322+
323+ // 内边界抗锯齿(与填充混合)- 仅当靠近内边界时
324+ if inner_dist < aa_range && inner_dist >= 0.0 {
325+ let alpha = inner_dist / aa_range;
326+ color = Self :: blend_colors ( color, * fill_color, 1.0 - alpha) ;
327+ }
328+
329+ color
330+ }
331+ } ;
332+
333+ Self :: draw_pixel_aa ( buffer, px, py, & final_color, 1.0 ) ;
215334 }
216335 }
217336 }
@@ -234,35 +353,41 @@ impl DrawRectangleFilter {
234353 } ;
235354
236355 // Draw filled rectangle
356+ // Skip if we have a rounded rectangle with border (will be handled together)
237357 if let Some ( fill) = self . fill_color {
238358 let fill_color = Rgba ( apply_opacity ( fill) ) ;
239359
240- if corner_radius == 0 {
241- // Simple filled rectangle
242- for dy in 0 ..height {
243- for dx in 0 ..width {
244- let px = x + dx as i32 ;
245- let py = y + dy as i32 ;
246- if px >= 0
247- && py >= 0
248- && px < buffer. width ( ) as i32
249- && py < buffer. height ( ) as i32
250- {
251- Self :: draw_pixel_aa ( buffer, px as u32 , py as u32 , & fill_color, 1.0 ) ;
360+ // Only draw fill separately if: no border OR corner_radius is 0
361+ let should_draw_fill_separately = self . border_color . is_none ( ) || corner_radius == 0 ;
362+
363+ if should_draw_fill_separately {
364+ if corner_radius == 0 {
365+ // Simple filled rectangle
366+ for dy in 0 ..height {
367+ for dx in 0 ..width {
368+ let px = x + dx as i32 ;
369+ let py = y + dy as i32 ;
370+ if px >= 0
371+ && py >= 0
372+ && px < buffer. width ( ) as i32
373+ && py < buffer. height ( ) as i32
374+ {
375+ Self :: draw_pixel_aa ( buffer, px as u32 , py as u32 , & fill_color, 1.0 ) ;
376+ }
252377 }
253378 }
379+ } else {
380+ // Rounded rectangle fill (no border)
381+ Self :: draw_filled_rounded_rect (
382+ buffer,
383+ x,
384+ y,
385+ width,
386+ height,
387+ corner_radius,
388+ & fill_color,
389+ ) ;
254390 }
255- } else {
256- // Rounded rectangle fill
257- Self :: draw_filled_rounded_rect (
258- buffer,
259- x,
260- y,
261- width,
262- height,
263- corner_radius,
264- & fill_color,
265- ) ;
266391 }
267392 }
268393
@@ -334,8 +459,21 @@ impl DrawRectangleFilter {
334459 }
335460 }
336461 } else {
337- // Note: Border rendering is not supported for rounded rectangles
338- // Only the fill will be rendered
462+ // Rounded rectangle with border support
463+ let fill_rgba = self . fill_color . map ( |f| Rgba ( apply_opacity ( f) ) )
464+ . unwrap_or ( Rgba ( [ 0 , 0 , 0 , 0 ] ) ) ;
465+
466+ Self :: draw_rounded_rectangle_with_border (
467+ buffer,
468+ x. max ( 0 ) as u32 ,
469+ y. max ( 0 ) as u32 ,
470+ width,
471+ height,
472+ corner_radius,
473+ & fill_rgba,
474+ self . border_width ,
475+ & border_color,
476+ ) ;
339477 }
340478 }
341479
0 commit comments