Python完成SVG转PNG格式——方法二

2021-07-16 14:47:28 浏览数 (1)

一、前情提要

在Python完成SVG转PNG格式中,虽然图片格式成功转换了,但是会出现几个问题,如下所示

1、原本透明背景的SVG格式图片,转换成PNG格式之后,图片变成了白色的背景

白色背景变透明的方法可看我上一篇文章python把png的白色背景变透明

直接转换之后的结果直接转换之后的结果
在上面转换结果的基础上,在进行透明背景的处理在上面转换结果的基础上,在进行透明背景的处理

2、有的图片在成功转换之后出现了奇怪的线

原图没有这个线原图没有这个线

3、控制台出现报错

应该是2D库中的线段共线问题,这是因为用renderPM模块转换SVG到PNG格式导致的应该是2D库中的线段共线问题,这是因为用renderPM模块转换SVG到PNG格式导致的

总结:

1、会出现白色背景,是因为 renderPM 模块转换出来的PNG格式的图片是24位深的,即只能控制RGB通道,所以,会从透明背景变成白色的背景,无法避免,只能转换完成之后再处理;

2、出现奇怪的线,是因为 renderPM 模块内部转换过程中出现的问题,无法避免,只能转换完成之后再处理;

3、控制台报错 x_order_2: colinear! ,是因为 renderPM 模块,是读取了SVG格式的图片内容之后,再在一块画布上画出PNG格式的图像,但是此时的PNG图像只有24位深了,所以控制透明背景的 Alpha 通道只能与另外三个共线了。

二、解决问题

通过总结,我们可以发现,所有问题的根源都是因为我们使用了 renderPM 模块来完成SVG格式到PNG格式的转换,所以,想要解决问题,最好的办法就是采用一个全新的方案去转换格式,这里我找到的了一个cairosvg.svg2png( )方法来转换,上述问题都消失了,并且转换效果很不错,下面介绍一下,具体应该怎么做。

三、实现步骤

1、CarioSVG模块仅支持python3,注意一下python解释器的版本控制。在命令行输入以下指令:

代码语言:javascript复制
pip install cairosvg

等待安装完成,完成之后,先别急着用,用不了的,因为会出现如下提示,这是因为缺少语言环境

错误提示,不要慌错误提示,不要慌

2、下载GTK libraries,二选一即可,下载的内容都是一样的

有一点需要注意,安装的过程中,不要修改 它安装的路径,就让它 安装在默认的路径下,不然之后运行的时候,会发现CairoSVG找不着你安装的GTK,然后就会一直报上面说的这个错误,安装了也是白装

正确路径应该是类似于这样的,三选一正确路径应该是类似于这样的,三选一

1、有很多博客是让大家去github的GTK for Windows Runtime Environment Installer: 64-bit去下载,但是有时会加载不了网页

2、我把自己用的这个GTK3放在百度网盘了,也可以去我这里下载。

链接: gtk3-runtime-3.24.29-2021-04-29-ts-win64.exe

提取码: qhw1

3、测试环境是否配置正确

在命令行使用CairoSVG,输入以下代码,看一下能不能将 当前目录 下的xx.svg文件转换为xx.png文件:

注意:

①先通过命令行进入到你保存有SVG格式图片的那个文件夹下,再运行该语句

②xx.svg 这个必须是你当前文件夹下有的svg格式的图片

②xx.png 这个名字自己定义的

代码语言:javascript复制
cairosvg xx.svg -o xx.png

正常情况下,这么一套流程走下来,就没有问题了,转换好的PNG文件会保存在当前目录下,即与SVG格式的图片,放在同一个路径下,可以自己去查看,转换的效果什么的

四、完整代码展示

SvgToPng.ui 这个是用Qt设计师画的界面,和我方法一中的那个界面一模一样,没变化,想参考的话,可以过去跟着我画一下,Python完成SVG转PNG格式

代码语言:javascript复制
# -*- coding: utf-8 -*-
# @Time    : 2021/7/15 14:23
# @Author  : Elsa
# @File    : SvgToPng.py

import os
import cairosvg
from PySide2.QtCore import QStringListModel
from PySide2.QtGui import QPixmap
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QFileDialog, QMessageBox


