[rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(05):svg图片转 ...

打印 上一主题 下一主题

主题 881|帖子 881|积分 2643

媒介
本文是关于iced库的部件先容,iced库是基于rust的GUI库,作者自述是受Elm启发。
iced目前的版本是0.13.1,相较于此前的0.12版本,有较大改动。
本合集是基于新版本的关于分部件(widget)的使用先容,包罗源代码先容、实例使用等。
环境配置
系统:window10
平台:visual studio code
语言:rust
库:iced 0.13
扩展库:iced_aw
svg转png

在之前的第一篇博文中,就说过图片格式的转换,主要是将png转为icon,以便于获取图片作为iced窗口的图标。
我们使用了一个图片处置惩罚库image,我们需要添加依赖:
  1. cargo add image
复制代码
然后导入时为了不与iced自己的image产生冲突,因此可以重新命名:
  1. extern crate image as eximg
复制代码
不过,外部image库并不支持直接转换svg格式,所以我们将使用另一个库,用于处置惩罚svg图片:
  1. cargo add resvg
复制代码

1、iced中表现svg

在iced中,如果要表现svg图片,如同添加image部件一样,需要先开启features:
  1. iced={version ="0.13.1",features = ["svg","image"]}
复制代码
然后在主程序中导入svg:
  1. use iced::widget::{button, column, row, svg, text,container};
复制代码
表现svg图片与表现png图片一样,我们在view函数中编写:
  1. let svghandle=svg::Handle::from_path(self.srcpath.as_str());
  2. let svgcolor=Color::parse("#56F25EFF").unwrap();
  3. let svg1=svg(svghandle).content_fit(iced::ContentFit::Contain)
  4.          .style(move |t,s|styles::mysvgstyle(t,s,svgcolor));
复制代码
可以看到,svg的参数也是Handle,与image是一样的,但是二者的struct构成有所区别。
官方源码
  1. /// A handle of Svg data.
  2. #[derive(Debug, Clone, PartialEq, Eq)]
  3. pub struct Handle {
  4.     id: u64,
  5.     data: Arc<Data>,
  6. }
复制代码
我们去网站上下载一张svg格式的图片,比如:

我们在iced窗口中表现,由于svg图片是矢量图形,我们可以设置一个背景色,以便于观察:

hover状态:

2、svg转png

说一下本文的思路,使用resvg库将svg图片转为字节数组,字节数组作为通用格式,使用image库将其转为png格式。
基本上,这是一个很简单好用的思路,无论什么格式的图片,都能够转为比力底层的数据,即字节数组,这也是非常通用的数据格式,只要能处置惩罚字节数组,就能够还原其图像数据。
所以,我们的转换的中转站,就是Vec。
我们在此前的博文里,创建过一个imgconvert.rs,添加了imgtoico函数,现在,我们可以在此文件中再创建一个函数:
  1. ///
  2. /// svg转png
  3. ///
  4. pub fn svgtoimg(
  5.     svgpath: &str,
  6.     destimgpath: &str,
  7. ) ->Result<(), eximg::ImageError>{
  8.     let mut opt=resvg::usvg::Options::default();
  9.     opt.resources_dir=std::fs::canonicalize(svgpath)
  10.                                  .ok()
  11.                                  .and_then(|p| p.parent().map(|p| p.to_path_buf()));
  12.     opt.fontdb_mut().load_system_fonts();
  13.     let svgdata=std::fs::read(svgpath).unwrap();
  14.     let tree=resvg::usvg::Tree::from_data(&svgdata,&opt).unwrap();
  15.     let pixmap_size = tree.size().to_int_size();
  16.     let mut pixmap = resvg::tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap();
  17.     resvg::render(&tree, resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut());
  18.     //pixmap.save_png(destimgpath).unwrap();
  19.     let pp=pixmap.encode_png().unwrap();
  20.     let img=eximg::ImageReader::new(std::io::Cursor::new(pp))
  21.                                         .with_guessed_format()?.decode()?;
  22.     img.save(destimgpath).unwrap();
  23.     Ok(())
  24. }
复制代码
我们只需要为函数输入源图片即svg图片的路径与目标图片即png图片的路径即可。
此处转换的核心是resvg库,上述函数的部分代码就是resvg的示例代码,直接复制使用即可。基本上用到了resvg的usvg和tiny_skia这两个子库。此处如果想要深入研究,可以去检察resvg的源码,本文不作赘述。(目前我也说不清楚,会用即可)
3、综述

本文,我们实现的是,通过一个导入按钮导入svg图片,然后通过另一个转换按钮转换格式至png,并生存图片。
由于我们会使用到文件对话框以及获取本地日期,所以我们还需要添加两个库:
  1. rfd="0.15.2"
  2. chrono = "0.4.39"
复制代码
我们在update函数中编写按钮的逻辑:
  1.      Message::Load =>{
  2.                 let res=FileDialog::new()
  3.                                     .set_title("载入svg")
  4.                                     .add_filter("Svg Files",&["svg"])
  5.                                     .set_directory("/")
  6.                                     .pick_file();
  7.                 match res {
  8.                     Some(path) =>{
  9.                         self.srcpath = path.display().to_string();
  10.                         self.tipcontent="".to_string();
  11.                     },
  12.                     None =>{
  13.                         self.srcpath =String::new();
  14.                         
  15.                     }
  16.                 }
  17.             }
  18.         Message::Convert =>{
  19.                 if self.srcpath.is_empty() {
  20.                     self.tipcontent="请先导入svg文件!".to_string();
  21.                 }
  22.                 else{
  23.                     self.tipcontent="".to_string();
  24.                     let now=Local::now();
  25.                     let date_str=now.format("%Y-%m-%d-%H-%M-%S").to_string();
  26.                     //println!("转换时间:{}",date_str);
  27.                     //获取源图片的父路径
  28.                     let mut path = std::path::PathBuf::from(&self.srcpath).parent().unwrap().to_path_buf();
  29.                     let imgname="output-".to_string() + date_str.as_str();
  30.                     path.push(imgname);
  31.                     path.set_extension("png");
  32.                     self.dstpath =path.to_str().unwrap().to_string();
  33.                     //svg转png函数
  34.                     let res=imgconvert::svgtoimg(&self.srcpath, &self.dstpath);
  35.                     match res {
  36.                         Ok(_) =>{
  37.                         },
  38.                         Err(e) =>{
  39.                             MessageDialog::new()
  40.                                 .set_title("提示!")
  41.                                 .set_description(&e.to_string())
  42.                                 .show();
  43.                         }
  44.                     }
  45.                 }
  46.             }
复制代码
当我们转换后,会在本地文件夹天生带有日期的png图片。
动态演示:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表