一、前情提要
在Python完成SVG转PNG格式中,虽然图片格式成功转换了,但是会出现几个问题,如下所示
1、原本透明背景的SVG格式图片,转换成PNG格式之后,图片变成了白色的背景
白色背景变透明的方法可看我上一篇文章python把png的白色背景变透明
2、有的图片在成功转换之后出现了奇怪的线
3、控制台出现报错
总结:
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、测试环境是否配置正确
代码语言:javascript复制在命令行使用CairoSVG,输入以下代码,看一下能不能将 当前目录 下的xx.svg文件转换为xx.png文件:
注意:
①先通过命令行进入到你保存有SVG格式图片的那个文件夹下,再运行该语句
②xx.svg 这个必须是你当前文件夹下有的svg格式的图片
②xx.png 这个名字自己定义的
cairosvg xx.svg -o xx.png
正常情况下,这么一套流程走下来,就没有问题了,转换好的PNG文件会保存在当前目录下,即与SVG格式的图片,放在同一个路径下,可以自己去查看,转换的效果什么的
四、完整代码展示
代码语言:javascript复制SvgToPng.ui 这个是用Qt设计师画的界面,和我方法一中的那个界面一模一样,没变化,想参考的话,可以过去跟着我画一下,Python完成SVG转PNG格式
# -*- 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_()