<iced><rust><GUI>基于rust的GUI库iced的学习(02):svg图片转png

前言

本专栏是基于rust的GUI库iced的介绍,主要包括iced部件、iced实例的讲解与学习。如果你也对iced感兴趣,不妨来看看。

发文平台

稀土掘金

环境配置

  • 平台:windows
  • 软件:vscode
  • 语言:rust
  • 库:iced(0.13)、iced_aw

1、新建iced窗口

关于如何新建iced窗口并设置窗口参数,可以参考博文:

基于rust的GUI库iced的学习(00):一个典型的iced窗口的实现

本文不再赘述。

本文的目的是创建一个窗口,对于导入的svg图片,进行格式转换,转换为常用的png格式。因此,我们需要添加以下依赖:

bash 复制代码
cargo add image
bash 复制代码
cargo add resvg

resvg这个库用于处理svg图片:

2、在iced中显示svg

我们在对svg进行转换之前,先要将svg图片显示出来。我们先准备一张svg格式的图片,可以去网上下载:

为了在iced中显示svg图片,我们需先启用features:

toml 复制代码
iced={version ="0.13.1",features = ["svg","image"]}

然后在主程序中导入svg:

rust 复制代码
use iced::widget::{button, column, row, svg, text,container};

然后在iced的view函数中显示svg图片:

rust 复制代码
let svghandle=svg::Handle::from_path(self.srcpath.as_str());
let svgcolor=Color::parse("#56F25EFF").unwrap();
let svg1=svg(svghandle).content_fit(iced::ContentFit::Contain)
         .style(move |t,s|styles::mysvgstyle(t,s,svgcolor));

可以看到,svg与其他image元素的显示是一样的,都是获取图像的handle,然后传入svg元素。

官方源码
rust 复制代码
/// A handle of Svg data.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Handle {
    id: u64,
    data: Arc<Data>,
}

看一下运行后的效果:

3、svg转png

这里先说一下思路:

使用resvg库将svg图片转为字节数组,字节数组作为通用格式,使用image库将其转为png格式。

基本上,这是一个很简单好用的思路,无论什么格式的图片,都能够转为比较底层的数据,即字节数组,这也是非常通用的数据格式,只要能处理字节数组,就能够还原其图像数据。

所以,我们的转换的中转站 ,就是Vec<u8>

我们新创建一个函数:

rust 复制代码
///
/// svg转png
/// 
pub fn svgtoimg(
    svgpath: &str,
    destimgpath: &str,
) ->Result<(), eximg::ImageError>{
    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();
    let pp=pixmap.encode_png().unwrap();
    let img=eximg::ImageReader::new(std::io::Cursor::new(pp))
                                        .with_guessed_format()?.decode()?;
    img.save(destimgpath).unwrap();
    Ok(())

}

我们只需要为函数输入源图片即svg图片的路径与目标图片即png图片的路径即可。

此处转换的核心是resvg库,上述函数的部分代码就是resvg的示例代码,直接复制使用即可。基本上用到了resvg的usvg和tiny_skia这两个子库。此处如果想要深入研究,可以去查看resvg的源码,本文不作赘述。

4、实例演示

我们在使用中,为iced窗口添加两个按钮,用于进行图片导入以及转换的触发。而文件导入对话框,我们使用rfd这个库。

rust 复制代码
cargo add rfd

另外,我们再添加一个库:

rust 复制代码
cargo add chrono

用于获取本地日期时间,添加到保存图片的路径上,以记录图片。 我们在iced的update函数中,添加文件导入与图片转换的逻辑:

rust 复制代码
match message {
                Message::Loadimg =>{
                    let res = FileDialog::new()
                              .set_title("载入svg")
                              .add_filter("SVG", &["svg"])
                              .set_directory("/")
                              .pick_file();
                    match res{
                        Some(path) =>{
                            self.srcpath = path.display().to_string();
                        },
                        None =>{
                            self.srcpath = String::new();
                        }
                    }
                }
                Message::Convertimg=>{

                    if self.srcpath.is_empty(){
                        MessageDialog::new()
                            .set_title("错误")
                            .set_description("请先载入图片")
                            .show();
                    } else {
                        let now = Local::now();
                        let date_str = now.format("%Y-%m-%d-%H-%M-%S").to_string();
                        let mut path = std::path::PathBuf::from(&self.srcpath).parent().unwrap().to_path_buf();
                        let imgname = "output-".to_string() + &date_str;
                        path.push(imgname);
                        path.set_extension("png");
                        self.dstpath = path.to_str().unwrap().to_string();
                        let res = imgconvert::svgtoimg(&self.srcpath,&self.dstpath);
                        match res{
                            Ok(_)=>{},
                            Err(e)=>{
                                
                            }
                        }
                    }

                }
            }

好了,我们来看下实例演示:

相关推荐
Victor3561 小时前
Redis(104)Redis的最大数据量是多少?
后端
Victor3561 小时前
Redis(105)Redis的数据类型支持哪些操作?
后端
鬼火儿8 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
cr7xin8 小时前
缓存三大问题及解决方案
redis·后端·缓存
间彧9 小时前
Kubernetes的Pod与Docker Compose中的服务在概念上有何异同?
后端
间彧9 小时前
从开发到生产,如何将Docker Compose项目平滑迁移到Kubernetes?
后端
间彧9 小时前
如何结合CI/CD流水线自动选择正确的Docker Compose配置?
后端
间彧9 小时前
在多环境(开发、测试、生产)下,如何管理不同的Docker Compose配置?
后端
间彧9 小时前
如何为Docker Compose中的服务配置健康检查,确保服务真正可用?
后端
间彧10 小时前
Docker Compose和Kubernetes在编排服务时有哪些核心区别?
后端