赞
踩
前言
本文是使用rust库resvg来将svg图片转为png图片。
环境配置
系统:windows
平台:visual studio code
语言:rust
库:resvg
resvg是一个基于rust的svg渲染库,其官方地址:
An SVG rendering library
resvg库的核心是svg的渲染,但本文暂且不关注如何渲染svg,本文关注如何将svg转为png格式,官方有提供演示代码。
本文参考官方示例,将代码稍作修改,并结合rust的文件库rfd,编写一个简单的程序,可以导入svg图片,然后转为png图片,并保存。
首先看一下核心的转换代码:
官方代码:
fn main() { let args: Vec<String> = std::env::args().collect(); if args.len() != 3 { println!("Usage:\n\tminimal <in-svg> <out-png>"); return; } let tree = { let mut opt = usvg::Options::default(); // Get file's absolute directory. opt.resources_dir = std::fs::canonicalize(&args[1]) .ok() .and_then(|p| p.parent().map(|p| p.to_path_buf())); opt.fontdb_mut().load_system_fonts(); let svg_data = std::fs::read(&args[1]).unwrap(); usvg::Tree::from_data(&svg_data, &opt).unwrap() }; let pixmap_size = tree.size().to_int_size(); let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap(); resvg::render(&tree, tiny_skia::Transform::default(), &mut pixmap.as_mut()); pixmap.save_png(&args[2]).unwrap(); }
本地使用时,简单封装成一个函数,如下:
/// /// svg转png /// pub fn svgtopng( svgpath: &str, destimgpath: &str, ) { let mut opt=resvg::usvg::Options::default(); opt.resources_dir=std::fs::canonicalize(svgpath) .ok() .and_then(|p| p.parent().map(|p| p.to_path_buf())); opt.fontdb_mut().load_system_fonts(); let svgdata=std::fs::read(svgpath).unwrap(); let tree=resvg::usvg::Tree::from_data(&svgdata,&opt).unwrap(); let pixmap_size = tree.size().to_int_size(); let mut pixmap = resvg::tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap(); resvg::render(&tree, resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut()); pixmap.save_png(destimgpath).unwrap(); }
转换的程序就好了,然后我们结合rust的GUI库iced来编写一个简单的带UI的转换程序,所以,我们还需要添加iced库,看一下toml文件:
[package]
name = "gui-serial"
version = "0.1.0"
edition = "2021"
[dependencies]
iced={version="0.12.1"}
iced_widget={version="0.12.3",features=[]}
serialport="4.3.0"
clap="4.5.7"
image="0.25.1"
resvg={version="0.42.0",features=[]}
关于iced以及rfd库的使用,此处不再赘述,可以参考本人的另外的博文:
Rust UI开发(三):iced如何打开图片(对话框)并在窗口显示图片?
我直接把主程序的代码贴在这:
use std::{io::{self,Write}, process::CommandArgs}; use eximg::codecs::png; use imgtoicon::image_to_icon; use resvg::usvg::filter::Merge; use serialport::{DataBits,StopBits,Parity}; //use clap::{value_parser, Arg, ArgAction, Command}; mod ser; mod imgtoicon; mod resvgpro; use iced::{Application, Command, Element, Font, Renderer, Settings, Subscription}; use iced_widget::{container,button,text,column,row,svg,image}; use rfd::FileDialog; extern crate resvg; extern crate image as eximg; #[derive(Debug,Clone)] enum Message{ Cvt, Open, Save, } struct Serial{ portname:String, baudrate:u32, databits:DataBits, stopbits:StopBits, parity:Parity, timeout:u64, openfile:String, destfile:String, } fn main() ->iced::Result { let myicon=imgtoicon::image_to_icon("..\\gui-serial\\img\\mainicon4.png"); let myfont="微软雅黑"; Serial::run(Settings{ id:Some("mw".to_string()), window:iced::window::Settings{ size:iced::Size{width:800.0,height:600.0}, min_size:Some(iced::Size { width: 200.0, height: 200.0 }), max_size:Some(iced::Size { width: 1000.0, height: 800.0 }), position:iced::window::Position::Specific(iced::Point::new(100.0,100.0)), icon:Some(myicon), level:iced::window::Level::Normal, ..Default::default() }, default_font:Font::with_name(myfont), ..Default::default() }) } impl Application for Serial{ type Executor = iced::executor::Default; type Message = Message; type Flags = (); type Theme = iced::Theme; fn new(flags: Self::Flags) -> (Self, Command<Self::Message>) { (Self{ portname:String::from("COM1"), baudrate:9600, databits:DataBits::Eight, stopbits:StopBits::One, parity:Parity::None, timeout:1000, openfile:String::from(""), destfile:String::from(""), }, Command::none()) } fn title(&self) -> String { String::from("串口调试工具-rs") } fn update(&mut self, message: Self::Message) -> Command<Self::Message> { match message{ Message::Cvt=>{ resvgpro::svgtopng(&self.openfile, &self.destfile) } Message::Open=>{ if let Some(file)=FileDialog::new() .set_title("打开文件") .add_filter("svg", &["svg"]) .pick_file(){ self.openfile=file.display().to_string(); } else{ println!("打开文件失败") }; } Message::Save=>{ if let Some(file)=FileDialog::new() .set_title("保存文件") .add_filter("png", &["png"]) .save_file(){ let filestr=file.display().to_string(); resvgpro::svgtopng(&self.openfile, &filestr); self.destfile=filestr; } else{ println!("保存文件失败") }; } } Command::none() } fn subscription(&self) -> Subscription<Self::Message> { Subscription::none() } fn view(&self) -> Element<'_, Self::Message, Self::Theme, crate::Renderer> { //let btn1=button("转换").on_press(Message::Cvt); let btn2=button("打开").on_press(Message::Open); let btn3=button("转换并保存").on_press(Message::Save); let svghandle=svg::Handle::from_path(&self.openfile); let pnghandle=image::Handle::from_path(&self.destfile); let col1=column![ btn2, text(format!("打开文件路径:{}",&self.openfile)).size(15), btn3, text(format!("保存文件路径:{}",&self.destfile)).size(15), //btn1, row![ svg(svghandle).content_fit(iced::ContentFit::Contain).width(300), image(pnghandle).content_fit(iced::ContentFit::Contain).width(300), ].padding(5).spacing(20), ].padding(5).spacing(5); let cont=container(col1).padding(5); cont.into() } }
实例演示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。