<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)=>{
                                
                            }
                        }
                    }

                }
            }

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

相关推荐
佚名涙3 小时前
go中锁的入门到进阶使用
开发语言·后端·golang
Source.Liu7 小时前
【学Rust写CAD】20 平铺模式结构体(spread.rs)
rust·cad
草捏子8 小时前
从CPU原理看:为什么你的代码会让CPU"原地爆炸"?
后端·cpu
嘟嘟MD9 小时前
程序员副业 | 2025年3月复盘
后端·创业
胡图蛋.9 小时前
Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?
java·spring boot·后端
无责任此方_修行中9 小时前
关于 Node.js 原生支持 TypeScript 的总结
后端·typescript·node.js
吃海鲜的骆驼10 小时前
SpringBoot详细教程(持续更新中...)
java·spring boot·后端
迷雾骑士10 小时前
SpringBoot中WebMvcConfigurer注册多个拦截器(addInterceptors)时的顺序问题(二)
java·spring boot·后端·interceptor
uhakadotcom10 小时前
Thrift2: HBase 多语言访问的利器
后端·面试·github
Asthenia041211 小时前
Java 类加载规则深度解析:从双亲委派到 JDBC 与 Tomcat 的突破
后端