class Stats:
    # 初始化
    def __init__(self):
        # 动态加载ui文件
        self.ui = QUiLoader().load('SvgToPng.ui')

        # 信号与槽链接
        self.ui.btn_file.clicked.connect(self.ChangeOne)
        self.ui.btn_files.clicked.connect(self.ChangeMore)
        self.ui.listView.clicked.connect(self.ShowMore)

        # 变量定义
        self.file_name = ''  # 选择的文件/文件夹
        self.save_file_name = ''  # 最终保存的文件夹位置
        self.image_name = ''

        self.file_paths = []  # 文件列表
        self.file_index = 0  # 文件索引
        self.file_num = ''  # 文件个数

    # 选择单个文件转换
    def ChangeOne(self):
        # 选择svg格式的文件
        self.file_name = QFileDialog.getOpenFileName(None, "选择文件", "/", "*.svg")
        self.file_name = str(self.file_name).split(',')[0].strip('(').replace("'", "")
        if self.file_name == '':
            QMessageBox.warning(
                self.ui,
                '提示',
                '未打开文件!')
        # 将打开文件路径显示在文本框中
        self.ui.edit_svg.setText(self.file_name)
        # 得到源文件位置
        self.image_name = self.file_name
        # 转换格式
        self.SvgToPng()
        # 显示转换后的png文件路径
        slm = QStringListModel()
        show = [self.save_file_name, '']
        slm.setStringList(show)
        self.ui.listView.setModel(slm)
        # 预览
        self.ShowOne()

    # 选择文件夹转换
    def ChangeMore(self):
        # 选择文件夹
        self.file_name = QFileDialog.getExistingDirectory(None, '选择文件夹', '/')  # 返回选中的文件夹路径
        # 将打开的文件夹路径显示在文本框中
        self.ui.edit_svg.setText(self.file_name)
        # 读取文件夹的文件
        self.file_paths.clear()
        for root, dirs, files in os.walk(self.file_name, topdown=False):
            for file in files:
                self.file_paths.append(os.path.join(root, file))
        line_name = str(self.file_paths[0]).replace('\', '/').split('/')[-1]
        # 读取出来的列表,第一个数据是一个系统文件,可能有可能无,所以判断一下
        if line_name == 'desktop.ini':
            self.file_paths = self.file_paths[1:]
        # 列表长度,统计有多少个文件
        self.file_num = len(self.file_paths)
        if self.file_num <= 0:
            QMessageBox.warning(
                self.ui,
                '提示',
                '文件夹为空!')
            return
        # 批量转换
        for self.file_index in range(0, self.file_num):
            self.image_name = self.file_paths[self.file_index].replace('\', '/')
            # 处理文件
            self.SvgToPng()
            self.file_paths[self.file_index] = self.save_file_name
        # 控制右侧的列表仅展示png文件
        self.file_index = 0
        for self.file_index in range(0, int(self.file_num / 2)):
            image_name_now = self.file_paths[self.file_index].replace('\', '/').split('/')[-1].split('.')[-1]
            if image_name_now == 'svg':
                del self.file_paths[self.file_index]

        # 去掉列表中的重复项
        self.file_num = int(len(self.file_paths) / 2)
        for i in range(0, self.file_num):
            for j in range(0, self.file_num):
                png_name_one = self.file_paths[i].replace('\', '/').split('/')[-1].split('.')[0]
                png_name_two = self.file_paths[j].replace('\', '/').split('/')[-1].split('.')[0]
                if png_name_one == png_name_two:
                    del self.file_paths[i]
        # 先预览最后一张
        self.ShowOne()
        # 显示图片列表
        slm = QStringListModel()
        slm.setStringList(self.file_paths)
        self.ui.listView.setModel(slm)

    # 格式转换
    def SvgToPng(self):
        # 获取当前文件的后缀名
        image_name_now = self.image_name.split('/')[-1].split('.')[-1]
        if image_name_now == 'svg':
            # 设置保存的文件名为“./名字_1.png”
            image_png_name = self.image_name.split('/')[-1]
            self.save_file_name = self.image_name.strip(image_png_name)   image_png_name.strip('.svg')   '_1.png'
            cairosvg.svg2png(file_obj=open(self.image_name, "rb"), write_to=self.save_file_name)

    # 展示图片
    def ShowOne(self):
        # 预览png图标
        pix = QPixmap(self.save_file_name)
        self.ui.label_print.setPixmap(pix)
        # 图片自适应
        self.ui.label_print.setScaledContents(True)

    # 列表展示图片
    def ShowMore(self, qModelIndex):
        self.save_file_name = self.file_paths[qModelIndex.row()]
        self.ShowOne()


if __name__ == '__main__':
    app = QApplication([])
    app.setStyle('Fusion')  # 设置窗口显示的风格
    stats = Stats()
    stats.ui.show()
    app.exec_()

五、结果展示

没有x_order_2: colinear!的报错了没有x_order_2: colinear!的报错了
图片的问题也解决了图片的问题也解决了

0 人点赞