Skip to content

Instantly share code, notes, and snippets.

@v6ak
Last active March 12, 2019 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save v6ak/ae593ad5edf12b643e354d5cc284d2a5 to your computer and use it in GitHub Desktop.
Save v6ak/ae593ad5edf12b643e354d5cc284d2a5 to your computer and use it in GitHub Desktop.
Creates grid from SVG. Note that full image can be recovered from any piece, because any piece contain the full image just with modified boundaries.
#!/usr/bin/env python3
import argparse
import xml.etree.ElementTree
import re
import os
from collections import namedtuple
from decimal import Decimal
from fractions import Fraction
SIZE_REGEX = re.compile("^([0-9.]+)([a-z]*)$")
VIEWBOX_REGEX = re.compile("[ ,]+")
class Size(namedtuple('Size', ['number', 'unit'])):
@staticmethod
def parse(size):
items = SIZE_REGEX.fullmatch(size)
return Size(
Fraction(Decimal(items.group(1))),
items.group(2)
)
@staticmethod
def parse_number(number):
return Size(Fraction(Decimal(number)), "")
def __truediv__(self, divisor):
return Size(self.number / divisor, self.unit)
def __rmul__(self, multiplicator):
return self*multiplicator
def __mul__(self, multiplicator):
return Size(self.number * multiplicator, self.unit)
def __add__(self, summand):
if isinstance(summand, Size):
if self.unit != summand.unit:
raise Error("Cannot add apples to oranges!")
return self + summand.number
return Size(self.number+summand, self.unit)
def __radd(self, summand):
return self+summand
def to_svg_string(self):
return str(float(self.number))+self.unit
DEFAULT_OUTPUT_FILENAMES="{input_basename}-{y}-{x}.svg"
parser = argparse.ArgumentParser(description='Divides an SVG image to pieces of a grid. A bit dirty script focused primarily on SVGs from Inkscape.')
parser.add_argument('file', type=str, help='input file')
parser.add_argument('--vertical-parts', type=int, help='Number of vertical parts.', default=1)
parser.add_argument('--horizontal-parts', type=int, help='Number of horizontal parts.', default=1)
parser.add_argument('--output-filenames', type=str, help='Format string for output file names. By default, it is '+DEFAULT_OUTPUT_FILENAMES, default=DEFAULT_OUTPUT_FILENAMES)
args = parser.parse_args()
input_file=args.file
vertical_parts=args.vertical_parts
horizontal_parts=args.horizontal_parts
output_filenames=args.output_filenames
input_basename=os.path.splitext(input_file)[0]
tree = xml.etree.ElementTree.parse(input_file)
svg_root = tree.getroot()
# parse and calculate canvas size
canvas_base_height=Size.parse(svg_root.attrib["height"])
canvas_base_width=Size.parse(svg_root.attrib["width"])
canvas_part_height=canvas_base_height/vertical_parts
canvas_part_width=canvas_base_width/horizontal_parts
# parse and calculate viewBox
[base_offset_x, base_offset_y, base_width, base_height] = list(map(Size.parse_number, VIEWBOX_REGEX.split(svg_root.attrib["viewBox"])))
part_height=base_height/vertical_parts
part_width=base_width/horizontal_parts
# adjust canvas size
svg_root.set("width", canvas_part_width.to_svg_string())
svg_root.set("height", canvas_part_height.to_svg_string())
for x in range(horizontal_parts):
x_offset=base_offset_x+x*part_width
for y in range(vertical_parts):
y_offset=part_height*y
svg_root.set("viewBox", " ".join(map(lambda x: x.to_svg_string(), [x_offset, y_offset, part_width, part_height])))
tree.write(output_filenames.format(x=x, y=y, input_file=input_file, input_basename=input_basename), "utf-8")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment