hjc-owo
init repo
966ae59
# -*- coding: utf-8 -*-
# Author: ximing
# Description: SVGDreamer - merge
# Copyright (c) 2023, XiMing Xing.
# License: MIT License
from typing import Tuple, AnyStr
import omegaconf
from svgpathtools import svg2paths, wsvg
from .type import is_valid_svg
from .shape import *
def merge_svg_files(
svg_path_1: AnyStr,
svg_path_2: AnyStr,
merge_type: str,
output_svg_path: AnyStr,
out_size: Tuple[int, int], # e.g.: (600, 600)
):
is_valid_svg(svg_path_1)
is_valid_svg(svg_path_2)
# set merge ops
if merge_type.startswith('vert'): # Move up/down vertically
if '+' in merge_type: # move up
move_val = merge_type.split("+")[1]
move_val = int(move_val)
elif '-' in merge_type: # move down
move_val = merge_type.split("-")[1]
move_val = -int(move_val)
else:
raise NotImplemented(f'{merge_type} is invalid.')
merge_svg_by_group(svg_path_1, svg_path_2,
cp_offset=(0, move_val),
svg_out=output_svg_path, out_size=out_size)
elif merge_type.startswith('cp'): # Move all control points
if '+' in merge_type:
move_val = merge_type.split("+")[1]
move_val = int(move_val)
elif '-' in merge_type:
move_val = merge_type.split("-")[1]
move_val = -int(move_val)
else:
raise NotImplemented(f'{merge_type} is invalid.')
merge_svg_by_cp(svg_path_1, svg_path_2,
p_offset=move_val,
svg_out=output_svg_path, out_size=out_size)
elif merge_type == 'simple': # simply combine two SVG files
simple_merge(svg_path_1, svg_path_2, output_svg_path, out_size)
else:
raise NotImplemented(f'{str(merge_type)} is not support !')
def simple_merge(svg_path1, svg_path2, output_path, out_size):
# read svg to paths
paths1, attributes1 = svg2paths(svg_path1)
paths2, attributes2 = svg2paths(svg_path2)
# merge path and attributes
paths = paths1 + paths2
attributes = attributes1 + attributes2
# write merged svg
wsvg(paths,
attributes=attributes,
filename=output_path,
viewbox=f"0 0 {out_size[0]} {out_size[1]}")
def merge_svg_by_group(
svg_path_1: AnyStr,
svg_path_2: AnyStr,
cp_offset: Tuple[float, float],
svg_out: AnyStr,
out_size: Tuple[int, int], # e.g.: (600, 600)
):
# load svg_path_1
tree1 = ET.parse(svg_path_1)
root1 = tree1.getroot()
# new group, and add paths form svg_path_1
group1 = ET.Element('g')
for i, element in enumerate(root1.iter()):
element.tag = element.tag.split('}')[-1]
if element.tag in ['path', 'polygon']:
group1.append(element)
# load svg_path_2
tree2 = ET.parse(svg_path_2)
root2 = tree2.getroot()
# new group, and add paths form svg_path_2
group2 = ET.Element('g')
for j, path in enumerate(root2.findall('.//{http://www.w3.org/2000/svg}path')):
# Remove the 'svg:' prefix from the tag name
path.tag = path.tag.split('}')[-1]
group2.append(path)
# new svg
svg = ET.Element('svg',
xmlns="http://www.w3.org/2000/svg",
version='1.1',
width=str(out_size[0]),
height=str(out_size[1]))
# control group2
if 'transform' in group2.attrib:
group2.attrib['transform'] += f' translate({cp_offset[0]}, {cp_offset[1]})'
else:
group2.attrib['transform'] = f'translate({cp_offset[0]}, {cp_offset[1]})'
# add two group
svg.append(group1)
svg.append(group2)
# write svg
tree = ET.ElementTree(svg)
tree.write(svg_out, encoding='utf-8', xml_declaration=True)
def merge_svg_by_cp(
svg_path_1: AnyStr,
svg_path_2: AnyStr,
p_offset: float,
svg_out: AnyStr,
out_size: Tuple[int, int], # e.g.: (600, 600)
):
# load svg_path_1
tree1 = ET.parse(svg_path_1)
root1 = tree1.getroot()
# new group, and add paths form svg_path_1
group1 = ET.Element('g')
for i, element in enumerate(root1.iter()):
element.tag = element.tag.split('}')[-1]
if element.tag in ['path', 'polygon']:
group1.append(element)
# load svg_path_2
tree2 = ET.parse(svg_path_2)
root2 = tree2.getroot()
# new group, and add paths form svg_path_2
group2 = ET.Element('g')
for j, path in enumerate(root2.findall('.//{http://www.w3.org/2000/svg}path')):
# remove the 'svg:' prefix from the tag name
path.tag = path.tag.split('}')[-1]
d = path.get('d')
# parse paths
path_data = d.split()
new_path_data = []
for i in range(len(path_data)):
if path_data[i].replace('.', '').isdigit(): # get point coordinates
new_param = float(path_data[i]) + p_offset
new_path_data.append(str(new_param))
else:
new_path_data.append(path_data[i])
# update new d attrs
path.set('d', ' '.join(new_path_data))
group2.append(path)
# new svg
svg = ET.Element('svg',
xmlns="http://www.w3.org/2000/svg",
version='1.1',
width=str(out_size[0]),
height=str(out_size[1]))
# add two group
svg.append(group1)
svg.append(group2)
# write svg
tree = ET.ElementTree(svg)
tree.write(svg_out, encoding='utf-8', xml_declaration=True)
def merge_two_svgs_edit(
svg_path_1: AnyStr,
svg_path_2: AnyStr,
def_cfg: omegaconf.DictConfig,
p2_offset: Tuple[float, float],
svg_out: AnyStr,
out_size: Tuple[int, int], # e.g.: (600, 600)
):
# load svg_path_1
tree1 = ET.parse(svg_path_1)
root1 = tree1.getroot()
# new group, and add paths form svg_path_1
group1 = ET.Element('g')
for i, element in enumerate(root1.iter()):
element.tag = element.tag.split('}')[-1]
if element.tag in ['path', 'polygon']:
group1.append(element)
# load svg_path_2
tree2 = ET.parse(svg_path_2)
root2 = tree2.getroot()
# new group, and add paths form svg_path_2
group2 = ET.Element('g')
for j, path in enumerate(root2.findall('.//{http://www.w3.org/2000/svg}path')):
# remove the 'svg:' prefix from the tag name
path.tag = path.tag.split('}')[-1]
d = path.get('d')
# parse paths
path_data = d.split()
new_path_data = []
d_idx = 0 # count digit
for i in range(len(path_data)):
if path_data[i].replace('.', '').isdigit(): # get point coordinates
d_idx += 1
if d_idx % 2 == 1: # update y
new_param = float(path_data[i]) + (p2_offset[1])
new_path_data.append(str(new_param))
else:
new_path_data.append(path_data[i])
else:
new_path_data.append(path_data[i])
# update new d attrs
path.set('d', ' '.join(new_path_data))
group2.append(path)
# new svg
svg = ET.Element('svg',
xmlns="http://www.w3.org/2000/svg",
version='1.1',
width=str(out_size[0]),
height=str(out_size[1]))
# add two group
svg.append(group1)
svg.append(group2)
# write svg
tree = ET.ElementTree(svg)
tree.write(svg_out, encoding='utf-8', xml_declaration=True)