diff --git a/extensions/fablabchemnitz_primitive.inx b/extensions/fablabchemnitz_primitive.inx new file mode 100644 index 00000000..0d95169b --- /dev/null +++ b/extensions/fablabchemnitz_primitive.inx @@ -0,0 +1,45 @@ + + + Primitive (Michael Fogleman) + fablabchemnitz.de.primitive + + + false + 100 + + + + + + + + + + + + 0 + 256 + 1024 + 128 + true + 255 + 0 + + + + + + + + + image + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz_primitive/fablabchemnitz_primitive.py b/extensions/fablabchemnitz_primitive/fablabchemnitz_primitive.py new file mode 100644 index 00000000..cc98f01d --- /dev/null +++ b/extensions/fablabchemnitz_primitive/fablabchemnitz_primitive.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 + +import sys +import inkex +import os +import base64 +import urllib.request as urllib +from PIL import Image +from io import BytesIO +from lxml import etree +from inkex import Color + +""" +Extension for InkScape 1.X +Features + - Primitive - Reproducing images with geometric primitives written in Go. + +Author: Mario Voigt / FabLab Chemnitz +Mail: mario.voigt@stadtfabrikanten.org +Date: 21.08.2020 +Last patch: 21.08.2020 +License: GNU GPL v3 + +Used version of Primitive: https://github.com/fogleman/primitive/commit/0373c216458be1c4b40655b796a3aefedf8b7d23 +""" + +class Primitive (inkex.Effect): + + def rgbToHex(self, pickerColor): + longcolor = int(pickerColor) + if longcolor < 0: + longcolor = longcolor & 0xFFFFFFFF + return '#' + format(longcolor >> 8, '06X') + + def checkImagePath(self, node): + xlink = node.get('xlink:href') + if xlink and xlink[:5] == 'data:': + # No need, data alread embedded + return + + url = urllib.urlparse(xlink) + href = urllib.url2pathname(url.path) + + # Primary location always the filename itself. + path = self.absolute_href(href or '') + + # Backup directory where we can find the image + if not os.path.isfile(path): + path = node.get('sodipodi:absref', path) + + if not os.path.isfile(path): + inkex.errormsg('File not found "{}". Unable to embed image.').format(path) + return + + if (os.path.isfile(path)): + return path + + def __init__(self): + inkex.Effect.__init__(self) + self.arg_parser.add_argument("--keeporiginal", type=inkex.Boolean, default=False, help="Keep original image on canvas") + self.arg_parser.add_argument("--n", type=int, default=100, help="Number of shapes") + self.arg_parser.add_argument("--m", default=1, help="Mode") + self.arg_parser.add_argument("--rep", type=int, default=0,help="Extra shapes/iteration") + self.arg_parser.add_argument("--r", type=int, default=256, help="Resize to size before processing (px)") + self.arg_parser.add_argument("--s", type=int, default=1024, help="Output image size (px)") + self.arg_parser.add_argument("--a", type=int, default=128, help="Color alpha") + self.arg_parser.add_argument("--bg_enabled", type=inkex.Boolean, default=True, help="Use average starting background color") + self.arg_parser.add_argument("--bg", type=Color, default=255, help="Starting background color") + self.arg_parser.add_argument("--j", type=int, default=0, help="Number of parallel workers") + + def effect(self): + + # internal overwrite for scale: + self.options.scale = 1.0 + + if (self.options.ids): + for node in self.svg.selected.values(): + if node.tag == inkex.addNS('image', 'svg'): + self.path = self.checkImagePath(node) # This also ensures the file exists + if self.path is None: # check if image is embedded or linked + image_string = node.get('{http://www.w3.org/1999/xlink}href') + # find comma position + i = 0 + while i < 40: + if image_string[i] == ',': + break + i = i + 1 + image = Image.open(BytesIO(base64.b64decode(image_string[i + 1:len(image_string)]))) + else: + image = Image.open(self.path) + + # Write the embedded or linked image to temporary directory + exportfile = "Primitive.png" + image.save(exportfile, "png") + + ## Build up Primitive command according to your settings from extension GUI + command = "primitive" + command += " -m " + str(self.options.m) + command += " -rep " + str(self.options.rep) + command += " -r " + str(self.options.r) + command += " -s " + str(self.options.s) + command += " -a " + str(self.options.a) + if not self.options.bg_enabled: + command += " -bg " + self.rgbToHex(self.options.bg) + command += " -j " + str(self.options.j) + command += " -i " + exportfile + command += " -o " + exportfile + ".svg" + command += " -n " + str(self.options.n) + + inkex.utils.debug(command) + + # Create the vector new SVG file + with os.popen(command, "r") as proc: + result = proc.read() + #inkex.utils.debug(result) + + # proceed if new SVG file was successfully created + if os.path.exists(exportfile + ".svg"): + # Delete the temporary png file again because we do not need it anymore + if os.path.exists(exportfile): + os.remove(exportfile) + + # new parse the SVG file and insert it as new group into the current document tree + doc = etree.parse(exportfile + ".svg").getroot() + newGroup = self.document.getroot().add(inkex.Group()) + newGroup.attrib['transform'] = "matrix(" + \ + str(float(node.get('width')) / float(doc.get('width'))) + \ + ", 0, 0 , " + \ + str(float(node.get('height')) / float(doc.get('height'))) + \ + "," + node.get('x') + \ + "," + node.get('y') + ")" + newGroup.append(doc) + + # Delet the temporary svg file + if os.path.exists(exportfile + ".svg"): + os.remove(exportfile + ".svg") + + #remove the old image or not + if self.options.keeporiginal is not True: + node.getparent().remove(node) + else: + inkex.utils.debug("No image found for tracing. Please select an image first.") + +Primitive().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz_primitive/primitive.exe b/extensions/fablabchemnitz_primitive/primitive.exe new file mode 100644 index 00000000..9eb92597 Binary files /dev/null and b/extensions/fablabchemnitz_primitive/primitive.exe differ