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

                }
            }

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

相关推荐
用户608186527903 分钟前
WPF 命令 ICommand 从原理到实战
后端
liuqun03195 分钟前
go进阶之gc
开发语言·后端·golang
李小狼lee5 分钟前
以一个简单案例来讲解RAG
后端
程序员清风10 分钟前
OpenAI创始人学AI的底层逻辑,普通人照着做就能上手!
java·后端·面试
元俭11 分钟前
【Eino 框架入门】用 JSONL 实现会话持久化
后端
Rust研习社11 分钟前
构建可扩展 Rust 项目:从模块化到 Workspace 工程化实践
rust
Memory_荒年12 分钟前
Netty面试终极指南:从“Hello World”到源码深处
java·后端
0xDevNull13 分钟前
Java IO流教程:从入门到最佳实践
java·后端
好家伙VCC13 分钟前
**发散创新:用 Rust实现数据编织(DataWrangling)的高效流式处理架构**在现
java·开发语言·python·架构·rust
Memory_荒年17 分钟前
Netty深度解构:高性能背后的核心机制与实战精要
java·后端