img-gen-renderer 0.1.0

A library to render images from img-gen-spec
Documentation
use super::{ConcreteSize, Renderer};
use crate::{ImgGenRendererError, Layer, Result};
use image::RgbaImage;
use img_gen_spec::PolygonSides;
use resvg::tiny_skia::PathBuilder;

impl Renderer<'_> {
    pub fn render_polygon(
        &self,
        layer: &Layer,
        size: ConcreteSize,
        canvas: &mut RgbaImage,
    ) -> Result<()> {
        if let Some(l) = layer.polygon.as_ref() {
            let border_width = l.border.as_ref().map_or(0, |b| b.width.get());

            let path = {
                let mut pb = PathBuilder::new();
                match &l.sides {
                    PolygonSides::Regular(sides) => {
                        let sides = sides.get();
                        let radius = size.width.min(size.height) as f32 / 2.0 - border_width as f32;
                        for i in 0..sides {
                            let angle =
                                ((360.0 / sides as f32 * i as f32) - l.rotation).to_radians();
                            let x = angle.cos() * radius + (size.width as f32 / 2.0);
                            let y = angle.sin() * radius + (size.height as f32 / 2.0);
                            if i == 0 {
                                pb.move_to(x, y);
                            } else {
                                pb.line_to(x, y);
                            }
                        }
                    }
                    PolygonSides::Irregular(offsets) => {
                        let x_min = if border_width > 0 {
                            border_width as i32
                        } else {
                            0
                        };
                        let y_min = if border_width > 0 {
                            border_width as i32
                        } else {
                            0
                        };
                        let x_max = if border_width > 0 {
                            size.width.saturating_sub(border_width) as i32
                        } else {
                            size.width as i32
                        };
                        let y_max = if border_width > 0 {
                            size.height.saturating_sub(border_width) as i32
                        } else {
                            size.height as i32
                        };

                        for (i, offset) in offsets.as_slice().iter().enumerate() {
                            let x = offset.x.clamp(x_min, x_max) as f32;
                            let y = offset.y.clamp(y_min, y_max) as f32;
                            if i == 0 {
                                pb.move_to(x, y);
                            } else {
                                pb.line_to(x, y);
                            }
                        }
                    }
                }
                pb.close();
                pb.finish()
                    .ok_or(ImgGenRendererError::InvalidPathBounds { shape: "polygon" })?
            };
            Self::render_shape(path, &l.color, size, &layer.offset, &l.border, canvas)?
        }
        Ok(())
    }
}