<Rust><iced><resvg>基于rust使用iced构建GUI实例:使用resvg库实现svg转png

news2025/1/20 1:44:16

前言
本文是使用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()
    }
}


实例演示:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1847754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024会展行业发展趋势预测

在当今这个数字化浪潮汹涌的时代&#xff0c;会展行业也迎来了自己的变革时刻。 根据《2023中国会展主办机构数字化调研报告》&#xff0c;我们可以清晰地看到几个显著的趋势&#xff1a; 首先&#xff0c;数字化转型已经不再是一道选择题&#xff0c;而是必答题。 超过90%的…

深入探索C++中的AVL树

引言 在数据结构和算法的世界里&#xff0c;平衡二叉搜索树&#xff08;Balanced Binary Search Tree, BST&#xff09;是一种非常重要的数据结构。AVL树&#xff08;Adelson-Velsky和Landis发明的树&#xff09;就是平衡二叉搜索树的一种&#xff0c;它通过自平衡来维护其性质…

噪声-降噪引脚如何提高系统性能

由于LDO是电子器件&#xff0c;因此它们会自行产生一定量的噪声。选择低噪声LDO并采取措施来降低内部噪声对于生成不会影响系统性能的清洁电源轨而言不可或缺。 识别噪声 理想的 LDO 会生成没有交流元件的电压轨。遗憾的是&#xff0c;LDO 会像其他电子器件一样自行产生噪声。…

【C++】关于代码编译自动更新版本的问题

在写代码的时候&#xff0c;总是需要添加一个版本号&#xff0c;用于后续的版本管理 我常遇到的一个问题是&#xff0c;开发过程中&#xff0c;不一定会记得这件事情&#xff0c;导致有时候会出现同样的版本 于是希望有一个方式&#xff0c;能在编译代码的时候自动生成一个版…

价值驱动型PMO如何实现项目战略目标?

近期&#xff0c;看到一个帖子&#xff0c;一位PMO&#xff08;小刘&#xff09;吐槽自己就是一个无情的项目推动机器&#xff0c;但还总被领导diss&#xff0c;他不知道问题出在哪了。评论区也有很多项目管理人吐槽自己也踩过类似的坑&#xff0c;那么本期就围绕这个案例展开相…

后端程序员的Linux命令指南

后端程序员的终极命令指南&#xff1a;考考自己是不是真正掌握Linux的使用 欢迎各位穿着格子衬衫&#xff0c;常年抱着键盘睡觉的后端小伙伴们&#x1f44b;&#x1f44b;&#x1f44b;&#xff01;今天&#xff0c;考考你们是不是掌握以下让你们在日后在服务器上叱咤风云的命令…

【环境变量问题:计算机删除环境变量的恢复方法;此环境变量太大。此对话框允许将值设置为最长2047个字符】

不小心误删了win10系统环境变量可以试试下文方法恢复。 本方法针对修改环境变量未重启的用户可以使用&#xff0c;如果修改环境变量&#xff0c;然后还重启了&#xff0c;只能说重新来。 方法一&#xff1a;使用命令提示符恢复 被修改的系统Path只是同步到了注册表中&#x…

天津这场智博会,成了智能时代的风向标

毫无疑问&#xff0c;这是一场智能产业的盛宴。 2024年6月20日至23日&#xff0c;国家会展中心&#xff08;天津&#xff09;迎来了一场智能科技领域的盛会——世界智能产业博览会&#xff1a;这场以“智行天下、能动未来”为主题的博览会&#xff0c;汇聚了全球49个国家和地区…

海外版coze前端代码助手

定位 解决前端同事的开发问题 参数配置 测试 支持 最屌的大模型及语音播报。 体验地址 海外版前端代码助手 需要魔法才能体验油

智能网联汽车实训教学“好帮手”——渡众机器人自动驾驶履带车

智能网联汽车实训教学“好帮手”——渡众机器人自动驾驶履带车 人工智能技术的兴起&#xff0c;为传统汽车行业注入了强有力的变革基因&#xff0c;以AI技术为驱动的无人驾驶成为汽车产业的未来&#xff0c;同样也面临诸多机遇和挑战。 一方面智能网联汽车的发展&#xff0c;为…

