Last active
March 12, 2019 09:13
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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