index/utils/
style.rs

1use std::rc::Rc;
2
3use image::{codecs::png::PngEncoder, guess_format, load_from_memory_with_format, ImageBuffer, RgbaImage};
4use usvg::{Opacity, Paint};
5use wasm_bindgen::prelude::*;
6use base64::{prelude::BASE64_STANDARD, Engine};
7
8use crate::utils::interpolation::{inverse_lerp, lerp};
9
10use super::{console::log, point2d::Point2D};
11
12/// A color with red, green, blue, and alpha components.
13#[wasm_bindgen]
14#[derive(Debug, Clone, Copy)]
15pub struct Color {
16    /// The red component of the color.
17    pub red: u8,
18    /// The green component of the color.
19    pub green: u8,
20    /// The blue component of the color.
21    pub blue: u8,
22    /// The alpha component of the color.
23    pub alpha: f32,
24}
25
26impl Default for Color {
27    fn default() -> Self {
28        Color {
29            red: 0,
30            green: 0,
31            blue: 0,
32            alpha: 0.0,
33        }
34    }
35}
36
37#[wasm_bindgen]
38impl Color {
39    /// Creates a new Color with the given red, green, blue, and alpha components.
40    #[wasm_bindgen(constructor, return_description = "A new color.")]
41    pub fn new(
42        #[wasm_bindgen(param_description = "The red component of the color.")]
43        red: u8,
44        #[wasm_bindgen(param_description = "The green component of the color.")]
45        green: u8,
46        #[wasm_bindgen(param_description = "The blue component of the color.")]
47        blue: u8,
48        #[wasm_bindgen(param_description = "The alpha component of the color.")]
49        alpha: f32
50    ) -> Color {
51        Color {
52            red,
53            green,
54            blue,
55            alpha,
56        }
57    }
58    /// Returns the default color, which is a fully transparent black.
59    #[wasm_bindgen(return_description = "The default color.")]
60    pub fn default_color() -> Color {
61        Color::default()
62    }
63    /// Linearly interpolates between two Colors given a progress value.
64    #[wasm_bindgen]
65    pub fn lerp(
66        #[wasm_bindgen(param_description = "The start color.")]
67        color1: &Color,
68        #[wasm_bindgen(param_description = "The end color.")]
69        color2: &Color,
70        #[wasm_bindgen(param_description = "The progress value.")]
71        t: f32
72    ) -> Color {
73        let red = lerp(color1.red as f32, color2.red as f32, t) as u8;
74        let green = lerp(color1.green as f32, color2.green as f32, t) as u8;
75        let blue = lerp(color1.blue as f32, color2.blue as f32, t) as u8;
76        let alpha = lerp(color1.alpha, color2.alpha, t);
77        Color {
78            red,
79            green,
80            blue,
81            alpha,
82        }
83    }
84}
85
86/// A color stop for a gradient with a color and a position.
87#[wasm_bindgen]
88#[derive(Debug, Clone, Copy)]
89pub struct ColorStop {
90    /// The color of the stop.
91    pub color: Color,
92    /// The position of the stop.
93    pub position: f32,
94}
95
96impl Default for ColorStop {
97    fn default() -> Self {
98        ColorStop {
99            color: Color::default(),
100            position: 0.0,
101        }
102    }
103}
104
105#[wasm_bindgen]
106impl ColorStop {
107    /// Creates a new ColorStop with the given color and position.
108    #[wasm_bindgen(constructor, return_description = "A new color stop.")]
109    pub fn new(
110        #[wasm_bindgen(param_description = "The color of the stop.")]
111        color: Color,
112        #[wasm_bindgen(param_description = "The position of the stop.")]
113        position: f32
114    ) -> ColorStop {
115        ColorStop {
116            color,
117            position,
118        }
119    }
120}
121
122/// A linear gradient with a start and end point and color stops.
123#[wasm_bindgen]
124#[derive(Debug, Clone)]
125pub struct LinearGradient {
126    /// The start point of the gradient.
127    pub p1: Point2D,
128    /// The end point of the gradient.
129    pub p2: Point2D,
130    /// The color stops of the gradient.
131    color_stops: Rc<Vec<ColorStop>>,
132}
133
134impl Default for LinearGradient {
135    fn default() -> Self {
136        LinearGradient {
137            p1: Point2D::default(),
138            p2: Point2D::default(),
139            color_stops: Rc::new(vec![]),
140        }
141    }
142}
143
144#[wasm_bindgen]
145impl LinearGradient {
146    /// Creates a new LinearGradient with the given start point, end point, and ColorStops.
147    #[wasm_bindgen(constructor, return_description = "A new linear gradient.")]
148    pub fn new(
149        #[wasm_bindgen(param_description = "The start point of the gradient.")]
150        p1: Point2D,
151        #[wasm_bindgen(param_description = "The end point of the gradient.")]
152        p2: Point2D,
153        #[wasm_bindgen(param_description = "The color stops of the gradient.")]
154        color_stops: Vec<ColorStop>
155    ) -> LinearGradient {
156        LinearGradient {
157            p1,
158            p2,
159            color_stops: Rc::new(color_stops),
160        }
161    }
162    /// Returns the default LinearGradient, which is a gradient from the start to the end the same color.
163    #[wasm_bindgen(return_description = "The default linear gradient.")]
164    pub fn single_color_gradient(
165        #[wasm_bindgen(param_description = "The start point of the gradient.")]
166        p1: Point2D,
167        #[wasm_bindgen(param_description = "The end point of the gradient.")]
168        p2: Point2D,
169        #[wasm_bindgen(param_description = "The color of the gradient.")]
170        color: Color,
171        #[wasm_bindgen(param_description = "Number of times to repeat the color.")]
172        repeats: Option<usize>
173    ) -> LinearGradient {
174        let repeats = repeats.unwrap_or(2);
175        let mut color_stops = vec![];
176        for i in 0..repeats {
177            color_stops.push(ColorStop { color, position: i as f32 / (repeats - 1) as f32 });
178        }
179        LinearGradient {
180            p1,
181            p2,
182            color_stops: Rc::new(color_stops),
183        }
184    }
185    /// Returns the default LinearGradient, which is a gradient from the origin to the origin with no ColorStops.
186    #[wasm_bindgen(return_description = "The default linear gradient.")]
187    pub fn default_linear_gradient() -> LinearGradient {
188        LinearGradient::default()
189    }
190    /// Gets the ColorStops of the gradient.
191    #[wasm_bindgen(getter, return_description = "The color stops of the gradient.")]
192    pub fn color_stops(&self) -> Vec<ColorStop> {
193        self.color_stops.to_vec()
194    }
195    /// Sets the ColorStops of the gradient.
196    #[wasm_bindgen(setter)]
197    pub fn set_color_stops(
198        &mut self,
199        #[wasm_bindgen(param_description = "The color stops of the gradient.")]
200        color_stops: Vec<ColorStop>
201    ) {
202        self.color_stops = Rc::new(color_stops);
203    }
204    /// Gets the Color at a given offset along the gradient.
205    #[wasm_bindgen(return_description = "The color at the given offset.")]
206    pub fn color_at_offset(
207        &self,
208        #[wasm_bindgen(param_description = "The offset to get the color at.")]
209        position: f32
210    ) -> Color {
211        let mut the_stops = Rc::clone(&self.color_stops);
212        let stops = Rc::make_mut(&mut the_stops);
213        stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
214        for i in 0..stops.len() {
215            if position < stops[i].position {
216                if i == 0 {
217                    return stops[i].color;
218                }
219                let t = inverse_lerp(stops[i - 1].position, stops[i].position, position);
220                return Color::lerp(&stops[i - 1].color, &stops[i].color, t);
221            }
222        }
223        stops[stops.len() - 1].color
224    }
225    /// Gets the Color at a given point along the gradient.
226    #[wasm_bindgen(return_description = "The color at the given point.")]
227    pub fn color_at(
228        &self,
229        #[wasm_bindgen(param_description = "The point to get the color at.")]
230        p: Point2D
231    ) -> Color {
232        let t = p.project_onto_line(&self.p1, &self.p2);
233        self.color_at_offset(t)
234    }
235    /// Linearly interpolates between two LinearGradients given a progress value.
236    #[wasm_bindgen(return_description = "The interpolated linear gradient.")]
237    pub fn lerp(
238        #[wasm_bindgen(param_description = "The first linear gradient.")]
239        gradient1: &LinearGradient,
240        #[wasm_bindgen(param_description = "The second linear gradient.")]
241        gradient2: &LinearGradient,
242        #[wasm_bindgen(param_description = "The progress value.")]
243        t: f32
244    ) -> LinearGradient {
245        let p1 = Point2D::lerp(&gradient1.p1, &gradient2.p1, t);
246        let p2 = Point2D::lerp(&gradient1.p2, &gradient2.p2, t);
247        let length = gradient1.color_stops.len().max(gradient2.color_stops.len());
248        let mut color_stops = vec![];
249        for i in 0..length {
250            let color1 = if i < gradient1.color_stops.len() {
251                gradient1.color_stops[i].color
252            } else {
253                Color::default()
254            };
255            let color2 = if i < gradient2.color_stops.len() {
256                gradient2.color_stops[i].color
257            } else {
258                Color::default()
259            };
260            let color = Color::lerp(&color1, &color2, t);
261            let position = if i < gradient1.color_stops.len() {
262                lerp(gradient1.color_stops[i].position, gradient2.color_stops[i].position, t)
263            } else {
264                lerp(0.0, gradient2.color_stops[i].position, t)
265            };
266            color_stops.push(ColorStop { color, position });
267        }
268        LinearGradient {
269            p1,
270            p2,
271            color_stops: Rc::new(color_stops),
272        }
273    }
274}
275
276/// A radial gradient with two circles and color stops.
277#[wasm_bindgen]
278#[derive(Debug, Clone)]
279pub struct RadialGradient {
280    /// The start circle center point of the gradient.
281    pub f: Point2D,
282    /// The end circle center point of the gradient.
283    pub c: Point2D,
284    /// The radius of the gradient.
285    pub r: f32,
286    /// The color stops of the gradient.
287    color_stops: Rc<Vec<ColorStop>>,
288}
289
290impl Default for RadialGradient {
291    fn default() -> Self {
292        RadialGradient {
293            f: Point2D::default(),
294            c: Point2D::default(),
295            r: 0.0,
296            color_stops: Rc::new(vec![]),
297        }
298    }
299}
300
301#[wasm_bindgen]
302impl RadialGradient {
303    /// Creates a new RadialGradient with the given focal point, center point, radius, and ColorStops.
304    #[wasm_bindgen(constructor, return_description = "A new radial gradient.")]
305    pub fn new(
306        #[wasm_bindgen(param_description = "The start circle center point of the gradient.")]
307        f: Point2D,
308        #[wasm_bindgen(param_description = "The end circle center point of the gradient.")]
309        c: Point2D,
310        #[wasm_bindgen(param_description = "The radius of the gradient.")]
311        r: f32,
312        #[wasm_bindgen(param_description = "The color stops of the gradient.")]
313        color_stops: Vec<ColorStop>
314    ) -> RadialGradient {
315        RadialGradient {
316            f,
317            c,
318            r,
319            color_stops: Rc::new(color_stops),
320        }
321    }
322    /// Returns the default RadialGradient, which is a gradient from the focal point to the center with the same color.
323    #[wasm_bindgen(return_description = "The default radial gradient.")]
324    pub fn default_radial_gradient() -> RadialGradient {
325        RadialGradient::default()
326    }
327    /// Gets the ColorStops of the gradient.
328    #[wasm_bindgen(getter, return_description = "The color stops of the gradient.")]
329    pub fn color_stops(&self) -> Vec<ColorStop> {
330        self.color_stops.to_vec()
331    }
332    /// Sets the ColorStops of the gradient.
333    #[wasm_bindgen(setter)]
334    pub fn set_color_stops(
335        &mut self,
336        #[wasm_bindgen(param_description = "The color stops of the gradient.")]
337        color_stops: Vec<ColorStop>
338    ) {
339        self.color_stops = Rc::new(color_stops);
340    }
341    /// Gets the Color at a given offset along the gradient.
342    #[wasm_bindgen(return_description = "The color at the given offset.")]
343    pub fn color_at_offset(
344        &self,
345        #[wasm_bindgen(param_description = "The offset to get the color at.")]
346        position: f32
347    ) -> Color {
348        let mut stops = Rc::clone(&self.color_stops);
349        let stops = Rc::make_mut(&mut stops);
350        stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
351        for i in 0..stops.len() {
352            if position < stops[i].position {
353                if i == 0 {
354                    return stops[i].color;
355                }
356                let t = inverse_lerp(stops[i - 1].position, stops[i].position, position);
357                return Color::lerp(&stops[i - 1].color, &stops[i].color, t);
358            }
359        }
360        stops[stops.len() - 1].color
361    }
362    /// Gets the Color at a given point along the gradient.
363    #[wasm_bindgen(return_description = "The color at the given point.")]
364    pub fn color_at(
365        &self,
366        #[wasm_bindgen(param_description = "The point to get the color at.")]
367        p: Point2D
368    ) -> Color {
369        // We need first to solve this equation: dist(c, f + (p - f) * t) = r
370        // where dist is the distance between two points, c is the center point, f is the focal point, p is the point, and r is the radius.
371        // This simplifies to a quadratic equation At^2 + Bt + C = 0, where:
372        // A = (p.x - f.x)^2 + (p.y - f.y)^2
373        // B = 2 * (f.x - c.x) * (p.x - f.x) + 2 * (f.y - c.y) * (p.y - f.y)
374        // C = (f.x - c.x)^2 + (f.y - c.y)^2 - r^2
375        // The solutions are t = (-B ± sqrt(B^2 - 4AC)) / 2A and we choose the one with plus sign.
376        let a = (p.x - self.f.x).powi(2) + (p.y - self.f.y).powi(2);
377        let b = 2.0 * (self.f.x - self.c.x) * (p.x - self.f.x) + 2.0 * (self.f.y - self.c.y) * (p.y - self.f.y);
378        let c = (self.f.x - self.c.x).powi(2) + (self.f.y - self.c.y).powi(2) - self.r.powi(2);
379        // It may be possible that A = 0, in which case the distance from p to f is 0, then p is f, so the offset is 0.0
380        if a == 0.0 {
381            return self.color_at_offset(0.0);
382        }
383        let t = (-b + (b.powi(2) - 4.0 * a * c).sqrt()) / (2.0 * a);
384        // Then let's project the point onto the line segment from f to f + (p - f) * t
385        let projection = p.project_onto_line(&self.f, &(self.f + (p - self.f) * t));
386        self.color_at_offset(projection)
387    }
388    /// Returns a single color radial gradient.
389    #[wasm_bindgen(return_description = "A single color radial gradient.")]
390    pub fn single_color_gradient(
391        #[wasm_bindgen(param_description = "The start circle center point of the gradient.")]
392        f: Point2D,
393        #[wasm_bindgen(param_description = "The end circle center point of the gradient.")]
394        c: Point2D,
395        #[wasm_bindgen(param_description = "The radius of the gradient.")]
396        r: f32,
397        #[wasm_bindgen(param_description = "The color of the gradient.")]
398        color: Color,
399        #[wasm_bindgen(param_description = "Number of times to repeat the color.")]
400        repeats: Option<usize>
401    ) -> RadialGradient {
402        let repeats = repeats.unwrap_or(2);
403        let mut color_stops = vec![];
404        for i in 0..repeats {
405            color_stops.push(ColorStop { color, position: i as f32 / (repeats - 1) as f32 });
406        }
407        RadialGradient {
408            f,
409            c,
410            r,
411            color_stops: Rc::new(color_stops),
412        }
413    }
414    /// Linearly interpolates between two RadialGradients given a progress value.
415    #[wasm_bindgen(return_description = "The interpolated radial gradient.")]
416    pub fn lerp(
417        #[wasm_bindgen(param_description = "The first radial gradient.")]
418        gradient1: &RadialGradient,
419        #[wasm_bindgen(param_description = "The second radial gradient.")]
420        gradient2: &RadialGradient,
421        #[wasm_bindgen(param_description = "The progress value.")]
422        t: f32
423    ) -> RadialGradient {
424        let f = Point2D::lerp(&gradient1.f, &gradient2.f, t);
425        let c = Point2D::lerp(&gradient1.c, &gradient2.c, t);
426        let r = lerp(gradient1.r, gradient2.r, t);
427        let length = gradient1.color_stops.len().max(gradient2.color_stops.len());
428        let mut color_stops = vec![];
429        for i in 0..length {
430            let color1 = if i < gradient1.color_stops.len() {
431                gradient1.color_stops[i].color
432            } else {
433                Color::default()
434            };
435            let color2 = if i < gradient2.color_stops.len() {
436                gradient2.color_stops[i].color
437            } else {
438                Color::default()
439            };
440            let color = Color::lerp(&color1, &color2, t);
441            let position = if i < gradient1.color_stops.len() {
442                lerp(gradient1.color_stops[i].position, gradient2.color_stops[i].position, t)
443            } else {
444                lerp(0.0, gradient2.color_stops[i].position, t)
445            };
446            color_stops.push(ColorStop { color, position });
447        }
448        RadialGradient {
449            f,
450            c,
451            r,
452            color_stops: Rc::new(color_stops),
453        }
454    }
455}
456
457/// An image bitmap with pixel data.
458#[wasm_bindgen]
459#[derive(Debug, Clone)]
460pub struct ImageBitmap {
461    /// The x coordinate of the bitmap.
462    pub x: f32,
463    /// The y coordinate of the bitmap.
464    pub y: f32,
465    /// The width of the bitmap.
466    pub width: f32,
467    /// The height of the bitmap.
468    pub height: f32,
469    /// Number of pixels in a row of the bitmap.
470    pub data_width: usize,
471    /// Number of pixels in a column of the bitmap.
472    pub data_height: usize,
473    /// Rgba data of the bitmap.
474    rgba_image: ImageBuffer<image::Rgba<u8>, Vec<u8>>,
475}
476
477impl Default for ImageBitmap {
478    fn default() -> Self {
479        ImageBitmap {
480            x: 0.0,
481            y: 0.0,
482            width: 0.0,
483            height: 0.0,
484            data_width: 0,
485            data_height: 0,
486            rgba_image: RgbaImage::new(0, 0)
487        }
488    }
489}
490
491#[wasm_bindgen]
492impl ImageBitmap {
493    /// Creates a new ImageBitmap with the given x, y, width, height, and pixel data.
494    #[wasm_bindgen(constructor, return_description = "A new image bitmap.")]
495    pub fn new(
496        #[wasm_bindgen(param_description = "The x coordinate of the bitmap.")]
497        x: f32,
498        #[wasm_bindgen(param_description = "The y coordinate of the bitmap.")]
499        y: f32,
500        #[wasm_bindgen(param_description = "The width of the bitmap.")]
501        width: f32,
502        #[wasm_bindgen(param_description = "The height of the bitmap.")]
503        height: f32,
504        #[wasm_bindgen(param_description = "Number of pixels in a row of the bitmap.")]
505        data_width: usize,
506        #[wasm_bindgen(param_description = "Number of pixels in a column of the bitmap.")]
507        data_height: usize,
508        #[wasm_bindgen(param_description = "The pixel data of the bitmap.")]
509        data: Vec<u8>
510    ) -> Result<ImageBitmap, JsError> {
511        let rgba_image = guess_format(&data).and_then(|format| {
512            let img = load_from_memory_with_format(&data, format)?;
513            let img = img.to_rgba8();
514            Ok(img)
515        });
516        if rgba_image.is_err() {
517            log("Failed to create image bitmap.");
518            return Err(JsError::new("Failed to create image bitmap."));
519        }
520        let rgba_image = rgba_image.unwrap();
521        Ok(ImageBitmap {
522            x,
523            y,
524            width,
525            height,
526            data_width,
527            data_height,
528            rgba_image,
529        })
530    }
531    /// Gets the pixel data of the bitmap.
532    #[wasm_bindgen(getter, return_description = "The pixel data of the bitmap.")]
533    pub fn data(&self) -> Vec<u8> {
534        self.rgba_image.clone().into_raw()
535    }
536    /// Sets the pixel data of the bitmap.
537    #[wasm_bindgen]
538    pub fn set_data(
539        &mut self,
540        #[wasm_bindgen(param_description = "The number of pixels in a row of the bitmap.")]
541        data_width: f32,
542        #[wasm_bindgen(param_description = "The number of pixels in a column of the bitmap.")]
543        data_height: f32,
544        #[wasm_bindgen(param_description = "The pixel data of the bitmap.")]
545        data: Vec<u8>
546    ) -> Result<(), JsError> {
547        self.data_width = data_width as usize;
548        self.data_height = data_height as usize;
549        self.rgba_image = RgbaImage::from_raw(data_width as u32, data_height as u32, data).ok_or(JsError::new("Failed to set image bitmap data."))?;
550        Ok(())
551    }
552    /// Returns the default ImageBitmap, which is an empty bitmap.
553    #[wasm_bindgen(return_description = "The default image bitmap.")]
554    pub fn default_image_bitmap() -> ImageBitmap {
555        ImageBitmap::default()
556    }
557    /// Gets the color of a Point2D in the bitmap.
558    #[wasm_bindgen(return_description = "The color of the pixel.")]
559    pub fn get_pixel(
560        &self,
561        #[wasm_bindgen(param_description = "The point to get the pixel color at.")]
562        p: Point2D
563    ) -> Color {
564        let x = ((p.x - self.x) % self.width / self.width * self.data_width as f32) as u32;
565        let y = ((p.y - self.y) % self.height / self.height * self.data_height as f32) as u32;
566        let pixel = self.rgba_image.get_pixel(x, y);
567        Color::new(pixel[0], pixel[1], pixel[2], pixel[3] as f32 / 255.0)
568    }
569    /// Sets a pixel color at a Point2D in the bitmap.
570    pub fn set_pixel(
571        &mut self,
572        #[wasm_bindgen(param_description = "The point to set the pixel color at.")]
573        p: Point2D,
574        #[wasm_bindgen(param_description = "The color of the pixel.")]
575        color: &Color
576    ) {
577        let x = ((p.x - self.x) % self.width / self.width * self.data_width as f32) as u32;
578        let y = ((p.y - self.y) % self.height / self.height * self.data_height as f32) as u32;
579        self.rgba_image.put_pixel(x, y, image::Rgba([color.red, color.green, color.blue, (color.alpha * 255.0) as u8]));
580    }
581    /// Gets a bitmap that is filled with a color.
582    #[wasm_bindgen(return_description = "The filled image bitmap.")]
583    pub fn fill(
584        #[wasm_bindgen(param_description = "The x coordinate of the bitmap.")]
585        x: f32,
586        #[wasm_bindgen(param_description = "The y coordinate of the bitmap.")]
587        y: f32,
588        #[wasm_bindgen(param_description = "The width of the bitmap.")]
589        width: f32,
590        #[wasm_bindgen(param_description = "The height of the bitmap.")]
591        height: f32,
592        #[wasm_bindgen(param_description = "Number of pixels in a row of the bitmap.")]
593        data_width: usize,
594        #[wasm_bindgen(param_description = "Number of pixels in a column of the bitmap.")]
595        data_height: usize,
596        #[wasm_bindgen(param_description = "The color to fill the bitmap with.")]
597        color: &Color
598    ) -> ImageBitmap {
599        let rgba_image = RgbaImage::from_pixel(data_width as u32, data_height as u32, image::Rgba([color.red, color.green, color.blue, (color.alpha * 255.0) as u8]));
600        ImageBitmap {
601            x,
602            y,
603            width,
604            height,
605            data_width,
606            data_height,
607            rgba_image: rgba_image.clone(),
608        }
609    }
610    /// Gets a bitmap that is filled with a linear gradient.
611    #[wasm_bindgen(return_description = "The filled image bitmap.")]
612    pub fn fill_linear_gradient(
613        #[wasm_bindgen(param_description = "The x coordinate of the bitmap.")]
614        x: f32,
615        #[wasm_bindgen(param_description = "The y coordinate of the bitmap.")]
616        y: f32,
617        #[wasm_bindgen(param_description = "The width of the bitmap.")]
618        width: f32,
619        #[wasm_bindgen(param_description = "The height of the bitmap.")]
620        height: f32,
621        #[wasm_bindgen(param_description = "Number of pixels in a row of the bitmap.")]
622        data_width: usize,
623        #[wasm_bindgen(param_description = "Number of pixels in a column of the bitmap.")]
624        data_height: usize,
625        #[wasm_bindgen(param_description = "The linear gradient to fill the bitmap with.")]
626        gradient: &LinearGradient,
627    ) -> ImageBitmap {
628        let rgba_image = RgbaImage::from_fn(data_width as u32, data_height as u32, |x_raw, y_raw| {
629            let p = Point2D::new(x_raw as f32 / data_width as f32 * width + x, y_raw as f32 / data_height as f32 * height + y);
630            let color = gradient.color_at(p);
631            image::Rgba([color.red, color.green, color.blue, (color.alpha * 255.0) as u8])
632        });
633        ImageBitmap {
634            x,
635            y,
636            width,
637            height,
638            data_width,
639            data_height,
640            rgba_image: rgba_image.clone(),
641        }
642    }
643    /// Gets a bitmap that is filled with a radial gradient.
644    #[wasm_bindgen(return_description = "The filled image bitmap.")]
645    pub fn fill_radial_gradient(
646        #[wasm_bindgen(param_description = "The x coordinate of the bitmap.")]
647        x: f32,
648        #[wasm_bindgen(param_description = "The y coordinate of the bitmap.")]
649        y: f32,
650        #[wasm_bindgen(param_description = "The width of the bitmap.")]
651        width: f32,
652        #[wasm_bindgen(param_description = "The height of the bitmap.")]
653        height: f32,
654        #[wasm_bindgen(param_description = "Number of pixels in a row of the bitmap.")]
655        data_width: usize,
656        #[wasm_bindgen(param_description = "Number of pixels in a column of the bitmap.")]
657        data_height: usize,
658        #[wasm_bindgen(param_description = "The radial gradient to fill the bitmap with.")]
659        gradient: &RadialGradient,
660    ) -> ImageBitmap {
661        let rgba_image = RgbaImage::from_fn(data_width as u32, data_height as u32, |x_raw, y_raw| {
662            let p = Point2D::new(x_raw as f32 / data_width as f32 * width + x, y_raw as f32 / data_height as f32 * height + y);
663            let color = gradient.color_at(p);
664            image::Rgba([color.red, color.green, color.blue, (color.alpha * 255.0) as u8])
665        });
666        ImageBitmap {
667            x,
668            y,
669            width,
670            height,
671            data_width,
672            data_height,
673            rgba_image: rgba_image.clone(),
674        }
675    }
676    /// Gets the data as base64 encoded string.
677    #[wasm_bindgen(getter, return_description = "The base64 encoded string of the image bitmap.")]
678    pub fn base64(&self) -> Result<String, String> {
679        let mut png_data = vec![];
680        let encoder = PngEncoder::new(&mut png_data);
681        self.rgba_image.write_with_encoder(encoder).map_err(|e| e.to_string())?;
682        let base64 = BASE64_STANDARD.encode(&png_data);
683        Ok(base64)
684    }
685    /// Linearly interpolates between two ImageBitmaps given a progress value.
686    #[wasm_bindgen(return_description = "The interpolated image bitmap.")]
687    pub fn lerp(
688        #[wasm_bindgen(param_description = "The first image bitmap.")]
689        bitmap1: &ImageBitmap,
690        #[wasm_bindgen(param_description = "The second image bitmap.")]
691        bitmap2: &ImageBitmap,
692        #[wasm_bindgen(param_description = "The progress value.")]
693        t: f32,
694    ) -> ImageBitmap {
695        let x = bitmap1.x.min(bitmap2.x);
696        let y = bitmap1.y.min(bitmap2.y);
697        let width = bitmap1.width.max(bitmap2.width);
698        let height = bitmap1.height.max(bitmap2.height);
699        let data_width = bitmap1.data_width.max(bitmap2.data_width);
700        let data_height = bitmap1.data_height.max(bitmap2.data_height);
701        let new_image = RgbaImage::from_fn(data_width as u32, data_height as u32, |x_raw, y_raw| {
702            let p = Point2D::new(x_raw as f32 / data_width as f32 * width + x, y_raw as f32 / data_height as f32 * height + y);
703            let color1 = bitmap1.get_pixel(p);
704            let color2 = bitmap2.get_pixel(p);
705            let color = Color::lerp(&color1, &color2, t);
706            image::Rgba([color.red, color.green, color.blue, (color.alpha * 255.0) as u8])
707        });
708        ImageBitmap {
709            x,
710            y,
711            width,
712            height,
713            data_width,
714            data_height,
715            rgba_image: new_image.clone(),
716        }
717    }
718}
719
720/// A style with a color, linear gradient, radial gradient, or image.
721#[wasm_bindgen]
722#[derive(Debug, Clone)]
723pub struct Style {
724    /// The color of the style.
725    color: Option<Color>,
726    /// The linear gradient of the style.
727    linear_gradient: Option<LinearGradient>,
728    /// The radial gradient of the style.
729    radial_gradient: Option<RadialGradient>,
730    /// The image of the style.
731    image: Option<ImageBitmap>,
732}
733
734impl Default for Style {
735    fn default() -> Self {
736        Style {
737            color: Color::default().into(),
738            linear_gradient: None,
739            radial_gradient: None,
740            image: None,
741        }
742    }
743}
744
745#[wasm_bindgen]
746impl Style {
747    /// Creates a new Style with the given color, linear gradient, radial gradient, or image. It must have exactly one of these.
748    #[wasm_bindgen(constructor, return_description = "A new style.")]
749    pub fn new(
750        #[wasm_bindgen(param_description = "The color of the style, if provided.")]
751        color: Option<Color>,
752        #[wasm_bindgen(param_description = "The linear gradient of the style, if provided.")]
753        linear_gradient: Option<LinearGradient>,
754        #[wasm_bindgen(param_description = "The radial gradient of the style, if provided.")]
755        radial_gradient: Option<RadialGradient>,
756        #[wasm_bindgen(param_description = "The image of the style, if provided.")]
757        image: Option<ImageBitmap>
758    ) -> Result<Style, JsError> {
759        let mut not_none = 0;
760        if color.is_some() {
761            not_none += 1;
762        }
763        if linear_gradient.is_some() {
764            not_none += 1;
765        }
766        if radial_gradient.is_some() {
767            not_none += 1;
768        }
769        if image.is_some() {
770            not_none += 1;
771        }
772        if not_none != 1 {
773            let err = JsError::new("Exactly one of color, linear_gradient, radial_gradient, or image must be provided.");
774            return Err(err);
775        }
776        Ok(Style {
777            color,
778            linear_gradient,
779            radial_gradient,
780            image,
781        })
782    }
783    /// Clones the Style.
784    #[wasm_bindgen(js_name = clone, return_description = "The cloned style.")]
785    pub fn clone_js(&self) -> Style {
786        self.clone()
787    }
788    /// Creates a new Style with the given color.
789    #[wasm_bindgen(return_description = "A new style from the color.")]
790    pub fn from_color(
791        #[wasm_bindgen(param_description = "The color of the style.")]
792        color: Color
793    ) -> Style {
794        Style::new(Some(color), None, None, None).unwrap()
795    }
796    /// Creates a new Style with the given linear gradient.
797    #[wasm_bindgen(return_description = "A new style from the linear gradient.")]
798    pub fn from_linear_gradient(
799        #[wasm_bindgen(param_description = "The linear gradient of the style.")]
800        gradient: LinearGradient
801    ) -> Style {
802        Style::new(None, Some(gradient), None, None).unwrap()
803    }
804    /// Creates a new Style with the given radial gradient.
805    #[wasm_bindgen(return_description = "A new style from the radial gradient.")]
806    pub fn from_radial_gradient(gradient: RadialGradient) -> Style {
807        Style::new(None, None, Some(gradient), None).unwrap()
808    }
809    /// Creates a new Style with the given image.
810    #[wasm_bindgen(return_description = "A new style from the image.")]
811    pub fn from_image(
812        #[wasm_bindgen(param_description = "The image of the style.")]
813        image: ImageBitmap
814    ) -> Style {
815        Style::new(None, None, None, Some(image)).unwrap()
816    }
817    /// Returns the default Style, which is a color with the default color.
818    #[wasm_bindgen(return_description = "The default style.")]
819    pub fn default_style() -> Style {
820        Style::default()
821    }
822    /// Fades the Style by a given amount.
823    #[wasm_bindgen(return_description = "The faded style.")]
824    pub fn fade(
825        &self,
826        #[wasm_bindgen(param_description = "The amount to fade the style by.")]
827        amount: f32
828    ) -> Style {
829        let mut color = self.color.clone();
830        let mut linear_gradient = self.linear_gradient.clone();
831        let mut radial_gradient = self.radial_gradient.clone();
832        let mut image = self.image.clone();
833        if let Some(color) = &mut color {
834            color.alpha = color.alpha * (1.0 - amount);
835        }
836        if let Some(linear_gradient) = &mut linear_gradient {
837            for stop in Rc::make_mut(&mut linear_gradient.color_stops) {
838                stop.color.alpha = stop.color.alpha * (1.0 - amount);
839            }
840        }
841        if let Some(radial_gradient) = &mut radial_gradient {
842            for stop in Rc::make_mut(&mut radial_gradient.color_stops) {
843                stop.color.alpha = stop.color.alpha * (1.0 - amount);
844            }
845        }
846        if let Some(image) = &mut image {
847            for pixel in image.rgba_image.pixels_mut() {
848                pixel[3] = (pixel[3] as f32 * (1.0 - amount)) as u8;
849            }
850        }
851        Style {
852            color,
853            linear_gradient,
854            radial_gradient,
855            image,
856        }
857    }
858    /// Gets the Color of the style, if it's a color.
859    #[wasm_bindgen(getter, return_description = "The color of the style.")]
860    pub fn color(&self) -> Option<Color> {
861        self.color.clone()
862    }
863    /// Sets the style to a Color.
864    #[wasm_bindgen(setter)]
865    pub fn set_color(
866        &mut self,
867        #[wasm_bindgen(param_description = "The color of the style.")]
868        color: Color
869    ) {
870        self.color = Some(color);
871        self.linear_gradient = None;
872        self.radial_gradient = None;
873        self.image = None;
874    }
875    /// Gets the LinearGradient of the style, if it's a linear gradient.
876    #[wasm_bindgen(getter, return_description = "The linear gradient of the style.")]
877    pub fn linear_gradient(&self) -> Option<LinearGradient> {
878        self.linear_gradient.clone()
879    }
880    /// Sets the style to a LinearGradient.
881    #[wasm_bindgen(setter)]
882    pub fn set_linear_gradient(
883        &mut self,
884        #[wasm_bindgen(param_description = "The linear gradient of the style.")]
885        linear_gradient: LinearGradient
886    ) {
887        self.color = None;
888        self.linear_gradient = Some(linear_gradient);
889        self.radial_gradient = None;
890        self.image = None;
891    }
892    /// Gets the RadialGradient of the style, if it's a radial gradient.
893    #[wasm_bindgen(getter, return_description = "The radial gradient of the style.")]
894    pub fn radial_gradient(&self) -> Option<RadialGradient> {
895        self.radial_gradient.clone()
896    }
897    /// Sets the style to a RadialGradient.
898    #[wasm_bindgen(setter)]
899    pub fn set_radial_gradient(
900        &mut self,
901        #[wasm_bindgen(param_description = "The radial gradient of the style.")]
902        radial_gradient: RadialGradient
903    ) {
904        self.color = None;
905        self.linear_gradient = None;
906        self.radial_gradient = Some(radial_gradient);
907        self.image = None;
908    }
909    /// Gets the ImageBitmap of the style, if it's an image.
910    #[wasm_bindgen(getter, return_description = "The image of the style.")]
911    pub fn image(&self) -> Option<ImageBitmap> {
912        self.image.clone()
913    }
914    /// Sets the style to an ImageBitmap.
915    #[wasm_bindgen(setter)]
916    pub fn set_image(&mut self, image: ImageBitmap) {
917        self.color = None;
918        self.linear_gradient = None;
919        self.radial_gradient = None;
920        self.image = Some(image);
921    }
922    /// Gets the Color at a given point.
923    #[wasm_bindgen(return_description = "The color at the given point.")]
924    pub fn color_at(
925        &self,
926        #[wasm_bindgen(param_description = "The x coordinate of the point.")]
927        p: Point2D
928    ) -> Color {
929        if let Some(color) = self.color() {
930            return color;
931        }
932        if let Some(linear_gradient) = self.linear_gradient() {
933            return linear_gradient.color_at(p);
934        }
935        if let Some(radial_gradient) = self.radial_gradient() {
936            return radial_gradient.color_at(p);
937        }
938        if let Some(image) = self.image() {
939            return image.get_pixel(p);
940        }
941        Color::default()
942    }
943    /// Linearly interpolates between two Styles given a progress value.
944    #[wasm_bindgen(return_description = "The interpolated style.")]
945    pub fn lerp(
946        #[wasm_bindgen(param_description = "The first style.")]
947        style1: &Style,
948        #[wasm_bindgen(param_description = "The second style.")]
949        style2: &Style,
950        #[wasm_bindgen(param_description = "The progress value.")]
951        t: f32,
952        #[wasm_bindgen(param_description = "Top left x coordinate of the bitmap. Must be provided if both styles are images.")]
953        x: Option<f32>,
954        #[wasm_bindgen(param_description = "Top left y coordinate of the bitmap. Must be provided if both styles are images.")]
955        y: Option<f32>,
956        #[wasm_bindgen(param_description = "Width of the bitmap. Must be provided if both styles are images.")]
957        width: Option<f32>,
958        #[wasm_bindgen(param_description = "Height of the bitmap. Must be provided if both styles are images.")]
959        height: Option<f32>,
960        #[wasm_bindgen(param_description = "Number of pixels in a row of the bitmap. Must be provided if both styles are different kinds of gradients or one of them is an image.")]
961        data_width: Option<usize>,
962        #[wasm_bindgen(param_description = "Number of pixels in a column of the bitmap. Must be provided if both styles are different kinds of gradients or one of them is an image.")]
963        data_height: Option<usize>
964    ) -> Result<Style, String> {
965        let color1 = style1.color();
966        let color2 = style2.color();
967        let linear_gradient1 = style1.linear_gradient();
968        let linear_gradient2 = style2.linear_gradient();
969        let radial_gradient1 = style1.radial_gradient();
970        let radial_gradient2 = style2.radial_gradient();
971        let image1 = style1.image();
972        let image2 = style2.image();
973        if color1.is_some() && color2.is_some() {
974            let color = Color::lerp(&color1.unwrap(), &color2.unwrap(), t);
975            return Ok(Style::from_color(color));
976        }
977        if linear_gradient1.is_some() && linear_gradient2.is_some() {
978            let linear_gradient = LinearGradient::lerp(&linear_gradient1.unwrap(), &linear_gradient2.unwrap(), t);
979            return Ok(Style::from_linear_gradient(linear_gradient));
980        }
981        if radial_gradient1.is_some() && radial_gradient2.is_some() {
982            let radial_gradient = RadialGradient::lerp(&radial_gradient1.unwrap(), &radial_gradient2.unwrap(), t);
983            return Ok(Style::from_radial_gradient(radial_gradient));
984        }
985        if image1.is_some() && image2.is_some() {
986            let image = ImageBitmap::lerp(&image1.unwrap(), &image2.unwrap(), t);
987            return Ok(Style::from_image(image));
988        }
989        if color1.is_some() {
990            let color = color1.unwrap();
991            if linear_gradient2.is_some() {
992                let linear_gradient2 = linear_gradient2.unwrap();
993                let linear_gradient1 = LinearGradient::single_color_gradient(linear_gradient2.p1, linear_gradient2.p2, color, Some(linear_gradient2.color_stops.len()));
994                return Style::lerp(&Style::from_linear_gradient(linear_gradient1), &Style::from_linear_gradient(linear_gradient2), t, x, y, width, height, data_width, data_height);
995            }
996            if radial_gradient2.is_some() {
997                let radial_gradient2 = radial_gradient2.unwrap();
998                let radial_gradient1 = RadialGradient::single_color_gradient(radial_gradient2.f, radial_gradient2.c, radial_gradient2.r, color, Some(radial_gradient2.color_stops.len()));
999                return Style::lerp(&Style::from_radial_gradient(radial_gradient1), &Style::from_radial_gradient(radial_gradient2), t, x, y, width, height, data_width, data_height);
1000            }
1001            if image2.is_some() {
1002                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1003                    return Err("Bitmap data must be provided if one of the styles is an image.".to_string());
1004                }
1005                let image2 = image2.unwrap();
1006                let image1 = ImageBitmap::fill(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &color);
1007                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1008            }
1009        }
1010        if linear_gradient1.is_some() {
1011            let linear_gradient1 = linear_gradient1.unwrap();
1012            if color2.is_some() {
1013                let color2 = color2.unwrap();
1014                let linear_gradient2 = LinearGradient::single_color_gradient(linear_gradient1.p1, linear_gradient1.p2, color2, Some(linear_gradient1.color_stops.len()));
1015                return Style::lerp(&Style::from_linear_gradient(linear_gradient1), &Style::from_linear_gradient(linear_gradient2), t, x, y, width, height, data_width, data_height);
1016            }
1017            if radial_gradient2.is_some() {
1018                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1019                    return Err("Bitmap data must be provided if both styles are different kinds of gradients.".to_string());
1020                }
1021                let radial_gradient2 = radial_gradient2.unwrap();
1022                let image2 = ImageBitmap::fill_radial_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &radial_gradient2);
1023                let image1 = ImageBitmap::fill_linear_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &linear_gradient1);
1024                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1025            }
1026            if image2.is_some() {
1027                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1028                    return Err("Bitmap data must be provided if both styles are different kinds of gradients.".to_string());
1029                }
1030                let image2 = image2.unwrap();
1031                let image1 = ImageBitmap::fill_linear_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &linear_gradient1);
1032                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1033            }
1034        }
1035        if radial_gradient1.is_some() {
1036            let radial_gradient1 = radial_gradient1.unwrap();
1037            if color2.is_some() {
1038                let color2 = color2.unwrap();
1039                let radial_gradient2 = RadialGradient::single_color_gradient(radial_gradient1.f, radial_gradient1.c, radial_gradient1.r, color2, Some(radial_gradient1.color_stops.len()));
1040                return Style::lerp(&Style::from_radial_gradient(radial_gradient1), &Style::from_radial_gradient(radial_gradient2), t, x, y, width, height, data_width, data_height);
1041            }
1042            if linear_gradient2.is_some() {
1043                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1044                    return Err("Bitmap data must be provided if both styles are different kinds of gradients.".to_string());
1045                }
1046                let linear_gradient2 = linear_gradient2.unwrap();
1047                let image2 = ImageBitmap::fill_linear_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &linear_gradient2);
1048                let image1 = ImageBitmap::fill_radial_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &radial_gradient1);
1049                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1050            }
1051            if image2.is_some() {
1052                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1053                    return Err("Bitmap data must be provided if both styles are different kinds of gradients.".to_string());
1054                }
1055                let image2 = image2.unwrap();
1056                let image1 = ImageBitmap::fill_radial_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &radial_gradient1);
1057                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1058            }
1059        }
1060        if image1.is_some() {
1061            let image1 = image1.unwrap();
1062            if color2.is_some() {
1063                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1064                    return Err("Bitmap data must be provided if one of the styles is an image.".to_string());
1065                }
1066                let color2 = color2.unwrap();
1067                let image2 = ImageBitmap::fill(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &color2);
1068                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1069            }
1070            if linear_gradient2.is_some() {
1071                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1072                    return Err("Bitmap data must be provided if one of the styles is an image.".to_string());
1073                }
1074                let linear_gradient2 = linear_gradient2.unwrap();
1075                let image2 = ImageBitmap::fill_linear_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &linear_gradient2);
1076                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1077            }
1078            if radial_gradient2.is_some() {
1079                if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
1080                    return Err("Bitmap data must be provided if one of the styles is an image.".to_string());
1081                }
1082                let radial_gradient2 = radial_gradient2.unwrap();
1083                let image2 = ImageBitmap::fill_radial_gradient(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap(), data_width.unwrap(), data_height.unwrap(), &radial_gradient2);
1084                return Style::lerp(&Style::from_image(image1), &Style::from_image(image2), t, x, y, width, height, data_width, data_height);
1085            }
1086        }
1087        Err("Exactly one of color, linear_gradient, radial_gradient, or image must be provided.".to_string())
1088    }
1089}
1090
1091impl Style {
1092    /// Creates a style given a Paint and a Opacity.
1093    pub fn from_paint_and_opacity(
1094        paint: &Paint,
1095        opacity: &Opacity,
1096    ) -> Style {
1097        match &paint {
1098            Paint::Color(color) => {
1099                let color = Color::new(color.red, color.green, color.blue, opacity.get());
1100                Style::from_color(color)
1101            }
1102            Paint::LinearGradient(gradient) => {
1103                let start = Point2D::new(gradient.x1(), gradient.y1());
1104                let end = Point2D::new(gradient.x2(), gradient.y2());
1105                let linear_gradient = LinearGradient::new(start, end, gradient.stops().iter().map(|stop| {
1106                    ColorStop {
1107                        color: Color::new(stop.color().red, stop.color().green, stop.color().blue, stop.opacity().get() * opacity.get()),
1108                        position: stop.offset().get(),
1109                    }
1110                }).collect());
1111                Style::from_linear_gradient(linear_gradient)
1112            }
1113            Paint::RadialGradient(gradient) => {
1114                let start = Point2D::new(gradient.fx(), gradient.fy());
1115                let end = Point2D::new(gradient.cx(), gradient.cy());
1116                let radial_gradient = RadialGradient::new(start, end, gradient.r().get(), gradient.stops().iter().map(|stop| {
1117                    ColorStop {
1118                        color: Color::new(stop.color().red, stop.color().green, stop.color().blue, stop.opacity().get() * opacity.get()),
1119                        position: stop.offset().get(),
1120                    }
1121                }).collect());
1122                Style::from_radial_gradient(radial_gradient)
1123            }
1124            Paint::Pattern(pattern) => {
1125                let root = pattern.root();
1126                let bounding_box = pattern.rect();
1127                let x = bounding_box.x();
1128                let y = bounding_box.y();
1129                let width = bounding_box.width();
1130                let height = bounding_box.height();
1131                for child in root.children() {
1132                    return Style::from_pattern_child(&child, x, y, width, height);
1133                }
1134                log("Unsupported pattern. Fallback to default style (fully transparent black).");
1135                Style::default()
1136            }
1137        }
1138    }
1139    pub fn from_pattern_child(
1140        child: &usvg::Node,
1141        x: f32,
1142        y: f32,
1143        width: f32,
1144        height: f32,
1145    ) -> Style {
1146        match &child {
1147            usvg::Node::Image(image) => {
1148                let kind = image.kind();
1149                let size = image.size();
1150                let data_width = size.width().round() as usize;
1151                let data_height = size.height().round() as usize;
1152                match &kind {
1153                    usvg::ImageKind::JPEG(data) => {
1154                        let new_data = data.to_vec();
1155                        let image = ImageBitmap::new(x, y, width, height, data_width, data_height, new_data);
1156                        if image.is_err() {
1157                            log("Failed to create image bitmap.");
1158                            return Style::default();
1159                        }
1160                        return Style::from_image(image.unwrap());
1161                    }
1162                    usvg::ImageKind::PNG(data) => {
1163                        let new_data = data.to_vec();
1164                        let image = ImageBitmap::new(x, y, width, height, data_width, data_height, new_data);
1165                        if image.is_err() {
1166                            log("Failed to create image bitmap.");
1167                            return Style::default();
1168                        }
1169                        return Style::from_image(image.unwrap());
1170                    }
1171                    usvg::ImageKind::WEBP(data) => {
1172                        let new_data = data.to_vec();
1173                        let image = ImageBitmap::new(x, y, width, height, data_width, data_height, new_data);
1174                        if image.is_err() {
1175                            log("Failed to create image bitmap.");
1176                            return Style::default();
1177                        }
1178                        return Style::from_image(image.unwrap());
1179                    }
1180                    _ => {
1181                        log("Unsupported image format. Fallback to default style (fully transparent black).");
1182                        return Style::default();
1183                    }
1184                }
1185            }
1186            usvg::Node::Group(group) => {
1187                for child in group.children() {
1188                    return Style::from_pattern_child(&child, x, y, width, height);
1189                }
1190                log("Unsupported pattern. Fallback to default style (fully transparent black).");
1191                return Style::default();
1192            }
1193            _ => {
1194                log("Unsupported pattern. Fallback to default style (fully transparent black).");
1195                return Style::default();
1196            }
1197        }
1198    }
1199}