设置浏览器互不干扰

目录 一、查看浏览器文件路径 二、 其他盘新建文件夹Cache 三、以管理员运行CMD 四、执行命令 一、查看浏览器文件路径 chrome://version/ 二、 其他盘新建文件夹Cache D:\chrome\Cache 三、以管理员运行CMD 四、执行命令 Mklink /d "C:\Users\Lenovo\AppData\Loca…

【启明智显产品介绍】Model3C工业级HMI芯片详解专题(一)芯片性能

【启明智显产品介绍】工业级HMI芯片Model3C详解&#xff08;一&#xff09;芯片性能 Model3C 是一款基于 RISC-V 的高性能、国产自主、工业级高清显示与智能控制 MCU&#xff0c;配置平头哥E907&#xff0c;主频400MHz&#xff0c;强大的 2D 图形加速处理器、PNG/JPEG 解码引擎…

[240621] Anthropic 发布了 Claude 3.5 Sonnet AI 助手 | Socket.IO 拒绝服务漏洞

目录 Anthropic 发布 Claude 3.5 Sonnet AI 助手Scoket.IO 拒绝服务漏洞&#xff08;CVE-2024-38355&#xff09; Anthropic 发布 Claude 3.5 Sonnet AI 助手 Claude 3.5 Sonnet: 更智能、更快速、更安全的 AI 助手 一、 引言 Anthropic 发布了 Claude 3.5 Sonnet&#xff0…

excel基本操作

excel 若要取消在数据表中进行的所有筛选 步骤操作&#xff1a; 单击“数据”选项卡。在“排序和筛选”组中&#xff0c;找到“清除”按钮。点击“清除”按钮。 图例&#xff1a; 将文本文件的数据导入到Excel工作表中进行数据处理 步骤&#xff1a; 在Excel中&#xff0c…

详细解读“找不到mfc140u.dll无法继续执行代码”问题

当你打开某个软件或者运行游戏&#xff0c;系统提示mfc140u.dll丢失&#xff0c;此时这个软件或者游戏根本无法运行。其实&#xff0c;mfc140u.dll是动态库文件&#xff0c;它是VS2010编译的软件所产生的&#xff0c;如果电脑运行程序时提示缺少mfc140u.dll文件&#xff0c;程序…

高德行政区查询-综合省市县三级选择跳转

一、需求&#xff1a; 需要使用高德地图进行省市县的一个选择&#xff0c;每选择一次就在地图上对选择的省市县进行定位并画出该区域的范围。 最终效果&#xff1a; 二、准备工作 高德的API的key&#xff1a;两种 三、完整页面代码 综合的是这两篇中的内容&#xff08;不…

python pyautogui实现图片识别点击失败后重试

安装库 pip install Pillow pip install opencv-python confidence作用 confidence 参数是用于指定图像匹配的信度&#xff08;或置信度&#xff09;的&#xff0c;它表示图像匹配的准确程度。这个参数的值在 0 到 1 之间&#xff0c;数值越高表示匹配的要求越严格。 具体来…

Java中将文件转换为Base64编码的字节码

在Java中&#xff0c;将文件转换为Base64编码的字节码通常涉及以下步骤&#xff1a; 读取文件内容到字节数组。使用java.util.Base64类对字节数组进行编码。 下面是一个简单的Java示例代码&#xff0c;演示如何实现这个过程&#xff1a; import java.io.File; import java.io…

实验13 简单拓扑BGP配置

实验13 简单拓扑BGP配置 一、 原理描述二、 实验目的三、 实验内容四、 实验配置五、 实验步骤 一、 原理描述 BGP&#xff08;Border Gateway Protocol&#xff0c;边界网关协议&#xff09;是一种用于自治系统间的动态路由协议&#xff0c;用于在自治系统&#xff08;AS&…

太牛了!AI换脸数字人,限制解除,免费用!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 今天给大家安利一款美图公司出品的神器&#xff0c;功能限制完全解除&#xff0c;可以免费使用AI换脸数字人、AI提词器、AI脚本、AI抠图、AI清除、AI封面等超多超实用功能&#xff0c;…