通过python进行PNG转SVG

背景

在项目中遇到需要批量进行png to svg,虽然在linux上使用inlscape很方便,但是遇到大量的转换工作时,还是需要通过脚本替代人工。

在图片转换方面没有过研究,所以通过百度找其他人的经验。

但是发现好多文章不仅重复,而且将代码复制下来,无法使用。

还花了一些币进行脚本下载,但是毫无意外,还是无法使用。

通过百度搜索的到的资料都不能正常运行,总结归纳了如下脚本。

可以进行批量的转换,但转换速度还有优化空间,后续有时间再进行优化。

使用方法:

python3 pngtosvg.py

运行脚本,会自动寻找脚本所在的文件夹内的png格式的图片,并进行转换,并将转换的图片保存至同一文件夹内

python3 pngtosvg.py 指定目录

指定转换的文件夹目录,自动在指定目录寻找可转换的png图片,并将转换好的svg格式的图片保存至指定文件夹下

部分代码展示如下,代码有些繁琐,可以通过下方链接直接下载使用。

def rgba_image_to_svg_pixels(im):
	s = io.StringIO()
	s.write(svg_header(*im.size))

	width, height = im.size
	for x in range(width):
		for y in range(height):
			here = (x, y)
			rgba = im.getpixel(here)
			if not rgba[3]:
				continue
			s.write("""  <rect x="%d" y="%d" width="1" height="1" style="fill:rgb%s; fill-opacity:%.3f; stroke:none;" />\n""" % (x, y, rgba[0:3], float(rgba[3]) / 255))
		print ("Converting pixels: "+str(x*100/width) + "%")
	s.write("""</svg>\n""")
	return s.getvalue()


def joined_edges(assorted_edges, keep_every_point=False):
	pieces = []
	piece = []
	directions = deque([
		(0, 1),
		(1, 0),
		(0, -1),
		(-1, 0),
		])
	while assorted_edges:
		if not piece:
			piece.append(assorted_edges.pop())
		current_direction = normalize(direction(piece[-1]))
		while current_direction != directions[2]:
			directions.rotate()
		for i in range(1, 4):
			next_end = add_tuple(piece[-1][1], directions[i])
			next_edge = (piece[-1][1], next_end)
			if next_edge in assorted_edges:
				assorted_edges.remove(next_edge)
				if i == 2 and not keep_every_point:
					# same direction
					piece[-1] = (piece[-1][0], next_edge[1])
				else:
					piece.append(next_edge)
				if piece[0][0] == piece[-1][1]:
					if not keep_every_point and normalize(direction(piece[0])) == normalize(direction(piece[-1])):
						piece[-1] = (piece[-1][0], piece.pop(0)[1])
						# same direction
					pieces.append(piece)
					piece = []
				break
		else:
			raise Exception("Failed to find connecting edge")
	return pieces


def rgba_image_to_svg_contiguous(im, keep_every_point=False):

	# collect contiguous pixel groups
	
	adjacent = ((1, 0), (0, 1), (-1, 0), (0, -1))
	visited = Image.new("1", im.size, 0)
	
	color_pixel_lists = {}

	width, height = im.size
	for x in range(width):
		for y in range(height):
			here = (x, y)
			if visited.getpixel(here):
				continue
			rgba = im.getpixel((x, y))
			if not rgba[3]:
				continue
			piece = []
			queue = [here]
			visited.putpixel(here, 1)
			while queue:
				here = queue.pop()
				for offset in adjacent:
					neighbour = add_tuple(here, offset)
					if not (0 <= neighbour[0] < width) or not (0 <= neighbour[1] < height):
						continue
					if visited.getpixel(neighbour):
						continue
					neighbour_rgba = im.getpixel(neighbour)
					if neighbour_rgba != rgba:
						continue
					queue.append(neighbour)
					visited.putpixel(neighbour, 1)
				piece.append(here)

			if not rgba in color_pixel_lists:
				color_pixel_lists[rgba] = []
			color_pixel_lists[rgba].append(piece)
		print ("Converting image: "+str(round(x*100/width, 2)) + "%")
	del adjacent
	del visited

	# calculate clockwise edges of pixel groups

	edges = {
		(-1, 0):((0, 0), (0, 1)),
		(0, 1):((0, 1), (1, 1)),
		(1, 0):((1, 1), (1, 0)),
		(0, -1):((1, 0), (0, 0)),
		}
			
	color_edge_lists = {}

	counter = 0
	for rgba, pieces in color_pixel_lists.items():
		for piece_pixel_list in pieces:
			edge_set = set([])
			for coord in piece_pixel_list:
				for offset, (start_offset, end_offset) in edges.items():
					neighbour = add_tuple(coord, offset)
					start = add_tuple(coord, start_offset)
					end = add_tuple(coord, end_offset)
					edge = (start, end)
					if neighbour in piece_pixel_list:
						continue
					edge_set.add(edge)
			if not rgba in color_edge_lists:
				color_edge_lists[rgba] = []
			color_edge_lists[rgba].append(edge_set)
		counter = counter+1
		print ("Calculating edges: "+str(round(counter*100/len(color_pixel_lists.items()),2)) + "%")
	del color_pixel_lists
	del edges

	# join edges of pixel groups

	color_joined_pieces = {}

	for color, pieces in color_edge_lists.items():
		color_joined_pieces[color] = []
		for assorted_edges in pieces:
			color_joined_pieces[color].append(joined_edges(assorted_edges, keep_every_point))

	s = io.StringIO()
	s.write(svg_header(*im.size))

	counter = 0
	for color, shapes in color_joined_pieces.items():
		for shape in shapes:
			s.write(""" <path d=" """)
			for sub_shape in shape:
				here = sub_shape.pop(0)[0]
				s.write(""" M %d,%d """ % here)
				for edge in sub_shape:
					here = edge[0]
					s.write(""" L %d,%d """ % here)
				s.write(""" Z """)
			s.write(""" " style="fill:rgb%s; fill-opacity:%.3f; stroke:none;" />\n""" % (color[0:3], float(color[3]) / 255))
		counter = counter+1
		print ("Joining edges: "+str(round(counter*100/len(color_joined_pieces.items()), 2)) + "%")
	s.write("""</svg>\n""")
	return s.getvalue()

大家还可以下载源码后,自行修改,修改为转换指定的png图片,修改方法很简单.

可以通过此链接下载脚本:

图片格式转换+PNGtoSVG(亲测可用)-Python文档类资源-CSDN下载

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值