diff --git a/Cargo.toml b/Cargo.toml index ffcbf75..ab01092 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rasterize" -version = "0.3.7" +version = "0.3.8" authors = ["Pavel Aslanov "] description = "Simple and small 2D rendering library" edition = "2021" diff --git a/examples/rasterize.rs b/examples/rasterize.rs index e420a78..7c1ef1a 100644 --- a/examples/rasterize.rs +++ b/examples/rasterize.rs @@ -31,6 +31,7 @@ struct Args { tr: Transform, fg: Option, bg: Option, + bbox: Option, } impl Args { @@ -54,6 +55,7 @@ impl Args { tr: Transform::identity(), fg: None, bg: None, + bbox: None, }; let mut positional = 0; let mut args = env::args(); @@ -68,6 +70,10 @@ impl Args { let width = args.next().ok_or("-w requires argument")?; result.width = Some(width.parse()?); } + "-b" => { + let bbox = args.next().ok_or("-b requires argument")?; + result.bbox = Some(bbox.parse()?); + } "-t" => { result.tr = args.next().ok_or("-t requires argument")?.parse()?; } @@ -118,11 +124,12 @@ impl Args { ); eprintln!("\nUSAGE:"); eprintln!( - " {} [-w ] [-s ] [-f ] [-o] [-a] [-fg ] [-bg ] ", + " {} [-w ] [-b ] [-s ] [-f ] [-o] [-a] [-fg ] [-bg ] ", cmd ); eprintln!("\nARGS:"); eprintln!(" -w width in pixels of the output image"); + eprintln!(" -b custom bounding box"); eprintln!(" -t apply transform"); eprintln!(" -s stroke path before rendering"); eprintln!(" -o show outline with control points instead of filling"); @@ -246,7 +253,10 @@ fn main() -> Result<(), Error> { // transform if needed let tr = match args.width { Some(width) if width > 2 => { - let src_bbox = path.bbox(args.tr).ok_or("path is empty")?; + let src_bbox = match args.bbox { + Some(bbox) => bbox.transform(args.tr), + None => path.bbox(args.tr).ok_or("path is empty")?, + }; let width = width as Scalar; let height = src_bbox.height() * width / src_bbox.width(); let dst_bbox = BBox::new(Point::new(1.0, 1.0), Point::new(width - 1.0, height - 1.0)); @@ -274,9 +284,12 @@ fn main() -> Result<(), Error> { let scene = Scene::group(group); // add background or checkerboard - let bbox = scene - .bbox(Transform::identity()) - .ok_or("nothing to render")?; + let bbox = match args.bbox { + Some(bbox) => bbox.transform(tr), + None => scene + .bbox(Transform::identity()) + .ok_or("nothing to render")?, + }; let bbox = BBox::new((bbox.x().round(), bbox.y().round()), bbox.max()); let (scene, bg) = match args.bg { None => { diff --git a/src/geometry.rs b/src/geometry.rs index 2da971c..951b348 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -594,6 +594,15 @@ impl BBox { pub fn unit_transform(&self) -> Transform { Transform::new_translate(self.x(), self.y()).pre_scale(self.width(), self.height()) } + + /// Compute new bounding box such that it will include original bounding box after transformation + pub fn transform(&self, tr: Transform) -> BBox { + let p00 = tr.apply(self.min); + let p01 = tr.apply(Point::new(self.min.x(), self.max.y())); + let p10 = tr.apply(Point::new(self.max.x(), self.min.y())); + let p11 = tr.apply(self.max); + BBox::new(p00, p11).extend(p10).extend(p01) + } } /// Find intersection of two ranges diff --git a/src/path.rs b/src/path.rs index 5762482..d921458 100644 --- a/src/path.rs +++ b/src/path.rs @@ -117,7 +117,7 @@ impl Default for LineCap { } /// Style used to generate stroke -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StrokeStyle { /// Width of the stroke diff --git a/src/svg.rs b/src/svg.rs index f0eb35f..157e2df 100644 --- a/src/svg.rs +++ b/src/svg.rs @@ -293,7 +293,7 @@ impl SvgPathParser { self.parser.unparse_byte(byte); match self.prev_op { Some(op) => Ok(Some(op)), - None => Err(SvgParserError::InvalidCmd(op)), + None => Err(SvgParserError::InvalidCmd(op.into())), } } } @@ -561,7 +561,7 @@ impl FromStr for Transform { #[derive(Debug)] pub enum SvgParserError { /// Failed to parse SVG command - InvalidCmd(u8), + InvalidCmd(char), /// Failed to parse scalar value InvalidScalar, /// Failed to parse flag value