Added primitive extension
This commit is contained in:
parent
db0f31054b
commit
ac56527f8f
45
extensions/fablabchemnitz_primitive.inx
Normal file
45
extensions/fablabchemnitz_primitive.inx
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Primitive (Michael Fogleman)</name>
|
||||
<id>fablabchemnitz.de.primitive</id>
|
||||
<label appearance="header">Settings</label>
|
||||
<separator/>
|
||||
<param name="keeporiginal" type="bool" gui-text="Keep original image on canvas">false</param>
|
||||
<param name="n" type="int" min="0" max="99999" gui-text="Number of shapes">100</param>
|
||||
<param name="m" appearance="combo" type="optiongroup" default="1" gui-text="Mode">
|
||||
<option value="0">Combo</option>
|
||||
<option value="1">Triangle</option>
|
||||
<option value="2">Rectangle</option>
|
||||
<option value="3">Ellipse</option>
|
||||
<option value="4">Circle</option>
|
||||
<option value="5">Rotated rectangle</option>
|
||||
<option value="6">Beziers</option>
|
||||
<option value="7">Rotated ellipse</option>
|
||||
<option value="8">Polygon</option>
|
||||
</param>
|
||||
<param name="rep" type="int" min="0" max="99999" gui-text="Extra shapes/iteration" gui-description="Sdd N extra shapes each iteration with reduced search (mostly good for beziers)">0</param>
|
||||
<param name="r" type="int" min="1" max="99999" gui-text="Resize to size before processing (px)">256</param>
|
||||
<param name="s" type="int" min="1" max="99999" gui-text="Output image size (px)">1024</param>
|
||||
<param name="a" type="int" min="0" max="255" gui-text="Color alpha" gui-description="Use 0 to let the algorithm choose alpha for each shape">128</param>
|
||||
<param name="bg_enabled" type="bool" gui-text="Use average starting background color">true</param>
|
||||
<param name="bg" type="color" appearance="colorbutton" min="0" max="255" gui-text="Starting background color" gui-description="You need to disable average starting background to use this option">255</param>
|
||||
<param name="j" type="int" min="0" max="32" gui-text="Number of parallel workers" gui-description="Default (0) uses all cores">0</param>
|
||||
<spacer/>
|
||||
<label appearance="header">About</label>
|
||||
<separator/>
|
||||
<label>Primitive - Reproducing images with geometric primitives written in Go. Wrapped for InkScape 1.X by Mario Voigt / Stadtfabrikanten e.V. (2020)</label>
|
||||
<label appearance="url">https://github.com/fogleman/primitive</label>
|
||||
<label appearance="url">https://fablabchemnitz.de</label>
|
||||
<label>License: GNU GPL v3 for the wrapper, MIT for primitive</label>
|
||||
<effect needs-live-preview="true">
|
||||
<object-type>image</object-type>
|
||||
<effects-menu>
|
||||
<submenu name="FabLab Chemnitz">
|
||||
<submenu name="Tracing/Edge Detection"/>
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
<command location="inx" interpreter="python">./fablabchemnitz_primitive/fablabchemnitz_primitive.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
144
extensions/fablabchemnitz_primitive/fablabchemnitz_primitive.py
Normal file
144
extensions/fablabchemnitz_primitive/fablabchemnitz_primitive.py
Normal file
@ -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()
|
BIN
extensions/fablabchemnitz_primitive/primitive.exe
Normal file
BIN
extensions/fablabchemnitz_primitive/primitive.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user