diff --git a/extensions/fablabchemnitz/another_perspective/another_perspective.inx b/extensions/fablabchemnitz/another_perspective/another_perspective.inx new file mode 100644 index 0000000..9ad3e57 --- /dev/null +++ b/extensions/fablabchemnitz/another_perspective/another_perspective.inx @@ -0,0 +1,16 @@ + + + Another Perspective + fablabchemnitz.de.another_perspective + + path + + + + + + + + diff --git a/extensions/fablabchemnitz/another_perspective/another_perspective.py b/extensions/fablabchemnitz/another_perspective/another_perspective.py new file mode 100644 index 0000000..cf23c89 --- /dev/null +++ b/extensions/fablabchemnitz/another_perspective/another_perspective.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python3 + +""" +Copyright (C) 2017 Corentin Brulé + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Special thanks and orignal copyrigths : Aaron Spike (2005) and Timo Kähkönen (2012) +""" + +import inkex +import re +from lxml import etree +from inkex.transforms import Transform +from inkex.paths import Path, CubicSuperPath + +__version__ = '0.1' + +debug=False + +def distort_path(path_str,source,destination): + path_arr = path_string_to_array(path_str) + + subpath_type="" + is_num ="" + xy_counter ="" + xy="" + path_arr2=[] + subpath_type_upper="" + point="" + i=0 + for i in range(len(path_arr)): + patt1 = r"[mzlhvcsqta]" + + curr = path_arr[i] + if re.match(patt1,curr,flags=re.I): + xy_counter = -1 + subpath_type = curr + subpath_type_upper = subpath_type.upper() + is_num = False + path_arr2.append(curr) + else : + is_num = True + curr = float(curr) + + if xy_counter%2 == 0: + xy="x" + else: + xy="y" + + if is_num : + if xy=="y" : + point = transferPoint(float(path_arr[i-1]),curr,source,destination) + path_arr2.append(point["x"]) + path_arr2.append(point["y"]) + + xy_counter+=1 + + path_str = path_array_to_string(path_arr2) + return path_str + + +def path_array_to_string(path_arr): + + path_str=str(path_arr) + + path_str=path_str.replace(r"([0-9]),([-0-9])", "$1 $2") + path_str=path_str.replace(r"([0-9]),([-0-9])", "$1 $2") + path_str=path_str.replace(",", "") + path_str=path_str.replace("[", "").replace("]","") + path_str=path_str.replace("'", "") + + return path_str + +def path_string_to_array(path_str): + + patt1=r"[mzlhvcsqta]|-?[0-9.]+" #gi + #path_arr=path_str.match(patt1) #array de résultats + path_arr = re.findall(patt1,path_str,flags=re.I) + + patt1=r"[mzlhvcsqta]" #i + i = 0 + for i in range(len(path_arr)): + if re.match(path_arr[i],patt1,flags=re.I) == -1: + path_arr[i] = float(path_arr[i]) + + return path_arr + +''' +def isPermissible(p): + p0 = {x:c0.attr("cx"),y:c0.attr("cy")} + p1 = {x:c1.attr("cx"),y:c1.attr("cy")} + p2 = {x:c2.attr("cx"),y:c2.attr("cy")} + p3 = {x:c3.attr("cx"),y:c3.attr("cy")} + a0 = angle(p3, p0, p1) + a1 = angle(p0, p1, p2) + a2 = angle(p1, p2, p3) + a3 = angle(p2, p3, p0) + if not (a0 > 0 and a0 < 180) or not (a1 > 0 and a1 < 180) or not(a2 > 0 and a2 < 180) or not(a3 > 0 and a3 < 180) : + return False + else : + return True +} + +def angle(c, b, a): + ab = {x: b.x - a.x, y: b.y - a.y } + cb = {x: b.x - c.x, y: b.y - c.y } + dot = (ab.x * cb.x + ab.y * cb.y) + cross = (ab.x * cb.y - ab.y * cb.x) + alpha = Math.atan2(cross, dot) + return alpha * 180 / PI +} +''' + +def transferPoint (xI, yI, source, destination): + + ADDING = 0.001 # to avoid dividing by zero + + xA = source[0]["x"] + yA = source[0]["y"] + + xC = source[2]["x"] + yC = source[2]["y"] + + xAu = destination[0]["x"] + yAu = destination[0]["y"] + + xBu = destination[1]["x"] + yBu = destination[1]["y"] + + xCu = destination[2]["x"] + yCu = destination[2]["y"] + + xDu = destination[3]["x"] + yDu = destination[3]["y"] + + # Calcultations + if xBu==xCu : + xCu+=ADDING + if xAu==xDu : + xDu+=ADDING + if xAu==xBu : + xBu+=ADDING + if xDu==xCu : + xCu+=ADDING + kBC = float(yBu-yCu)/float(xBu-xCu) + kAD = float(yAu-yDu)/float(xAu-xDu) + kAB = float(yAu-yBu)/float(xAu-xBu) + kDC = float(yDu-yCu)/float(xDu-xCu) + + if kBC==kAD : + kAD += ADDING + xE = float(kBC*xBu - kAD*xAu + yAu - yBu) / float(kBC-kAD) + yE = kBC*(xE - xBu) + yBu + + if kAB==kDC : + kDC += ADDING + xF = float(kAB*xBu - kDC*xCu + yCu - yBu) / float(kAB-kDC) + yF = kAB*(xF - xBu) + yBu + + if xE==xF : + xF += ADDING + kEF = float(yE-yF) / float(xE-xF) + + if kEF==kAB: + kAB += ADDING + xG = float(kEF*xDu - kAB*xAu + yAu - yDu) / float(kEF-kAB) + yG = kEF*(xG - xDu) + yDu + + if kEF==kBC : + kBC+=ADDING + xH = float(kEF*xDu - kBC*xBu + yBu - yDu) / float(kEF-kBC) + yH = kEF*(xH - xDu) + yDu + + rG = float(yC-yI)/float(yC-yA) + rH = float(xI-xA)/float(xC-xA) + + xJ = (xG-xDu)*rG + xDu + yJ = (yG-yDu)*rG + yDu + + xK = (xH-xDu)*rH + xDu + yK = (yH-yDu)*rH + yDu + + if xF==xJ: + xJ+=ADDING + if xE==xK: + xK+=ADDING + kJF = float(yF-yJ) / float(xF-xJ) + kKE = float(yE-yK) / float(xE-xK) + + xKE = "" + if kJF==kKE: + kKE += ADDING + xIu = float(kJF*xF - kKE*xE + yE - yF) / float(kJF-kKE) + yIu = kJF * (xIu - xJ) + yJ + + b = {"x":xIu,"y":yIu} + b["x"] = round(b["x"]) + b["y"] = round(b["y"]) + return b + + +def projection(path_object,coords): + + pp_object = Path(path_object).to_arrays() + + bounds = Path(path_object).bounding_box() + + # Make array of coordinates, every array member represent corner of text path + source = [ + {"x":bounds.left,"y":bounds.top}, + {"x":bounds.right,"y":bounds.top}, + {"x":bounds.right,"y":bounds.bottom}, + {"x":bounds.left,"y":bounds.bottom} + ] + + destination=[ + {"x":coords[0][0],"y":coords[0][1]}, + {"x":coords[1][0],"y":coords[1][1]}, + {"x":coords[2][0],"y":coords[2][1]}, + {"x":coords[3][0],"y":coords[3][1]} + ] + + path_destination = distort_path(path_object,source,destination) + + return path_destination +''' +def complex2tulpe(complexNb): + return (complexNb.real,complexNb.imag) +''' +class AnotherPerspective(inkex.EffectExtension): + + def envelope2coords(self, path_envelope): + pp_envelope = CubicSuperPath(path_envelope) + if len(pp_envelope[0]) < 4: + inkex.errormsg("The selected envelope (your second path) does not contain enough nodes. Check to have at least 4 nodes.") + exit() + + c0 = pp_envelope[0][0][0] + c1 = pp_envelope[0][1][0] + c2 = pp_envelope[0][2][0] + c3 = pp_envelope[0][3][0] + # inkex.debug(str(c0)+" "+str(c1)+" "+str(c2)+" "+str(c3)) + return [c0, c1, c2, c3] + + def effect(self): + if len(self.options.ids) < 2: + inkex.errormsg("This extension requires two selected paths.") + exit() + + obj = self.svg.selected[self.options.ids[0]] + envelope = self.svg.selected[self.options.ids[1]] + + if obj.get(inkex.addNS('type','sodipodi')): + inkex.errormsg("The first selected object is of type '%s'.\nTry using the procedure Path->Object to Path." % obj.get(inkex.addNS('type','sodipodi'))) + exit() + + if obj.tag == inkex.addNS('path','svg') or obj.tag == inkex.addNS('g','svg'): + if envelope.tag == inkex.addNS('path','svg'): + mat = envelope.transform @ Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) + path = CubicSuperPath(envelope.get('d')) + Path(path).transform(mat) + absolute_envelope_path = envelope.get('d') + # inkex.debug(absolute_envelope_path) + coords_to_project = self.envelope2coords(absolute_envelope_path) + + if obj.tag == inkex.addNS('path','svg'): + mat = obj.transform @ Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) + absolute_d = str(Path(obj.get('d'))) + path = CubicSuperPath(absolute_d) + Path(path).transform(mat) + absolute_object_path = str(path) + # inkex.debug(absolute_object_path) + + elif obj.tag == inkex.addNS('g','svg'): + absolute_object_path="" + for p in obj.iterfind(".//{http://www.w3.org/2000/svg}path"): + + absolute_d = str(Path(p.get('d'))) + mat = p.transform * Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) + path = CubicSuperPath(absolute_d) + Path(path).transform(mat) + absolute_object_path += str(Path(path)) + # inkex.debug(absolute_object_path) + + new_path = projection(absolute_object_path,coords_to_project) + attributes = {'d':new_path, 'style':str(obj.style)} + new_element = etree.SubElement(self.svg.get_current_layer(),inkex.addNS('path','svg'),attributes) + + else: + if envelope.tag == inkex.addNS('g','svg'): + inkex.errormsg("The second selected object is a group, not a path.\nTry using the procedure Object->Ungroup.") + else: + inkex.errormsg("The second selected object is not a path.\nTry using the procedure Path->Object to Path.") + exit() + else: + inkex.errormsg("The first selected object is not a path.\nTry using the procedure Path->Object to Path.") + exit() + +if __name__ == '__main__': + AnotherPerspective().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/another_perspective/meta.json b/extensions/fablabchemnitz/another_perspective/meta.json new file mode 100644 index 0000000..6354b30 --- /dev/null +++ b/extensions/fablabchemnitz/another_perspective/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Another Perspective", + "id": "fablabchemnitz.de.another_perspective", + "path": "another_perspective", + "dependent_extensions": null, + "original_name": "AnotherPerspective", + "original_id": "macrico.anotherperspective", + "license": "GNU GPL v3", + "license_url": "https://github.com/CorentinBrule/inkscape_another_perspective_extension/blob/master/anotherperspective.py", + "comment": "ported to Inkscape v1 by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/another_perspective", + "fork_url": "https://github.com/CorentinBrule/inkscape_another_perspective_extension", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Another+Perspective", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/CorentinBrule", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/circular_ground_from_template.inx b/extensions/fablabchemnitz/bobbinlace/circular_ground_from_template.inx new file mode 100644 index 0000000..3587bbb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/circular_ground_from_template.inx @@ -0,0 +1,54 @@ + + + Bobbin Lace - Circular Ground from Template + fablabchemnitz.de.bobbinlace.circular_ground_from_template + + + ./templates/ + + + 45.0 + + + 30 + + + + 50 + + + + + + + + + + 3 + + + + 1 + + + + + + + + + + 255 + + + all + + + + + + + + diff --git a/extensions/fablabchemnitz/bobbinlace/circular_ground_from_template.py b/extensions/fablabchemnitz/bobbinlace/circular_ground_from_template.py new file mode 100644 index 0000000..d636f07 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/circular_ground_from_template.py @@ -0,0 +1,434 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2017, Ben Connors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +from math import sin, cos, acos, tan, radians, pi, sqrt, ceil, floor +import inkex +from lxml import etree + +__author__ = 'Ben Connors' +__credits__ = ['Ben Connors', 'Veronika Irvine', 'Jo Pol', 'Mark Shafer'] +__license__ = 'Simplified BSD' + +class Vector: + def __repr__(self): + return 'Vector(%.4f, %.4f)' % (self.dx,self.dy) + + def __hash__(self): + return hash((self.dx,self.dy)) + + def rotate(self,theta): + """ Rotate counterclockwise by theta.""" + return self.mag*Vector(cos(self.theta+theta), + sin(self.theta+theta), + _theta=self.theta+theta) + + def __mul__(self,other): + return Vector(self.dx*other,self.dy*other,_theta=self.theta) + + def __rmul__(self,other): + return self*other + + def __init__(self,dx,dy,_theta=None): + """ Create a vector with the specified components. + _theta should NOT be passed in normal use - this value is passed by + vector functions where the angle of the new vector is known in order + to eliminate that calculation. + """ + self.dx = float(dx) + self.dy = float(dy) + self.mag = sqrt(dx**2 + dy**2) + self.tuple = (dx,dy) + + ## Angle to positive X axis + if _theta == None: + _theta = acos(self.dx/self.mag) + self.theta = 2*pi-_theta if self.dy < 0 else _theta + else: + self.theta = _theta + + +class CircularGroundFromTemplate(inkex.EffectExtension): + + def unitToUu(self,param): + """ Convert units. + Converts a number in some units into the units used internally by + Inkscape. + + param is a string representing a number with units attached. An + example would be '3.8mm'. Any units supported by Inkscape + are supported by this function. + + This wrapper function catches changes made to the location + of the function between Inkscape versions. + """ + try: + return self.svg.unittouu(param) + except: + return inkex.unittouu(param) + + def loadFile(self): + """ Load the specification for the unit cell from the file given. + Note that the specification should be in the following format: + TYPE ROWS COLS + [x1,y1,x2,y2,x3,y3] [x4,y4,x5 ... + + And so on. The TYPE is always CHECKER and is ignored by this program. + ROWS specifies the height of the unit cell (i.e. max_y - min_y) + and COLS specifies the same for the width (i.e. max_x - min_x). + Note that this is not enforced when drawing the unit cell - points + may be outside this range. These values are used to determine the + distance between unit cells (i.e. unit cells may overlap). + """ + # Ensure that file exists and has the proper extension + if not self.options.file: + inkex.errormsg('You must specify a template file.') + exit() + self.options.file = self.options.file.strip() + if self.options.file == '': + inkex.errormsg('You must specify a template file.') + exit() + if not os.path.isfile(self.options.file): + inkex.errormsg('You have not specified a valid path for the template file.\n\nYour entry: '+self.options.file) + exit() + extension = os.path.splitext(self.options.file)[1] + if extension != '.txt': + inkex.errormsg('The file name must end with .txt.\n\nYour entry: '+self.options.file) + exit() + + data = [] + rows, cols = -1, -1 + with open(self.options.file,'r') as f: + for line in f: + line = line.strip() + ## If rows is not a positive integer, we're on the first line + if rows == -1: + tmp = line.split('\t') + _type,cols,rows = tmp[0],int(tmp[1]),int(tmp[2]) + else: + data.append([]) + for cell in line[1:-1].split(']\t['): + cell = cell.strip() + ## The pattern must be rotated 90 degrees clockwise. It's + ## simplest to just do that here + tmp = [float(n) for n in cell.split(',')] + data[-1].append([a for b in zip([rows-i for i in tmp[1::2]],[cols-i for i in tmp[::2]]) for a in b]) + return {'type': _type, 'rows': rows, 'cols': cols, 'data' : data} + + def line(self,points): + """ + Draw a line from point at (x1, y1) to point at (x2, y2). + Style of line is hard coded and specified by 's'. + """ + # define the motions + path = ('M%.4f,%.4fL' % tuple(points[0][:2])) + 'L'.join([('%f,%f' % tuple(a[:2])) for a in points[1:]]) + + # define the stroke style + s = {'stroke-linejoin': 'miter', + 'stroke-width': self.options.linewidth, + 'stroke-opacity': '1.0', + 'fill-opacity': '1.0', + 'stroke': self.options.linecolor, + 'stroke-linecap': 'butt', + 'stroke-linejoin': 'miter', + 'fill': 'none' + } + + + ## Attributes for new element + attribs = {'style':str(inkex.Style(s)), + 'd' : path} + + ## Add new element + etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path', 'svg'), attribs) + + def baseVectors(self,segments): + """ Create vectors for all vertices on the specified polygon.""" + ## Start at 12 o'clock + theta = pi/2 + ## Move clockwise + dtheta = -2*pi/segments + + vector = Vector(0,self.options.diameter/2) + vectors = [vector] + for i in range(1,segments): + vector = vector.rotate(dtheta) + vectors.append(vector) + return vectors + + def fuzzyEquality(self,a,b): + return (a-b <= 1e-8) + + def circleWrap(self,points,segments): + """ Wrap a grid around the origin. + <> is a list of 2- or 3-tuples. + In the case of 3-tuples, they should be laid out like: (x,y,name) + Whereas 2-tuples should eliminate the name portion. + Only one format may be passed; they may not be mixed. + x- and y- values are rounded to the nearest integer. + If more precision is desired, scale up the points before calling this function. + x-values should be within [0,segments) + Values not within range will be moved within range. + y-values must be greater than 0 + An error will be raised if a y-value is less than 0. + The 'name' portion is not touched by this function; it is merely + passed along. This may be used to identify points or groups of points. + <> is the inside radius (i.e. distance to origin from a point with + a y-value of 0). + <> is the number of segments (sides) of the polygon. + <> is the angle of the diagonal of the square approximation. It must be + somewhere on (0,pi/2). + """ + angle = self.options.angle + if angle <= 0 or angle >= pi/2: + raise ValueError('Angle must be in (0,pi/2)') + + vectors = self.baseVectors(segments) + theta = 2*pi/segments + + """ + Determine the coefficient to multiply the vectors by in order to deal + with a higher x-value. + With R being the large radius (radius to next y-value) and r being the + small radius (radius to current y-value): + + a^2 = r^2 (1 - cos(theta)) ## Cosine law + b^2 = R^2 (1 - cos(theta)) + + To get the most square-like trapezoid: + R - r = 0.5(a+b) + + Subbing in the equations for b^2 and a^2 yields the following lines. + """ + C = sqrt(2*(1-cos(theta))) + val = 2*tan(pi/2-angle) + coeff = (val+C)/(val-C) + diff = coeff-1 + + ## Sort points in order of increasing y-value. + named = False + if len(points[0]) == 3: + named = True + points = [(x,y,name) for x,y,name in sorted(points,key=lambda a: a[1])] + else: + points = [(x,y,None) for x,y in sorted(points,key=lambda a: a[1])] + + done = [] + cur_y = 0 + for point in points: + x,y,name = point + + ## Check constraints + if y < cur_y: + raise ValueError('Invalid point (%d,%d)' % (x,y)) + elif y >= cur_y+1: + ## Multiply vectors accordingly + delta = floor(y-cur_y) + vectors = [(coeff**delta)*v for v in vectors] + cur_y = floor(y) + + ## Wrap x-value to lie in the proper place + ## lazy + while x < 0: + x += segments + while x >= segments: + x -= segments + + if self.fuzzyEquality(y,int(y)) and self.fuzzyEquality(x,int(x)): + x = int(x) + ## Can do it the quick way + wx,wy = vectors[x].tuple + else: + ## Use vector rotation + ## Determine nearest vector (counterclockwise) + pointer = vectors[floor(x)] + ## Scale x and y to be within (0,1) + x -= int(x) + y -= int(y) + c = C*x ## This value is used a lot, cache it + ## Now the angle of rotation must be determined using cosine law + factor = 1 + if not self.fuzzyEquality(x,0): + ## x isn't equal to 0, must rotate vector + n2 = 1+c**2-2*c*cos((pi-theta)/2) + factor = sqrt(n2) + phi = acos((n2+1-c**2)/(2*factor)) + pointer = pointer.rotate(-phi) + ## Correct vector magnitude + pointer = (1+y*diff)*factor*pointer + wx,wy = pointer.tuple + if named: + done.append((wx,wy,name)) + else: + done.append((wx,wy)) + return done + + def createGround(self,unit,rows,cols,scale=1): + """ Return a lace ground. + + This function returns a list of points and corresponding lines that may + be transformed or passed to a drawing function (such as draw_image) in + order to draw a lace ground. + + unit is the pattern for the lace ground, in the format returned by + loadFile. + + rows and cols are integers and represent the number of horizontal repeats + and vertical repeats of the pattern, respectively. + + scale is an optional value that can be used to scale the pattern before it + is repeated. Note that this comes with some constraints - the + template's rows and cols after scaling (i.e. unit['rows']*scale) must + be an integer. For example, a template with 4 rows and 4 cols before + scaling may be scaled by any integer value above 1 and select values + between 1 and 0 (namely 0.25,0.5,0.75). A scale value of 'True' may be + passed if each repeat of the template should fit within a 1x1 square. + """ + data = unit['data'] + unit_rows = unit['rows'] + unit_cols = unit['cols'] + if scale <= 0: + raise ValueError('Scale must be greater than zero') + elif scale != 1: + ## The user wants to scale the template + _data = [] + for row in data: + _row = [] + for c in row: + if scale == True: + _row.append([i for n in zip([a/unit_cols for a in c[::2]],[a/unit_rows for a in c[1::2]]) for i in n]) + else: + _row.append([a*scale for a in c]) + _data.append(_row) + data = _data + unit_rows *= scale + unit_cols *= scale + ## Catching invalid input + if not self.fuzzyEquality(unit_rows,int(unit_rows)): + raise ValueError('Scale factor must result in an integer value for template rows') + if not self.fuzzyEquality(unit_cols,int(unit_cols)): + raise ValueError('Scale factor must result in an integer value for template cols') + unit_rows = int(unit_rows) + unit_cols = int(unit_cols) + line_num = 0 + points = [] + for c in range(cols): + ## Do each column first + x = c*unit_cols + for r in range(rows): + y = r*unit_rows + for row in data: + for x1,y1,x2,y2,x3,y3 in row: + ## In order to draw lines in the correct order, an extra + ## point must be added + p1 = (x+x1,y+y1,'%09da,1'%line_num) + p2 = (x+x2,y+y2,'%09da,2'%line_num) + p1a = (x+x1,y+y1,'%09db,1'%line_num) + p3 = (x+x3,y+y3,'%09db,3'%line_num) + points.extend([p1,p2,p1a,p3]) + line_num += 1 + return points + + def draw(self, points,line=lambda a: None): + """ Draw the image. + points - a list of points, as returned by createGround. + line - a function that draws a line connecting all points in the passed list in order. + """ + groups = {} + ## This loop scales points, sorts them into groups, and gets image parameters + xs = [] + ys = [] + for x,y,n in points: + xs.append(x) + ys.append(y) + sn = n.split(',',1) + ident = 0 + if len(sn) == 2: + ident = int(sn[1]) + n = sn[0] + if n not in groups: + groups[n] = [] + groups[n].append((x,y,ident)) + max_x = max(xs) + min_x = min(xs) + max_y = max(ys) + min_y = min(ys) + ## Sort all groups to draw lines in order + for group in groups: + groups[group].sort(key=lambda a:a[2]) + ## Sort all groups to draw groups in order + groups = sorted([(name,pts) for name,pts in groups.items()],key=lambda a:a[0]) + ## Draw lines + for name,pts in groups: + _pts = [] + for p in pts: + _pts.append([p[0]-min_x,p[1]-min_y]) + self.line(_pts) + + def add_arguments(self, pars): + pars.add_argument('--file') + pars.add_argument('--angle', type=int) + pars.add_argument('--cols', type=int) + pars.add_argument('--diameter', type=float) + pars.add_argument('--diamunits') + pars.add_argument('--rows', type=int) + pars.add_argument('--linewidth', type=float) + pars.add_argument('--lineunits') + pars.add_argument('--linecolor', type=inkex.Color) + + def effect(self): + ## Load the file + unit = self.loadFile() + self.options.linecolor = self.options.linecolor.to_rgb() + + ## Change the input to universal units + self.options.diameter = self.unitToUu(str(self.options.diameter)+self.options.diamunits) + self.options.linewidth = self.unitToUu(str(self.options.linewidth)+self.options.lineunits) + + ## Convert the angle + self.options.angle = radians(self.options.angle) + + ## Ensure no y-values are below 0 + min_y = min([b for a in [i[1::2] for row in unit['data'] for i in row] for b in a]) + if min_y < 0: + data = [] + for row in unit['data']: + _row = [] + for c in row: + _row.append([a for b in zip(c[::2],[i-min_y for i in c[1::2]]) for a in b]) + data.append(_row) + unit['data'] = data + + ## Create the ground coordinates + points = self.createGround(unit,self.options.rows,self.options.cols) + + ## Wrap it around a polygon + points = self.circleWrap(points,self.options.cols*unit['cols']) + + ## Draw everything + self.draw(points,line=lambda a: self.line(a)) + +if __name__ == '__main__': + CircularGroundFromTemplate().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/ground_from_template.inx b/extensions/fablabchemnitz/bobbinlace/ground_from_template.inx new file mode 100644 index 0000000..5f9b2d3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/ground_from_template.inx @@ -0,0 +1,60 @@ + + + Bobbin Lace - Ground From Template + fablabchemnitz.de.bobbinlace.ground_from_template + + ./templates/ + + + 45.0 + + + 5.0 + + + + + + + + + + + 50 + + + + + + + + + + 50 + + + + 1 + + + + + + + + + + 255 + + + all + + + + + + + + diff --git a/extensions/fablabchemnitz/bobbinlace/ground_from_template.py b/extensions/fablabchemnitz/bobbinlace/ground_from_template.py new file mode 100644 index 0000000..c2a435f --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/ground_from_template.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2017, Veronika Irvine +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice,# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +from math import sin, cos, radians, ceil +from lxml import etree +import inkex + +__author__ = 'Veronika Irvine' +__credits__ = ['Ben Connors', 'Veronika Irvine', 'Mark Shafer'] +__license__ = 'Simplified BSD' + +class GroundFromTemplate(inkex.EffectExtension): + + def loadFile(self): + # Ensure that file exists and has the proper extension + if not self.options.file: + inkex.errormsg('You must specify a template file.') + exit() + self.options.file = self.options.file.strip() + if self.options.file == '': + inkex.errormsg('You must specify a template file.') + exit() + if not os.path.isfile(self.options.file): + inkex.errormsg('You have not specified a valid path for the template file.\n\nYour entry: '+self.options.file) + exit() + extension = os.path.splitext(self.options.file)[1] + if extension != '.txt': + inkex.errormsg('The file name must end with .txt.\n\nYour entry: '+self.options.file) + exit() + + data = [] + rowCount = 0 + colCount = 0 + with open(self.options.file,'r') as f: + first = True + for line in f: + if first: + # first line of file gives row count and column count + first = False + line = line.strip() + temp = line.split('\t') + type = temp[0] + rowCount = int(temp[1]) + colCount = int(temp[-1]) + + else: + line = line.strip() + line = line.lstrip('[') + line = line.rstrip(']') + rowData = line.split(']\t[') + data.append([]) + for cell in rowData: + cell = cell.strip() + data[-1].append([float(num) for num in cell.split(',')]) + + return {'type':type, 'rowCount':rowCount, 'colCount':colCount, 'data':data} + + def line(self, x1, y1, x2, y2): + """ + Draw a line from point at (x1, y1) to point at (x2, y2). + Style of line is hard coded and specified by 's'. + """ + # define the motions + path = 'M %s,%s L %s,%s' %(x1,y1,x2,y2) + + # define the stroke style + s = {'stroke-linejoin': 'miter', + 'stroke-width': self.options.linewidth, + 'stroke-opacity': '1.0', + 'fill-opacity': '1.0', + 'stroke': self.options.linecolor, + 'stroke-linecap': 'butt', + 'stroke-linejoin': 'miter', + 'fill': 'none' + } + + # create attributes from style and path + attribs = {'style':str(inkex.Style(s)), 'd':path} + + # insert path object into current layer + etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path', 'svg'), attribs) + + def draw(self, data, rowCount, colCount): + a = self.options.distance + theta = self.options.angle + deltaX = a*sin(theta) + deltaY = a*cos(theta) + maxRows = ceil(self.options.height / deltaY) + maxCols = ceil(self.options.width / deltaX) + + x = 0.0 + y = 0.0 + repeatY = 0 + repeatX = 0 + + while repeatY * rowCount < maxRows: + x = 0.0 + repeatX = 0 + + while repeatX * colCount < maxCols: + + for row in data: + for coords in row: + x1 = x + coords[0]*deltaX + y1 = y + coords[1]*deltaY + x2 = x + coords[2]*deltaX + y2 = y + coords[3]*deltaY + x3 = x + coords[4]*deltaX + y3 = y + coords[5]*deltaY + + self.line(x1,y1,x2,y2) + self.line(x1,y1,x3,y3) + + repeatX += 1 + x += deltaX * colCount + + repeatY += 1 + y += deltaY * rowCount + + def add_arguments(self, pars): + pars.add_argument('-f', '--file', help='File containing lace ground description') + pars.add_argument('--angle', type=float) + pars.add_argument('--distance', type=float) + pars.add_argument('--pinunits') + pars.add_argument('--width', type=float) + pars.add_argument('--patchunits') + pars.add_argument('--height', type=float) + pars.add_argument('--linewidth', type=float) + pars.add_argument('--lineunits') + pars.add_argument('--linecolor', type=inkex.Color) + + def effect(self): + result = self.loadFile() + + # Convert input to universal units + self.options.width = self.svg.unittouu(str(self.options.width)+self.options.patchunits) + self.options.height = self.svg.unittouu(str(self.options.height)+self.options.patchunits) + self.options.linewidth = self.svg.unittouu(str(self.options.linewidth)+self.options.lineunits) + self.options.distance = self.svg.unittouu(str(self.options.distance)+self.options.pinunits) + + # Users expect distance to be the vertical distance between footside pins + # (vertical distance between every other row) but in the script we use it + # as the diagonal distance between grid points + # therefore convert distance based on the angle chosen + self.options.angle = radians(self.options.angle) + self.options.distance = self.options.distance/(2.0*cos(self.options.angle)) + + # Draw a ground based on file description and user inputs + self.options.linecolor = self.options.linecolor.to_rgb() + # For now, assume style is Checker but could change in future + self.draw(result['data'],result['rowCount'],result['colCount']) + +if __name__ == '__main__': + GroundFromTemplate().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/meta.json b/extensions/fablabchemnitz/bobbinlace/meta.json new file mode 100644 index 0000000..1029603 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/meta.json @@ -0,0 +1,24 @@ +[ + { + "name": "", + "id": "fablabchemnitz.de.bobbinlace.", + "path": "bobbinlace", + "dependent_extensions": null, + "original_name": "", + "original_id": "tesselace.", + "license": "GNU GPL v3 / Simplified BSD License", + "license_url": "https://d-bl.github.io/inkscape-bobbinlace/", + "comment": "Mixed licenses", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/bobbinlace", + "fork_url": "https://github.com/d-bl/inkscape-bobbinlace", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Bobbin+Lace", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/d-bl", + "github.com/veronika", + "github.com/Neon22", + "github.com/jo-pol", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/polar_grid.inx b/extensions/fablabchemnitz/bobbinlace/polar_grid.inx new file mode 100644 index 0000000..e0df3b1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/polar_grid.inx @@ -0,0 +1,71 @@ + + + Bobbin Lace - Polar Grid + fablabchemnitz.de.bobbinlace.polar_grid + + + + 45.0 + + + 180 + + + + + + + + + + + + + + + + + 160 + + + + + + + + + + 100 + + + + + + + + + + 0.5 + + + + + + + + + + 255 + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/polar_grid.py b/extensions/fablabchemnitz/bobbinlace/polar_grid.py new file mode 100644 index 0000000..1353be5 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/polar_grid.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +# Copyright 2015 Jo Pol +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/. + +from __future__ import division +from math import pi, sin, cos, tan, radians +from lxml import etree + +# We will use the inkex module with the predefined +# Effect base class. +import inkex + +__author__ = 'Jo Pol' +__credits__ = ['Veronika Irvine','Jo Pol','Mark Shafer'] +__license__ = 'GPLv3' + +class PolarGrid(inkex.EffectExtension): + + def add_arguments(self, pars): + pars.add_argument('-a', '--angle', type=float, default=45, help='grid angle (degrees)') + pars.add_argument('-d', '--dots', type=int, default=180, help='number of dots on a circle') + pars.add_argument('-o', '--outerDiameter', type=float, default=160, help='outer diameter (mm)') + pars.add_argument('-i', '--innerDiameter', type=float, default=100, help='minimum inner diameter (mm)') + pars.add_argument('-f', '--fill', type=inkex.Color, default='-6711040', help='dot color') + pars.add_argument('-A', '--alignment', default='outside', help='exact diameter on [inside|outside]') + pars.add_argument('-s', '--size', type=float, default=0.5, help='dot diameter (mm)') + pars.add_argument('-v', '--variant', default='', help='omit rows to get [|rectangle|hexagon1]') + pars.add_argument('-cu', '--circleDiameterUnits', default = 'mm', help = 'Circle diameter is measured in these units') + pars.add_argument('-du', '--dotUnits', default = 'px', help = 'Dot diameter is measured in these unites') + + def group(self, diameter): + """ + Create a group labeled with the diameter + """ + label = 'diameter: {0:.2f} mm'.format(diameter) + attribs = {inkex.addNS('label', 'inkscape'):label} + return etree.SubElement(self.gridContainer, inkex.addNS('g', 'svg'), attribs) + + def dots(self, diameter, circleNr, group): + """ + Draw dots on a grid circle + """ + offset = (circleNr % 2) * 0.5 + for dotNr in range (0, self.options.dots): + a = (dotNr + offset) * self.alpha + x = (diameter / 2.0) * cos(a) + y = (diameter / 2.0) * sin(a) + attribs = {'style':self.dotStyle, 'cx':str(x * self.circleScale), 'cy':str(y * self.circleScale), 'r':self.dotR} + etree.SubElement(group, inkex.addNS('circle', 'svg'), attribs) + + def iterate(self, diameter, circleNr): + """ + Create a group with a ring of dots. + Returns half of the arc length between the dots + which becomes the distance to the next ring. + """ + group = self.group(diameter) + self.dots(diameter, circleNr, group) + self.generatedCircles.append(group) + return diameter * self.change + + def generate(self): + """ + Generate rings with dots, either inside out or outside in + """ + circleNr = 0 + flag_error = False + minimum = 2 * self.options.size * self.options.dots /pi + if minimum < self.options.innerDiameter: + minimum = self.options.innerDiameter + else: + flag_error = True + if self.options.alignment == 'outside': + diameter = self.options.outerDiameter + while diameter > minimum: + diameter -= self.iterate(diameter, circleNr) + circleNr += 1 + else: + diameter = minimum + while diameter < self.options.outerDiameter: + diameter += self.iterate(diameter, circleNr) + circleNr += 1 + # Display message + if flag_error: + # Leave message on top + font_height = 8 + text_style = { 'font-size': str(font_height), + 'font-family': 'sans-serif', + 'text-anchor': 'middle', + 'text-align': 'center', + 'fill': '#000000' } + text_atts = {'style':str(inkex.Style(text_style)), + 'x': '0', 'y': '0'} + text = etree.SubElement(self.gridContainer, 'text', text_atts) + text.text = "Dots overlap. inner changed to %4.1f" % (minimum) + + def removeGroups(self, start, increment): + """ + Remove complete rings with dots + """ + for i in range(start, len(self.generatedCircles), increment): + self.svg.get_current_layer().remove(self.generatedCircles[i]) + + def removeDots(self, i, offset, step): + """ + Remove dots from one circle + """ + group = self.generatedCircles[i] + dots = list(group) + start = len(dots) - 1 - offset + for j in range(start, -1, 0-step): + group.remove(dots[j]) + + def computations(self, angle): + self.alpha = radians(360.0 / self.options.dots) + correction = pi / (4 * self.options.dots) + correction *= tan(angle*0.93) + self.change = tan(angle - correction) * pi / self.options.dots + + def effect(self): + """ + Effect behaviour. + Overrides base class' method and draws something. + """ + + # constants + self.dotStyle = str(inkex.Style({'fill': self.options.fill.to_rgb(),'stroke':'none'})) + self.dotScale = self.svg.unittouu("1" + self.options.dotUnits) + self.dotR = str(self.options.size * (self.dotScale/2)) + self.circleScale = self.svg.unittouu("1" + self.options.circleDiameterUnits) + self.computations(radians(self.options.angle)) + + # processing variables + self.generatedCircles = [] + self.gridContainer = self.svg.get_current_layer() + + self.generate() + + if self.options.variant == 'rectangle': + self.removeGroups(1, 2) + elif self.options.variant == 'hexagon1': + self.removeGroups(0, 3) + elif self.options.variant == 'hexagon2' or self.options.variant == 'snow2': + for i in range(0, len(self.generatedCircles), 1): + self.removeDots(i, (((i%2)+1)*2)%3, 3) + elif self.options.variant == 'hexagon3': + for i in range(0, len(self.generatedCircles), 2): + self.removeDots(i, (i//2+1)%2, 2) + elif self.options.variant == 'hexagon4': + self.removeGroups(0, 4) + elif self.options.variant == 'hexagon5' or self.options.variant == 'snow1': + for i in range(0, len(self.generatedCircles), 2): + self.removeDots(i, 1, 2) + + self.dotStyle = str(inkex.Style({'fill': 'none','stroke':self.options.fill.to_rgb(),'stroke-width':0.7})) + self.dotR = str((((self.options.innerDiameter * pi) / self.options.dots) / 2) * self.dotScale) + self.generatedCircles = [] + if self.options.variant == 'snow2': + self.options.dots = self.options.dots // 3 + self.computations(radians(self.options.angle)) + self.generate() + elif self.options.variant == 'snow1': + self.generate() + self.removeGroups(1, 2) + for i in range(0, len(self.generatedCircles), 2): + self.removeDots(i, i%4, 2) + for i in range(0, len(self.generatedCircles), 2): + self.removeDots(i, (i+1)%2, 2) + for i in range(2, len(self.generatedCircles), 4): + self.removeDots(i, 0, self.options.dots) + +if __name__ == '__main__': + PolarGrid().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/regular_grid.inx b/extensions/fablabchemnitz/bobbinlace/regular_grid.inx new file mode 100644 index 0000000..8801b1f --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/regular_grid.inx @@ -0,0 +1,60 @@ + + + Bobbin Lace - Regular Grid + fablabchemnitz.de.bobbinlace.regular_grid + + + + + 45.0 + + + 5.0 + + + + + + + + + + + 50 + + + + + + + + + + 50 + + + + 2 + + + + + + + + + + 255 + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/regular_grid.py b/extensions/fablabchemnitz/bobbinlace/regular_grid.py new file mode 100644 index 0000000..3e54d0b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/regular_grid.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2017, Veronika Irvine +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from math import sin, cos, radians, ceil +import inkex +from lxml import etree + +__author__ = 'Veronika Irvine' +__credits__ = ['Ben Connors', 'Veronika Irvine', 'Mark Shafer'] +__license__ = 'Simplified BSD' + +class RegularGrid(inkex.EffectExtension): + def circle(self, x, y, r, fill): + # define the stroke style + s = {'fill': fill} + + # create attributes from style and define path + attribs = {'style':str(inkex.Style(s)), + 'cx':str(x), + 'cy':str(y), + 'r':str(r)} + + # insert path object into current layer + etree.SubElement(self.svg.get_current_layer(), inkex.addNS('circle', 'svg'), attribs) + + def drawDot(self, x, y): + self.circle(x, y, self.options.dotwidth, self.options.dotcolor) + + def draw(self): + + a = self.options.distance + theta = self.options.angle + + hgrid = a*sin(theta); + vgrid = a*cos(theta) + rows = int(ceil(self.options.height / vgrid)) + cols = int(ceil(self.options.width / hgrid)) + y = 0.0 + + for r in range(rows): + x = 0.0 + if (r % 2 == 1): + x += hgrid + + for c in range(ceil(cols/2)): + self.drawDot(x, y) + x += 2.0*hgrid; + + y += vgrid; + + def add_arguments(self, pars): + pars.add_argument('--angle', type=float) + pars.add_argument('--distance', type=float) + pars.add_argument('--pinunits') + pars.add_argument('--width', type=float) + pars.add_argument('--patchunits') + pars.add_argument('--height', type=float) + pars.add_argument('--dotwidth', type=float) + pars.add_argument('--dotunits') + pars.add_argument('--dotcolor', type=inkex.Color) + + def effect(self): + """ + Effect behaviour. + Overrides base class' method and draws something. + """ + # Convert user input to universal units + self.options.width = self.svg.unittouu(str(self.options.width)+self.options.patchunits) + self.options.height = self.svg.unittouu(str(self.options.height)+self.options.patchunits) + self.options.distance = self.svg.unittouu(str(self.options.distance)+self.options.pinunits) + # Convert from diameter to radius + self.options.dotwidth = self.svg.unittouu(str(self.options.dotwidth)+self.options.dotunits)/2 + # Users expect distance to be the vertical distance between footside pins + # (vertical distance between every other row) but in the script we use it + # as as diagonal distance between grid points + # therefore convert distance based on the angle chosen + self.options.angle = radians(self.options.angle) + self.options.distance = self.options.distance/(2.0*cos(self.options.angle)) + + # Draw a grid of dots based on user inputs + self.options.dotcolor = self.options.dotcolor.to_rgb() + self.draw() + +if __name__ == '__main__': + RegularGrid().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/bobbinlace/templates/1x1_1.png b/extensions/fablabchemnitz/bobbinlace/templates/1x1_1.png new file mode 100644 index 0000000..acd38ae Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/1x1_1.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/1x1_1.txt b/extensions/fablabchemnitz/bobbinlace/templates/1x1_1.txt new file mode 100644 index 0000000..48d6163 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/1x1_1.txt @@ -0,0 +1,2 @@ +CHECKER 1 1 +[0,0,1,0,-1,1] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x1_2.png b/extensions/fablabchemnitz/bobbinlace/templates/2x1_2.png new file mode 100644 index 0000000..5ff8782 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x1_2.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x1_2.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x1_2.txt new file mode 100644 index 0000000..17f40db --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x1_2.txt @@ -0,0 +1,3 @@ +CHECKER 2 1 +[0,0,1,0,0,1] +[0,1,-1,1,0,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x2_2.png b/extensions/fablabchemnitz/bobbinlace/templates/2x2_2.png new file mode 100644 index 0000000..32e66ce Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x2_2.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x2_2.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x2_2.txt new file mode 100644 index 0000000..b3f6a7b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x2_2.txt @@ -0,0 +1,3 @@ +CHECKER 2 2 +[0,0,1,0,-1,0] [1,0,0,1,2,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x2_5.png b/extensions/fablabchemnitz/bobbinlace/templates/2x2_5.png new file mode 100644 index 0000000..6b3be64 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x2_5.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x2_5.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x2_5.txt new file mode 100644 index 0000000..8f22cfe --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x2_5.txt @@ -0,0 +1,3 @@ +CHECKER 2 2 +[0,0,1,0,-1,1] [1,0,2,0,1,1] +[1,1,0,2,1,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_1.png b/extensions/fablabchemnitz/bobbinlace/templates/2x4_1.png new file mode 100644 index 0000000..ccb6225 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x4_1.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_1.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x4_1.txt new file mode 100644 index 0000000..7bf3607 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x4_1.txt @@ -0,0 +1,3 @@ +CHECKER 2 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,3,0,1,1] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,2,1,0,2] [2,1,3,1,1,2] [3,1,2,2,4,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_10.png b/extensions/fablabchemnitz/bobbinlace/templates/2x4_10.png new file mode 100644 index 0000000..22aef0a Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x4_10.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_10.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x4_10.txt new file mode 100644 index 0000000..990f4a3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x4_10.txt @@ -0,0 +1,3 @@ +CHECKER 2 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,2] [3,1,2,2,4,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_11.png b/extensions/fablabchemnitz/bobbinlace/templates/2x4_11.png new file mode 100644 index 0000000..d3daaff Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x4_11.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_11.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x4_11.txt new file mode 100644 index 0000000..ee05656 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x4_11.txt @@ -0,0 +1,3 @@ +CHECKER 2 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,4,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_4.png b/extensions/fablabchemnitz/bobbinlace/templates/2x4_4.png new file mode 100644 index 0000000..8720da4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x4_4.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_4.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x4_4.txt new file mode 100644 index 0000000..0d58835 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x4_4.txt @@ -0,0 +1,3 @@ +CHECKER 2 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,0,2] [2,1,1,2,3,2] [3,1,2,1,4,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_7.png b/extensions/fablabchemnitz/bobbinlace/templates/2x4_7.png new file mode 100644 index 0000000..1b63bbc Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x4_7.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_7.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x4_7.txt new file mode 100644 index 0000000..d317997 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x4_7.txt @@ -0,0 +1,3 @@ +CHECKER 2 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,2] [3,1,3,2,4,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_8.png b/extensions/fablabchemnitz/bobbinlace/templates/2x4_8.png new file mode 100644 index 0000000..7e9f464 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/2x4_8.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/2x4_8.txt b/extensions/fablabchemnitz/bobbinlace/templates/2x4_8.txt new file mode 100644 index 0000000..d7e3b97 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/2x4_8.txt @@ -0,0 +1,3 @@ +CHECKER 2 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/3x3_1.png b/extensions/fablabchemnitz/bobbinlace/templates/3x3_1.png new file mode 100644 index 0000000..3ac3a6c Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/3x3_1.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/3x3_1.txt b/extensions/fablabchemnitz/bobbinlace/templates/3x3_1.txt new file mode 100644 index 0000000..16b89fc --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/3x3_1.txt @@ -0,0 +1,4 @@ +CHECKER 3 3 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] +[0,1,1,1,-1,1] [1,1,2,1,0,2] [2,1,1,2,3,2] +[0,2,1,2,-1,2] [1,2,2,2,0,3] [2,2,1,3,3,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/3x3_3.png b/extensions/fablabchemnitz/bobbinlace/templates/3x3_3.png new file mode 100644 index 0000000..cd268ec Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/3x3_3.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/3x3_3.txt b/extensions/fablabchemnitz/bobbinlace/templates/3x3_3.txt new file mode 100644 index 0000000..485f98b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/3x3_3.txt @@ -0,0 +1,3 @@ +CHECKER 3 3 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,3,0,2,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_10.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_10.png new file mode 100644 index 0000000..820c683 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_10.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_10.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_10.txt new file mode 100644 index 0000000..1ff626d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_10.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,2,1,3,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_100.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_100.png new file mode 100644 index 0000000..739ddf8 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_100.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_100.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_100.txt new file mode 100644 index 0000000..074d0c7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_100.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_101.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_101.png new file mode 100644 index 0000000..76beff7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_101.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_101.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_101.txt new file mode 100644 index 0000000..d8becdf --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_101.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,0,4,1,3] [2,2,3,2,1,3] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_102.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_102.png new file mode 100644 index 0000000..1e93c65 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_102.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_102.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_102.txt new file mode 100644 index 0000000..952e612 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_102.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,1,2,2,2] [3,1,2,2,3,2] +[0,2,0,4,1,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_103.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_103.png new file mode 100644 index 0000000..bbf7615 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_103.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_103.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_103.txt new file mode 100644 index 0000000..ece15f7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_103.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,2] [3,0,2,0,3,2] +[1,1,0,2,2,2] +[0,2,0,4,1,3] [2,2,3,2,1,3] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_104.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_104.png new file mode 100644 index 0000000..2fb68ab Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_104.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_104.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_104.txt new file mode 100644 index 0000000..8f19ae5 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_104.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,2] [3,0,2,0,3,2] +[1,1,0,2,1,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_105.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_105.png new file mode 100644 index 0000000..fb40d23 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_105.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_105.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_105.txt new file mode 100644 index 0000000..44b88b4 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_105.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,2] [3,0,2,0,3,2] +[1,1,1,2,2,2] +[0,2,0,4,1,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_106.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_106.png new file mode 100644 index 0000000..1331742 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_106.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_106.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_106.txt new file mode 100644 index 0000000..a953d5e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_106.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,2] [2,0,2,2,3,1] [3,0,2,0,3,1] +[3,1,2,2,3,2] +[0,2,0,4,1,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_107.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_107.png new file mode 100644 index 0000000..13b0eb4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_107.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_107.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_107.txt new file mode 100644 index 0000000..9d51cbb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_107.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,2] [3,1,2,2,4,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_108.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_108.png new file mode 100644 index 0000000..bad38b1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_108.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_108.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_108.txt new file mode 100644 index 0000000..ad36e4e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_108.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_109.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_109.png new file mode 100644 index 0000000..d4dad84 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_109.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_109.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_109.txt new file mode 100644 index 0000000..72311f1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_109.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,2,2,4,2] +[0,2,0,4,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_11.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_11.png new file mode 100644 index 0000000..0c2b80b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_11.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_11.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_11.txt new file mode 100644 index 0000000..4f15e22 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_11.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,2,1,3,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,1,2,2,2] [2,1,1,1,2,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_110.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_110.png new file mode 100644 index 0000000..9cf800f Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_110.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_110.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_110.txt new file mode 100644 index 0000000..81e90a5 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_110.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_111.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_111.png new file mode 100644 index 0000000..4462267 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_111.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_111.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_111.txt new file mode 100644 index 0000000..2bf6b35 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_111.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_112.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_112.png new file mode 100644 index 0000000..ca2647e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_112.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_112.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_112.txt new file mode 100644 index 0000000..48adeed --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_112.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,4,2] +[0,2,0,4,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_113.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_113.png new file mode 100644 index 0000000..a866db2 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_113.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_113.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_113.txt new file mode 100644 index 0000000..a7e2d20 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_113.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,3,0,2,2] [3,0,4,0,3,1] +[3,1,3,2,4,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_114.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_114.png new file mode 100644 index 0000000..2b25854 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_114.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_114.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_114.txt new file mode 100644 index 0000000..9656dda --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_114.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [3,1,2,2,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_115.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_115.png new file mode 100644 index 0000000..c205e00 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_115.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_115.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_115.txt new file mode 100644 index 0000000..742ec2d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_115.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_116.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_116.png new file mode 100644 index 0000000..82773d9 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_116.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_116.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_116.txt new file mode 100644 index 0000000..eba8c00 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_116.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_117.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_117.png new file mode 100644 index 0000000..c55ebb4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_117.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_117.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_117.txt new file mode 100644 index 0000000..9b7614a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_117.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,3,0,3,1] [3,0,4,0,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_118.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_118.png new file mode 100644 index 0000000..146b85d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_118.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_118.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_118.txt new file mode 100644 index 0000000..b3dfe8d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_118.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,3,0,2,2] [3,0,4,0,3,2] +[1,1,0,2,1,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_119.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_119.png new file mode 100644 index 0000000..8e2b5d1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_119.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_119.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_119.txt new file mode 100644 index 0000000..78548e7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_119.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,3,0,1,1] [3,0,4,0,3,2] +[1,1,1,2,2,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_12.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_12.png new file mode 100644 index 0000000..8a4e4cb Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_12.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_12.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_12.txt new file mode 100644 index 0000000..208a790 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_12.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_120.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_120.png new file mode 100644 index 0000000..e90eac3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_120.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_120.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_120.txt new file mode 100644 index 0000000..dbf9d6e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_120.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,3,0,1,1] [3,0,4,0,3,2] +[1,1,0,2,2,2] +[0,2,-1,2,1,3] [2,2,1,3,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_121.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_121.png new file mode 100644 index 0000000..df07a83 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_121.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_121.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_121.txt new file mode 100644 index 0000000..85e8908 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_121.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,3,0,3,1] [3,0,4,0,3,1] +[3,1,2,2,3,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_122.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_122.png new file mode 100644 index 0000000..e35b83c Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_122.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_122.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_122.txt new file mode 100644 index 0000000..78b1462 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_122.txt @@ -0,0 +1,4 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,3,0,2,2] [3,0,4,0,3,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] [3,2,2,2,3,4] +[1,3,0,4,1,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_124.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_124.png new file mode 100644 index 0000000..0af4861 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_124.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_124.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_124.txt new file mode 100644 index 0000000..4b92ac3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_124.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,3,0,1,1] [3,0,4,0,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_126.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_126.png new file mode 100644 index 0000000..d9ceeea Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_126.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_126.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_126.txt new file mode 100644 index 0000000..2d3ff51 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_126.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,3,0,1,1] [3,0,4,0,3,1] +[1,1,0,2,1,3] [3,1,3,3,4,2] +[0,2,-1,3,1,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_127.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_127.png new file mode 100644 index 0000000..361d544 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_127.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_127.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_127.txt new file mode 100644 index 0000000..92f30cf --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_127.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,3,0,2,2] [3,0,4,0,3,1] +[3,1,3,2,4,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_128.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_128.png new file mode 100644 index 0000000..c5b70fe Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_128.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_128.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_128.txt new file mode 100644 index 0000000..aefd200 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_128.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_129.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_129.png new file mode 100644 index 0000000..f514ce0 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_129.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_129.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_129.txt new file mode 100644 index 0000000..4936945 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_129.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,1,1,0,2] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,1,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_13.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_13.png new file mode 100644 index 0000000..397193b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_13.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_13.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_13.txt new file mode 100644 index 0000000..1854a7f --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_13.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,2,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_130.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_130.png new file mode 100644 index 0000000..a371cfa Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_130.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_130.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_130.txt new file mode 100644 index 0000000..0158ec1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_130.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_131.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_131.png new file mode 100644 index 0000000..fcd2d4b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_131.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_131.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_131.txt new file mode 100644 index 0000000..78723e9 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_131.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_132.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_132.png new file mode 100644 index 0000000..a4ae8c6 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_132.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_132.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_132.txt new file mode 100644 index 0000000..363c063 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_132.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,3,1] [3,0,4,0,3,1] +[0,1,1,1,0,2] [1,1,1,2,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,1,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_133.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_133.png new file mode 100644 index 0000000..389e6f0 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_133.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_133.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_133.txt new file mode 100644 index 0000000..02da742 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_133.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,3,0,3,1] [3,0,4,0,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_134.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_134.png new file mode 100644 index 0000000..4927bee Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_134.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_134.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_134.txt new file mode 100644 index 0000000..ae3c3cc --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_134.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,3,0,3,1] [3,0,4,0,3,1] +[1,1,1,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,1,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_135.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_135.png new file mode 100644 index 0000000..2b4adb3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_135.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_135.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_135.txt new file mode 100644 index 0000000..9529d0d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_135.txt @@ -0,0 +1,4 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,3,0,2,2] [3,0,4,0,3,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_136.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_136.png new file mode 100644 index 0000000..49b438d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_136.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_136.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_136.txt new file mode 100644 index 0000000..2ffadf9 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_136.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,3,0,3,1] [3,0,4,0,3,1] +[3,1,2,2,3,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_137.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_137.png new file mode 100644 index 0000000..b782bb2 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_137.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_137.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_137.txt new file mode 100644 index 0000000..0341ff8 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_137.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_138.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_138.png new file mode 100644 index 0000000..b65039b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_138.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_138.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_138.txt new file mode 100644 index 0000000..172d335 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_138.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,2] [3,1,2,2,4,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_139.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_139.png new file mode 100644 index 0000000..f9b33fd Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_139.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_139.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_139.txt new file mode 100644 index 0000000..d01aa16 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_139.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_14.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_14.png new file mode 100644 index 0000000..723aa62 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_14.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_14.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_14.txt new file mode 100644 index 0000000..814505a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_14.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [2,1,3,1,1,1] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_140.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_140.png new file mode 100644 index 0000000..cc956fb Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_140.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_140.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_140.txt new file mode 100644 index 0000000..df05846 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_140.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_142.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_142.png new file mode 100644 index 0000000..cb97b95 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_142.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_142.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_142.txt new file mode 100644 index 0000000..48742b1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_142.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,3] [3,1,3,3,4,2] +[0,2,-1,3,1,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_143.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_143.png new file mode 100644 index 0000000..5c45e72 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_143.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_143.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_143.txt new file mode 100644 index 0000000..4774afd --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_143.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_144.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_144.png new file mode 100644 index 0000000..624d5e4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_144.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_144.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_144.txt new file mode 100644 index 0000000..2da23a6 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_144.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,4,2] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_145.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_145.png new file mode 100644 index 0000000..d333ffd Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_145.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_145.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_145.txt new file mode 100644 index 0000000..8308e8b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_145.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_146.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_146.png new file mode 100644 index 0000000..44092ad Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_146.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_146.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_146.txt new file mode 100644 index 0000000..0ee845d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_146.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,3,2,4,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_147.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_147.png new file mode 100644 index 0000000..8d6b955 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_147.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_147.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_147.txt new file mode 100644 index 0000000..d5349dd --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_147.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,1,1,0,2] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,1,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_148.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_148.png new file mode 100644 index 0000000..1d7e529 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_148.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_148.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_148.txt new file mode 100644 index 0000000..c7c6021 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_148.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_149.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_149.png new file mode 100644 index 0000000..0355bf2 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_149.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_149.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_149.txt new file mode 100644 index 0000000..b3f7c2e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_149.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_15.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_15.png new file mode 100644 index 0000000..3c604b1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_15.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_15.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_15.txt new file mode 100644 index 0000000..6349250 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_15.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,0,1,2,1] [2,0,1,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [2,1,1,1,3,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [2,2,1,3,2,3] [3,2,4,2,2,2] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_150.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_150.png new file mode 100644 index 0000000..617cfc4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_150.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_150.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_150.txt new file mode 100644 index 0000000..6d40e32 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_150.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_151.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_151.png new file mode 100644 index 0000000..5401404 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_151.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_151.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_151.txt new file mode 100644 index 0000000..33191e1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_151.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_152.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_152.png new file mode 100644 index 0000000..6b20815 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_152.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_152.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_152.txt new file mode 100644 index 0000000..df26518 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_152.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_153.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_153.png new file mode 100644 index 0000000..57c7e4e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_153.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_153.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_153.txt new file mode 100644 index 0000000..28e0261 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_153.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_154.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_154.png new file mode 100644 index 0000000..844d24b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_154.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_154.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_154.txt new file mode 100644 index 0000000..40980c2 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_154.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_155.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_155.png new file mode 100644 index 0000000..145952c Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_155.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_155.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_155.txt new file mode 100644 index 0000000..c06da6a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_155.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_156.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_156.png new file mode 100644 index 0000000..7807af4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_156.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_156.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_156.txt new file mode 100644 index 0000000..9e80bf1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_156.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,1,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_157.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_157.png new file mode 100644 index 0000000..531ebea Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_157.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_157.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_157.txt new file mode 100644 index 0000000..b29ed78 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_157.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_158.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_158.png new file mode 100644 index 0000000..4c94ac1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_158.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_158.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_158.txt new file mode 100644 index 0000000..5e97b68 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_158.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_159.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_159.png new file mode 100644 index 0000000..21f7ae8 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_159.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_159.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_159.txt new file mode 100644 index 0000000..1649a54 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_159.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_161.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_161.png new file mode 100644 index 0000000..9571d30 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_161.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_161.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_161.txt new file mode 100644 index 0000000..ae31c8e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_161.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,2] [3,1,2,2,4,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_162.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_162.png new file mode 100644 index 0000000..85c087d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_162.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_162.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_162.txt new file mode 100644 index 0000000..46180c2 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_162.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,2] [3,1,3,2,4,2] +[0,2,1,2,-1,2] [1,2,2,2,1,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_163.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_163.png new file mode 100644 index 0000000..e297341 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_163.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_163.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_163.txt new file mode 100644 index 0000000..c5ecb05 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_163.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,3] [3,1,3,3,4,2] +[0,2,-1,3,1,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_164.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_164.png new file mode 100644 index 0000000..2d4df29 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_164.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_164.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_164.txt new file mode 100644 index 0000000..10bd468 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_164.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,1,2] [3,1,3,3,4,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_165.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_165.png new file mode 100644 index 0000000..04b1037 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_165.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_165.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_165.txt new file mode 100644 index 0000000..dc9e6b4 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_165.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,2,2] [3,1,3,3,4,2] +[0,2,0,4,1,3] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_166.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_166.png new file mode 100644 index 0000000..9f6400b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_166.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_166.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_166.txt new file mode 100644 index 0000000..0553bba --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_166.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,1,2,2,2] [3,1,3,3,4,2] +[0,2,0,4,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_167.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_167.png new file mode 100644 index 0000000..e3c7519 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_167.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_167.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_167.txt new file mode 100644 index 0000000..16f6a94 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_167.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,1,3] [3,1,2,2,3,2] +[0,2,0,4,1,3] [2,2,3,2,3,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_168.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_168.png new file mode 100644 index 0000000..f45c648 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_168.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_168.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_168.txt new file mode 100644 index 0000000..fe441ab --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_168.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[0,1,1,1,0,2] [1,1,0,2,1,3] [3,1,4,1,2,2] +[0,2,-1,3,0,4] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_169.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_169.png new file mode 100644 index 0000000..2825ee2 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_169.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_169.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_169.txt new file mode 100644 index 0000000..35a0f3c --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_169.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[0,1,1,1,0,2] [1,1,1,2,2,2] [3,1,4,1,3,3] +[0,2,-1,3,0,4] [1,2,0,2,1,3] [2,2,1,2,1,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_17.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_17.png new file mode 100644 index 0000000..e0c74c2 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_17.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_17.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_17.txt new file mode 100644 index 0000000..ebacc6e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_17.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_170.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_170.png new file mode 100644 index 0000000..82e3160 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_170.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_170.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_170.txt new file mode 100644 index 0000000..5d8a089 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_170.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[0,1,1,1,0,2] [1,1,0,2,1,3] [3,1,4,1,3,2] +[0,2,-1,2,0,4] [2,2,1,3,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_171.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_171.png new file mode 100644 index 0000000..2b067f3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_171.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_171.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_171.txt new file mode 100644 index 0000000..ac0edf8 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_171.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,1,3,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,0,4] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_172.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_172.png new file mode 100644 index 0000000..a2f77ab Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_172.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_172.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_172.txt new file mode 100644 index 0000000..0a75642 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_172.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,1,2,2,2] [3,1,3,3,4,2] +[0,2,-1,3,0,4] [1,2,0,2,1,3] [2,2,1,2,1,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_173.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_173.png new file mode 100644 index 0000000..7ca84b4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_173.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_173.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_173.txt new file mode 100644 index 0000000..5a472f7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_173.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,3,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,4] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_174.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_174.png new file mode 100644 index 0000000..d6c4c90 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_174.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_174.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_174.txt new file mode 100644 index 0000000..c0b1a74 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_174.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,0,2,1,3] [3,1,2,2,4,2] +[0,2,-1,3,0,4] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_175.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_175.png new file mode 100644 index 0000000..c984bff Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_175.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_175.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_175.txt new file mode 100644 index 0000000..3c9062a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_175.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,3,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,4] [2,2,1,3,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_176.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_176.png new file mode 100644 index 0000000..7bb40ee Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_176.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_176.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_176.txt new file mode 100644 index 0000000..1429d3d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_176.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,3,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,4] [2,2,1,3,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_177.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_177.png new file mode 100644 index 0000000..e182bc1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_177.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_177.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_177.txt new file mode 100644 index 0000000..f44e2d2 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_177.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,3,3] +[0,2,-1,3,1,3] [2,2,1,3,2,4] +[1,3,0,4,1,4] [3,3,3,5,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_178.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_178.png new file mode 100644 index 0000000..0a41ea9 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_178.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_178.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_178.txt new file mode 100644 index 0000000..6e20e13 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_178.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,0,2,1,3] [3,1,3,2,4,2] +[0,2,-1,2,0,4] [2,2,1,3,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_179.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_179.png new file mode 100644 index 0000000..df45541 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_179.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_179.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_179.txt new file mode 100644 index 0000000..37ea243 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_179.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,3] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[1,3,0,4,1,4] [3,3,3,5,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_18.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_18.png new file mode 100644 index 0000000..77deb5f Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_18.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_18.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_18.txt new file mode 100644 index 0000000..54edbe0 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_18.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_180.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_180.png new file mode 100644 index 0000000..df4744f Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_180.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_180.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_180.txt new file mode 100644 index 0000000..ab3130d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_180.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,3,3] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[1,3,0,4,1,4] [3,3,3,5,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_181.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_181.png new file mode 100644 index 0000000..585eb22 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_181.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_181.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_181.txt new file mode 100644 index 0000000..a7083d7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_181.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,0,2,1,3] [3,1,3,2,4,2] +[0,2,-1,2,-1,3] [2,2,1,3,2,4] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,3,5,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_182.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_182.png new file mode 100644 index 0000000..8cfbbbb Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_182.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_182.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_182.txt new file mode 100644 index 0000000..2b4936e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_182.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,2,2,3,3] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[1,3,0,4,1,4] [3,3,3,5,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_183.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_183.png new file mode 100644 index 0000000..5de6699 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_183.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_183.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_183.txt new file mode 100644 index 0000000..8b2d33f --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_183.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_184.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_184.png new file mode 100644 index 0000000..4f240dd Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_184.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_184.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_184.txt new file mode 100644 index 0000000..2497ecf --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_184.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,1,1] [3,0,4,0,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [3,1,2,2,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_185.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_185.png new file mode 100644 index 0000000..b40cbb9 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_185.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_185.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_185.txt new file mode 100644 index 0000000..39bfd76 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_185.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,1,1,0,2] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [2,2,1,3,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_186.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_186.png new file mode 100644 index 0000000..f1d9fd6 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_186.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_186.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_186.txt new file mode 100644 index 0000000..d3362b3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_186.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,1,1,0,2] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_187.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_187.png new file mode 100644 index 0000000..c4cc88c Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_187.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_187.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_187.txt new file mode 100644 index 0000000..fd1fc40 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_187.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_188.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_188.png new file mode 100644 index 0000000..f4e5db1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_188.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_188.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_188.txt new file mode 100644 index 0000000..3c97bd3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_188.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,3,1] [3,0,4,0,3,1] +[0,1,1,1,0,2] [1,1,1,2,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_189.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_189.png new file mode 100644 index 0000000..2919ab5 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_189.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_189.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_189.txt new file mode 100644 index 0000000..cac9f5d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_189.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_19.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_19.png new file mode 100644 index 0000000..fb1cd91 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_19.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_19.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_19.txt new file mode 100644 index 0000000..e7553c6 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_19.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_190.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_190.png new file mode 100644 index 0000000..23cf703 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_190.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_190.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_190.txt new file mode 100644 index 0000000..8e626db --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_190.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,2] [3,1,2,2,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_191.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_191.png new file mode 100644 index 0000000..dc2c340 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_191.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_191.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_191.txt new file mode 100644 index 0000000..5d67373 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_191.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_192.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_192.png new file mode 100644 index 0000000..89960cf Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_192.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_192.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_192.txt new file mode 100644 index 0000000..8966e72 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_192.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_193.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_193.png new file mode 100644 index 0000000..cd5348a Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_193.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_193.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_193.txt new file mode 100644 index 0000000..790cb17 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_193.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,2,3,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_194.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_194.png new file mode 100644 index 0000000..6daa193 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_194.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_194.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_194.txt new file mode 100644 index 0000000..32bf097 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_194.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_195.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_195.png new file mode 100644 index 0000000..68c5272 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_195.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_195.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_195.txt new file mode 100644 index 0000000..463f7d5 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_195.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,1,1,0,2] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [2,2,1,3,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_196.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_196.png new file mode 100644 index 0000000..e324703 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_196.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_196.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_196.txt new file mode 100644 index 0000000..d85e699 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_196.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [3,1,2,2,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_197.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_197.png new file mode 100644 index 0000000..7e9c0f4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_197.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_197.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_197.txt new file mode 100644 index 0000000..0d2f228 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_197.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,1,1,0,2] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_198.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_198.png new file mode 100644 index 0000000..5be86fd Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_198.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_198.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_198.txt new file mode 100644 index 0000000..28a5452 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_198.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_199.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_199.png new file mode 100644 index 0000000..747e7f7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_199.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_199.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_199.txt new file mode 100644 index 0000000..f3b6406 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_199.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,1,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,1,2,-1,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_2.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_2.png new file mode 100644 index 0000000..64422b4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_2.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_2.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_2.txt new file mode 100644 index 0000000..3619582 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_2.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,0,1] [2,0,1,1,2,1] +[0,1,1,1,-1,2] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,4,1,2,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_20.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_20.png new file mode 100644 index 0000000..cf7dcea Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_20.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_20.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_20.txt new file mode 100644 index 0000000..fae8478 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_20.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_200.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_200.png new file mode 100644 index 0000000..92166fd Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_200.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_200.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_200.txt new file mode 100644 index 0000000..4613943 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_200.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[0,1,-1,1,0,2] [1,1,0,1,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_201.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_201.png new file mode 100644 index 0000000..221fae7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_201.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_201.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_201.txt new file mode 100644 index 0000000..d74fc0b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_201.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,-1,3] [2,2,1,3,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_202.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_202.png new file mode 100644 index 0000000..e0bbc18 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_202.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_202.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_202.txt new file mode 100644 index 0000000..ece142d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_202.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,-1,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_203.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_203.png new file mode 100644 index 0000000..3fcb531 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_203.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_203.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_203.txt new file mode 100644 index 0000000..e33d433 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_203.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,1,2] [3,1,3,3,4,2] +[0,2,1,2,0,4] [1,2,2,2,1,3] [2,2,2,3,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_204.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_204.png new file mode 100644 index 0000000..2c24b8e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_204.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_204.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_204.txt new file mode 100644 index 0000000..1f4b9ce --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_204.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,2,2] [3,1,3,3,4,2] +[0,2,0,4,1,3] [2,2,2,3,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_205.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_205.png new file mode 100644 index 0000000..19b5d4e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_205.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_205.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_205.txt new file mode 100644 index 0000000..985778e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_205.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,1,3,2,2] [3,1,3,2,4,2] +[0,2,-1,3,0,4] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_206.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_206.png new file mode 100644 index 0000000..d34a497 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_206.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_206.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_206.txt new file mode 100644 index 0000000..d66d209 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_206.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[0,1,1,1,0,2] [1,1,0,2,2,2] [3,1,4,1,3,3] +[0,2,-1,3,0,4] [2,2,1,3,2,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_207.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_207.png new file mode 100644 index 0000000..43bb63c Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_207.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_207.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_207.txt new file mode 100644 index 0000000..385ad33 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_207.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[0,1,1,1,0,2] [1,1,1,2,2,2] [3,1,4,1,3,3] +[0,2,-1,3,0,4] [1,2,0,2,1,3] [2,2,1,2,2,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_208.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_208.png new file mode 100644 index 0000000..0736f67 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_208.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_208.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_208.txt new file mode 100644 index 0000000..d837f52 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_208.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,0,2,2,2] [3,1,3,3,4,2] +[0,2,-1,3,0,4] [2,2,1,3,2,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_209.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_209.png new file mode 100644 index 0000000..3b8d076 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_209.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_209.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_209.txt new file mode 100644 index 0000000..c219a05 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_209.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,1,1] [1,0,2,0,1,1] [2,0,2,2,3,1] +[1,1,0,2,1,3] [3,1,2,2,4,2] +[0,2,-1,3,0,4] [2,2,2,3,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_21.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_21.png new file mode 100644 index 0000000..7cf15be Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_21.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_21.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_21.txt new file mode 100644 index 0000000..39c2084 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_21.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_210.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_210.png new file mode 100644 index 0000000..4d96833 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_210.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_210.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_210.txt new file mode 100644 index 0000000..3c89bf7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_210.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,1,3,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,0,4] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_211.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_211.png new file mode 100644 index 0000000..437d10b Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_211.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_211.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_211.txt new file mode 100644 index 0000000..3cdcb38 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_211.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,3,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,4] [2,2,3,2,2,3] [3,2,4,2,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_212.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_212.png new file mode 100644 index 0000000..dbba2e7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_212.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_212.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_212.txt new file mode 100644 index 0000000..9aaddbe --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_212.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,3,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,4] [2,2,2,3,3,3] +[1,3,0,4,1,4] [2,3,1,3,2,4] [3,3,2,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_213.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_213.png new file mode 100644 index 0000000..850a9e3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_213.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_213.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_213.txt new file mode 100644 index 0000000..85aedd3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_213.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,2,2,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_214.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_214.png new file mode 100644 index 0000000..62b2bf4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_214.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_214.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_214.txt new file mode 100644 index 0000000..8139518 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_214.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,0,1,2,1] [2,0,1,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [2,1,1,1,3,2] [3,1,4,1,2,1] +[0,2,0,4,1,3] [2,2,1,3,2,4] [3,2,4,2,2,2] +[1,3,0,4,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_215.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_215.png new file mode 100644 index 0000000..83bb398 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_215.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_215.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_215.txt new file mode 100644 index 0000000..c6d2f62 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_215.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,-1,1,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_217.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_217.png new file mode 100644 index 0000000..4a30c96 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_217.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_217.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_217.txt new file mode 100644 index 0000000..6f1b997 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_217.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,2,2,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,0,4,2,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_219.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_219.png new file mode 100644 index 0000000..3bad031 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_219.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_219.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_219.txt new file mode 100644 index 0000000..3ff3dfe --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_219.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,-1,1,1,1] [2,0,1,1,2,2] +[1,1,0,2,2,2] [3,1,3,3,4,2] +[0,2,0,4,1,3] [2,2,1,3,3,3] +[1,3,0,4,2,4] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_22.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_22.png new file mode 100644 index 0000000..e486e32 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_22.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_22.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_22.txt new file mode 100644 index 0000000..419aada --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_22.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_220.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_220.png new file mode 100644 index 0000000..0825533 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_220.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_220.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_220.txt new file mode 100644 index 0000000..d119e19 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_220.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,3,3] +[0,2,-1,3,0,4] [1,2,0,2,1,4] [2,2,1,2,2,4] +[3,3,3,5,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_221.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_221.png new file mode 100644 index 0000000..0aa0bde Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_221.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_221.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_221.txt new file mode 100644 index 0000000..4b75916 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_221.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,-1,1,0,2] [2,0,1,1,2,2] +[1,1,1,3,2,2] [3,1,3,3,4,2] +[0,2,0,4,1,3] [2,2,2,4,3,3] +[1,3,0,4,1,5] [3,3,2,4,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_23.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_23.png new file mode 100644 index 0000000..98db8f7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_23.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_23.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_23.txt new file mode 100644 index 0000000..a488c89 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_23.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_24.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_24.png new file mode 100644 index 0000000..0ad7d2e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_24.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_24.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_24.txt new file mode 100644 index 0000000..c3a305e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_24.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_25.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_25.png new file mode 100644 index 0000000..db877f1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_25.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_25.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_25.txt new file mode 100644 index 0000000..22d06f9 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_25.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_26.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_26.png new file mode 100644 index 0000000..792fd2d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_26.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_26.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_26.txt new file mode 100644 index 0000000..3db6bd9 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_26.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_27.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_27.png new file mode 100644 index 0000000..2690210 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_27.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_27.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_27.txt new file mode 100644 index 0000000..d8fb034 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_27.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_28.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_28.png new file mode 100644 index 0000000..c40220d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_28.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_28.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_28.txt new file mode 100644 index 0000000..2890ac1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_28.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_29.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_29.png new file mode 100644 index 0000000..c58c784 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_29.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_29.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_29.txt new file mode 100644 index 0000000..3477bfa --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_29.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,1,3] [3,1,3,3,4,2] +[0,2,-1,3,0,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_30.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_30.png new file mode 100644 index 0000000..7671912 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_30.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_30.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_30.txt new file mode 100644 index 0000000..34361eb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_30.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,2,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_31.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_31.png new file mode 100644 index 0000000..bd20a6e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_31.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_31.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_31.txt new file mode 100644 index 0000000..749967a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_31.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,2,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_32.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_32.png new file mode 100644 index 0000000..7af82e0 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_32.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_32.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_32.txt new file mode 100644 index 0000000..ecd6eee --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_32.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,2,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_33.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_33.png new file mode 100644 index 0000000..45567cf Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_33.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_33.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_33.txt new file mode 100644 index 0000000..d7d65c1 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_33.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,0,1] [2,0,1,1,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [3,1,4,1,2,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_34.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_34.png new file mode 100644 index 0000000..4d1b151 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_34.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_34.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_34.txt new file mode 100644 index 0000000..1f68044 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_34.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [3,1,4,1,2,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_35.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_35.png new file mode 100644 index 0000000..a50a066 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_35.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_35.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_35.txt new file mode 100644 index 0000000..02ec231 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_35.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,1,2,2,2] [3,1,4,1,2,2] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,2,3] +[1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_37.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_37.png new file mode 100644 index 0000000..66e94ea Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_37.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_37.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_37.txt new file mode 100644 index 0000000..e0fbefb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_37.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_38.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_38.png new file mode 100644 index 0000000..b808ef0 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_38.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_38.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_38.txt new file mode 100644 index 0000000..7f5e8e3 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_38.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_39.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_39.png new file mode 100644 index 0000000..fcaec4f Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_39.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_39.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_39.txt new file mode 100644 index 0000000..e6297e2 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_39.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_4.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_4.png new file mode 100644 index 0000000..afbf4d3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_4.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_4.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_4.txt new file mode 100644 index 0000000..85c1ecb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_4.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,0,1] [2,0,2,1,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_40.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_40.png new file mode 100644 index 0000000..c2273d4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_40.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_40.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_40.txt new file mode 100644 index 0000000..eb47311 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_40.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_41.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_41.png new file mode 100644 index 0000000..fc6bf58 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_41.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_41.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_41.txt new file mode 100644 index 0000000..7d4d567 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_41.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,-1,1,1,2] [1,1,2,1,0,1] [2,1,3,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [1,2,0,2,2,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [2,3,1,3,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_42.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_42.png new file mode 100644 index 0000000..f193ab8 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_42.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_42.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_42.txt new file mode 100644 index 0000000..3e4c6c0 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_42.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,4,1] +[0,1,-1,1,1,2] [1,1,2,1,0,1] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,2,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [2,3,1,3,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_43.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_43.png new file mode 100644 index 0000000..d3a125c Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_43.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_43.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_43.txt new file mode 100644 index 0000000..ed89d2b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_43.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_44.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_44.png new file mode 100644 index 0000000..3c91b31 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_44.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_44.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_44.txt new file mode 100644 index 0000000..1b2b5e4 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_44.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_45.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_45.png new file mode 100644 index 0000000..7abea31 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_45.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_45.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_45.txt new file mode 100644 index 0000000..157e241 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_45.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,-1,1,1,2] [1,1,0,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,2,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [2,3,1,3,3,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_46.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_46.png new file mode 100644 index 0000000..03d8b43 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_46.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_46.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_46.txt new file mode 100644 index 0000000..36258f8 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_46.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_47.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_47.png new file mode 100644 index 0000000..d0fdbfd Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_47.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_47.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_47.txt new file mode 100644 index 0000000..af6529a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_47.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_48.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_48.png new file mode 100644 index 0000000..32b3341 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_48.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_48.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_48.txt new file mode 100644 index 0000000..65c2389 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_48.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,3] [3,1,3,3,4,2] +[0,2,-1,3,0,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_49.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_49.png new file mode 100644 index 0000000..a459ac8 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_49.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_49.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_49.txt new file mode 100644 index 0000000..998d3eb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_49.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,1,2,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_5.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_5.png new file mode 100644 index 0000000..1062e42 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_5.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_5.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_5.txt new file mode 100644 index 0000000..9e8ed7e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_5.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,0,1] [2,0,1,1,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [3,1,4,1,2,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_50.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_50.png new file mode 100644 index 0000000..adbad18 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_50.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_50.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_50.txt new file mode 100644 index 0000000..56d144e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_50.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_51.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_51.png new file mode 100644 index 0000000..1f6ff28 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_51.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_51.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_51.txt new file mode 100644 index 0000000..6cf6db0 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_51.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_52.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_52.png new file mode 100644 index 0000000..4829515 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_52.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_52.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_52.txt new file mode 100644 index 0000000..af4ff95 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_52.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,1,2,2,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_53.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_53.png new file mode 100644 index 0000000..d92f56e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_53.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_53.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_53.txt new file mode 100644 index 0000000..72e1eca --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_53.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_54.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_54.png new file mode 100644 index 0000000..3fa9eb4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_54.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_54.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_54.txt new file mode 100644 index 0000000..0bf224e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_54.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_55.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_55.png new file mode 100644 index 0000000..7249877 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_55.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_55.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_55.txt new file mode 100644 index 0000000..a3f6194 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_55.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_56.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_56.png new file mode 100644 index 0000000..b571e61 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_56.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_56.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_56.txt new file mode 100644 index 0000000..76faacd --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_56.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_57.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_57.png new file mode 100644 index 0000000..2991c77 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_57.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_57.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_57.txt new file mode 100644 index 0000000..13bf602 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_57.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_58.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_58.png new file mode 100644 index 0000000..c8867b3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_58.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_58.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_58.txt new file mode 100644 index 0000000..88ec70d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_58.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_59.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_59.png new file mode 100644 index 0000000..cf3554e Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_59.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_59.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_59.txt new file mode 100644 index 0000000..f298704 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_59.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_6.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_6.png new file mode 100644 index 0000000..cc84035 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_6.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_6.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_6.txt new file mode 100644 index 0000000..f52647b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_6.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,4,1,2,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_60.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_60.png new file mode 100644 index 0000000..db961a0 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_60.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_60.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_60.txt new file mode 100644 index 0000000..c465d2f --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_60.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_61.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_61.png new file mode 100644 index 0000000..5829985 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_61.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_61.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_61.txt new file mode 100644 index 0000000..6b02e39 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_61.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_63.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_63.png new file mode 100644 index 0000000..5a0a877 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_63.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_63.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_63.txt new file mode 100644 index 0000000..7d3bdec --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_63.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,1,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_64.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_64.png new file mode 100644 index 0000000..ccd9717 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_64.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_64.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_64.txt new file mode 100644 index 0000000..4284b83 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_64.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,1,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_65.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_65.png new file mode 100644 index 0000000..982fce9 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_65.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_65.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_65.txt new file mode 100644 index 0000000..ffe1407 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_65.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,1,3] [3,1,3,3,4,2] +[0,2,-1,3,0,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_66.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_66.png new file mode 100644 index 0000000..f401f34 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_66.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_66.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_66.txt new file mode 100644 index 0000000..12904e0 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_66.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[0,1,-1,2,1,2] [1,1,2,1,0,1] [2,1,1,2,3,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [1,2,2,2,0,2] [2,2,1,3,3,3] [3,2,4,2,2,2] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_67.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_67.png new file mode 100644 index 0000000..4d74aaf Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_67.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_67.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_67.txt new file mode 100644 index 0000000..4a29288 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_67.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,2,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_68.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_68.png new file mode 100644 index 0000000..0394b14 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_68.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_68.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_68.txt new file mode 100644 index 0000000..98c0444 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_68.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,2,1,3,1] [3,0,2,0,3,1] +[1,1,0,2,2,2] [2,1,1,1,2,2] [3,1,2,1,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_7.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_7.png new file mode 100644 index 0000000..c7dc2e4 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_7.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_7.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_7.txt new file mode 100644 index 0000000..ad65014 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_7.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,2,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,4,1,2,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_70.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_70.png new file mode 100644 index 0000000..866cb6f Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_70.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_70.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_70.txt new file mode 100644 index 0000000..74c32eb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_70.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,2,2] [3,0,2,0,3,2] +[1,1,0,2,2,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_71.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_71.png new file mode 100644 index 0000000..01edf63 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_71.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_71.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_71.txt new file mode 100644 index 0000000..aa4ae19 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_71.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,2] [2,0,2,2,3,1] [3,0,2,0,3,1] +[3,1,2,2,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_72.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_72.png new file mode 100644 index 0000000..68bc35a Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_72.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_72.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_72.txt new file mode 100644 index 0000000..5b3de1b --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_72.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,2] [2,0,2,2,3,1] [3,0,2,0,3,1] +[3,1,2,2,4,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_73.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_73.png new file mode 100644 index 0000000..bded9f5 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_73.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_73.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_73.txt new file mode 100644 index 0000000..4184a8d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_73.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,2] [2,0,2,2,3,1] [3,0,2,0,3,1] +[3,1,3,2,4,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_74.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_74.png new file mode 100644 index 0000000..cd2a998 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_74.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_74.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_74.txt new file mode 100644 index 0000000..6da0b08 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_74.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,1,3] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,2,4] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_75.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_75.png new file mode 100644 index 0000000..800db4d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_75.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_75.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_75.txt new file mode 100644 index 0000000..5599134 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_75.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[0,1,-1,1,0,2] [1,1,0,1,0,2] [3,1,2,2,3,3] +[0,2,0,3,1,3] [2,2,2,4,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_76.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_76.png new file mode 100644 index 0000000..002e5f9 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_76.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_76.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_76.txt new file mode 100644 index 0000000..0a98179 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_76.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,1,3] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,2,4,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_77.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_77.png new file mode 100644 index 0000000..bc775fe Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_77.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_77.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_77.txt new file mode 100644 index 0000000..8d57c76 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_77.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,2] +[1,1,0,2,1,3] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,2,4,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_78.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_78.png new file mode 100644 index 0000000..53d4286 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_78.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_78.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_78.txt new file mode 100644 index 0000000..12ad8db --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_78.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,2,1] +[1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,2,2,3,3] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_79.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_79.png new file mode 100644 index 0000000..f768700 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_79.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_79.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_79.txt new file mode 100644 index 0000000..da04863 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_79.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,1,2,2,2] [3,1,2,2,3,3] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_8.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_8.png new file mode 100644 index 0000000..300d5df Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_8.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_8.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_8.txt new file mode 100644 index 0000000..e6f24c4 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_8.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [3,1,4,1,2,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_80.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_80.png new file mode 100644 index 0000000..c544091 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_80.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_80.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_80.txt new file mode 100644 index 0000000..bdeaf20 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_80.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,1,3] [3,1,2,2,3,2] +[0,2,-1,2,0,3] [2,2,2,4,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_81.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_81.png new file mode 100644 index 0000000..a96cb81 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_81.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_81.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_81.txt new file mode 100644 index 0000000..3e6c010 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_81.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,3,3] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_82.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_82.png new file mode 100644 index 0000000..22e44d3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_82.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_82.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_82.txt new file mode 100644 index 0000000..4ad32a9 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_82.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,1,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,3] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,1,2,2,4] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_83.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_83.png new file mode 100644 index 0000000..b06385a Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_83.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_83.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_83.txt new file mode 100644 index 0000000..322580e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_83.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,1] [2,0,2,1,3,1] +[1,1,0,2,1,3] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,2,0,3] [2,2,2,4,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,5] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_84.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_84.png new file mode 100644 index 0000000..3423fd7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_84.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_84.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_84.txt new file mode 100644 index 0000000..ec8a81c --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_84.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_85.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_85.png new file mode 100644 index 0000000..07207c1 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_85.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_85.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_85.txt new file mode 100644 index 0000000..a8a1ef0 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_85.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,1,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_86.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_86.png new file mode 100644 index 0000000..fff7379 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_86.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_86.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_86.txt new file mode 100644 index 0000000..b828026 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_86.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,3,2,4,2] +[0,2,-1,2,0,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_87.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_87.png new file mode 100644 index 0000000..5d33a0a Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_87.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_87.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_87.txt new file mode 100644 index 0000000..b1027af --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_87.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,1,3] [2,1,3,1,1,1] [3,1,3,3,4,2] +[0,2,-1,3,0,3] +[0,3,1,3,0,4] [1,3,0,4,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_88.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_88.png new file mode 100644 index 0000000..cbaab18 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_88.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_88.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_88.txt new file mode 100644 index 0000000..c120a98 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_88.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,0,1,2,1] [2,0,1,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [2,1,1,1,3,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [2,2,1,3,3,3] [3,2,4,2,2,2] +[0,3,1,3,0,4] [1,3,0,4,2,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_9.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_9.png new file mode 100644 index 0000000..76fe17d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_9.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_9.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_9.txt new file mode 100644 index 0000000..e129f8c --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_9.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[0,1,1,1,-1,2] [1,1,1,2,2,2] [3,1,4,1,2,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,2,3] +[0,3,1,3,0,4] [1,3,2,3,0,4] [2,3,3,3,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_90.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_90.png new file mode 100644 index 0000000..b326713 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_90.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_90.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_90.txt new file mode 100644 index 0000000..4f91955 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_90.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [2,1,3,1,1,1] [3,1,2,2,4,2] +[0,2,-1,3,0,3] [2,2,2,3,3,3] +[0,3,1,3,0,4] [1,3,0,4,2,4] [2,3,1,3,2,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_91.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_91.png new file mode 100644 index 0000000..009b017 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_91.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_91.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_91.txt new file mode 100644 index 0000000..1c55320 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_91.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,0,1,2,1] [2,0,1,0,3,1] +[0,1,1,1,-1,2] [1,1,0,2,2,2] [2,1,1,1,3,2] [3,1,4,1,2,1] +[0,2,-1,3,0,3] [2,2,2,3,3,3] [3,2,4,2,2,2] +[0,3,1,3,0,4] [1,3,0,4,2,4] [2,3,1,3,2,4] [3,3,4,3,2,3] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_92.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_92.png new file mode 100644 index 0000000..a1efb14 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_92.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_92.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_92.txt new file mode 100644 index 0000000..fcc2c6e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_92.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_93.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_93.png new file mode 100644 index 0000000..43667df Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_93.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_93.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_93.txt new file mode 100644 index 0000000..8a49ca7 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_93.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,0,2,2,2] [3,1,2,2,4,2] +[0,2,-1,3,1,3] [2,2,1,3,3,3] +[1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_94.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_94.png new file mode 100644 index 0000000..35448d7 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_94.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_94.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_94.txt new file mode 100644 index 0000000..8226fbb --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_94.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,0,1] [2,0,1,1,3,1] [3,0,2,0,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[1,3,2,3,0,4] [2,3,1,4,3,4] [3,3,2,3,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_95.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_95.png new file mode 100644 index 0000000..72b838f Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_95.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_95.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_95.txt new file mode 100644 index 0000000..7395f6a --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_95.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,0,1,2,1] [2,0,3,0,1,0] [3,0,2,1,4,1] +[0,1,1,1,-1,1] [1,1,1,2,2,2] [2,1,3,1,1,1] [3,1,3,2,4,2] +[0,2,1,2,0,3] [1,2,2,2,1,3] [2,2,3,2,2,3] [3,2,4,2,3,3] +[0,3,-1,3,0,4] [1,3,0,3,0,4] [2,3,1,3,2,4] [3,3,2,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_96.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_96.png new file mode 100644 index 0000000..dedb93d Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_96.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_96.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_96.txt new file mode 100644 index 0000000..68620e0 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_96.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,0,1] [1,0,2,0,1,1] [2,0,3,0,2,1] [3,0,4,0,3,1] +[0,1,1,1,0,2] [1,1,2,1,1,2] [2,1,3,1,2,2] [3,1,4,1,3,2] +[0,2,-1,2,0,3] [1,2,0,2,1,3] [2,2,1,2,2,3] [3,2,2,2,3,3] +[0,3,-1,3,0,4] [1,3,0,3,1,4] [2,3,1,3,2,4] [3,3,2,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_98.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_98.png new file mode 100644 index 0000000..4fa40ac Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_98.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_98.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_98.txt new file mode 100644 index 0000000..f4289c6 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_98.txt @@ -0,0 +1,3 @@ +CHECKER 4 4 +[0,0,1,0,0,2] [1,0,2,0,1,2] [2,0,3,0,2,2] [3,0,4,0,3,2] +[0,2,-1,2,0,4] [1,2,0,2,1,4] [2,2,1,2,2,4] [3,2,2,2,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_99.png b/extensions/fablabchemnitz/bobbinlace/templates/4x4_99.png new file mode 100644 index 0000000..1361e58 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/4x4_99.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/4x4_99.txt b/extensions/fablabchemnitz/bobbinlace/templates/4x4_99.txt new file mode 100644 index 0000000..d49836e --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/4x4_99.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,2] [2,0,2,2,3,1] +[3,1,2,2,4,2] +[0,2,-1,3,0,4] [1,2,0,2,1,4] [2,2,1,2,3,3] +[3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/basic.png b/extensions/fablabchemnitz/bobbinlace/templates/basic.png new file mode 100644 index 0000000..c35eaf3 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/basic.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/basic.txt b/extensions/fablabchemnitz/bobbinlace/templates/basic.txt new file mode 100644 index 0000000..ee8ac26 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/basic.txt @@ -0,0 +1,3 @@ +CHECKER 2 2 +[0,0,-1,1,1,1] +[1,1,0,2,2,2] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/bias.png b/extensions/fablabchemnitz/bobbinlace/templates/bias.png new file mode 100644 index 0000000..53f5b82 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/bias.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/bias.txt b/extensions/fablabchemnitz/bobbinlace/templates/bias.txt new file mode 100644 index 0000000..1fab8f8 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/bias.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,2,1] +[1,1,2,1,0,2] [2,1,3,1,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [2,2,3,2,1,3] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/devonshire.png b/extensions/fablabchemnitz/bobbinlace/templates/devonshire.png new file mode 100644 index 0000000..f425032 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/devonshire.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/devonshire.txt b/extensions/fablabchemnitz/bobbinlace/templates/devonshire.txt new file mode 100644 index 0000000..4a69e81 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/devonshire.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,3,0,1,1] [3,0,4,0,3,1] +[1,1,1,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,1,3] [1,2,0,2,1,3] [2,2,1,2,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/kat.png b/extensions/fablabchemnitz/bobbinlace/templates/kat.png new file mode 100644 index 0000000..1b7b5ce Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/kat.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/kat.txt b/extensions/fablabchemnitz/bobbinlace/templates/kat.txt new file mode 100644 index 0000000..9f854cc --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/kat.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,-1,1,0,2] [2,0,2,2,3,1] +[3,1,2,2,4,2] +[0,2,0,4,1,3] [2,2,1,3,2,4] +[1,3,0,4,2,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/pinwheel.png b/extensions/fablabchemnitz/bobbinlace/templates/pinwheel.png new file mode 100644 index 0000000..a41c617 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/pinwheel.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/pinwheel.txt b/extensions/fablabchemnitz/bobbinlace/templates/pinwheel.txt new file mode 100644 index 0000000..9dfed1d --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/pinwheel.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,1] [1,0,2,0,1,1] [2,0,1,1,3,1] +[1,1,0,2,2,2] [3,1,3,2,4,2] +[0,2,-1,2,1,3] [2,2,1,3,3,3] [3,2,2,2,3,3] +[1,3,0,4,1,4] [3,3,2,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/rose.png b/extensions/fablabchemnitz/bobbinlace/templates/rose.png new file mode 100644 index 0000000..fc723ed Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/rose.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/rose.txt b/extensions/fablabchemnitz/bobbinlace/templates/rose.txt new file mode 100644 index 0000000..f2ea221 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/rose.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,1,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,1,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[1,3,0,4,1,4] [3,3,3,4,4,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/rose_var1.png b/extensions/fablabchemnitz/bobbinlace/templates/rose_var1.png new file mode 100644 index 0000000..1ad78ec Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/rose_var1.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/rose_var1.txt b/extensions/fablabchemnitz/bobbinlace/templates/rose_var1.txt new file mode 100644 index 0000000..e29b28f --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/rose_var1.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,1,1,3,1] [3,0,2,0,3,1] +[1,1,1,2,2,2] [3,1,2,2,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/bobbinlace/templates/rose_var2.png b/extensions/fablabchemnitz/bobbinlace/templates/rose_var2.png new file mode 100644 index 0000000..d425644 Binary files /dev/null and b/extensions/fablabchemnitz/bobbinlace/templates/rose_var2.png differ diff --git a/extensions/fablabchemnitz/bobbinlace/templates/rose_var2.txt b/extensions/fablabchemnitz/bobbinlace/templates/rose_var2.txt new file mode 100644 index 0000000..f1fca15 --- /dev/null +++ b/extensions/fablabchemnitz/bobbinlace/templates/rose_var2.txt @@ -0,0 +1,5 @@ +CHECKER 4 4 +[0,0,1,0,-1,0] [1,0,2,0,1,1] [2,0,2,1,3,1] [3,0,2,0,3,1] +[1,1,1,2,2,2] [2,1,1,1,2,2] [3,1,2,1,3,2] +[0,2,-1,3,0,3] [1,2,0,2,1,3] [2,2,3,2,1,2] [3,2,4,2,3,3] +[0,3,1,3,0,4] [1,3,0,4,1,4] [3,3,4,3,3,4] diff --git a/extensions/fablabchemnitz/delete_above/delete_above.inx b/extensions/fablabchemnitz/delete_above/delete_above.inx new file mode 100644 index 0000000..65e8165 --- /dev/null +++ b/extensions/fablabchemnitz/delete_above/delete_above.inx @@ -0,0 +1,16 @@ + + + Delete Above + fablabchemnitz.de.delete_above + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/delete_above/delete_above.py b/extensions/fablabchemnitz/delete_above/delete_above.py new file mode 100644 index 0000000..76fa6af --- /dev/null +++ b/extensions/fablabchemnitz/delete_above/delete_above.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +""" +Inkscape plugin: delete the selected object(s) and any objects on top of them. + +I.E. delete the selected node(s) and any other nodes that are completely +within the bounding-boxes of the selected nodes that have a greater z-order + +Simply put, you select a "background" rectangle, then use this plugin to +delete it and everything that appears on top of it. +""" + +import collections +import subprocess +import os +import pprint +import inkex + +Point = collections.namedtuple('Point', ['x', 'y']) + +Box = collections.namedtuple('Box', ['tl', 'tr', 'br', 'bl']) +# tl=top left, tr=top right, br=bottom right, bl=bottom left + +nodeInfo = collections.namedtuple('nodeInfo', + ['x', 'y', 'width', 'height']) + + +def contains(outer, inner): + """ Return true if the Box inner is completely within the Box outer """ + return inner.tl.x >= outer.tl.x and inner.tl.y >= outer.tl.y and \ + inner.br.x <= outer.br.x and inner.br.y <= outer.br.y + + +class DeleteAbove(inkex.EffectExtension): + """ Delete the selected node and everything above it """ + node_info = None + + def load_node_info(self): + """ Ask inkscape for information about all object bounding boxes """ + node_info = dict() + command = ['inkscape', '--query-all', self.options.input_file] + check_output = subprocess.check_output + + with open(os.devnull, 'w') as null: + for line in check_output(command, stderr=null).splitlines(): + raw_id, raw_x, raw_y, raw_width, raw_height = line.split(b',') + node_info[raw_id.decode("UTF-8")] = nodeInfo(float(raw_x), + float(raw_y), + float(raw_width), + float(raw_height)) + + self.node_info = node_info + return + + def remove(self, node): + """ Remove the specified node from the document tree """ + parent = node.getparent() + if parent is None: + return + parent.remove(node) + + def bbox(self, node): + """ Return the bounding-box of the given node """ + node_id = node.get('id') + #inkex.utils.debug("Check if " + str(node_id) + " is in " + str(self.node_info)) + info = self.node_info[node_id] + + x = info.x + y = info.y + width = info.width + height = info.height + + return Box(Point(x, y), + Point(x + width, y), + Point(x + width, y + height), + Point(x, y + height)) + + def effect(self): + """ + For every selected node, remove it and all items on top of it + """ + self.load_node_info() + nodes_to_remove = list() + + for id, node in self.svg.selected.items(): + selected_node_bbox = self.bbox(node) + nodes_to_remove.append(node) + + # search the document tree for the selected node + # when found, every subsequent node will be "above" it. + # (i.e. svg documents draw from the background up, so a background + # node will appear first, then nodes that are progressively + # closer to the viewer will appear subsequently in the svg file) + found_selected_node = False + for node in self.document.getiterator(): + if not found_selected_node: + if node == node: + found_selected_node = True + continue + # Hereafter we are iterating over all nodes above the + # selected node. We need to delete them if they appear to + # be "on top of" the selection (i.e. within the bounding box + # of the selection) + try: + node_bbox = self.bbox(node) + except KeyError: + continue + if contains(selected_node_bbox, node_bbox): + nodes_to_remove.append(node) + + # Now we remove the items we've previously found. Search and remove + # need to be separate bulk steps because tree search is disrupted by + # tree modification + for condemned_node in set(nodes_to_remove): + self.remove(condemned_node) + +if __name__ == '__main__': + if False: + # Some tools for debug use + PPRINTER = pprint.PrettyPrinter(indent=4) + FMT = PPRINTER.pformat + DUMP = lambda obj: inkex.debug(FMT(obj)) + + DeleteAbove().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/delete_above/meta.json b/extensions/fablabchemnitz/delete_above/meta.json new file mode 100644 index 0000000..608455a --- /dev/null +++ b/extensions/fablabchemnitz/delete_above/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Delete Above", + "id": "fablabchemnitz.de.delete_above", + "path": "delete_above", + "dependent_extensions": null, + "original_name": "Delete Above", + "original_id": "com.galvanist.sw.plugins.deleteabove", + "license": "BSD-3-Clause License", + "license_url": "https://github.com/glvnst/cruft/blob/master/delete_above/LICENSE.txt", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/delete_above", + "fork_url": "https://github.com/glvnst/cruft/tree/master/delete_above", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Delete+Above", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/glvnst", + "github.com/eridur-de" + ] + } +] diff --git a/extensions/fablabchemnitz/eraser_laser/eraser_layer.inx b/extensions/fablabchemnitz/eraser_laser/eraser_layer.inx new file mode 100644 index 0000000..d9dff89 --- /dev/null +++ b/extensions/fablabchemnitz/eraser_laser/eraser_layer.inx @@ -0,0 +1,16 @@ + + + Eraser Layer + fablabchemnitz.de.eraser_layer + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/eraser_laser/eraser_layer.py b/extensions/fablabchemnitz/eraser_laser/eraser_layer.py new file mode 100644 index 0000000..35c6e06 --- /dev/null +++ b/extensions/fablabchemnitz/eraser_laser/eraser_layer.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +''' +This extension Create a eraser layer + +Copyright (C) 2012 Jabiertxo Arraiza, jabier.arraiza@marker.es + +Version 0.4 - Eraser + +TODO: +Comment Better!!! + +CHANGE LOG +0.1 Start 30/07/2012 +0.3 fix bug with borders + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +import inkex +import sys +from lxml import etree + +class EraserLayer(inkex.EffectExtension): + + #inserta el flltro que pasa a negro la mascara + def insertFilter(self, svg): + xpathStr = '//filter[@id="Decolorize_0001"]' + filterElement = svg.xpath(xpathStr, namespaces=inkex.NSS) + if filterElement == []: + xpathStr = '//svg:defs' + defs = svg.xpath(xpathStr, namespaces=inkex.NSS) + flt = etree.SubElement(defs[0],inkex.addNS('filter','svg')) + for k, v in [('id', 'Decolorize_0001'), ('color-interpolation-filters', 'sRGB'), + ('height', '100'), ('width', '100'), + ('x', '-50'), ('y', '-50')]: + flt.set(k, v) + fltColorMatrix = etree.SubElement(flt,inkex.addNS('feColorMatrix','svg')) + for k, v in [('id', 'feColorMatrix_0001'),('values','1'), ('in', 'SourceGraphic'), + ('type', 'saturate'), ('result', 'result2')]: + fltColorMatrix.set(k, v) + fltFlood = etree.SubElement(flt,inkex.addNS('feFlood','svg')) + for k, v in [('id', 'feFlood_0001'),('flood-color','rgb(255,255,255)'), ('flood-opacity', '1'), + ('result', 'result1')]: + fltFlood.set(k, v) + fltComposite = etree.SubElement(flt,inkex.addNS('feComposite','svg')) + for k, v in [('id', 'feComposite_0001'),('operator', 'atop'),('in2', 'SourceGraphic') + ,('k2', '1'),('result', 'result4')]: + fltComposite.set(k, v) + + fltInverse = etree.SubElement(defs[0],inkex.addNS('filter','svg')) + for k, v in [('id', 'Inverse_0001'), ('color-interpolation-filters', 'sRGB'), + ('height', '100'), ('width', '100'), + ('x', '-50'), ('y', '-50')]: + fltInverse.set(k, v) + fltColorMatrixInverse = etree.SubElement(fltInverse,inkex.addNS('feColorMatrix','svg')) + for k, v in [('id', 'feColorMatrixInverse_0001'),('values','1'), + ('type', 'saturate'), ('result', 'fbSourceGraphic')]: + fltColorMatrixInverse.set(k, v) + fltColorMatrixInverse = etree.SubElement(fltInverse,inkex.addNS('feColorMatrix','svg')) + for k, v in [('id', 'feColorMatrixInverse_0002'),('in','fbSourceGraphic'), + ('values', '-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 ')]: + fltColorMatrixInverse.set(k, v) + + #Inserta la mascara desde el grupo eraser + def insertMask(self, idLayer, svg): + xpathStr = '//mask[@id="MaskEraser_' + idLayer + '"]' + maskElement = svg.xpath(xpathStr, namespaces=inkex.NSS) + if maskElement == []: + xpathStr = '//svg:defs' + defs = svg.xpath(xpathStr, namespaces=inkex.NSS) + msk = etree.SubElement(defs[0],inkex.addNS('mask','svg')) + for k, v in [('id', 'Eraser_' + idLayer), ('maskUnits', 'userSpaceOnUse')]: + msk.set(k, v) + use = etree.SubElement(msk,inkex.addNS('use','svg')) + for k, v in [('id', 'Use_Eraser_' + idLayer), ('{http://www.w3.org/1999/xlink}href', + "#EraserLayer_" + idLayer),('style',"filter:url(#Inverse_0001)")]: + use.set(k, v) + rct = etree.SubElement(msk,inkex.addNS('rect','svg')) + for k, v in [('id', 'Background_' + idLayer), ('x', '-25000000'), + ('y', '-25000000'), ('width', '50000000'), ('height', '50000000'), + ('style', 'fill:#FFFFFF;fill-opacity:1')]: + rct.set(k, v) + + + ##crea el grupo contenedor que hara de borrador + def createEraserLayer(self, layer,idLayer): + container = etree.Element("g") + container.set("id","ContainerEraserLayer_" + idLayer) + container.set('style',"opacity:0.000000000000000000000000000000000000000000000001") + container.set("{http://www.inkscape.org/namespaces/inkscape}groupmode","layer") + container.set("{http://www.inkscape.org/namespaces/inkscape}label", "[container eraser] " + layer[0].get("{http://www.inkscape.org/namespaces/inkscape}label")) + for position, item in enumerate(layer[0].getparent().getchildren()): + if item == layer[0]: + break; + layer[0].getparent().insert(position+1,container) + eraser = etree.Element("g") + eraser.set("id","EraserLayer_" + idLayer) + eraser.set('style',"filter:url(#Decolorize_0001)") + eraser.set('transform',"rotate(360)") + eraser.set("{http://www.inkscape.org/namespaces/inkscape}groupmode","layer") + eraser.set("{http://www.inkscape.org/namespaces/inkscape}label", "[eraser] " + layer[0].get("{http://www.inkscape.org/namespaces/inkscape}label")) + layer[0].set('mask',"url(#Eraser_" + idLayer + ")") + selected = [] + for id, node in self.svg.selected.items(): + eraser.insert(1,node) + container.insert(1,eraser) + + def effect(self): + saveout = sys.stdout + sys.stdout = sys.stderr + svg = self.document.getroot() + xpathStr = '//sodipodi:namedview' + namedview = svg.xpath(xpathStr, namespaces=inkex.NSS) + idLayer = namedview[0].get('{http://www.inkscape.org/namespaces/inkscape}current-layer'); + if idLayer.startswith("[mask] ") == False and idLayer.startswith("[eraser] ") == False: + xpathStr = '//svg:g[@id="EraserLayer_'+idLayer+'"]' + filterElement = svg.xpath(xpathStr, namespaces=inkex.NSS) + if filterElement == []: + xpathStr = '//svg:g[@id="'+idLayer+'"]' + layer = svg.xpath(xpathStr, namespaces=inkex.NSS) + if len(layer) > 0 and layer[0] is not None and layer[0].get("{http://www.inkscape.org/namespaces/inkscape}label") is not None: + self.insertFilter(svg) + self.insertMask(idLayer, svg) + self.createEraserLayer(layer,idLayer) + else: + print ("Layer not found, Maybe insisde a group?") + else: + for id, node in self.svg.selected.items(): + filterElement[0].insert(1,node) + sys.stdout = saveout + +if __name__ == '__main__': + EraserLayer().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/eraser_laser/meta.json b/extensions/fablabchemnitz/eraser_laser/meta.json new file mode 100644 index 0000000..4cb30d7 --- /dev/null +++ b/extensions/fablabchemnitz/eraser_laser/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Eraser Layer", + "id": "fablabchemnitz.de.eraser_laser", + "path": "eraser_laser", + "dependent_extensions": null, + "original_name": "Erase Layer", + "original_id": "org.inkscape.erase.layer", + "license": "GNU GPL v2", + "license_url": "https://inkscape.org/~jabiertxof/%E2%98%85eraser-layer", + "comment": "ported to Inkscape v1 by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/eraser_laser", + "fork_url": "https://inkscape.org/~jabiertxof/%E2%98%85eraser-layer", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Eraser+Layer", + "inkscape_gallery_url": null, + "main_authors": [ + "inkscape.org/jabiertxof", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.eslintrc.json b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.eslintrc.json new file mode 100644 index 0000000..87f6bce --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.eslintrc.json @@ -0,0 +1,24 @@ +{ + "env": { + "browser": true + }, + "extends": "eslint:recommended", + "rules": { + "indent": [ + 2, + "tab" + ], + "linebreak-style": [ + 2, + "windows" + ], + "quotes": [ + 2, + "single" + ], + "semi": [ + 2, + "always" + ] + } +} \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.project b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.project new file mode 100644 index 0000000..4a32755 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.project @@ -0,0 +1,17 @@ + + + imagetracerjs + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/.jsdtscope b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/.jsdtscope new file mode 100644 index 0000000..c19fafc --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/.jsdtscope @@ -0,0 +1,6 @@ + + + + + + diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/org.eclipse.wst.jsdt.ui.superType.container b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..49c8cd4 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.JRE_CONTAINER \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/org.eclipse.wst.jsdt.ui.superType.name b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..11006e2 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Global \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/LICENSE b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/LICENSE new file mode 100644 index 0000000..a84c395 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/LICENSE @@ -0,0 +1,25 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/README.md b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/README.md new file mode 100644 index 0000000..6e9d6c9 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/README.md @@ -0,0 +1,306 @@ +# imagetracerjs +![alt Bitmap to Svg](docimages/s1.png) + +Simple raster image tracer and vectorizer written in JavaScript. + +--- + +## Table of contents +- [Getting started](#getting-started) +- [News](#news) +- [API](#api) +- [Options](#options) +- [Examples](#examples) +- [Process overview](#process-overview) +- [License](#license) + +--- + +## Getting started + +### Using in the Browser +Include the script: +```javascript + +``` +Then: +```javascript +// Loading an image, tracing with the 'posterized2' option preset, and appending the SVG to an element with id="svgcontainer" +ImageTracer.imageToSVG( + + 'panda.png', /* input filename / URL */ + + function(svgstr){ ImageTracer.appendSVGString( svgstr, 'svgcontainer' ); }, /* callback function to run on SVG string result */ + + 'posterized2' /* Option preset */ + +); +``` + +### Using with Node.js + +Node.js Command line interface example: + +``` +imagetracerjs/nodecli>node nodecli ../panda.png outfilename panda.svg scale 10 +``` + +Expected result: + +``` +imagetracerjs/nodecli/panda.svg was saved! +``` + +--- + +## News + +### 1.2.6 + - FIXED: hole shape parent search (Issues #31 #39) + - FIXED: Handle (absolute) paths in CLI correctly Issue #42 + +### 1.2.5 + - RGBA ImageData check in colorquantization(), solving Issue #24 and #18 + +### 1.2.4 + - ```options.layering``` : default 0 = sequential, new method ; 1 = parallel, old method. (Enhancement Issue #17) + - case insensitive option preset names + - README.md reorganizing + +[Version history](https://github.com/jankovicsandras/imagetracerjs/blob/master/version_history.md) + +--- + +## API +|Function name|Arguments|Returns|Run type| +|-------------|---------|-------|--------| +|```imageToSVG```|```image_url /*string*/ , callback /*function*/ , options /*optional object or preset name*/```|Nothing, ```callback(svgstring)``` will be executed|Asynchronous, Browser only| +|```imagedataToSVG```|```imagedata /*object*/ , options /*optional object or preset name*/```|```svgstring /*string*/```|Synchronous, Browser & Node.js| +|```imageToTracedata```|```image_url /*string*/ , callback /*function*/ , options /*optional object or preset name*/```|Nothing, ```callback(tracedata)``` will be executed|Asynchronous, Browser only| +|```imagedataToTracedata```|```imagedata /*object*/ , options /*optional object or preset name*/```|```tracedata /*object*/```|Synchronous, Browser & Node.js| + +```imagedata``` is standard [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) here, ```canvas``` is [canvas](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) . + +### Helper Functions (Browser only) +|Function name|Arguments|Returns|Run type| +|-------------|---------|-------|--------| +|```appendSVGString```|```svgstring /*string*/, parentid /*string*/```|Nothing, an SVG will be appended to the container DOM element with id=parentid.|Synchronous, Browser only| +|```loadImage```|```url /*string*/, callback /*function*/```|Nothing, loading an image from a URL, then executing ```callback(canvas)```|Asynchronous, Browser only| +|```getImgdata```|```canvas /*object*/```|```imagedata /*object*/```|Synchronous, Browser only| + +```imagedata``` is standard [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) here, ```canvas``` is [canvas](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) . +There are more functions for advanced users, read the source if you are interested. :) + +"Browser only" means that Node.js doesn't have built-in canvas and DOM support as of 2018, so loading an image to an ImageData object needs an external library. + +--- + +## Options +You can use an option preset name (string) or an [options object](https://github.com/jankovicsandras/imagetracerjs/blob/master/options.md) to control the tracing and rendering process. + +![Option presets gallery](docimages/option_presets_small.png) + +These strings can be passed instead of the options object: +```'default'``` +```'posterized1'``` +```'posterized2'``` +```'posterized3'``` +```'curvy'``` +```'sharp'``` +```'detailed'``` +```'smoothed'``` +```'grayscale'``` +```'fixedpalette'``` +```'randomsampling1'``` +```'randomsampling2'``` +```'artistic1'``` +```'artistic2'``` +```'artistic3'``` +```'artistic4'``` + +[Read more about options.](https://github.com/jankovicsandras/imagetracerjs/blob/master/options.md) + +--- + +## Examples + +### Using in the Browser +Include the script: +```javascript + +``` +Then +```javascript +// Loading smiley.png, tracing and calling alert callback on the SVG string result +ImageTracer.imageToSVG( 'smiley.png', alert ); + + +// Almost the same with options, and the ImageTracer.appendSVGString callback will append the SVG +ImageTracer.imageToSVG( 'smiley.png', ImageTracer.appendSVGString, { ltres:0.1, qtres:1, scale:10, strokewidth:5 } ); + + +// This uses the 'posterized2' option preset and appends the SVG to an element with id="svgcontainer" +ImageTracer.imageToSVG( + 'panda.png', + function(svgstr){ ImageTracer.appendSVGString( svgstr, 'svgcontainer' ); }, + 'posterized2' +); + + +// The helper function loadImage() loads an image to a canvas, then executing callback: +// appending the canvas to a div here. +ImageTracer.loadImage( + 'panda.png', + function(canvas){ (document.getElementById('canvascontainer')).appendChild(canvas); } +); + + +// ImageData can be traced to an SVG string synchronously. +ImageTracer.loadImage( + 'smiley.png', + function(canvas){ + + // Getting ImageData from canvas with the helper function getImgdata(). + var imgd = ImageTracer.getImgdata( canvas ); + + // Synchronous tracing to SVG string + var svgstr = ImageTracer.imagedataToSVG( imgd, { scale:5 } ); + + // Appending SVG + ImageTracer.appendSVGString( svgstr, 'svgcontainer' ); + + } +); + + +// This will load an image, trace it when loaded, and execute callback on the tracedata: +// stringifying and alerting it here. +ImageTracer.imageToTracedata( + 'smiley.png', + function(tracedata){ alert( JSON.stringify( tracedata ) ); }, + { ltres:0.1, qtres:1, scale:10 } +); + + +// imagedataToTracedata() is very similar to the previous functions. This returns tracedata synchronously. +ImageTracer.loadImage( + 'smiley.png', + function(canvas){ + + // Getting ImageData from canvas with the helper function getImgdata(). + var imgd = ImageTracer.getImgdata(canvas); + + // Synchronous tracing to tracedata + var tracedata = ImageTracer.imagedataToTracedata( imgd, { ltres:1, qtres:0.01, scale:10 } ); + + alert( JSON.stringify( tracedata ) ); + } +); +``` + +### Using with Node.js CLI + +Node.js Command line interface example: + +``` +imagetracerjs/nodecli>node nodecli ../panda.png outfilename panda.svg scale 10 +``` + +Expected result: + +``` +imagetracerjs/nodecli/panda.svg was saved! +``` + +CLI parameter names are supported both with and without trailing dash: ```-scale 10``` and ```scale 10``` are both correct. +Almost all options are supported, except ```pal``` and ```layercontainerid```. + +### Simple Node.js converting example + +```javascript +"use strict"; + +var fs = require('fs'); + +var ImageTracer = require( __dirname + '/../imagetracer_v1.2.6' ); + +// This example uses https://github.com/arian/pngjs +// , but other libraries can be used to load an image file to an ImageData object. +var PNGReader = require( __dirname + '/PNGReader' ); + +// Input and output filepaths / URLs +var infilepath = __dirname + '/' + 'panda.png'; +var outfilepath = __dirname + '/' + 'panda.svg'; + + +fs.readFile( + + infilepath, + + function( err, bytes ){ // fs.readFile callback + if(err){ console.log(err); throw err; } + + var reader = new PNGReader(bytes); + + reader.parse( function( err, png ){ // PNGReader callback + if(err){ console.log(err); throw err; } + + // creating an ImageData object + var myImageData = { width:png.width, height:png.height, data:png.pixels }; + + // tracing to SVG string + var options = { scale: 5 }; // options object; option preset string can be used also + + var svgstring = ImageTracer.imagedataToSVG( myImageData, options ); + + // writing to file + fs.writeFile( + outfilepath, + svgstring, + function(err){ if(err){ console.log(err); throw err; } console.log( outfilepath + ' was saved!' ); } + ); + + });// End of reader.parse() + + }// End of readFile callback() + +);// End of fs.readFile() +``` + +### Tracedata processing / Simplify.js example +It's possible to process the traced geometry and color data before SVG rendering. This example [simplify_interop.html](https://github.com/jankovicsandras/imagetracerjs/blob/master/simplify_interop.html) shows polyline simplification. You need to download simplify.js from https://github.com/mourner/simplify-js . + +--- + +## Process overview +See [Process overview and Ideas for improvement](https://github.com/jankovicsandras/imagetracerjs/blob/master/process_overview.md) + +--- + +## License +### The Unlicense / PUBLIC DOMAIN + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to [http://unlicense.org](http://unlicense.org) diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/bower.json b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/bower.json new file mode 100644 index 0000000..5fcf697 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/bower.json @@ -0,0 +1,34 @@ +{ + "name": "imagetracerjs", + "description": "raster image tracer and vectorizer, bitmap to SVG converter", + "repository": { + "type": "git", + "url": "https://github.com/jankovicsandras/imagetracerjs.git" + }, + "main": "imagetracer_v1.2.6.js", + "keywords": [ + "image", + "tracer", + "tracing", + "vector", + "raster", + "vectorize", + "vectorizing", + "convert", + "conversion", + "converting", + "bitmap", + "svg", + "bmp", + "png", + "jpg", + "jpeg", + "gif" + ], + "authors": [ "András Jankovics" ], + "license": "Unlicense", + "bugs": { + "url": "https://github.com/jankovicsandras/imagetracerjs/issues" + }, + "homepage": "https://github.com/jankovicsandras/imagetracerjs#readme" +} diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/cover_problem.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/cover_problem.png new file mode 100644 index 0000000..f457b68 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/cover_problem.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/option_presets.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/option_presets.png new file mode 100644 index 0000000..49be0a9 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/option_presets.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/option_presets_small.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/option_presets_small.png new file mode 100644 index 0000000..dc21ab6 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/option_presets_small.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s1.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s1.png new file mode 100644 index 0000000..469e2ac Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s1.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s10.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s10.png new file mode 100644 index 0000000..358cb02 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s10.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s11.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s11.png new file mode 100644 index 0000000..3af8e7c Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s11.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s12.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s12.png new file mode 100644 index 0000000..e0c8f69 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s12.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s13.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s13.png new file mode 100644 index 0000000..64eb1f6 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s13.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s14.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s14.png new file mode 100644 index 0000000..4a61d94 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s14.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s15.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s15.png new file mode 100644 index 0000000..33d7506 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s15.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s2.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s2.png new file mode 100644 index 0000000..ddde649 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s2.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s3.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s3.png new file mode 100644 index 0000000..2045a10 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s3.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s4.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s4.png new file mode 100644 index 0000000..c517488 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s4.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s7.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s7.png new file mode 100644 index 0000000..6aaf04d Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s7.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s8.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s8.png new file mode 100644 index 0000000..1e02424 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s8.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s9.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s9.png new file mode 100644 index 0000000..1728559 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/s9.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/transparency_problem.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/transparency_problem.png new file mode 100644 index 0000000..754593e Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/docimages/transparency_problem.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_examples.html b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_examples.html new file mode 100644 index 0000000..32d6ce7 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_examples.html @@ -0,0 +1,82 @@ + + + + + + + + + +
+
+ \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_options_gallery.html b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_options_gallery.html new file mode 100644 index 0000000..1866d65 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_options_gallery.html @@ -0,0 +1,69 @@ + + + + + + + imagetracer.js options gallery + + + + + + + +
+ + + + + +

Original
+
+ + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_test_automation.html b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_test_automation.html new file mode 100644 index 0000000..ff17b68 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_test_automation.html @@ -0,0 +1,334 @@ + + + + + imagetracer.js test automation + + + + + + +
+

Test images

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
















+

Settings

+
+
+
+
+ Example Custom Options:
{"ltres":1,"qtres":1,"pathomit":8,"colorsampling":true,"numberofcolors":16,"mincolorratio":0.02,"colorquantcycles":3,"scale":1,"simplifytolerance":0,"roundcoords":1,"lcpr":0,"qcpr":0,"desc":true,"viewbox":false,"blurradius":0,"blurdelta":20}
+
+ + +
+ +

Result (if Draw SVG is active)

+ + + + + + + + + + + + +
Traced SVGOriginal rasterSVG rendered as rasterDifference
+ +

Measurements

+
+ + + + + + + + + + + + + + + + + + + +
RowIDFilenamewidth (pixels)height (pixels)area (pixels)SVG string length (bytes)Tracing time (ms)Rendering time (ms)Nr. of pathsRGBA difference (cummulative RGBA difference / (area*4))Different pixels (%)Options
+ +
+ \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_v1.2.6.js b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_v1.2.6.js new file mode 100644 index 0000000..6c62432 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/imagetracer_v1.2.6.js @@ -0,0 +1,1217 @@ +/* + imagetracer.js version 1.2.6 + Simple raster image tracer and vectorizer written in JavaScript. + andras@jankovics.net +*/ + +/* + +The Unlicense / PUBLIC DOMAIN + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to http://unlicense.org/ + +*/ + +(function(){ 'use strict'; + +function ImageTracer(){ + var _this = this; + + this.versionnumber = '1.2.6', + + //////////////////////////////////////////////////////////// + // + // API + // + //////////////////////////////////////////////////////////// + + // Loading an image from a URL, tracing when loaded, + // then executing callback with the scaled svg string as argument + this.imageToSVG = function( url, callback, options ){ + options = _this.checkoptions(options); + // loading image, tracing and callback + _this.loadImage( + url, + function(canvas){ + callback( + _this.imagedataToSVG( _this.getImgdata(canvas), options ) + ); + }, + options + ); + },// End of imageToSVG() + + // Tracing imagedata, then returning the scaled svg string + this.imagedataToSVG = function( imgd, options ){ + options = _this.checkoptions(options); + // tracing imagedata + var td = _this.imagedataToTracedata( imgd, options ); + // returning SVG string + return _this.getsvgstring(td, options); + },// End of imagedataToSVG() + + // Loading an image from a URL, tracing when loaded, + // then executing callback with tracedata as argument + this.imageToTracedata = function( url, callback, options ){ + options = _this.checkoptions(options); + // loading image, tracing and callback + _this.loadImage( + url, + function(canvas){ + callback( + _this.imagedataToTracedata( _this.getImgdata(canvas), options ) + ); + }, + options + ); + },// End of imageToTracedata() + + // Tracing imagedata, then returning tracedata (layers with paths, palette, image size) + this.imagedataToTracedata = function( imgd, options ){ + options = _this.checkoptions(options); + + // 1. Color quantization + var ii = _this.colorquantization( imgd, options ); + + if(options.layering === 0){// Sequential layering + + // create tracedata object + var tracedata = { + layers : [], + palette : ii.palette, + width : ii.array[0].length-2, + height : ii.array.length-2 + }; + + // Loop to trace each color layer + for(var colornum=0; colornum pathscan -> internodes -> batchtracepaths + var tracedlayer = + _this.batchtracepaths( + + _this.internodes( + + _this.pathscan( + _this.layeringstep( ii, colornum ), + options.pathomit + ), + + options + + ), + + options.ltres, + options.qtres + + ); + + // adding traced layer + tracedata.layers.push(tracedlayer); + + }// End of color loop + + }else{// Parallel layering + // 2. Layer separation and edge detection + var ls = _this.layering( ii ); + + // Optional edge node visualization + if(options.layercontainerid){ _this.drawLayers( ls, _this.specpalette, options.scale, options.layercontainerid ); } + + // 3. Batch pathscan + var bps = _this.batchpathscan( ls, options.pathomit ); + + // 4. Batch interpollation + var bis = _this.batchinternodes( bps, options ); + + // 5. Batch tracing and creating tracedata object + var tracedata = { + layers : _this.batchtracelayers( bis, options.ltres, options.qtres ), + palette : ii.palette, + width : imgd.width, + height : imgd.height + }; + + }// End of parallel layering + + // return tracedata + return tracedata; + + },// End of imagedataToTracedata() + + this.optionpresets = { + 'default': { + + // Tracing + corsenabled : false, + ltres : 1, + qtres : 1, + pathomit : 8, + rightangleenhance : true, + + // Color quantization + colorsampling : 2, + numberofcolors : 16, + mincolorratio : 0, + colorquantcycles : 3, + + // Layering method + layering : 0, + + // SVG rendering + strokewidth : 1, + linefilter : false, + scale : 1, + roundcoords : 1, + viewbox : false, + desc : false, + lcpr : 0, + qcpr : 0, + + // Blur + blurradius : 0, + blurdelta : 20 + + }, + 'posterized1': { colorsampling:0, numberofcolors:2 }, + 'posterized2': { numberofcolors:4, blurradius:5 }, + 'curvy': { ltres:0.01, linefilter:true, rightangleenhance:false }, + 'sharp': { qtres:0.01, linefilter:false }, + 'detailed': { pathomit:0, roundcoords:2, ltres:0.5, qtres:0.5, numberofcolors:64 }, + 'smoothed': { blurradius:5, blurdelta: 64 }, + 'grayscale': { colorsampling:0, colorquantcycles:1, numberofcolors:7 }, + 'fixedpalette': { colorsampling:0, colorquantcycles:1, numberofcolors:27 }, + 'randomsampling1': { colorsampling:1, numberofcolors:8 }, + 'randomsampling2': { colorsampling:1, numberofcolors:64 }, + 'artistic1': { colorsampling:0, colorquantcycles:1, pathomit:0, blurradius:5, blurdelta: 64, ltres:0.01, linefilter:true, numberofcolors:16, strokewidth:2 }, + 'artistic2': { qtres:0.01, colorsampling:0, colorquantcycles:1, numberofcolors:4, strokewidth:0 }, + 'artistic3': { qtres:10, ltres:10, numberofcolors:8 }, + 'artistic4': { qtres:10, ltres:10, numberofcolors:64, blurradius:5, blurdelta: 256, strokewidth:2 }, + 'posterized3': { ltres: 1, qtres: 1, pathomit: 20, rightangleenhance: true, colorsampling: 0, numberofcolors: 3, + mincolorratio: 0, colorquantcycles: 3, blurradius: 3, blurdelta: 20, strokewidth: 0, linefilter: false, + roundcoords: 1, pal: [ { r: 0, g: 0, b: 100, a: 255 }, { r: 255, g: 255, b: 255, a: 255 } ] } + },// End of optionpresets + + // creating options object, setting defaults for missing values + this.checkoptions = function(options){ + options = options || {}; + // Option preset + if(typeof options === 'string'){ + options = options.toLowerCase(); + if( _this.optionpresets[options] ){ options = _this.optionpresets[options]; }else{ options = {}; } + } + // Defaults + var ok = Object.keys(_this.optionpresets['default']); + for(var k=0; k + return options; + },// End of checkoptions() + + //////////////////////////////////////////////////////////// + // + // Vectorizing functions + // + //////////////////////////////////////////////////////////// + + // 1. Color quantization + // Using a form of k-means clustering repeatead options.colorquantcycles times. http://en.wikipedia.org/wiki/Color_quantization + this.colorquantization = function( imgd, options ){ + var arr = [], idx=0, cd,cdl,ci, paletteacc = [], pixelnum = imgd.width * imgd.height, i, j, k, cnt, palette; + + // imgd.data must be RGBA, not just RGB + if( imgd.data.length < pixelnum * 4 ){ + var newimgddata = new Uint8ClampedArray(pixelnum * 4); + for(var pxcnt = 0; pxcnt < pixelnum ; pxcnt++){ + newimgddata[pxcnt*4 ] = imgd.data[pxcnt*3 ]; + newimgddata[pxcnt*4+1] = imgd.data[pxcnt*3+1]; + newimgddata[pxcnt*4+2] = imgd.data[pxcnt*3+2]; + newimgddata[pxcnt*4+3] = 255; + } + imgd.data = newimgddata; + }// End of RGBA imgd.data check + + // Filling arr (color index array) with -1 + for( j=0; j 0 ){ imgd = _this.blur( imgd, options.blurradius, options.blurdelta ); } + + // Repeat clustering step options.colorquantcycles times + for( cnt=0; cnt < options.colorquantcycles; cnt++ ){ + + // Average colors from the second iteration + if(cnt>0){ + // averaging paletteacc for palette + for( k=0; k < palette.length; k++ ){ + + // averaging + if( paletteacc[k].n > 0 ){ + palette[k] = { r: Math.floor( paletteacc[k].r / paletteacc[k].n ), + g: Math.floor( paletteacc[k].g / paletteacc[k].n ), + b: Math.floor( paletteacc[k].b / paletteacc[k].n ), + a: Math.floor( paletteacc[k].a / paletteacc[k].n ) }; + } + + // Randomizing a color, if there are too few pixels and there will be a new cycle + if( ( paletteacc[k].n/pixelnum < options.mincolorratio ) && ( cnt < options.colorquantcycles-1 ) ){ + palette[k] = { r: Math.floor(Math.random()*255), + g: Math.floor(Math.random()*255), + b: Math.floor(Math.random()*255), + a: Math.floor(Math.random()*255) }; + } + + }// End of palette loop + }// End of Average colors from the second iteration + + // Reseting palette accumulator for averaging + for( i=0; i < palette.length; i++ ){ paletteacc[i] = { r:0, g:0, b:0, a:0, n:0 }; } + + // loop through all pixels + for( j=0; j < imgd.height; j++ ){ + for( i=0; i < imgd.width; i++ ){ + + // pixel index + idx = (j*imgd.width+i)*4; + + // find closest color from palette by measuring (rectilinear) color distance between this pixel and all palette colors + ci=0; cdl = 1024; // 4 * 256 is the maximum RGBA distance + for( k=0; k p.y) !== (pa[j].y > p.y)) && (p.x < (pa[j].x - pa[i].x) * (p.y - pa[i].y) / (pa[j].y - pa[i].y) + pa[i].x) ) + ? !isin : isin; + } + + return isin; + }, + + // Lookup tables for pathscan + // pathscan_combined_lookup[ arr[py][px] ][ dir ] = [nextarrpypx, nextdir, deltapx, deltapy]; + this.pathscan_combined_lookup = [ + [[-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1]],// arr[py][px]===0 is invalid + [[ 0, 1, 0,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [ 0, 2,-1, 0]], + [[-1,-1,-1,-1], [-1,-1,-1,-1], [ 0, 1, 0,-1], [ 0, 0, 1, 0]], + [[ 0, 0, 1, 0], [-1,-1,-1,-1], [ 0, 2,-1, 0], [-1,-1,-1,-1]], + + [[-1,-1,-1,-1], [ 0, 0, 1, 0], [ 0, 3, 0, 1], [-1,-1,-1,-1]], + [[13, 3, 0, 1], [13, 2,-1, 0], [ 7, 1, 0,-1], [ 7, 0, 1, 0]], + [[-1,-1,-1,-1], [ 0, 1, 0,-1], [-1,-1,-1,-1], [ 0, 3, 0, 1]], + [[ 0, 3, 0, 1], [ 0, 2,-1, 0], [-1,-1,-1,-1], [-1,-1,-1,-1]], + + [[ 0, 3, 0, 1], [ 0, 2,-1, 0], [-1,-1,-1,-1], [-1,-1,-1,-1]], + [[-1,-1,-1,-1], [ 0, 1, 0,-1], [-1,-1,-1,-1], [ 0, 3, 0, 1]], + [[11, 1, 0,-1], [14, 0, 1, 0], [14, 3, 0, 1], [11, 2,-1, 0]], + [[-1,-1,-1,-1], [ 0, 0, 1, 0], [ 0, 3, 0, 1], [-1,-1,-1,-1]], + + [[ 0, 0, 1, 0], [-1,-1,-1,-1], [ 0, 2,-1, 0], [-1,-1,-1,-1]], + [[-1,-1,-1,-1], [-1,-1,-1,-1], [ 0, 1, 0,-1], [ 0, 0, 1, 0]], + [[ 0, 1, 0,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [ 0, 2,-1, 0]], + [[-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1], [-1,-1,-1,-1]]// arr[py][px]===15 is invalid + ], + + // 3. Walking through an edge node array, discarding edge node types 0 and 15 and creating paths from the rest. + // Walk directions (dir): 0 > ; 1 ^ ; 2 < ; 3 v + this.pathscan = function( arr, pathomit ){ + var paths=[], pacnt=0, pcnt=0, px=0, py=0, w = arr[0].length, h = arr.length, + dir=0, pathfinished=true, holepath=false, lookuprow; + + for(var j=0; j paths[pacnt].boundingbox[2] ){ paths[pacnt].boundingbox[2] = px-1; } + if( (py-1) < paths[pacnt].boundingbox[1] ){ paths[pacnt].boundingbox[1] = py-1; } + if( (py-1) > paths[pacnt].boundingbox[3] ){ paths[pacnt].boundingbox[3] = py-1; } + + // Next: look up the replacement, direction and coordinate changes = clear this cell, turn if required, walk forward + lookuprow = _this.pathscan_combined_lookup[ arr[py][px] ][ dir ]; + arr[py][px] = lookuprow[0]; dir = lookuprow[1]; px += lookuprow[2]; py += lookuprow[3]; + + // Close path + if( (px-1 === paths[pacnt].points[0].x ) && ( py-1 === paths[pacnt].points[0].y ) ){ + pathfinished = true; + + // Discarding paths shorter than pathomit + if( paths[pacnt].points.length < pathomit ){ + paths.pop(); + }else{ + + paths[pacnt].isholepath = holepath ? true : false; + + // Finding the parent shape for this hole + if(holepath){ + + var parentidx = 0, parentbbox = [-1,-1,w+1,h+1]; + for(var parentcnt=0; parentcnt < pacnt; parentcnt++){ + if( (!paths[parentcnt].isholepath) && + _this.boundingboxincludes( paths[parentcnt].boundingbox , paths[pacnt].boundingbox ) && + _this.boundingboxincludes( parentbbox , paths[parentcnt].boundingbox ) && + _this.pointinpoly( paths[pacnt].points[0], paths[parentcnt].points ) + ){ + parentidx = parentcnt; + parentbbox = paths[parentcnt].boundingbox; + } + } + + paths[parentidx].holechildren.push( pacnt ); + + }// End of holepath parent finding + + pacnt++; + + } + + }// End of Close path + + pcnt++; + + }// End of Path points loop + + }// End of Follow path + + }// End of i loop + }// End of j loop + + return paths; + },// End of pathscan() + + this.boundingboxincludes = function( parentbbox, childbbox ){ + return ( ( parentbbox[0] < childbbox[0] ) && ( parentbbox[1] < childbbox[1] ) && ( parentbbox[2] > childbbox[2] ) && ( parentbbox[3] > childbbox[3] ) ); + },// End of boundingboxincludes() + + // 3. Batch pathscan + this.batchpathscan = function( layers, pathomit ){ + var bpaths = []; + for(var k in layers){ + if(!layers.hasOwnProperty(k)){ continue; } + bpaths[k] = _this.pathscan( layers[k], pathomit ); + } + return bpaths; + }, + + // 4. interpollating between path points for nodes with 8 directions ( East, SouthEast, S, SW, W, NW, N, NE ) + this.internodes = function( paths, options ){ + var ins = [], palen=0, nextidx=0, nextidx2=0, previdx=0, previdx2=0, pacnt, pcnt; + + // paths loop + for(pacnt=0; pacnt 0){ + ins[pacnt].points[ ins[pacnt].points.length-1 ].linesegment = _this.getdirection( + ins[pacnt].points[ ins[pacnt].points.length-1 ].x, + ins[pacnt].points[ ins[pacnt].points.length-1 ].y, + paths[pacnt].points[pcnt].x, + paths[pacnt].points[pcnt].y + ); + } + + // This corner point + ins[pacnt].points.push({ + x : paths[pacnt].points[pcnt].x, + y : paths[pacnt].points[pcnt].y, + linesegment : _this.getdirection( + paths[pacnt].points[pcnt].x, + paths[pacnt].points[pcnt].y, + (( paths[pacnt].points[pcnt].x + paths[pacnt].points[nextidx].x ) /2), + (( paths[pacnt].points[pcnt].y + paths[pacnt].points[nextidx].y ) /2) + ) + }); + + }// End of right angle enhance + + // interpolate between two path points + ins[pacnt].points.push({ + x : (( paths[pacnt].points[pcnt].x + paths[pacnt].points[nextidx].x ) /2), + y : (( paths[pacnt].points[pcnt].y + paths[pacnt].points[nextidx].y ) /2), + linesegment : _this.getdirection( + (( paths[pacnt].points[pcnt].x + paths[pacnt].points[nextidx].x ) /2), + (( paths[pacnt].points[pcnt].y + paths[pacnt].points[nextidx].y ) /2), + (( paths[pacnt].points[nextidx].x + paths[pacnt].points[nextidx2].x ) /2), + (( paths[pacnt].points[nextidx].y + paths[pacnt].points[nextidx2].y ) /2) + ) + }); + + }// End of pathpoints loop + + }// End of paths loop + + return ins; + },// End of internodes() + + this.testrightangle = function( path, idx1, idx2, idx3, idx4, idx5 ){ + return ( (( path.points[idx3].x === path.points[idx1].x) && + ( path.points[idx3].x === path.points[idx2].x) && + ( path.points[idx3].y === path.points[idx4].y) && + ( path.points[idx3].y === path.points[idx5].y) + ) || + (( path.points[idx3].y === path.points[idx1].y) && + ( path.points[idx3].y === path.points[idx2].y) && + ( path.points[idx3].x === path.points[idx4].x) && + ( path.points[idx3].x === path.points[idx5].x) + ) + ); + },// End of testrightangle() + + this.getdirection = function( x1, y1, x2, y2 ){ + var val = 8; + if(x1 < x2){ + if (y1 < y2){ val = 1; }// SouthEast + else if(y1 > y2){ val = 7; }// NE + else { val = 0; }// E + }else if(x1 > x2){ + if (y1 < y2){ val = 3; }// SW + else if(y1 > y2){ val = 5; }// NW + else { val = 4; }// W + }else{ + if (y1 < y2){ val = 2; }// S + else if(y1 > y2){ val = 6; }// N + else { val = 8; }// center, this should not happen + } + return val; + },// End of getdirection() + + // 4. Batch interpollation + this.batchinternodes = function( bpaths, options ){ + var binternodes = []; + for (var k in bpaths) { + if(!bpaths.hasOwnProperty(k)){ continue; } + binternodes[k] = _this.internodes(bpaths[k], options); + } + return binternodes; + }, + + // 5. tracepath() : recursively trying to fit straight and quadratic spline segments on the 8 direction internode path + + // 5.1. Find sequences of points with only 2 segment types + // 5.2. Fit a straight line on the sequence + // 5.3. If the straight line fails (distance error > ltres), find the point with the biggest error + // 5.4. Fit a quadratic spline through errorpoint (project this to get controlpoint), then measure errors on every point in the sequence + // 5.5. If the spline fails (distance error > qtres), find the point with the biggest error, set splitpoint = fitting point + // 5.6. Split sequence and recursively apply 5.2. - 5.6. to startpoint-splitpoint and splitpoint-endpoint sequences + + this.tracepath = function( path, ltres, qtres ){ + var pcnt=0, segtype1, segtype2, seqend, smp = {}; + smp.segments = []; + smp.boundingbox = path.boundingbox; + smp.holechildren = path.holechildren; + smp.isholepath = path.isholepath; + + while(pcnt < path.points.length){ + // 5.1. Find sequences of points with only 2 segment types + segtype1 = path.points[pcnt].linesegment; segtype2 = -1; seqend=pcnt+1; + while( + ((path.points[seqend].linesegment === segtype1) || (path.points[seqend].linesegment === segtype2) || (segtype2 === -1)) + && (seqend < path.points.length-1) ){ + + if((path.points[seqend].linesegment!==segtype1) && (segtype2===-1)){ segtype2 = path.points[seqend].linesegment; } + seqend++; + + } + if(seqend === path.points.length-1){ seqend = 0; } + + // 5.2. - 5.6. Split sequence and recursively apply 5.2. - 5.6. to startpoint-splitpoint and splitpoint-endpoint sequences + smp.segments = smp.segments.concat( _this.fitseq(path, ltres, qtres, pcnt, seqend) ); + + // forward pcnt; + if(seqend>0){ pcnt = seqend; }else{ pcnt = path.points.length; } + + }// End of pcnt loop + + return smp; + },// End of tracepath() + + // 5.2. - 5.6. recursively fitting a straight or quadratic line segment on this sequence of path nodes, + // called from tracepath() + this.fitseq = function( path, ltres, qtres, seqstart, seqend ){ + // return if invalid seqend + if( (seqend>path.points.length) || (seqend<0) ){ return []; } + // variables + var errorpoint=seqstart, errorval=0, curvepass=true, px, py, dist2; + var tl = (seqend-seqstart); if(tl<0){ tl += path.points.length; } + var vx = (path.points[seqend].x-path.points[seqstart].x) / tl, + vy = (path.points[seqend].y-path.points[seqstart].y) / tl; + + // 5.2. Fit a straight line on the sequence + var pcnt = (seqstart+1) % path.points.length, pl; + while(pcnt != seqend){ + pl = pcnt-seqstart; if(pl<0){ pl += path.points.length; } + px = path.points[seqstart].x + vx * pl; py = path.points[seqstart].y + vy * pl; + dist2 = (path.points[pcnt].x-px)*(path.points[pcnt].x-px) + (path.points[pcnt].y-py)*(path.points[pcnt].y-py); + if(dist2>ltres){curvepass=false;} + if(dist2>errorval){ errorpoint=pcnt; errorval=dist2; } + pcnt = (pcnt+1)%path.points.length; + } + // return straight line if fits + if(curvepass){ return [{ type:'L', x1:path.points[seqstart].x, y1:path.points[seqstart].y, x2:path.points[seqend].x, y2:path.points[seqend].y }]; } + + // 5.3. If the straight line fails (distance error>ltres), find the point with the biggest error + var fitpoint = errorpoint; curvepass = true; errorval = 0; + + // 5.4. Fit a quadratic spline through this point, measure errors on every point in the sequence + // helpers and projecting to get control point + var t=(fitpoint-seqstart)/tl, t1=(1-t)*(1-t), t2=2*(1-t)*t, t3=t*t; + var cpx = (t1*path.points[seqstart].x + t3*path.points[seqend].x - path.points[fitpoint].x)/-t2 , + cpy = (t1*path.points[seqstart].y + t3*path.points[seqend].y - path.points[fitpoint].y)/-t2 ; + + // Check every point + pcnt = seqstart+1; + while(pcnt != seqend){ + t=(pcnt-seqstart)/tl; t1=(1-t)*(1-t); t2=2*(1-t)*t; t3=t*t; + px = t1 * path.points[seqstart].x + t2 * cpx + t3 * path.points[seqend].x; + py = t1 * path.points[seqstart].y + t2 * cpy + t3 * path.points[seqend].y; + + dist2 = (path.points[pcnt].x-px)*(path.points[pcnt].x-px) + (path.points[pcnt].y-py)*(path.points[pcnt].y-py); + + if(dist2>qtres){curvepass=false;} + if(dist2>errorval){ errorpoint=pcnt; errorval=dist2; } + pcnt = (pcnt+1)%path.points.length; + } + // return spline if fits + if(curvepass){ return [{ type:'Q', x1:path.points[seqstart].x, y1:path.points[seqstart].y, x2:cpx, y2:cpy, x3:path.points[seqend].x, y3:path.points[seqend].y }]; } + // 5.5. If the spline fails (distance error>qtres), find the point with the biggest error + var splitpoint = fitpoint; // Earlier: Math.floor((fitpoint + errorpoint)/2); + + // 5.6. Split sequence and recursively apply 5.2. - 5.6. to startpoint-splitpoint and splitpoint-endpoint sequences + return _this.fitseq( path, ltres, qtres, seqstart, splitpoint ).concat( + _this.fitseq( path, ltres, qtres, splitpoint, seqend ) ); + + },// End of fitseq() + + // 5. Batch tracing paths + this.batchtracepaths = function(internodepaths,ltres,qtres){ + var btracedpaths = []; + for(var k in internodepaths){ + if(!internodepaths.hasOwnProperty(k)){ continue; } + btracedpaths.push( _this.tracepath(internodepaths[k],ltres,qtres) ); + } + return btracedpaths; + }, + + // 5. Batch tracing layers + this.batchtracelayers = function(binternodes, ltres, qtres){ + var btbis = []; + for(var k in binternodes){ + if(!binternodes.hasOwnProperty(k)){ continue; } + btbis[k] = _this.batchtracepaths(binternodes[k], ltres, qtres); + } + return btbis; + }, + + //////////////////////////////////////////////////////////// + // + // SVG Drawing functions + // + //////////////////////////////////////////////////////////// + + // Rounding to given decimals https://stackoverflow.com/questions/11832914/round-to-at-most-2-decimal-places-in-javascript + this.roundtodec = function(val,places){ return +val.toFixed(places); }, + + // Getting SVG path element string from a traced path + this.svgpathstring = function( tracedata, lnum, pathnum, options ){ + + var layer = tracedata.layers[lnum], smp = layer[pathnum], str='', pcnt; + + // Line filter + if(options.linefilter && (smp.segments.length < 3)){ return str; } + + // Starting path element, desc contains layer and path number + str = ''; + + // Rendering control points + if(options.lcpr || options.qcpr){ + for(pcnt=0; pcnt'; + str += ''; + str += ''; + str += ''; + } + if( (!smp.segments[pcnt].hasOwnProperty('x3')) && options.lcpr){ + str += ''; + } + } + + // Hole children control points + for( var hcnt=0; hcnt < smp.holechildren.length; hcnt++){ + var hsmp = layer[ smp.holechildren[hcnt] ]; + for(pcnt=0; pcnt'; + str += ''; + str += ''; + str += ''; + } + if( (!hsmp.segments[pcnt].hasOwnProperty('x3')) && options.lcpr){ + str += ''; + } + } + } + }// End of Rendering control points + + return str; + + },// End of svgpathstring() + + // Converting tracedata to an SVG string + this.getsvgstring = function( tracedata, options ){ + + options = _this.checkoptions(options); + + var w = tracedata.width * options.scale, h = tracedata.height * options.scale; + + // SVG start + var svgstr = ''; + + // Drawing: Layers and Paths loops + for(var lcnt=0; lcnt < tracedata.layers.length; lcnt++){ + for(var pcnt=0; pcnt < tracedata.layers[lcnt].length; pcnt++){ + + // Adding SVG string + if( !tracedata.layers[lcnt][pcnt].isholepath ){ + svgstr += _this.svgpathstring( tracedata, lcnt, pcnt, options ); + } + + }// End of paths loop + }// End of layers loop + + // SVG End + svgstr+=''; + + return svgstr; + + },// End of getsvgstring() + + // Comparator for numeric Array.sort + this.compareNumbers = function(a,b){ return a - b; }, + + // Convert color object to rgba string + this.torgbastr = function(c){ return 'rgba('+c.r+','+c.g+','+c.b+','+c.a+')'; }, + + // Convert color object to SVG color string + this.tosvgcolorstr = function(c, options){ + return 'fill="rgb('+c.r+','+c.g+','+c.b+')" stroke="rgb('+c.r+','+c.g+','+c.b+')" stroke-width="'+options.strokewidth+'" opacity="'+c.a/255.0+'" '; + }, + + // Helper function: Appending an element to a container from an svgstring + this.appendSVGString = function(svgstr,parentid){ + var div; + if(parentid){ + div = document.getElementById(parentid); + if(!div){ + div = document.createElement('div'); + div.id = parentid; + document.body.appendChild(div); + } + }else{ + div = document.createElement('div'); + document.body.appendChild(div); + } + div.innerHTML += svgstr; + }, + + //////////////////////////////////////////////////////////// + // + // Canvas functions + // + //////////////////////////////////////////////////////////// + + // Gaussian kernels for blur + this.gks = [ [0.27901,0.44198,0.27901], [0.135336,0.228569,0.272192,0.228569,0.135336], [0.086776,0.136394,0.178908,0.195843,0.178908,0.136394,0.086776], + [0.063327,0.093095,0.122589,0.144599,0.152781,0.144599,0.122589,0.093095,0.063327], [0.049692,0.069304,0.089767,0.107988,0.120651,0.125194,0.120651,0.107988,0.089767,0.069304,0.049692] ], + + // Selective Gaussian blur for preprocessing + this.blur = function(imgd,radius,delta){ + var i,j,k,d,idx,racc,gacc,bacc,aacc,wacc; + + // new ImageData + var imgd2 = { width:imgd.width, height:imgd.height, data:[] }; + + // radius and delta limits, this kernel + radius = Math.floor(radius); if(radius<1){ return imgd; } if(radius>5){ radius = 5; } delta = Math.abs( delta ); if(delta>1024){ delta = 1024; } + var thisgk = _this.gks[radius-1]; + + // loop through all pixels, horizontal blur + for( j=0; j < imgd.height; j++ ){ + for( i=0; i < imgd.width; i++ ){ + + racc = 0; gacc = 0; bacc = 0; aacc = 0; wacc = 0; + // gauss kernel loop + for( k = -radius; k < radius+1; k++){ + // add weighted color values + if( (i+k > 0) && (i+k < imgd.width) ){ + idx = (j*imgd.width+i+k)*4; + racc += imgd.data[idx ] * thisgk[k+radius]; + gacc += imgd.data[idx+1] * thisgk[k+radius]; + bacc += imgd.data[idx+2] * thisgk[k+radius]; + aacc += imgd.data[idx+3] * thisgk[k+radius]; + wacc += thisgk[k+radius]; + } + } + // The new pixel + idx = (j*imgd.width+i)*4; + imgd2.data[idx ] = Math.floor(racc / wacc); + imgd2.data[idx+1] = Math.floor(gacc / wacc); + imgd2.data[idx+2] = Math.floor(bacc / wacc); + imgd2.data[idx+3] = Math.floor(aacc / wacc); + + }// End of width loop + }// End of horizontal blur + + // copying the half blurred imgd2 + var himgd = new Uint8ClampedArray(imgd2.data); + + // loop through all pixels, vertical blur + for( j=0; j < imgd.height; j++ ){ + for( i=0; i < imgd.width; i++ ){ + + racc = 0; gacc = 0; bacc = 0; aacc = 0; wacc = 0; + // gauss kernel loop + for( k = -radius; k < radius+1; k++){ + // add weighted color values + if( (j+k > 0) && (j+k < imgd.height) ){ + idx = ((j+k)*imgd.width+i)*4; + racc += himgd[idx ] * thisgk[k+radius]; + gacc += himgd[idx+1] * thisgk[k+radius]; + bacc += himgd[idx+2] * thisgk[k+radius]; + aacc += himgd[idx+3] * thisgk[k+radius]; + wacc += thisgk[k+radius]; + } + } + // The new pixel + idx = (j*imgd.width+i)*4; + imgd2.data[idx ] = Math.floor(racc / wacc); + imgd2.data[idx+1] = Math.floor(gacc / wacc); + imgd2.data[idx+2] = Math.floor(bacc / wacc); + imgd2.data[idx+3] = Math.floor(aacc / wacc); + + }// End of width loop + }// End of vertical blur + + // Selective blur: loop through all pixels + for( j=0; j < imgd.height; j++ ){ + for( i=0; i < imgd.width; i++ ){ + + idx = (j*imgd.width+i)*4; + // d is the difference between the blurred and the original pixel + d = Math.abs(imgd2.data[idx ] - imgd.data[idx ]) + Math.abs(imgd2.data[idx+1] - imgd.data[idx+1]) + + Math.abs(imgd2.data[idx+2] - imgd.data[idx+2]) + Math.abs(imgd2.data[idx+3] - imgd.data[idx+3]); + // selective blur: if d>delta, put the original pixel back + if(d>delta){ + imgd2.data[idx ] = imgd.data[idx ]; + imgd2.data[idx+1] = imgd.data[idx+1]; + imgd2.data[idx+2] = imgd.data[idx+2]; + imgd2.data[idx+3] = imgd.data[idx+3]; + } + } + }// End of Selective blur + + return imgd2; + + },// End of blur() + + // Helper function: loading an image from a URL, then executing callback with canvas as argument + this.loadImage = function(url,callback,options){ + var img = new Image(); + if(options && options.corsenabled){ img.crossOrigin = 'Anonymous'; } + img.onload = function(){ + var canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + var context = canvas.getContext('2d'); + context.drawImage(img,0,0); + callback(canvas); + }; + img.src = url; + }, + + // Helper function: getting ImageData from a canvas + this.getImgdata = function(canvas){ + var context = canvas.getContext('2d'); + return context.getImageData(0,0,canvas.width,canvas.height); + }, + + // Special palette to use with drawlayers() + this.specpalette = [ + {r:0,g:0,b:0,a:255}, {r:128,g:128,b:128,a:255}, {r:0,g:0,b:128,a:255}, {r:64,g:64,b:128,a:255}, + {r:192,g:192,b:192,a:255}, {r:255,g:255,b:255,a:255}, {r:128,g:128,b:192,a:255}, {r:0,g:0,b:192,a:255}, + {r:128,g:0,b:0,a:255}, {r:128,g:64,b:64,a:255}, {r:128,g:0,b:128,a:255}, {r:168,g:168,b:168,a:255}, + {r:192,g:128,b:128,a:255}, {r:192,g:0,b:0,a:255}, {r:255,g:255,b:255,a:255}, {r:0,g:128,b:0,a:255} + ], + + // Helper function: Drawing all edge node layers into a container + this.drawLayers = function(layers,palette,scale,parentid){ + scale = scale||1; + var w,h,i,j,k; + + // Preparing container + var div; + if(parentid){ + div = document.getElementById(parentid); + if(!div){ + div = document.createElement('div'); + div.id = parentid; + document.body.appendChild(div); + } + }else{ + div = document.createElement('div'); + document.body.appendChild(div); + } + + // Layers loop + for (k in layers) { + if(!layers.hasOwnProperty(k)){ continue; } + + // width, height + w=layers[k][0].length; h=layers[k].length; + + // Creating new canvas for every layer + var canvas = document.createElement('canvas'); canvas.width=w*scale; canvas.height=h*scale; + var context = canvas.getContext('2d'); + + // Drawing + for(j=0; j \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/process_overview.md b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/process_overview.md new file mode 100644 index 0000000..099dc9c --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/process_overview.md @@ -0,0 +1,57 @@ +### Process overview +#### 1. Color quantization +The **colorquantization** function creates an indexed image (https://en.wikipedia.org/wiki/Indexed_color) using a variant of the https://en.wikipedia.org/wiki/K-means_clustering or https://en.wikipedia.org/wiki/K-medians_clustering algorithm. + +![alt Original image (20x scale)](docimages/s2.png) + +#### 2. Layer separation and edge detection +The **layering** function creates arrays for every color, and calculates edge node types. These are at the center of every 4 pixels, shown here as dots. This, **pathscan** and **interpolation** are a reinvented variant of the https://en.wikipedia.org/wiki/Marching_squares algorithm. + +![alt layer 0: black](docimages/s3.png) +![alt layer 1: yellow](docimages/s4.png) +![alt edge node examples](docimages/s7.png) + +#### 3. Pathscan +The **pathscan** function finds chains of edge nodes, example: the cyan dots and lines. + +![alt an edge node path](docimages/s8.png) + +#### 4. Interpolation +The **internodes** function interpolates the coordinates of the edge node paths. Every line segment in the new path has one of the 8 directions (East, North East, N, NW, W, SW, S, SE). + +![alt interpolating](docimages/s9.png) +![alt interpolation result](docimages/s10.png) + +#### 5. Tracing +The **tracepath** function splits the interpolated paths into sequences with two directions. + +![alt a sequence](docimages/s11.png) + +The **fitseq** function tries to fit a straight line on the start- and endpoint of the sequence (black line). If the distance error between the calculated points (black line) and actual sequence points (blue dots) is greater than the treshold, the point with the greatest error is selected (red line). + +![alt fitting a straight line](docimages/s12.png) + +The **fitseq** function tries to fit a quadratic spline through the error point. + +![alt fitting a quadratic spline](docimages/s13.png) +![alt fitting line segments](docimages/s14.png) +![alt result with control points](docimages/s15.png) + +If the **fitseq** function can not fit a straight line or a quadratic spline to the sequence with the given error tresholds, then it will split the sequence in two and recursively call **fitseq** on each part (https://en.wikipedia.org/wiki/Divide_and_conquer_algorithm). + +#### 6. SVG rendering +The coordinates are rendered to [SVG Paths](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths) in the **getsvgstring** function. + +### Ideas for improvement + +- Error handling: there's very little error handling now, Out of memory can happen easily with big images or many layers. +- Color quantization: other algorithms e.g. https://en.wikipedia.org/wiki/Octree ? +- Color quantization: colors with few pixels are randomized, but probably the most distant colors should be found instead. +- Tracing: 5.1. finding more suitable sequences. +- Tracing: 5.5. splitpoint = fitpoint ; this is just a guess, there might be a better splitpoint. +- Tracing: 5.7. If splitpoint-endpoint is a spline, try to add new points from the next sequence; this is not implemented. +- Tracing: cubic splines or other curves? +- Default values: they are chosen because they seemed OK, not based on calculations. +- Output: [PDF](https://en.wikipedia.org/wiki/Portable_Document_Format), [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF), [G-code](https://en.wikipedia.org/wiki/G-code) or other output? +- comparing and integrating ideas from https://en.wikipedia.org/wiki/Potrace +- Pathomit with background hole path shrinking diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/simplify_interop.html b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/simplify_interop.html new file mode 100644 index 0000000..f53a71a --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/simplify_interop.html @@ -0,0 +1,126 @@ + + + + + + + + + + +
+ + diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/smiley.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/smiley.png new file mode 100644 index 0000000..f926601 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/smiley.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/smileyRGB.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/smileyRGB.png new file mode 100644 index 0000000..a7c9eee Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/smileyRGB.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/1.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/1.png new file mode 100644 index 0000000..225ee40 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/1.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/10.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/10.png new file mode 100644 index 0000000..425774b Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/10.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/11.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/11.png new file mode 100644 index 0000000..1cc5428 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/11.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/12.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/12.png new file mode 100644 index 0000000..8925922 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/12.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/13.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/13.png new file mode 100644 index 0000000..9dcc909 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/13.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/14.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/14.png new file mode 100644 index 0000000..433a73b Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/14.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/15.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/15.png new file mode 100644 index 0000000..394b800 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/15.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/16.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/16.png new file mode 100644 index 0000000..832f93d Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/16.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/2.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/2.png new file mode 100644 index 0000000..d598a47 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/2.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/3.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/3.png new file mode 100644 index 0000000..dda0fa3 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/3.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/4.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/4.png new file mode 100644 index 0000000..62b75c1 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/4.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/5.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/5.png new file mode 100644 index 0000000..5b5f550 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/5.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/6.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/6.png new file mode 100644 index 0000000..2192508 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/6.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/7.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/7.png new file mode 100644 index 0000000..1514eee Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/7.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/8.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/8.png new file mode 100644 index 0000000..7c8a32c Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/8.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/9.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/9.png new file mode 100644 index 0000000..caff72c Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/9.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/combined.png b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/combined.png new file mode 100644 index 0000000..a5741ea Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/testimages/combined.png differ diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/version_history.md b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/version_history.md new file mode 100644 index 0000000..ca1dd00 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs-master/version_history.md @@ -0,0 +1,75 @@ +## Version history + +### 1.2.6 + - FIXED: hole shape parent search (Issues #31 #39) + - FIXED: Handle (absolute) paths in CLI correctly Issue #42 + +### 1.2.5 + - RGBA ImageData check in colorquantization(), solving Issue #24 and #18 + +### 1.2.4 + - ```options.layering``` : default 0 = sequential, new method ; 1 = parallel, old method. (Enhancement Issue #17) + - case insensitive option preset names + - README.md reorganizing + +### 1.2.3 + + - Node.js Command line interface (Enhancement Issue #13) + - FIXED: Pathomit problem thanks to EusthEnoptEron (Issue #14) + - options.corsenabled for [CORS Image loading](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image) thanks to neel-radica (Issue #12) + +### 1.2.2 + + - FIXED: missing hole in path because of incorrect bounding box (Issue #11) + - Posterized3 option preset + - Changed svgpathstring() arguments to simplify getsvgstring() + +### 1.2.1 + + - FIXED: Gaussian blur preprocessing is now independent of DOM and canvas, thus working directly with Node.js (Issue #9) + +### 1.2.0 + +This is a major update, changing some internal logic and option default values. The API is compatible, so it should work out of the box. + + - FIXED: transparent holes are now possible. ( Issue #7 and #8 ) + - Deterministic output by default: ```options.colorsampling = 2``` ; ```options.mincolorratio = 0``` are deterministic and the defaults now. + - Right angle enhancing: ```options.rightangleenhance``` ( default : true ) + - Option presets (see below) + - Custom strokewidth with ```options.strokewidth``` ( default : 1 ) + - Line filter with ```options.linefilter``` ( default : false ) + - Simplified ```getsvgstring()```; ```options.desc = false``` by default; splitpoint = fitpoint in fitseq(); small bugfixes and optimizations + +Version history and README for the old 1.1.2 version is [here.](https://github.com/jankovicsandras/imagetracerjs/blob/master/README_v1.1.2.md) + +### 1.1.2 + +- minor bugfixes +- lookup based ```pathscan()``` + +### 1.1.1 + +- Bugfix: CSS3 RGBA output in SVG was technically incorrect (however supported by major browsers), so this is changed. [More info](https://stackoverflow.com/questions/6042550/svg-fill-color-transparency-alpha) + +### 1.1.0 + +- it works with Node.js (external library required to load image into an ImageData object) +- export as AMD module / Node module / browser or worker variable +- new syntax: ```ImageTracer112.imageToTracedata()```, no need to initialize +- fixed ```options``` with hasOwnProperty: 0 values are not replaced with defaults, fixed polygons with coordinates x=0 or y=0 +- transparency support: alpha is not discarded now, it is given more weight in color quantization +- new ```options.roundcoords``` : rounding coordinates to a given decimal place. This can reduce SVG length significantly (>20%) with minor loss of precision. +- new ```options.desc``` : setting this to false will turn off path descriptions, reducing SVG length. +- new ```options.viewbox``` : setting this to true will use viewBox instead of exact width and height +- new ```options.colorsampling``` : color quantization will sample the colors now by default, can be turned off. +- new ```options.blurradius``` : setting this to 1..5 will preprocess the image with a selective Gaussian blur with ```options.blurdelta``` treshold. This can filter noise and improve quality. +- ```imagedataToTracedata()``` returns image width and height in tracedata +- ```getsvgstring()``` needs now only ```tracedata``` and ```options``` as parameters +- ```colorquantization()``` needs now only ```imgd``` and ```options``` as parameters +- background field is removed from the results of color quantization +- ESLint passed +- test automation and simple statistics in imagetracer_test_automation.html + +### 1.0.0 - 1.0.4 + +- first published version + bugfixes \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.inx b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.inx new file mode 100644 index 0000000..6877757 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.inx @@ -0,0 +1,93 @@ + + + Imagetracer.js + fablabchemnitz.de.imagetracerjs + + + + + + + false + 1.0 + 1.0 + 8 + true + + + + + + + + + 16 + 0 + 3 + + + + + + + + + + + + 1.0 + false + + 1 + false + false + + + + 0 + 20.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../000_about_fablabchemnitz.svg + + + + all + + + + + + + + diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py new file mode 100644 index 0000000..990a282 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py @@ -0,0 +1,212 @@ +#!/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 + +""" +Extension for InkScape 1.X +Features + - will vectorize your beautiful image into a more beautiful SVG trace with separated infills(break apart into single surfaces like a puzzle) + +Author: Mario Voigt / FabLab Chemnitz +Mail: mario.voigt@stadtfabrikanten.org +Date: 18.08.2020 +Last patch: 24.04.2021 +License: GNU GPL v3 + +Used version of imagetracerjs: https://github.com/jankovicsandras/imagetracerjs/commit/4d0f429efbb936db1a43db80815007a2cb113b34 + +""" + +class Imagetracerjs(inkex.EffectExtension): + + def checkImagePath(self, element): + xlink = element.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 = element.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 add_arguments(self, pars): + pars.add_argument("--tab") + pars.add_argument("--keeporiginal", type=inkex.Boolean, default=False, help="Keep original image on canvas") + pars.add_argument("--ltres", type=float, default=1.0, help="Error treshold straight lines") + pars.add_argument("--qtres", type=float, default=1.0, help="Error treshold quadratic splines") + pars.add_argument("--pathomit", type=int, default=8, help="Noise reduction - discard edge node paths shorter than") + pars.add_argument("--rightangleenhance", type=inkex.Boolean, default=True, help="Enhance right angle corners") + pars.add_argument("--colorsampling", default="2",help="Color sampling") + pars.add_argument("--numberofcolors", type=int, default=16, help="Number of colors to use on palette") + pars.add_argument("--mincolorratio", type=int, default=0, help="Color randomization ratio") + pars.add_argument("--colorquantcycles", type=int, default=3, help="Color quantization will be repeated this many times") + pars.add_argument("--layering", default="0",help="Layering") + pars.add_argument("--strokewidth", type=float, default=1.0, help="SVG stroke-width") + pars.add_argument("--linefilter", type=inkex.Boolean, default=False, help="Noise reduction line filter") + #pars.add_argument("--scale", type=float, default=1.0, help="Coordinate scale factor") + pars.add_argument("--roundcoords", type=int, default=1, help="Decimal places for rounding") + pars.add_argument("--viewbox", type=inkex.Boolean, default=False, help="Enable or disable SVG viewBox") + pars.add_argument("--desc", type=inkex.Boolean, default=False, help="SVG descriptions") + pars.add_argument("--blurradius", type=int, default=0, help="Selective Gaussian blur preprocessing") + pars.add_argument("--blurdelta", type=float, default=20.0, help="RGBA delta treshold for selective Gaussian blur preprocessing") + + def effect(self): + + # internal overwrite for scale: + self.options.scale = 1.0 + + if len(self.svg.selected) > 0: + images = self.svg.selection.filter(inkex.Image).values() + if len(images) > 0: + for image in images: + self.path = self.checkImagePath(image) # This also ensures the file exists + if self.path is None: # check if image is embedded or linked + image_string = image.get('{http://www.w3.org/1999/xlink}href') + # find comma position + i = 0 + while i < 40: + if image_string[i] == ',': + break + i = i + 1 + img = Image.open(BytesIO(base64.b64decode(image_string[i + 1:len(image_string)]))) + else: + img = Image.open(self.path) + + # Write the embedded or linked image to temporary directory + if os.name == "nt": + exportfile = "imagetracerjs.png" + else: + exportfile ="/tmp/imagetracerjs.png" + + if img.mode != 'RGB': + img = img.convert('RGB') + img.save(exportfile, "png") + + nodeclipath = os.path.join("imagetracerjs-master", "nodecli", "nodecli.js") + + ## Build up imagetracerjs command according to your settings from extension GUI + command = "node --trace-deprecation " # "node.exe" or "node" on Windows or just "node" on Linux + if os.name=="nt": # your OS is Windows. We handle path separator as "\\" instead of unix-like "/" + command += str(nodeclipath).replace("\\", "\\\\") + else: + command += str(nodeclipath) + command += " " + exportfile + command += " ltres " + str(self.options.ltres) + command += " qtres " + str(self.options.qtres) + command += " pathomit " + str(self.options.pathomit) + command += " rightangleenhance " + str(self.options.rightangleenhance).lower() + command += " colorsampling " + str(self.options.colorsampling) + command += " numberofcolors " + str(self.options.numberofcolors) + command += " mincolorratio " + str(self.options.mincolorratio) + command += " numberofcolors " + str(self.options.numberofcolors) + command += " colorquantcycles " + str(self.options.colorquantcycles) + command += " layering " + str(self.options.layering) + command += " strokewidth " + str(self.options.strokewidth) + command += " linefilter " + str(self.options.linefilter).lower() + command += " scale " + str(self.options.scale) + command += " roundcoords " + str(self.options.roundcoords) + command += " viewbox " + str(self.options.viewbox).lower() + command += " desc " + str(self.options.desc).lower() + command += " blurradius " + str(self.options.blurradius) + command += " blurdelta " + str(self.options.blurdelta) + + # Create the vector traced SVG file + with os.popen(command, "r") as tracerprocess: + result = tracerprocess.read() + if "was saved!" not in result: + self.msg("Error while processing input: " + result) + self.msg("Check the image file (maybe convert and save as new file) and try again.") + self.msg("\nYour parser command:") + self.msg(command) + + + # proceed if traced 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()) + trace_width = None + trace_height = None + if doc.get('width') is not None and doc.get('height') is not None: + trace_width = doc.get('width') + trace_height = doc.get('height') + else: + viewBox = doc.get('viewBox') #eg "0 0 700 600" + trace_width = viewBox.split(' ')[2] + trace_height = viewBox.split(' ')[3] + + # add transformation to fit previous XY coordinates and width/height + # image might also be influenced by other transformations from parent: + parent = image.getparent() + if parent is not None and parent != self.document.getroot(): + tpc = parent.composed_transform() + x_offset = tpc.e + y_offset = tpc.f + else: + x_offset = 0.0 + y_offset = 0.0 + img_w = image.get('width') + img_h = image.get('height') + img_x = image.get('x') + img_y = image.get('y') + if img_w is not None and img_h is not None and img_x is not None and img_y is not None: + #if width/height are not unitless but end with px, mm, in etc. we have to convert to a float number + if img_w[-1].isdigit() is False: + img_w = self.svg.uutounit(img_w) + if img_h[-1].isdigit() is False: + img_h = self.svg.uutounit(img_h) + + transform = "matrix({:1.6f}, 0, 0, {:1.6f}, {:1.6f}, {:1.6f})"\ + .format(float(img_w) / float(trace_width), float(img_h) / float(trace_height), float(img_x) + x_offset, float(img_y) + y_offset) + newGroup.attrib['transform'] = transform + else: + t = image.composed_transform() + img_w = t.a + img_h = t.d + img_x = t.e + img_y = t.f + transform = "matrix({:1.6f}, 0, 0, {:1.6f}, {:1.6f}, {:1.6f})"\ + .format(float(img_w) / float(trace_width), float(img_h) / float(trace_height), float(img_x) + x_offset, float(img_y) + y_offset) + newGroup.attrib['transform'] = transform + + for child in doc.getchildren(): + newGroup.append(child) + + # Delete 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: + image.delete() + else: + self.msg("No images found in selection! Check if you selected a group instead.") + else: + self.msg("Selection is empty. Please select one or more images.") + +if __name__ == '__main__': + Imagetracerjs().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/meta.json b/extensions/fablabchemnitz/imagetracerjs/meta.json new file mode 100644 index 0000000..bd66223 --- /dev/null +++ b/extensions/fablabchemnitz/imagetracerjs/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Imagetracer.js", + "id": "fablabchemnitz.de.imagetracerjs", + "path": "imagetracerjs", + "dependent_extensions": null, + "original_name": "Imagetracer.js", + "original_id": "fablabchemnitz.de.imagetracerjs", + "license": "GNU GPL v3", + "license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/LICENSE", + "comment": "written by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/imagetracerjs", + "fork_url": null, + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Imagetracer.js", + "inkscape_gallery_url": "https://inkscape.org/~MarioVoigt/%E2%98%85imagetracerjs-for-inkscape", + "main_authors": [ + "github.com/jankovicsandras", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/node.exe b/extensions/fablabchemnitz/imagetracerjs/node.exe new file mode 100644 index 0000000..a57ccd9 Binary files /dev/null and b/extensions/fablabchemnitz/imagetracerjs/node.exe differ diff --git a/extensions/fablabchemnitz/jitter_gradients/jitter_gradients.inx b/extensions/fablabchemnitz/jitter_gradients/jitter_gradients.inx new file mode 100644 index 0000000..85562ef --- /dev/null +++ b/extensions/fablabchemnitz/jitter_gradients/jitter_gradients.inx @@ -0,0 +1,17 @@ + + + Jitter Gradients + fablabchemnitz.de.jitter_gradients + 0 + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/jitter_gradients/jitter_gradients.py b/extensions/fablabchemnitz/jitter_gradients/jitter_gradients.py new file mode 100644 index 0000000..40143a7 --- /dev/null +++ b/extensions/fablabchemnitz/jitter_gradients/jitter_gradients.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import inkex +from inkex import Style +import re +import random + +class JitterGradients(inkex.EffectExtension): + + def add_arguments(self, pars): + pars.add_argument('-j', '--jitter_amount', type=int, default=10, help='Relative to distance between gradient nodes') + + def getUrlFromString(self, text): + pattern = re.compile(r"url\(#([a-zA-Z0-9_-]+)\)") + result = re.search(pattern, text) + if (result): + return result.group(1) + else: + return 0; + + def getFill(self, element): + if(element.get('fill') and self.getUrlFromString(element.get('fill'))): + return self.getUrlFromString(element.get('fill')) + elif (element.get('style') and Style(element.get('style'))['fill'] and self.getUrlFromString(Style(element.get('style'))['fill'])): + return self.getUrlFromString(Style(element.get('style'))['fill']) + else: + return None + + def getGradientFromId(self, elementId): + element = self.svg.getElementById(elementId) + if (element is not None and element.tag.find("linearGradient") >= 0): + return element + else: + return None + + def effect(self): + option = self.options.jitter_amount + self._main_function(option) + + def _main_function(self, amount): + for element in self.svg.selected.values(): + fillId = self.getFill(element) + if (fillId is None): + continue + + gradient = self.getGradientFromId(fillId) + if (gradient is None): + continue + + x1 = self.svg.unittouu(gradient.get("x1")) + y1 = self.svg.unittouu(gradient.get("y1")) + x2 = self.svg.unittouu(gradient.get("x2")) + y2 = self.svg.unittouu(gradient.get("y2")) + + x1 += random.uniform(-amount, amount) + y1 += random.uniform(-amount, amount) + x2 += random.uniform(-amount, amount) + y2 += random.uniform(-amount, amount) + + gradient.set('x1', str(self.svg.uutounit(x1, self.svg.unit)) + self.svg.unit) + gradient.set('y1', str(self.svg.uutounit(y1, self.svg.unit)) + self.svg.unit) + gradient.set('x2', str(self.svg.uutounit(x2, self.svg.unit)) + self.svg.unit) + gradient.set('y2', str(self.svg.uutounit(y2, self.svg.unit)) + self.svg.unit) + +if __name__ == '__main__': + JitterGradients().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/jitter_gradients/meta.json b/extensions/fablabchemnitz/jitter_gradients/meta.json new file mode 100644 index 0000000..1a58262 --- /dev/null +++ b/extensions/fablabchemnitz/jitter_gradients/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Jitter Gradients", + "id": "fablabchemnitz.de.jitter_gradients", + "path": "jitter_gradients", + "dependent_extensions": null, + "original_name": "Jitter Gradients", + "original_id": "org.inkscape.color.jittergradients", + "license": "GNU GPL v2", + "license_url": "https://inkscape.org/~vermette/%E2%98%85jitter-gradients", + "comment": "ported to Inkscape v1 manually by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/jitter_gradients", + "fork_url": "https://inkscape.org/~vermette/%E2%98%85jitter-gradients", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Jitter+Gradients", + "inkscape_gallery_url": null, + "main_authors": [ + "inkscape.org/vermette", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/kvec/KVEC.KEY b/extensions/fablabchemnitz/kvec/KVEC.KEY new file mode 100644 index 0000000..f23428c Binary files /dev/null and b/extensions/fablabchemnitz/kvec/KVEC.KEY differ diff --git a/extensions/fablabchemnitz/kvec/README.txt b/extensions/fablabchemnitz/kvec/README.txt new file mode 100644 index 0000000..1202754 --- /dev/null +++ b/extensions/fablabchemnitz/kvec/README.txt @@ -0,0 +1,149 @@ +****************************************************************************** +* K V E C R E A D M E F I L E * +* (License conditions) * +* * +* +++ KK-Software +++ KK-Software +++ KK-Software +++ KK-Software +++ * +*----------------------------------------------------------------------------* +* Author: Karl-Heinz Kuhl, Brunnlohestr. 2, 92637 Weiden, Germany * +*----------------------------------------------------------------------------* +* Voice FAX E-Mail * +* +49 961 6340837 +49 961 61455 support@kvec.de * +****************************************************************************** + +This program was formerly licensed under the shareware concept. +It is now freeware (2010). + +It may be freely distributed, as long as it is complete. +It may not be altered in any way or +distributed by public domain distribution companies without further inquiry. +Furthermore it is not allowed to modify the program or any part of it in any +manner or to disassemble the program. + + +KVEC is provided "as is", without warranty of any kind or guarantee of +fitness for a particular purpose, either expressed or implied, all of which +are hereby explicitly disclaimed. +The author is not liable for damages of any kind which occur by improper +use of the program by the user, or which were caused by properties of the +operating system under which the program runs. + +The newest version of KVEC can be downloaded from my homepage. + + +Voice: (+49-9602) 9441945 (Mo-Fr, 10-12 Uhr) +Fax/Voice: (+49-9602) 9441946 (24h) +E-Mail: support@kvec.de +WWW: http://www.kvec.de + + +The KVEC software (Copyright (C) 1997 - 2019 by KK-Software) was developed +by KK-Software with the exception of the JPEG reader with the exception of +the JPEG reader and the zlib compression/decompression routines(see acknowledgements). + +A C K N O W L E D G E M E N T S: +-------------------------------- + +The code for the JPEG reader was taken from the free JPEG library +which is developed by the Independent JPEG Group (IJG). +Copyright (C) 1994-1998, Thomas G. Lane. + +The FAX G3/G4 decompression and compression algorithms were derived from parts +of Sam Leffler's free Tiff library. +Copyright (c) 1988-1997 Sam Leffler +Copyright (c) 1991-1997 Silicon Graphics, Inc. + +The code for the SVGZ and Flash MX SWF format uses the zlib compression method and was +taken from the free zlib library developed by Jean-loup Gailly and Mark Adler (C) 1995-2002 + +Many thanks also to (in alphabetical order): + + +Carsten Gehle (for the implementation on NeXT platforms) + +Till Jonas (for help with the AI-Format) + +Marcello Krebber (for support of the ART-Format and for OS/2 specific questions) + +Peter Neubaecker (for the 'bezier' algorithm and for the 'justifying' + algorithms and for the many discussions). + +Matthias Oepen (for the implementation on the HP-UNIX platform) + +Joe Czychosz (for the implementation of the thinning algorithm) + + + +============================================================================== + +****************************************************************************** +* K V E C R E A D M E D A T E I * +* (Lizenz-Bedingungen) * +* * +* +++ KK-Software +++ KK-Software +++ KK-Software +++ KK-Software +++ * +*----------------------------------------------------------------------------* +* Autor: Karl-Heinz Kuhl, Bergstr. 4, 92711 Parkstein, Deutschland * +*----------------------------------------------------------------------------* +* Tel. FAX E-Mail * +* +49 9602 9441945 +49 9602 9441946 support@kvec.de * +****************************************************************************** + +Dieses Programm wurde frher nach dem Sharewarekonzept vermarktet. +Es ist nun Freewareware (Stand: 2010) + +Diese Software Programm darf frei kopiert werden, +sofern sie vollstaendig ist. Sie darf in keiner Form veraendert, +oder ohne Rueckfrage durch Puplic-Domain-Versandtfirmen verschickt werden. +Weiterhin ist es nicht erlaubt, das Programm oder Teile des Programms in +irgendeiner Form zu modifizieren oder zu disassemblieren. + + +Der Autor uebernimmt keine Haftung fuer Schaeden irgendwelcher Art, die +durch unsachgemaessen Gebrauch des Programms duch den Benutzer verursacht +wurden, oder die von Eigenschaften des Betriebssystems herruehren, auf dem +KVEC laeuft. + + +Die neueste Version von KVEC steht immer in meiner Homepage zum +Download zur Verfuegung. + + +Die KVEC Software (Copyright (C) 1997 - 2010 by KK-Software) wurde +ausschliesslich von KK-Software entwickelt, mit Ausnahme des JPEG Readers +(siehe Acknowledgements) + +A C K N O W L E D G E M E N T S: +-------------------------------- + +Der Code fuer den JPEG Reader wurde aus der freien JPEG library (Vers. 6b) +uebernommen, die von der Independent JPEG Group (IJG) entwickelt wird. +Copyright (C) 1994-1998, Thomas G. Lane. + +Die FAX G3/G4 Kompressions- und Dekompressions-Algorithmen wurden aus Teilen +der frei verfuegbaren Tiff-Library von Sam Leffler abgeleitet. +Copyright (c) 1988-1997 Sam Leffler +Copyright (c) 1991-1997 Silicon Graphics, Inc. + +Der Code fuer die SVGZ und Flash MX SWF Formate benutzt die zlib Kompressions-Methode, die +von der freien zlib Library (entwickelt von Jean-loup Gailly and Mark Adler (C) 1995-2002) +uebernommen wurde. + + +Vielen Dank ausserdem an (in alphabetischer Reihenfolge): + + +Carsten Gehle (fuer die Implementierung auf der NeXT Plattform) + +Till Jonas (fuer die Hilfe beim AI-Format) + +Marcello Krebber (Fuer die Hilfe beim ART-Format und fuer OS/2 + spezifische Fragen) + +Peter Neubaecker (Fuer den the 'bezier' Algorithmus und fuer den + 'justify' Algorithmus und fuer die vielen Diskussionen + und Anregungen). + +Matthias Oepen (fuer die Implementierung unter HP-UNIX) + +Joe Czychosz (fuer die Implementation des 'thinning' Algorithmus) + + diff --git a/extensions/fablabchemnitz/kvec/kvec b/extensions/fablabchemnitz/kvec/kvec new file mode 100755 index 0000000..2c1bd5c Binary files /dev/null and b/extensions/fablabchemnitz/kvec/kvec differ diff --git a/extensions/fablabchemnitz/kvec/kvec.exe b/extensions/fablabchemnitz/kvec/kvec.exe new file mode 100644 index 0000000..a21cdeb Binary files /dev/null and b/extensions/fablabchemnitz/kvec/kvec.exe differ diff --git a/extensions/fablabchemnitz/kvec/kvec.inx b/extensions/fablabchemnitz/kvec/kvec.inx new file mode 100644 index 0000000..ea31841 --- /dev/null +++ b/extensions/fablabchemnitz/kvec/kvec.inx @@ -0,0 +1,169 @@ + + + KVEC + fablabchemnitz.de.kvec + + + + + + + false + true + false + true + + + false + true + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + false + 3 + false + false + + + + + + false + false + false + false + 2 + 2 + + + + + + + 32 + 0 + + + + + + 0 + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255 + + + + + + 255 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../000_about_fablabchemnitz.svg + + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/kvec/kvec.py b/extensions/fablabchemnitz/kvec/kvec.py new file mode 100644 index 0000000..0fb0073 --- /dev/null +++ b/extensions/fablabchemnitz/kvec/kvec.py @@ -0,0 +1,234 @@ +#!/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 + +class KVEC (inkex.EffectExtension): + + def checkImagePath(self, element): + xlink = element.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 = element.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 add_arguments(self, pars): + pars.add_argument("--tab") + + #General Settings + pars.add_argument("--keeporiginal", type=inkex.Boolean, default=False, help="Keep original image on canvas") + pars.add_argument("--fittooriginal", type=inkex.Boolean, default=False, help="Fit to original dimensions") + pars.add_argument("--debug", type=inkex.Boolean, default=False, help="Enable debug output") + pars.add_argument("--sysmalloc", type=inkex.Boolean, default=True, help="Use system-malloc routines") + pars.add_argument("--text", type=inkex.Boolean, default=True, help="Text output") + pars.add_argument("--font", type=inkex.Boolean, default=True, help="Generate optimized set of parameters") + pars.add_argument("--sort", default="max", help="Type of sort order for vectors") + + #Geometry/Quality + pars.add_argument("--grit", type=int, default=0, help="Filter out details smaller than x pixels") + pars.add_argument("--gapfill", type=int, default=0, help="Gap fill (jumping)") + pars.add_argument("--centerline", default="off", help="Generates single lines if linewidth small enough") + pars.add_argument("--bezier", type=inkex.Boolean, default=False, help="Generate Bezier-curves") + pars.add_argument("--errbez", type=int, default=3, help="Error-Parameter for Bezier-curves") + pars.add_argument("--reduce", default="orthogonal", help="Type of line reducing") + pars.add_argument("--overlapp", type=inkex.Boolean, default=False, help="Polygons overlap (1px)") + pars.add_argument("--smooth", type=inkex.Boolean, default=False, help="Smoothing of polylines") + pars.add_argument("--winding", default="original", help="Winding") + pars.add_argument("--high_resolution", type=inkex.Boolean, default=False, help="High vectorization resolution") + pars.add_argument("--subsampling", type=inkex.Boolean, default=False, help="If enabled, the output vectors are subsampled by a factor of 2. This will reduce the size of the output file and will also result in smoothing the vectors") + pars.add_argument("--lossless", type=inkex.Boolean, default=False, help="Generate lossless image") + pars.add_argument("--progressive", type=inkex.Boolean, default=False, help="image is build up from two successive layers (one 'rough' picture without details and one refined picture which contains only details).") + pars.add_argument("--progressive_gritfactor", type=int, default=2, help="The first layer has a grit-value multiplied by this") + pars.add_argument("--progressive_colorfactor", type=int, default=2, help="The first layer has a quantize-value divided by this") + + #Colors/Styles + pars.add_argument("--quantize", type=int, default=32, help="Color quantization") + pars.add_argument("--delta", type=int, default=0, help="Delta") + pars.add_argument("--fill", default="solid", help="Fill") + pars.add_argument("--lwidth", type=int, default=0, help="Line width") + pars.add_argument("--black", type=inkex.Boolean, default=False, help="Output-color is always black") + pars.add_argument("--palette", default="optimize", help="Palette") + pars.add_argument("--color_vectorization", default="normal", help="Color vectorization") + pars.add_argument("--colspace", default="rgb", help="Colorspace conversion parameters") + pars.add_argument("--colsep", default="rgb", help="Color separation parameters") + pars.add_argument("--tcolor_mode", default="none", help="Transparency color") + pars.add_argument("--tcolor_custom", type=Color, default=255, help="User-defined transparency color (RGB values)") + pars.add_argument("--vcolor_mode", default="none", help="Pick out regions with color") + pars.add_argument("--vcolor", type=Color, default=255, help="Region color") + def effect(self): + + so = self.options + + if (so.ids): + for element in self.svg.selected.values(): + if element.tag == inkex.addNS('image', 'svg'): + self.path = self.checkImagePath(element) # This also ensures the file exists + if self.path is None: # check if image is embedded or linked + image_string = element.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) + + if element.get('width')[-1].isdigit() is False or element.get('height')[-1].isdigit() is False: + inkex.utils.debug("Image seems to have some weird dimensions in XML structure. Please remove units from width and height attributes at ") + return + + # Write the embedded or linked image to temporary directory + if os.name == "nt": + exportfile = "kvec.png" + else: + exportfile = "/tmp/kvec.png" + + if image.mode != 'RGB': + image = image.convert('RGB') + image.save(exportfile, "png") + + #some crash avoidings + if so.lossless is True: + so.color_vectorization = "normal" + so.bezier = False + so.font = False + so.black = False + if so.high_resolution is True: + so.overlapp = False + + ## Build up command according to your settings from extension GUI + if os.name == "nt": + command = "kvec.exe" + else: + command = "./kvec" + command += " " + exportfile #input + command += " " + exportfile + ".svg" #output + command += " -format svg" + + #General Settings + if so.sysmalloc is False: command += " -sysmalloc off" + if so.font is True: command += " -font" + if so.text is False: command += " -text off" + command += " -sort " + so.sort + + #Geometry/Quality + if so.grit > 0: command += " -grit " + str(so.grit) + command += " -gapfill " + str(so.gapfill) + command += " -centerline " + so.centerline + command += " -winding " + so.winding + if so.bezier is True: command += " -bezier" + command += " -errbez " + str(so.errbez) + if so.overlapp is True: command += " -overlapp" + if so.smooth is True: command += " -smooth on" + command += " -reduce " + str(so.reduce) + if so.high_resolution is True: command += " -resolution high" + if so.subsampling is True: command += " -subsampling" + if so.lossless is True: command += " -lossless" + if so.progressive is True: + command += " -progressive gritfactor " + str(so.progressive_gritfactor) + command += " -progressive colorfactor " + str(so.progressive_colorfactor) + + #Colors/Styles + command += " -quantize " + str(so.quantize) + command += " -delta " + str(so.delta) + command += " -fill " + so.fill + command += " -lwidth " + str(so.lwidth) + command += " -palette " + so.palette + if so.black is True: command += " -black" + if so.color_vectorization != "normal": command += " -" + so.color_vectorization + command += " -colspace " + so.colspace + command += " -colsep " + so.colsep + if so.tcolor_mode == "auto": + command += " -tcolor auto" + elif so.tcolor_mode == "custom": + command += " -tcolor color {} {} {}".format(so.tcolor_custom.red, so.tcolor_custom.green, so.tcolor_custom.blue) + if so.vcolor_mode == "matching": + command += " -vcolor {} {} {}".format(so.vcolor.red, so.vcolor.green, so.vcolor.blue) + elif so.vcolor_mode == "not_matching": + command += " -vcolor {} {} {}".format(-so.vcolor.red, -so.vcolor.green, -so.vcolor.blue) + + #some debug stuff + if so.debug is True: + command += " -debug all" + inkex.utils.debug(command) + + # Create the vector new SVG file + with os.popen(command, "r") as proc: + result = proc.read() + if so.debug is True: inkex.utils.debug(result) + + # proceed if new SVG file was successfully created + doc = None + 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() + + parent = element.getparent() + idx = parent.index(element) + #newGroup = self.document.getroot().add(inkex.Group()) + newGroup = inkex.Group() + parent.insert(idx + 1,newGroup) + for child in doc: + newGroup.append(child) + + #doc.get('height') + #doc.get('width') + #doc.get('viewBox') + if so.fittooriginal is True: #fitting does not work in all cases so we make it available as option + bbox = newGroup.bounding_box() + newGroup.attrib['transform'] = "matrix({:0.6f}, 0, 0, {:0.6f}, {:0.6f}, {:0.6f})".format( + #float(element.get('width')) / float(doc.get('width')), + #float(element.get('height')) / float(doc.get('height')), + float(element.get('width')) / bbox.width, + float(element.get('height')) / bbox.height, + float(element.get('x')) - (float(element.get('width')) / bbox.width) * bbox.left, + float(element.get('y')) - (float(element.get('height')) / bbox.height) * bbox.top + ) + + # Delete the temporary svg file + if os.path.exists(exportfile + ".svg"): + try: + os.remove(exportfile + ".svg") + except: + pass + + else: + inkex.utils.debug("Error while creating output file! :-( The \"kvec\" executable seems to be missing, has no exec permissions or platform is imcompatible.") + exit(1) + #remove the old image or not + if so.keeporiginal is not True: + element.delete() + else: + inkex.utils.debug("No image found for tracing. Please select an image first.") + +if __name__ == '__main__': + KVEC().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/kvec/kvec.txt b/extensions/fablabchemnitz/kvec/kvec.txt new file mode 100644 index 0000000..de20294 --- /dev/null +++ b/extensions/fablabchemnitz/kvec/kvec.txt @@ -0,0 +1,3164 @@ +****************************************************************************** +* K V E C D O C U M E N T A T I O N * +* * +* +++ KK-Software +++ KK-Software +++ KK-Software +++ KK-Software +++ * +*----------------------------------------------------------------------------* +* Dipl.-Phys. Karl-Heinz Kuhl, Bergstr. 4, 92711 Parkstein, Germany * +*----------------------------------------------------------------------------* +* Voice FAX E-Mail * +* +49 9602 9441945 +49 9602 9441946 support@kvec.de * +****************************************************************************** + + + + +--------!-ABOUT_KVEC-E---------------------- +What is KVEC? + +KVEC is a freeware program that allows you to convert raster graphics to +vector graphics. You can freely use it. +Before 2010 it was distributed as shareware. Please download the freeware version +from the kvec web site. +It can be freely distributed and copied. +KVEC is very exacting with respect to memory demands. Vectorizing is a +critical process and often leads to a trade off between memory demands +and performance. It is crucial for the performance that your computer has enough +RAM. + +The selection of values for the switch parameters requires some caution. +Noisy pictures (typical for scanned colour pictures) or pictures with a lot of +very small details should be evaluated with larger 'grit values' and smaller +'quantize values' (explained below). +The output formats DXF and HPGL are not suited for vectorization of coloured +photos or coloured scanned pictures (unless you have lots of GigaBytes left +on your harddisk ;-) the output size would be immense. + +Vector representations of images have several advantages in contrast to +rastered block representations: operations like rotation, stretching, morphing +and warping can much easier be performed and one does not have to care about +aliasing and other unwanted effects. The application fields of a good +vectorizer reach from motion estimating in video sequences up to effective +image compression. + +Please feel free to contact the author if you have problems with KVEC +or if you find some bugs. KVEC is designed to run on several operating systems +(which have different hardware and graphical environments), therefore this +release of KVEC is a graphic-independend commandline version. + +The syntax is quite simple: + + KVEC (Inputfile) (Outputfile) [optional switches] + for example: + KVEC test.bmp test.dxf -format dxf + +Wildcards ('*' and '?' ) are allowed for the file names. +Nested subdirectories were not processed when using wildcards. +If the input filename contains wildcards, the outputfilenames will be derived +from the expanded input filenames and get different file suffixes. In the case +of identical input and output filenames KVEC adds an leading underscore ('_') +to the output filename in order to prevent overwriting. Full pathnames can be +specified for input files and output files. + +You can also start KVEC using a parameter file (KVEC.PAR) by typing: + + KVEC -readpar parfilename + +[filename] is the (optional) name of a KVEC parameter file. +The name of the parameter file must be KVEC.PAR (uppercase), if no filename +for the parameter file is specified. +You can use any of the example parameter files in the KVEC package (*.par). +Please note: The last line in a parameter file should be terminated by a +CR or a LF char. Otherwise it may not work for the linux or MAC-OS operating +systems. + +--------!-sequence-E------------------------ +Since version 3.90 you can start KVEC in 'sequenz-mode' by specifying two +parameter files and an optional parameter : + + KVEC -readpar parfilename1 parfilename2 + +This will produce a sequence of still images generated by gradually +interpolating all parameter values going from the values in parameterfile1 +to the values in parameterfile2. If no value for nseq is specified, a value +of nseq = 100 will be taken. +Important: The input/output filenames in parfilename1 must be identical with +those in parameterfile2. 'vnull' or 'null' (see below) together with the +internal random or demo images is also allowed. +The generated outputfiles will have indices (6 digits). Existing files will +be overwritten without prompting. +You can use any other conversion software to convert this sequence to one +video file and create nice animations (e.g. animated function plots). +Future releases of KVEC will also allow different input files for the two +parameterfiles and thus generate true morphing sequences. + + + +--------!-intro_in-E------------------------ +Inputfile is the name of a raster graphic file (Tiff, BMP, PCX, TGA, SGI, +IMG, PNM, JPEG, GIF, WPG, PNG or FAX). +If the name of the input-file is 'null' KVEC will create a 'white noise' +random or other test raster images. +If the name of the input-file is 'vnull' KVEC will create a random +vector image. The properties of this test image depend on +the parameter settings for the '-random' switch. + +--------!-intro_out-E----------------------- +Outputfile is the name of the desired vector graphic file. +Please note that the name of the output file must be specified with the +filename extension. You cannot omit it. + +Note: +If the input-file has already a vector-format (WMF or ART), most of the +switches will be disregarded. In this case KVEC only performs a format- +conversion from one vector format to another vector format. + + +Currently supported vector formats are: + - Windows Metafile, Postscript, AutoCad DXF, HPGL, LogoArt ART, + Adobe Illustrator Format, XFIG, PCS and the KVEC format KVC + SVG(Z) (Scalable vector format), SWF 6.x (Macromedia Flash Format) + DST (Tajiama stick format), HTML + +The switches are optional. If you don't specify any switches, the program +chooses a set of parameters which are optimized with respect to the kind of +graphic data. Switches may be abbreviated. +The filenames must be specified before the optional switches. +Some switches however don't require filenames and can be specified immediately +after KVEC. From these switches only one can be specified in each case: + +--------!-ehelp-E--------------------------- +KVEC -ehelp Displays help information in English language + +--------!-ghelp-E--------------------------- +KVEC -ghelp Displays help information in German language + +--------!-info-E---------------------------- +KVEC -info: Displays some useful information about KVEC on the screen. + +--------!-printform-E----------------------- +KVEC -printform: Automatically generates a registration form. This form can + be sent to the author by E-Mail, Fax, or postal mail in + order to get a registration key. The registration key is + a max. 5 digit number, which allows the user to register + the software and get access to extended features of KVEC. + You will be prompted to select a language. The registration + form will then be generated in your preferred language. + The registration form consists of plain ASCII text. + If you print it out from a text processing program, be + sure that you choose a monospaced font and not a + proportional font. For users from the European countries + a special registration form is available from: + www.kvec.de/files/download/kvec_reg_info_eng/reg_info_eng_europe.htm + +--------!-register-E------------------------ +KVEC -register: As soon as you get a registration key you can use this + switch to register the program. You will be prompted to + enter your name, the serial-number, and your registration + key. Please type all characters exactly as printed in the + registration confirmation you receive from the author. If + you have entered the information correctly, a message + appears which thanks you for your registration. The + received registration key is valid for updates and future + releases of KVEC. + +--------!-readpar-E------------------------- +KVEC -readpar: KVEC reads filenames and additional parameters from a + parameter file (KVEC.PAR) rather than the commandline. + Please note, that the parameter file must reside in the + actual working directory. The parameter file KVEC.PAR + is an ASCI file and can be edited with any text editor. + Comments in the parameter file must be marked by a + #-character and may appear anywhere behind a parameter + or at the beginning of a line. + +KVEC -readpar [filename]: + KVEC reads filenames and additional parameters from the + specified parameter file [filename]. + +--------!-rename-E-------------------------- +KVEC *.jpg *.jpg -rename: (only Windows version). This is a very special + switch for renaming multiple files. The renamed filenames + will have the prefix: "high_". This is useful in order to + prepare input files together with the switch "-html". + Generally this will be applied to jpg-files. Here + an example: 'kvec image*.jpg *.jpg -rename' + +--------!-writepar-E------------------------ +KVEC -writepar: Generates a KVEC parameter file. The user will be prompted + to enter filenames and additional parameters. + The name of the parameter file is always 'KVEC.PAR' + and will reside in the actual directory. + You can add comments behind the parameters you are + promped to input (see above). Parameters always begin with + a leading '-'character. After the parameter file has been + written, the program should be restarted using the + '-readpar' option. + +KVEC -writepar [filename]: + Generates a KVEC parameter file with the specified + filename. + +--------!-end of writepar-E----------------- + +The other switches must follow the input and output filenames: + +--------!-antialiasing-E-------------------- +-antialiasing : (Only for Vector-Raster-Conversion): Anti-Aliasing will + be applied when rendering. + : 0: no antialiasing, 1: good quality, 2: best quality + <-N>: the same as but will generate more compact lines + + +--------!-bezier-E-------------------------- +-bezier: The output will consist of bezier-curves instead of + straight lines. This allows you to zoom the image without + getting edges. For the output formats which don't support + bezier curves, the bezier algorithm will + be simulated and approximated by polylines. + +--------!-bkcolor-E------------------------- +-bkcolor : background color for plotting user-defined functions + (see switch '-function') + +--------!-black-E--------------------------- +-black: Output color for vectorization is always black + +--------!-centerline-E---------------------- +-centerline mixed: The effect of this parameter depends on the value of the + parameter -lwidth. (If used together with -centerline, + the meaning of the parameter -lwidth is modified). + Before vectorizing, all detected objects were checked for + its maximal thickness. All objects with a maximal + thickness less than -lwidth were treated as line objects; + all other objects were vectorized in the normal way. + The vectorization of line objects does not result in + border lines around the objects. It produces single lines + which are located along the centerlines of the objects. + The final linewidth of this generated single lines will + be adopted so that the area of the line object is about + the same as the area of the original object. + (this has no effect, if the output format cannot handle + variable linewidths). This is the DEFAULT. + +-centerline lines: The same as 'centerline mixed' except that only line + objects will be generated. All other objects will be + discarded. +-centerline off: Turns centerline vectorization off (Default) + +--------!-colspace-E------------------------ + Selects the internal color space which is used by kvec. + The effect of changing the internal color space will be + noticed when used together with the "colorsep" option + or when bitmap processing is performed ("process" option). +-colspace rgb: RGB color space (default). +-colspace rb: RB color space +-colspace gb: GB color space +-colspace gr: RG color space +-colspace cmyk: CMYK color space +-colspace cy: CY color space +-colspace my: MY color space +-colspace mc: CM color space + Note: If a color space other than RGB or CMYK is selected, + the colors will be changed such that the optical + impression will be quite near to the original image. + +--------!-colseparation-E------------------- + Selects the type of color separation. The output file + will only contain the specified color components. + Please note, that for cmyk separation the color space is + also set to the right value. +-colsep rgb: no color separation (default). +-colsep cmyk: no color separation +-colsep rb: extract R and B components +-colsep gb: extract G and B components +-colsep gr: extract R and G components +-colsep cy: extract C and Y components +-colsep my: extract M and Y components +-colsep mc: extract C and M components +-colsep rr: separate R color +-colsep gg: separate G color +-colsep bb: separate B color +-colsep cc: separate C color +-colsep mm: separate M color +-colsep yy: separate Y color + Note: It is useful to produce a gray-scale output file + for single component color separation. This can be + achieved by using the "-black" option together with colsep. + +--------!-coord-E--------------------------- + Specifies the type of internal scaling of coordinates +-coord optimize: coordinates may be rescaled in order to improve resolution + (default) +-coord pixel: the original pixel coordinate system will be used + +--------!-dimension-E----------------------- +-dimension N: Specifies the maximum extension (in x- or y-direction) + of the generated output image. Default: 512 pixels. + IMPORTANT: This parameter will only be evaluated, if + the input file is of vector type (or 'null'). + +--------!-xdim-E---------------------------- +-xdim N: Specifies the maximum extension (in x-direction) + of the generated (raster) image. Default: original value + +--------!-ydim-E---------------------------- +-ydim N: Specifies the maximum extension (in y-direction) + of the generated (raster) image. Default: original value + +--------!-dither-E-------------------------- +-dither off: Turns dithering off (Default) +-dither linear: Turns dithering on + Note: Dithering will only performed, if the output format + is a raster format. + +--------!-drcolor-E------------------------- +-drcolor : drawing color for plotting user-defined functions + (see switch '-function') + +--------!-dst-E----------------------------- +-dst dist : specifies the stitch distance in 0.1 mm +-dst width : specifies the line width in 0.1 mm +-dst fill hollow: Colored areas will not be filled +-dst fill hatch: Generates cross-hatched lines (see hatch1 ...), default +-dst fill zickzag: Generates zickzag lines + +--------!-dxfopt-E-------------------------- +-dxfopt type 2dim: Generates 2-dimensional coordinates (if the output format + is DXF. (Default) +-dxfopt type 3dim: Generates 3-dimensional coordinates (if the output format + is DXF. +-dxfopt form unix: adds only (line feed) at line ends (default) +-dxfopt form dos: adds at line ends + +--------!-fill-E---------------------------- +The fill parameters specify how the generated polylines/polygons will be +interpreted: + +-fill solid: Polygons are always closed (i.e. the last point of a + vector is identical with the first point). The Polygons + are filled with individual colors (DEFAULT). The sort + parameter should not be 'min' in this case because the + larger Polygons would cover and hide the smaller ones. + +-fill line: Output consists of polylines with individual colors. The + polylines are not closed. This is the preferable fill + parameter if the outputfile is generated for a pen-plotter. + The plotter pen will never plot more than one color one + upon another. The layout will depend on the sort order + specified with the 'sort' switch. With the switches + 'reduce' and 'smooth' you can once more refine the layout + of the output. + +-fill contour: The same as '-fill solid', however the interiors of the + polygons remain 'hollow'. Lines with different colour + can cover each other. The layout will depend on the + sort order specified with the 'sort' switch. + +--------!-font-E---------------------------- +-font: KVEC generates (before vectorization) an optimized set + of parameters, which is suited for vectorization of + dark colored text on a clear background. All objects + get a unique 'dark' color. Sort order "local" is + automatically turned on for generation od sub-polygons. + +--------!-format-E-------------------------- +The format parameters specify the output format: +(Please note that KVEC can also determine the output format by parsing the +file suffix from the output filename, if you don't specify a output-format) + +-format wmf: Output format is Windows Metafile format, *.WMF +-format amf: Output format is ALDUS WMF Metafile *.WMF +-format emf: Output format is Enhanced Windows Metafile format, *.EMF +-format ps: Output format is Postscript level 2, *.PS +-format eps: Output format is Encapsulated Postscript level 2, *.EPS +-format dxf: Output format is AutoCad DXF, *.DXF +-format hpgl: Output format is HPGL, *.HPG or *.PLT +-format art: Output format is ART LogoArt (OS/2-graphics program), *.ART +-format ai: Output format is Adobe Illustrator, *.AI +-format bmp: Output format is Windows Bitmap, *.BMP +-format tiff: Output format is Tiff, *.TIF +-format zyxel: Output format is ZYXEL FAX +-format pfax: Output format is PowerFax +-format kvc: Output format is KVEC vector format +-format xfig: Output format is XFIG vector format (Linux Drawing program) +-format pcs: Output format is Pfaff PCS vector format +-format dst: Output format is Tajiama stick format +-format wav: Output format is WAV +-format svg: Output format is SVG (scalable Vector Graphics) +-format svgz: Output format is SVGZ (compressed scalable Vector Graphics) +-format swf: Output format is SWF (Flash MX Format, DEFAULT) + The Macromedia Flash MX Editor only accepts special + settings which can be controlled by the switch 'winding' +-format png: Output format is PNG (Portable Network Graphics) +-format jpeg: Output format is JPEG +-format html: (only windows version) + Please Note: '-format html' is a synonym for the following + set of parameters: + '-format jpg' '-hmtl source default','-html screen default', + '-html preview default', '-mode isotrop' + + This is not a real output format, but a switch for a + very special application: Assume you have a lot of + image-files and you want to generate a set of html-files + which allow you to view all these files in a convenient way. + Note: This is very useful if you want to post hundreds or + thousands of photos in a web site offer a fast way of + viewing. Kvec will generate a seperate html-file for each + individual image. A html-file called "directory.htm" will + also be generated, which refers to the individual html-files + by preview images. + Each image will be created in 3 resolutions: + low (preview), medium (screen display), and high (download). + Therefore, 3 versions will be created from each image. + Assuming a input filename of test01.bmp we will get: + source_test01.jpg, screen_test01.jpg, previe_test01.jpg. + The following command will perform the whole procedure + + kvec source_dir\test*.bmp destination_dir\*.htm + + Assume we have 100 image files of any readable input format: + KVEC will generate 300 jpeg files in the destination + directory. KVEC will also generate 100 html files containing + links to the generated image files. + The preview images can be viewed in the file directory.htm + which will also be created in the destination directory. + + See also: '-html ...' + +--------!-function-E------------------------ +-function ...: (see also: '-nstep', '-bkcolor', '-drcolor', '-xmin', + '-xmax', '-ymin', '-ymax', '-tmin', 'tmax', -lwidth') + This switch is not for processing image files. + The function switch lets KVEC generate plots of mathematical + functions, which can be entered right after the function- + keyword. The definition of math. function also includes + the definition of user-specified constants. As the definition + of functions and variables can be very long, it is not + recommended to enter all this values on the commandline. + It is much more practicable to enter all the definitions in + a KVEC parameter file. + The strings following the '-function' keyword are interpreted + as a C-style written definition of up to 8 functions and + 100 Variables. The keyword 'endfunc' (without ";") terminates + the function definition. Assignments of variables (constants) + must precede the definition of functions! Thus, variables can + not be initialized with function results. + Some restrictions apply: + Functions must follow one the following naming conventions: + + f?(argument) ('?' can be any alphanumeric char) + (argument can be one of: x,y,z,t,i) + x?(argument) y?(argument) ('?' any alphanumeric char) + (parametric representation) + r?(phi-argument) ('?' can be any alphanumeric char) + (argument must be: p) + (representation in polar-coordinates) + Allowed are also x?(), y?() or f?() + (without argument, mainly for iterative functions) + Please note: The function names (two chars long) can also be + used as variable. This can be useful for initialization in + iterative functions or loops. + As initialization of constants and variables precede the + function definitions, they are 'global' and refer to all + (of the max. 8 possible) functions. + + Here a few examples: f1(x)=sin(x); fa(t)=cos(t); (allowed) + fabc(x)=x; (not allowed) + f1(x) = cos(x); (not allowed) + f2(x)=SUM(n=1,100,x^n/n!); (allowed) + x3(t)=cos(t); y3(t)=sin(t); (allowed) + y(x)=exp(x); (not allowed) + x1(i)=KV_PRIMES[i]; y1(i)=i; (allowed) + r1(p)=0.5*p; (allowed) + + Each statement ends with a ';' Within a statement, no blanks + or other white-spaces are allowed. Statements however can be + seperated by any white-space chars. + Please note that max. eight different functions are allowed. + + The function names are two chars long and must start with a + 'f', 'x', 'y' or 'r' followed by any alphanumeric char. If + we have a parameter representation (two functions, e.g. + x1(t)=... and y1(t)=...), the x1(t) function must precede the + y1(t) function. A parameter representation counts as one function. + If the order of definition is reversed, the result is + unpredictable. The function argument must be one of: + 'x', 'y', 'z', 't' or 'p' (in case of polar-coordinates). + Expressions can be nested by braces '(', ')'. Constants may + be defined like this (examples): + ABC=1.234; SQ2=1.414; ... + Note: Constants may not be defined by expressions. + + The following operators are allowed: + '+' Addition or unitary '+' + '-' Subtraction or unitary '-' + '*' Multiplication + '/' Division + '%' Modulus + '^' Raising to a power + '!' Factorial (can also be applied to expressions) + 'SUM' Summation. Syntax: SUM(n=,,); + e.g.: SUM(n=1,100,x^n/n!); + 'PROD' Products. Syntax: PROD(n=,,); + 'ITER' Iteration loops. Syntax: + ITER(n=,,,,); + 'iterate' (more flexible iteration loops.) Syntax: + iterate(n=,,,<(list of var-initializations>); + + (There can be only one loop-variable in the SUM,PROD or ITER + statements, loop-variables must be initialized with constants). + The 'ITER' command is intended for simple functions of one + variable (e.g. f1(x)=). The function + term must be definied as the last expression within the ITER() term. + The function-term may contain the function name as variable + (iteration). The Iteration starts with a loop variable of value + and ends when the loop variable is greater or equal than + or when the difference between the results of two iterations + is less than epsilon. Iteration loops for functions in parameter + representation (x(t) and y(t) is not possible with the 'ITER'command. + For this purpose please use the more general 'iterate()' command. + + Syntax: + iterate(n=,,,<(list of variable-initializations>); + + The 'iterate' command does not include the function definition. + the function-definition(s) must be defined right after the iterate + command. This command can also be used for iterating functions + of two variables or functions definied by parameter representation. + The variable definitions/initializations are only valid for the + function(s) following the 'iterate' command (not global), + + Note: Functions can also be definied without function arguments + (e.g. x1() = ). The function can also + contain the funcion name itself (iteration). The no. of iterations + is controled by the nstep parameter (globally by specifying + '-nstep ' outside of the region definied by '-function' and + 'endfunc') or individually for each definied function by 'nstep ;' + within the function region. The actual iteration index can be used + within the function by the internal variable 'II'. Please do not + assign any values to the variable 'II'. + + All functions defined in the C-ANSI standard can be used. + This covers most of the elementary mathematical functions. + The following higher mathematical functions can also be used + (at the moment, this set will be expanded): + + fakul(x) (factorial Function) + bernoulli(x) (Bernoulli Function) + gamma_r(x); (real Gamma Function) + PI_func(x); (no. of primes up to x) + nth_prime(x); (returns the n-th prime number) + nth_mprime(x); (returns n-th Mersenne prime-exponent) + nth_zzero(); (returns n-th zero of the zeta-function) + (only available in special MATH KVEC version) + IsPrime(x); (returns 0.0 or 1.0, in case of prime) + riemann_r(x); (real Riemann Function) + sigma(x); (no. of divisors function) + sigmaX(x); (like sigma(), excluding square divisors) + sigma4(x); (number of 4-dimensional lattice points function) + zeta_r(x); (real Zeta Function) + zeta_cr(x); (real Zeta-Function along crit. strip) + zeta_ci(x); (imaginary Zeta-Function along ") + primeSum2_2(x) (# of ways building x as sum of 2 primes, start 2) + primeSum2_3(x) (# of ways building x as sum of 2 primes, start 3) + primeSum2_5(x) (# of ways building x as sum of 2 primes, start 5) + primeSum2_7(x) (# of ways building x as sum of 2 primes, start 7) + primeSum2_11(x) (# of ways building x as sum of 2 primes, start 11) + primeSum3_2(x) (# of ways building x as sum of 3 primes, start 2) + primeSum3_11(x) (# of ways building x as sum of 3 primes, start 11) + primeSum4_2(x) (# of ways building x as sum of 4 primes, start 2) + primeSum4_11(x) (# of ways building x as sum of 4 primes, start 11) + getNextDigOfInvI(x) (get next digit in decimal expansion of 1/N) + getPerLengthOfInvI(x) (get period-length in decimal expansion of 1/N) + getDigitWithIndI(x) (get digit with index X in decimal expansion) + + KVEC offers also predefined mathematical constants and variables + which can be used (all capital letters): + M_PI + M_E (Euler-Constant) + M_G (Gamma-Constant) + M_LN2 (= log(2)) + M_Z3 (= zeta(3)) + + KV_PRIMES[n] (Primenumbers, n: 0-KV_MAXPRIME) + KV_MPRIMES[n] (Mersenne Prime-Exponents, n: 0-48) + KV_MPRIME_INDEX[n](Prime-Index of Mersenne Prime-Exponents,n: 0-48) + KV_ZETA_ZEROS[n] (zeros of zeta-function, along the + 'critical line', only available + in special MATH-version of KVEC, + allowed n: 0-99999 ) + BN[n] (Bernoulli-numbers, n: 0-99) + BN_FAK[n] (=BN[n]/n!, n: 0-99) + ZETA[n] (= zeta_r(n), n: 0-99) + II (Internal loop variable) + + Brackets ('[' and ']') must be used when this predefined + arrays ares used (instead of '(' or ')'). + Please note that indices start with 0, so the first prime + is in KV_PRIMES[0]. + + Special commands for getNextDigOfInvI(), getPerLengthOfInvI() + und etDigitWithIndI(): + numberbasis n: (set basis for decimal expansion. default: 10) + numberdenom n: (set number n for computation of 1/n) + + Graphical commands can be entered at any postion after the + section of the variables definition (please note that + there is no '=' char and no leading '-'). These commands + must be located between the '-function' and 'endfunc' + keywords. + + bkcolor r g b; (set the background color to (rgb) value) + drcolor r g b; (set actual drawing color to (rgb) value= + lwidth n; (set actual linewidth to n) + nstep n; (set actual no. of interpolation steps) + imin n; (set min value for integer function argument) + imax n; (set max value for integer function argument) + object ; (set type of KVEC object) + Object-type can be one of (specify without ''): + 'polyline' (this is the default) + 'polygon' + 'markcircle', 'markfilledcircle' + 'markrect','markfilledrect' + 'markrbox','markfilledrbox' + 'hline', 'vline' + 'polyspline', 'filledpolyspline' + + msize n; (set the marker size in % of image size) + pmode : (set drawing mode for functions with parametric + representation): + 'normal' (draw x-y plot, this is the default) + 'xt' (draw x-t plot) + 'yt' (draw y-t plot) + 'abs' (draw absolute value of (x,y) versus t) + The xt/yt/abs modes are useful if you want to plot the + real/imaginary part (or both) of a complex function in + dependence of a parameter t. + + + + IMPORTANT: Graphical settings will be applied only for the + currently processed (active) user-defined function (except + the bkcolor setting). They can be specified individually for + eych user-defined function. If not specified, default-values + will be applied. Graphical settings must precede the function + definition. Using 'polyline' or 'polygon' will result in + continuously drawn lines between the points with the given + spacing (see nstep). Using markers will set marker symbols + (circles, rectangle or line segments) at the plotting + positions without drawing lines between them. + IMPORTANT: The size of these marker symbols depends on the + 'plot-history' of all drawn objects. Thus, plotting markers + should be the last plotting action (after all other functions + have been plotted). + + When using SVG or SWF format, the output size and dimensions + should be controled with the following switches: + -paper user and/or + -mode aniso or -mode iso + + See also: '-nstep', '-bkcolor', '-drcolor', '-tmin', + '-xmin', '-xmax', '-ymin', '-ymax' + Here are examples of a KVEC parameters file which show the + use of kvec user-defined functions: + + # KVEC parameter file + # Don't add comments between "-func" and "endfunc" + # Example shows how to plot 2 mathematical functions + # using different colors + # input file must be "vnull": + vnull + # select output file; output format: SWF (Flash) + c:\test.swf + # Here starts the function definition: + -func + c1=5.0; + drcolor 0 0 128; + f1(x)=zeta_cr(x); + drcolor 192 64 64; + f2(x)=c1+sin(x/M_PI)*exp(cos(sin(x))); + endfunc + # set background color for the graph + -bkcolor 220 220 255 + # linewidth: + -lwidth 10 + # no. of interpolation steps + -nstep 4000 + # set up output size of the image (in mm) + -paper user 1000 100 + # set anisotropic scaling mode + -mode aniso + # x-range for plotting + -xmin 1000 -xmax 1200 + -monitor + + ++++++++++++++++++++++++++++++++++++++++++++++++ + + # Example shows how to use the summation symbol + # f1(x) is the series expansion of cos(x) + # using different colors + # input file must be "vnull": + vnull + test.swf + -func + c1=5.0; k=2; + drcolor 0 0 128; + f1(x)=1+SUM(n=1,25,(-1)^n*x^(2*n)/(2*n)!); + drcolor 128 0 64; + f2(x)=cos(x); + endfunc + -bkcolor 220 220 255 + -lwidth 1 + -nstep 1000 + -paper user 300 300 + -mode aniso + -xmin -20.5 -xmax 20.5 + -monitor + + The plotted values (x,y) can be printed to the specifified + output device be setting: '-debug plot' + +--------!-gapfill-E------------------------- +-gapfill N: This parameter controls whether the vectorizer can 'jump' + over gaps while tracing an object. The value N must be + specified in 10ths of a pixel. Allowed values: 0 - 30. + +--------!-grit-E---------------------------- +-grit N: Polylines or polygons which belong to a bounded area with + a number of pixels fewer than N will be filtered out (i.e. + small details are 'erased'). The default value depends on + the dimensions and the colour depth of the picture. The + use of a grit value > 0 increases the computing time + and increases also considerably the demand of memory. + If you have to deal economically with memory you should + try a grit value of 0 and decrease the quantization value. + +--------!-hatch-E--------------------------- +The hatching parameters will only be evaluated if the output format is +DXF, PCS, DST or HPGL. + +-hatch1 density N: The max. number of horizontal hatch lines will be limited + to N (use 0 in order to turn off hatching) +-hatch2 density N: The max. number of vertical hatch lines will be limited + to N (use 0 in order to turn off hatching) +-hatch1 angle N: hatch angle for horizontal hatch lines (Default: 40 deg.) +-hatch2 angle N: hatch angle for vertical hatch lines (Default: 40 deg.) + +--------!-html-E---------------------------- +The html parameters specify how to build additional html files which contain +links to the generated output images. (See also: '-format html') + +-html source none: No conversion to high-resolution version (source + resolution) will take place. Individual html files will + not contain links to high resolution images. +-html source original: A copy of the original image file (renamed to + source_xxx..) will be created in the destination + directory. Individual html-files will contain download- + links to them. +-html source format: Conversion and creation of high resolution files by + applying all parameters and output format. The files + will be created in the destination directory. Individual + html files will contain download links to them. +-html source default: (the same as 'format'). However: A copy (instead of + conversion) will be created, if source and destination + format are equal. + If the dimensions of the source image file are + dimx <=800 and dimy <= 600, no high resolution file will + generated and no download link in the html file. + +-html screen none: No conversion to screen-resolution version and no + embedding in the corresponding html file. +-html screen original: A copy of the original image file (renamed to + 'screen_xxx..") + will be created in the destination directory. Images + will embedded in the corresponding html-files. +-html screen format: Conversion and creation of screen resolution files by + applying all parameters and output format. The files will + be created in the destination directory. These images + will be embedded in the corresponding html-files. +-html screen default: (the same as 'format'). However: Only format-parameter + will be applied and resampling to 800*600 pixel (isotrop). + + +-html preview none: No conversion to preview-resolution version. + 'directory.htm'will not be created. +-html preview original: A copy of the original image file (renamed to + 'previe_xxx..") will be created in the destination + directory. Images will embedded in the files + 'directory.htm'. +-html preview format: Conversion and creation of preview resolution files by + applying all parameters and output format. The files will + be created in the destination directory. These images + will be embedded in the file 'directory.htm'. +-html preview default: (the same as 'format'). However: output-format is + 'JPEG' and resampling to 60*60 pixel (isotrop). + +--------!-jpg-E----------------------------- +-jpg quality : Selects the quality for the JPEG output format. + Allowed values: 1-100 (Default: 75) +-jpg grayscale on: Selects gray output for JPEG output images +-jpg grayscale off: colored output for JPEG output images (Default) + +--------!-justify-E------------------------- +The justify parameters will only be evaluated if input and output formats +are both raster type. The color depth of the input file can be 1 -24 bit. +The main application for these options is justifying and cleaning +binary (B/W) scanned images in order to embed them into documents. +The default justify parameters are optimized for justifying and cleaning +DIN A4 images (300 dpi) containing text. +Carbon copies often have dirty black margins or are slightly distorted +by an small angle because the source got out of place while copying. +KVEC can automatically correct these errors, if you choose a proper set +of justify parameters. + +-justify type off: No justification will be performed (default). +-justify type rotate:Justification will be performed only by rotation +-justify type all: Justification will be performed by rotation and cleaning + (cutting off) the dirty margins. +-justify type angle: No justification will be performed, only determination + of the rotation angle +-justify phimax N: maximal allowed rotation angle. This is the max. + distortion angle which can be corrected. Please note + that the computional time increases linear with the + size of phimax. Default: 5.0 degrees +-justify parameter N1 N2 N3: + These values control the operation of the internal + algorithms (detecting large rectangular blocks from + which the rotation angle is deducted) + N1: 'thicking' factor. Each pixel will be enlarged by + this factor in order to make block structures + more detectable. Default: 16 + N2: min. filter value. Regions with a coherent no. of + pixels less than N2 will be eliminated before the + internal block detection algorithm starts. + Default: 50 + N3 max. filter value. Regions with a coherent no. of + pixels greater than N2 will be eliminated before the + internal block detection algorithm starts. + Default: 400 + Note: The default parameter values are optimized for a + DIN A4 image (300 dpi resol.) containing an average text. + (the average size of charcters lies within the range + 50 up to 1000 pixels for a character). + This will ensure that only those parts of the image + which contain text information are relevant for the + computation of the rotation angle. + + For other types of B/W images (electronic circuits or + plans) other values for N1, N2 and N3 may work better. +-justify fill ...: margins and edges generated by rotation will be filled +-justify fill black: with black color (or the 'nearest' black color) +-justify fill white: with white color (or the 'nearest' white color), DEFAULT +-justify fill user : with a user-supplied color +-justify preserve off: output image can have dimensions different from input +-justify preserve on: output image has the same dimensions as input + +--------!-kvc-E----------------------------- +-kvc compress none: Disables any compression for the KVC Vector format +-kvc compress lzw: Applies the LZW compression technique to the KVC format + (lzw is the default compression) +-kvc bufsize : Specifies the size of the packets which were compressed +-kvc byteorder i: Selects the INTEL byteorder for the binary data (Default) +-kvc byteorder m: Selects the MOTOROLA byteorder for the binary data + +--------!-language-E------------------------ + (GUI-Parameter) specifies the language for the KVEC-GUI. + Note: the commandline version ignores GUI parameters. +-language default: Uses the precompiled setting. +-language english: English language +-language german: German language +-language czech: Czech language + +--------!-lwidth-E-------------------------- +-lwidth: Specifies the line width of the generated output vectors + in 10ths of a pixel. + Allowed values: 0-1000. Default value: 0. + Note that this parameter has a different meaning if + used together with the option -centerline. + In this case the default value for the lwidth is 100. + +--------!-maxpoints-E----------------------- +-maxpoints: Specifies the max. no. of points which are allowed for + the generated polylines or polygons. This is useful if + KVEC produces vectors with more than 32767 points and + you use the WMF output format (WMF does not support + polylines with more than 32767 points) + +--------!-mode-E---------------------------- +-mode iso: Select isotropic mode. This mode preserves the the X/Y ratio + of the picture. (A circle will also be a circle in the + output picture). This is the default setting. + (PostScript, AI, SWF and SVG format and + vector-raster conversion only) + +-mode aniso: Select anisotropic mode. The picture will be scaled to fit + the whole papersize according to the selected paperformat. + (PostScript, AI, SWF and SCG format and + vector-raster conversion only) +--------!-monitor-E------------------------- +-monitor: Turn on progress monitor. Information about the current + status and the progress of the program will be displayed. + +--------!-nstep-E--------------------------- +-nstep: Set no. of steps (interpolation points) for user defined + function (see switch '-function') +--------!-overlapp-E------------------------ +-overlap: If this switch is specified, Polygons will slightly + overlap, actually one pixel. (DEFAULT: no overlap). + If vector images show strange coloured gaps after they + have been rotated (especially along border lines between + adjacent Polygons) you should set this switch. + +--------!-palette-E------------------------- +-palette optimize: KVEC will use internal optimzed palette when color + reducing has to be done (default) +-palette fixed: KVEC will use a standard color palette when color + reducing has to be done. This often gives better vectorization + reults, especially if the raster image contains less than 16 colors. +-palette user R1,G1,B1, .... Rn,Gn,Bn: + Here you can specify a user supplied color palette which + contains colors. The value must be followed by + RGB triples. It is more practicable to use a parameter + file than entering all RGB values on the commandline. + The value for n may not exceed 256 colors. +--------!-paper-E--------------------------- +-paper (format): Select papersize. Currently this option controls the + output size for the following formats: + PostScript, Adobe Illustrator, SVG and SWF. + The format-string must be one of the following: + + 'user' width height (width and height in mm) + (the size of SVG or SWF graphic can be specified this way) + 'LETTER' (Letter 8 1/2 x 11 in) + 'TABLOID' (Tabloid 11 x 17 in) + 'LEDGER' (Ledger 17 x 11 in) + 'LEGAL' (Legal 8 1/2 x 14 in) + 'STATEMENT' (Statement 5 1/2 x 8 1/2 in) + 'EXECUTIVE' (Executive 7 1/4 x 10 1/2 in) + 'A3' (A3 297 x 420 mm) + 'A4' (A4 210 x 297 mm) + 'A5' (A5 148 x 210 mm) + 'B4' (B4 (JIS) 250 x 354) + 'B5' (B5 (JIS) 182 x 257 mm) + 'FOLIO' (Folio 8 1/2 x 13 in) + 'QUARTO' (Quarto 215 x 275 mm) + '10X14' (10x14 in) + 'NOTE' (Note 8 1/2 x 11 in) + 'ENV_9' (Envelope #9 3 7/8 x 8 7/8) + 'ENV_10' (Envelope #10 4 1/8 x 9 1/2) + 'ENV_11' (Envelope #11 4 1/2 x 10 3/8) + 'ENV_12' (Envelope #12 4 \276 x 11) + 'ENV_14' (Envelope #14 5 x 11 1/2) + 'ENV_DL' (Envelope DL 110 x 220 mm) + 'ENV_C5' (Envelope C5 162 x 229 mm) + 'ENV_C3' (Envelope C3 324 x 458 mm) + 'ENV_C4' (Envelope C4 229 x 324 mm) + 'ENV_C6' (Envelope C6 114 x 162 mm) + 'ENV_B4' (Envelope B4 250 x 353 mm) + 'ENV_B5' (Envelope B5 176 x 250 mm) + 'ENV_B6' (Envelope B6 176 x 125 mm) + 'ENV_ITALY' (Envelope 110 x 230 mm) + 'ENV_MONARCH' (Envelope Monarch 3.875 x 7.5 in) + 'ENV_PERSONAL' (6 3/4 Envelope 3 5/8 x 6 1/2 in) + 'FANFOLD_US' (US Std Fanfold 14 7/8 x 11 in) + 'FANFOLD_STD_GERMAN' (German Std Fanfold 8 1/2 x 12 in) + 'FANFOLD_LGL_GERMAN' (German Legal Fanfold 8 1/2 x 13 in) + 'ISO_B4' (B4 (ISO) 250 x 353 mm) + 'JAPANESE_POSTCARD' (Japanese Postcard 100 x 148 mm) + '9X11' (9 x 11 in) + '10X11' (10 x 11 in) + '15X11' (15 x 11 in) + 'ENV_INVITE' (Envelope Invite 220 x 220 mm) + 'A_PLUS' (SuperA/SuperA/A4 227 x 356 mm) + 'B_PLUS' (SuperB/SuperB/A3 305 x 487 mm) + 'A2' (A2 420 x 594 mm) + 'A1' (A1 594 x 840 mm) + 'A0' (A0 840 * 1188 mm) +--------!-pattern-E------------------------- +This parameter applies only to vector objects and is therefore without effect +for a pure raster-to-raster format conversion. +The last three parameters DR, DG and DB specify the max. color differences +used for color shading or random color patterns. Allowed values: 0 up to 255. +-pattern nodither D1 D2 D3: No color shading (default) +-pattern left2right D1 D2 D3: Color shading from left to right +-pattern right2left D1 D2 D3: Color shading from right to left +-pattern top2bottom D1 D2 D3: Color shading from top to bottom +-pattern bottom2top D1 D2 D3: Color shading from bottom to top +-pattern inout D1 D2 D3: Color shading from inside to outside +-pattern outin D1 D2 D3: Color shading from outside to inside +-pattern randrgb D1 D2 D3: Random color dithering + +Important: Please note, that the specified vector output format must support +color shading. Currently only the KVC and ART format support color shading. +Color shading will always be done if you choose a raster output format and +your input file has a vector format. + +--------!-png-E----------------------------- +The png-parameters will only be evaluated if the output format is the +PNG (Portable Network Graphics) format: + +-png bitdepth : Bitdepth of the PNG image. Allowed values: 1,4,8,24 + Palette images can only have up to 8 bits, RGB only 24 bit. + Default: 24 Bit +-png coltype gray: generates a gray scaled image +-png coltype pal: generates a palette image +-png coltype rgb: generates a RGB image with 24 bit bitdepth +-png coltype alpha2: generates gray image with alpha channel (not yet implemented) +-png coltype alpha4: generates RGB image with alpha channel + Default: rgb +-png tcolor : Selects a transparency color + Default: no transparency color +-png interlace: turns on interlacing (not yet implemented) + Default: No interlacing +-png gamma : specifies the gamma value Default: 0.45 + Please enter integer number. 100000 corresponds to a value 1.0 +-png addpalette: adds a palette to RGB (true color) images (not implemented) + Default: PNG file contains palette only for palette images +-png bkcolor : specifies a background color for the PNG image + Default: no background color +-png ppx : sets the value for pixels per unit in x-direction +-png ppy : sets the value for pixels per unit in y-direction +-png pixunit meter: selects the unit as 1 meter. +-png pixunit none: selects the unit as unknown (Default) + +KVEC gets the bitdepth and the color type from the input file and uses default +values for the png parameters if none of them are specified. +In the case of vector-format to PNG conversion KVEC tries to use the highest possible +bitdepth. This will be normally 24 bit unless another value is specified. + +--------!-primes-E-------------------------- +-primes : Initialize internal primenumber array up to N + (Default, if not specified: 1000000) + +--------!-quantize-E------------------------ +-quantize : The input file will be quantized down to N colors before + vectorization, if it contains more than N colours. + (Default: 32 colours). + For DXF and HPGL the default is 8 colors. + +--------!-reduce-E-------------------------- +The reduce parameters specify whether all those points of a vector laying on a +straight line may be replaced (= reduced) by two points (the start and the end +point of the straight line). This reduces the size of the outputfile. +Because straight lines can lie horizontally, vertically, or diagonally, +we have: + +-reduce orthogonal:straight horizontal and vertical line-segments will be + reduced. This is the default value. +-reduce all: All straight lines will be reduced (diagonal lines too). + Occasionally, small gaps may appear in the layout. +-reduce off: lines will not be reduced. The only case in which you may + want this setting is when you want the velocity of a + plotter pen to slow down for long straight lines. + +--------!-resolution-E---------------------- +The resolution parameters have some influence on the internal evaluation: + +-resolution low: very small details may get lost (default) +-resolution high: all details will be retained (needs more memory) + +--------!-rotate-E-------------------------- +-rotate N: Set rotation angle (value N in degrees) + Rotation will only be performed if the command list + specified by the -process switch contains a 'rotate' + command. The default rotation angle is 40 degrees. + Note: Only input raster files are concerned from rotation. + Rotation takes places before any vectorization. + +--------!-scale-E--------------------------- +The scaling parameters will obly be evaluated if the output format is +DXF or HPGL. + +-scale hpgl N: The output HPGL image will be scaled by a factor of N +-scale dxf N: The output DXF image will be scaled by a factor of N + See also -xyscale hpgl / -xyscale dxf + IMPORTANT: scale dxf can also be used to scale SWF output +--------!-sort-E---------------------------- +The sort parameters specify the sequence order in which the vectors appear in +the outputfile: + +-sort nosort: Vectors will not be sorted. Contours with different colours + may cover each other but the interior areas of each + vector cannot be covered by those of another vector. + +-sort max: This parameter depends on the filltype: For filltype + 'solid' the Polygons are sorted by the size of the bounded + area. For filltype line and color they are sorted by + the length of the vectors (sortorder is from maximimum to + minimum). This is the default value. + +-sort min: The same as sort 'max' but sortorder is from minimum to + maximum. This makes no sense together with '-fill solid'. + +-sort local: The generated output order preserves the local topology, + i.e. objects are drawn in the order in which they are + nested. The sort order in a group of nested objects is + from max to min. The sort order for groups is the same. + Needs more computing time. + If the sort order is local0, KVEC will try to generate + subpolygons having transparency color. This may be usefull + for vectorizing of text. The "-font" option will turn on + the local sort order automatically. + +-sort color: Polygons/polylines are sorted by color. You may want this + setting for HPGL output. + +--------!-subsampling-E--------------------- +-subsampling: The output vectors are subsampled by a factor of 2. This + will reduce the size of the output file and will also + result in smoothing the vectors. + +--------!-sysmalloc-E----------------------- +-sysmalloc on: (Default) Uses the memory-allocation routines from the + operating system +-sysmalloc off: KVEC uses its own memory allocation routines. Some + operating systems have slow allocation routines. Try this + switch if the performance of KVEC decreases. + +--------!-tcolor-E-------------------------- +The transparency parameters will only be evaluated if the output format is +a format which can handle filled objects. +The transparency color will be suppressed in the generated output image. +Some formats cannot handle subpolygons. For these formats the transparency +option will not work correctly in some cases. +Default: Transparency option is turned off. + +-tcolor auto: Autodedect transparency color +-tcolor color R G B: User-defined transparency color (RGB values) + +--------!-text-E---------------------------- +-text on/off: Generate or suppress output of text in the output file. + This applies only to formats which support text objects. + Default: -text on + +--------!-tiff-E---------------------------- +The Tiff-parameters will only be evaluated if the output format is the +Tiff or PowerFax format and control the generation of the Tiff-file: + +-tiff append: The image will be appended as subimage (Default: overwrite) +-tiff FillOrder msb2lsb: (for bilevel Fax images) Default +-tiff FillOrder lsb2msb: (for bilevel Fax images) +-tiff byteorder I: byte-order in the Tiff file will be 'INTEL' (DEFAULT) +-tiff byteorder M: byte-order in the Tiff file will be 'MOTOROLA' +-tiff compress none: no compression will be performed (DEFAULT) +-tiff compress huffman: 'Huffman-compression' will be used (bilevel images) +-tiff compress fax3: Fax group3 compression will be used (bilevel images) +-tiff compress fax4: Fax group4 compression will be used (bilevel images) +-tiff compress lzw: LZW compression will be used +-tiff compress packbits: 'packbits-compression' will be used +-tiff Group3Opt fill: insert fillbits before EOL (Fax only) +-tiff xres : Xresolution in pixels per inch (Default: 300) +-tiff yres : Yresolution in pixels per inch (Default: 300) +-tiff SubFileType normal: (Default) +-tiff SubFileType mask: Transparency mask +-tiff SubfileType page: multi page file (fax) +-tiff predictor: The Tiff-predictor field is set to 2 (for LZW compression) + DEFAULT: predictor field not set. +-tiff photo white: Photometric interpretation: 'MINISWHITE' + Tiff file will be of type 'bilevel' or 'grayscale' + (tiff class 'B' or 'G') +-tiff photo black: Photometric interpretation: 'MINISBLACK' + Tiff file will be of type 'bilevel' or 'grayscale' + (tiff class 'B' or 'G') +-tiff photo rgb: Tiff file will have 3 color components (RGB) + (tiff class 'R') (DEFAULT setting) +-tiff photo separated: Tiff file will have 4 color components (CMYK) + +-tiff photo pal: Tiff file will have a color palette + (tiff class 'P') +-tiff photo ycbcr: Tiff file will have luminance and chrominance components + (tiff class 'Y') +-tiff stripsize N: Tiff file will have a stripsize of N Bytes + Default: 32000 Bytes. + +--------!-trim-E---------------------------- +-trim: Trim picture. (Only WMF output format) + +--------!-xmin-E---------------------------- +-xmin : set x-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-xmax-E---------------------------- +-xmax : set x-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-ymin-E---------------------------- +-ymin : set y-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-ymax-E---------------------------- +-ymax : set y-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-zmin-E---------------------------- +-zmin : set z-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-zmax-E---------------------------- +-zmax : set z-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-tmin-E---------------------------- +-tmin : set t-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-tmax-E---------------------------- +-tmax : set t-range for plotting user-defined functions + (in arbitrary units) + (see switch '-function') + +--------!-phimin-E-------------------------- +-phimin : set phi-range for plotting user-defined functions + (in polar-coordinate units) + (see switch '-function') + +--------!-phimin-E-------------------------- +-phimax : set phi-range for plotting user-defined functions + (in polar-coordinate units) + (see switch '-function') + +--------!-vblack-E-------------------------- +-vblack: Only the colors with the 'darkest' RGB-values will be + vectorized (picks the 'black' lines out of the picture). + All other objects were treated as having one unique + 'white color'. The regions consisting of this 'white' + color will also be vectorized. Thus, white areas inside + of black areas will be shown correctly. + Note that a lower -quantize value results in the + generation of more 'black' lines. If the quantize + value is too high, the program will not catch all all + dark regions. + +--------!-voblack-E------------------------- +-voblack dark: The same as -vblack, except that only the dark areas + will be processed. Thus, white areas inside of black + areas might dissapear if the 'black' object is of type + 'filled polygon'. +-voblack nwhite: The same as -vblack, except that only 'not white' areas + will be processed. Thus, white areas inside of other + areas might dissapear if the object is of type + 'filled polygon'. + +--------!-viewtype-E------------------------ + (GUI-Parameter) specifies the viewer for the KVEC-GUI. + Note: the commandline version ignores GUI parameters. +-viewtype SWF: (default) Macromedia Shockwave (Flash) +-viewtype SVG: Adobe SVG Format (Scalable vector graphics) + + +--------!-winding-E------------------------- +-winding original: (Default) Winding of polygons will be unchanged, as + detected from the source or from the vectorizer. +-winding reversed: Reverse the winding direction. This may be necessary + for some types of input data. +-winding optimized: KVEC sets alternating winding directions for main- + and subpolygons, depending on the nesting depth. + + The winding settings are only relevant for the SWF + format (and especially if you want to import the + SWF files into the Macromedia Flash Editor). The + Flash Players can handle all types of winding directions + +The following switches are only available for registered users: + +The Debug switches specify the level of the debug-output. The debug-output +with informations about the status of the vectorization process is displayed +on the screen. (High level means more detailed debug output). + +--------!-debug-E--------------------------- +-debug N: Generate debug-output level N (1-8) (default: No debug) +-debug all: Generate very detailed debug-output + +--------!-delta-E--------------------------- +-delta N: This is the maximal allowed color difference between the + rough and the detail layer. The detail layer contains + a vector representation of these areas which have a colour + difference to the first layer greater than delta. + Note: delta has two different meanings: If used together + with the 'progressive' option it means a color difference + between two layers. If used together with the 'vcolor' + option it means a maximal allowed color tolerance. + Values: 0 up to 128. Default: 0 + +--------!-errbez-E-------------------------- +-errbez N: Use the value N for the Bezier error-parameter. + Allowed values: 1 - 20. Greater values for errbez will + allow more differences between the original and the + output picture and will reduce the size of the output. + The default value is 3. + +--------!-group-E--------------------------- +-group: Generates recursively nested groups of objects + This parameter applies for the LogoArt format only. + +--------!-lossless-E------------------------ +-lossless: Generates a lossless image. May need enormous memory. + This is a synonym for: + -resolution high -grit 0 -reduce orth. and no quantization + +--------!-process-E------------------------- +-process KVEC has built in some image processing features which + are hardly to be found in other graphic programs. + You can specify a list of instructions after the + 'process' keyword. These instructions must be entered + as strings or as ordinal numbers and must be seperated by + one of the following characters: ',',':','.','-'. + The 'string-keywords may be abbreviated. + The instructions were performed as soon as the image is + read from disk (or automatically generated by using the + '-random' switch). Here a few examples: + +(Apply Gauss Highpass filter) +KVEC x.bmp y.tif -for tif -proc fft_bm,gausshighpass,ifft_bm +KVEC x.bmp y.tif -for tif -proc 14,39,15 + +(Spectrum) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,log_bm,norm_byt,center_or +KVEC x.bmp y.tif -for tif -proc 11,14,12,8,33 + +(Spectral power density) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,abs_bm,log_bm,norm_rby,center_or +KVEC x.bmp y.tif -for tif -proc 11,14,7,12,9,33 + +(Autocorrelation function) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,abs_bm,ifft_bm,log_bm,norm_byt,center_or +KVEC x.bmp y.tif -for tif -proc 11,14,7,15,12,8,33 + +(1.st Derivative) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,derive1,ifft_bm,abs_bm,norm_byt +KVEC x.bmp y.tif -for tif -proc 11,14,34,15,7,8 + +(1.st Integral) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,integral1,ifft_bm,abs_bm,norm_byt +KVEC x.bmp y.tif -for tif -proc 11,14,35,15,7,8 + +(Try to reconstruct the original image from a bitmap which contains a logarithmic +spectrum) +KVEC x.bmp y.tif -for tif -proc center_or,norm_flo,exp_bm,ifft_bm,abs_bm,log_bm,norm_byt +KVEC x.bmp y.tif -for tif -proc 33,11,13,15,7,12,8 + +(Random - test image (24 bit color) having a 1/(F*F) spectrum +KVEC null y.tif -for tif -proc norm_flo,fft_bm,spect_2_f,ifft_bm,norm_byt -random 24 2 +KVEC null y.tif -for tif -proc 11,14,23,15,8 -random 24 2 + + + + The (first) instruction 'byte2complex' and the (last) + instruction 'complex2byte' need not to be specified, + KVEC executes them by default. + Example 2 (Spectrum): + This instructs KVEC to perform a fourier transformation + with the image, apply the log() function to it, normalize + the values to the range [0..255], put the origin of the + image into the center (which is the better choice for + frequency representations). After this KVEC continues + in evaluating the other switches. + + PLEASE NOTE THAT THE BITMAP MUST BE CONVERTED TO A COMPLEX + BITMAP. THIS MAY RESULT IN ENORMOUS MEMORY DEMANDS! + Here an example: If we have a 500 * 500 bitmap with a + colordepth of 4 bit (palette bitmap), the bitmap occupies + 500*500*1/2 * sizeof(BYTE) = 125 KByte. The converted + complex bitmap occupies + 500*500*(3 colorplanes)*sizeof(COMPLEX) = 6 MByte. + Here are the keywords and the ordinal numbers (some of + the functions may not yet be implemented). + Please type the keywords lowercase in the commandline. + instruction: ordinal number: + ========================================================= + NOOP 0 no operation + BYTE2COMPLEX 1 makes complex image of bitmap + COMPLEX2BYTE 2 makes a bitmap of a complex image + BYTE2REAL 3 fills real part of complex image + REAL2BYTE 4 makes a bitmap of the real-part image + BYTE2IMAGINARY 5 fills imaginary part of complex image + IMAGINARY2BYTE 6 makes a bitmap of the imaginary-part + ABS_BM_COMPLEX 7 build absolute values Abs(z) + NORM_BYTE 8 normalize all values to [0...255] + NORM_RBYTE 9 normalize real values to [0...255] + NORM_IBYTE 10 normalize imaginary values to [0...255] + NORM_FLOAT 11 normalize all values to [-1.0,1.0] + LOG_BM_COMPLEX 12 applies the Logarithm function + EXP_BM_COMPLEX 13 applies the Exponential function + FFT_BM_COMPLEX 14 performs a Fourier Transformation + IFFT_BM_COMPLEX 15 performs a inverse Fourier Transform. + SUPPRESS_DC 16 supresses the DC part of the spectrum + SET_ZERO 17 set a complex image to 0 + SET_IM_ZERO 18 set real part of complex image to 0 + SET_RE_ZERO 19 set imaginary part of complex image to 0 + MAKE_RAND_PHASE 20 build a random phase of all points + SPECT_LIN 21 give spectrum a decreasing linear shape + SPECT_1_F 22 give spectrum a 1/f shape + SPECT_2_F 23 give spectrum a 1/f*f shape + SPECT_RE_EVEN 24 force even symmetry for real spectrum + SPECT_RE_ODD 25 force odd symmetry for real spectrum + SPECT_IM_EVEN 26 force even symmetry for imaginary spectr. + SPECT_IM_ODD 27 force odd symmetry for imaginary spectr. + CAR2POL 28 convert image to polar representation + POL2CAR 29 convert image to cartesian representation + LOWPASS 30 Low Pass filter (rectangle) + HIGHPASS 31 High Pass filter (rectangle) + ROTATE 32 Rotate + CENTER_ORIGIN 33 move origin into center of the image + DERIVE1 34 Build first derivative of the image + INTEGRAL1 35 Build first integral of the image + DERIVE2 36 Build second derivative of the image + INTEGRAL2 37 Build second integral of the image + GAUSSLOWPASS 38 Low Pass filter (Gauss) + GAUSSHIGHPASS 39 High Pass filter (Gauss) + GRAY2COLOR 40 gray-to-color conversion + MAKE16MCOLOR 41 convert to image having 16 M unique colors + (Please note: needs 150 - 200 MB RAM and runs 12 - 100 hours!!) + +GRAY2COLOR: The colordepth of the generated colored image (default: 8 Bit) + can be specified by using the switch '-random . + The parameter value will be ignored. + +--------!-progressive-E--------------------- +KVEC offers you the possibility of building a 'progressive' image. +The term 'progressive' means that the image is build up from two successive +layers (one 'rough' picture without details and one refined picture which +contains only details). The two layers follow in this order as the image is +build up. This kind of image representation is very robust against all kinds +of transformations and local deformations. The difference of the two layers +with respect to colour quantization and resolution of details is expressed +by the gritfactor and the colorfactor: + + +-progressive gritfactor N: Generates a progressive image with 2 Layers + The first layer has a grit-value multiplied by N +-progressive colorfactor N: Generates a progressive image with 2 Layers + The first layer has a quantize-value divided by N + +--------!-random-E-------------------------- +-random N1 N2: Generates a random test image for input. The name of the + input file should be 'null' or 'vnull' in this case. The + parameter N1 specifies the color depth of the test image. + Allowed values: 1,4,8,24. + N2 specifies the type of the image. + + Allowed values for N2 for raster images ('null'): + 0 or 1 (White noise BW or gray), 2 (white noise colored) + Values 0,1, or 2 are not suited for vectorization. + 3 : generates an image of a well known logo... (Default) + 4 : generates an image of a space shuttle + 5 : generates an image having 16777216 different colors + 701: Circle filled with random points + 702: Fractal complex test image (by iteration) + 703: Mersenne Primes in phase space representation + 704: Zeta function test image ??? + 705 Mersenne numbers and quad iterations + + Allowed values for N2 for vector images ('vnull'): + 0: Random polylines, 1: random polygons + 2: random dots + 3: generates an image (butterfly)... (Default) + 4: generates an image (tiger) + 700: Perrin series (set debug outputlevel 8) + 701: Plot Zetafunction along critcal line + 702: Plot Zetafunction for real values + 703: Plot Gammafunction for real values + 704, 705, 706: ??? + 708: Plot Sigma function (R4) + 709, 710: ??? + +--------!-scmode-E-------------------------- + (GUI-Parameter) specifies the scaling mode. + Note: Will be ignored by the commanline version +-scmode N: 0: isotrop, 1: isotrop, 2: anisotrop, 3: no scaling + +--------!-smooth-E-------------------------- +-smooth on: Smooth polylines: the program will try to smoothen the + polylines and Polygons. This is involving some loss of + information. + Default: Depends on the output format. + Using the 'smooth on' with the WMF or EMF-Format will + increase the resolution of the outputfile by a factor + of 4. + +-smooth off: Turns smoothing off + +--------!-subimage-E------------------------ +-subimage N: Use subimage No. N in inputfile (Tiff or FAX formats) + The first subimage has no. 0. If subimage is not specified + KVEC will put all subimages together in one image + (for FAX format only) + +--------!-swf-E----------------------------- +-swf format mx: Flash format MX (Default. Writes compressed output) +-swf format 6: Flash format MX (writes compressed output) +-swf format 5: Flash format 5.x (uncompressed, for compatibility) +-swf compression zlib: Use zlib compression method (Default, for format mx) +-swf compression none: no compression + +--------!-xyscale-E------------------------- +KVEC offers the possibility of anisotropic scaling / translation for +DXF and HPGL output: +-xyscale hpgl X Y: Scale hpgl output with factors X (x-direction) and + Y (y-direction) +-xyscale dxf X Y: Scale dxf output with factors X (x-direction) and + Y (y-direction) +-xyoffset X Y: Add X and Y offset to the coordinates on output + (The switch -coord should be set to 'pixel' in this case) + +--------!-vcolor-E-------------------------- +-vcolor R G B: This switch can be be used to pick out regions of the + image which have the specified color. + The color representation is RGB (Red Green Blue) with + values from 0 up to 255. + Only these regions that match this colour will be + vectorized. + Note: If a delta value > 0 is specified ('-delta' option) + all colors which lie in the range (RGB +/- delta) will + be vectorized. +-vcolor -R -G -B: Only these regions that do not match this colour will be + vectorized. + Note: If a delta value > 0 is specified ('-delta' option) + all colors which lie in the range (RGB +/- delta) will + not be vectorized. + +--------!-zlib-E---------------------------- +-zlib bufsize : Buffersize for the zlib input/output buffers. Default: 32768 +-zlib clevel : Compression level for the zlib routines (Default: 6) + Allowed values: 1 up to 9 + (The zlib compression method can be applied to SVG and SWF formats) + +--------!-end-E----------------------------- + + +The newest version of KVEC and the current price list is always available +from http://www.kvec.de + + +=============================================================================== + + +****************************************************************************** +* K V E C D O K U M E N T A T I O N * +* * +* +++ KK-Software +++ KK-Software +++ KK-Software +++ KK-Software +++ * +*----------------------------------------------------------------------------* +*Dipl.-Phys. Karl-Heinz Kuhl, Brunnlohestr. 2, 92637 Weiden, Deutschland * +*----------------------------------------------------------------------------* +* Tel. 10-12 Uhr FAX E-Mail * +* +49 961 6340837 +49 961 61455 support@kvec.de * +****************************************************************************** + + + + +--------!-ABOUT_KVEC-G---------------------- +Was ist KVEC? + +KVEC ist ein Freeware-Programm, mit dem Sie Raster-Graphiken in Vektor- +Graphiken konvertieren koennen. Sie koennen es ohne Einschraenkungen benutzen. +Vor dem Jahr 2010 wurde KVEC als shareware vermatktet. Die freeware version +ist als Download auf der KVEC Internet Seite erhltlich. +Dieses Version darf frei weitergegeben und kopiert werden. + +KVEC ist ein Programm, das hohe Anforderungen an den Speicherbedarf stellt. +Vektorisierung ist ein rechenaufwendiger, komplizierter Prozess und fuehrt +oft zu einem Abwaegen zwischen Rechenzeit und Speicherbedarf. +Es ist entscheidend fuer die Performance, dass Ihr Computer mit genuegend +RAM-Speicher ausgestattet ist. +Die Auswahl der Werte fuer die (optionalen) Programmparameter erfordert +einige Vorsicht. 'Verrauschte' Bilder (typisch fuer gescannte Farbbilder) +oder Bilder mit sehr vielen sehr kleinen Details sollten mit groesseren +'grit' Werten und kleineren 'quantize' Werten (Erklaerung s. unten) +ausgewertet werden. + +Die Ausgabeformate DXF und HPGL sind nicht fuer die Vektorisierung von +farbigen Photos oder gescannten Farbbildern geeignet (ausser Sie haben viele +GBytes Speicher auf Ihrer Festplatte uebrig ;-) die Groesse der Ausgabe- +Datei waere riesig. + +Vektordarstellungen von Bildern haben gegenueber Rastergrafiken mehrere +Vorteile: Operationen, wie z.B. Rotation, Dehnen, Morphing und Warping sind +viel leichter durchzufuehren und unerwuenschte Effekte wie z. B. Aliasing +tauchen bei Vektor-Bildern erst gar nicht auf. Die Anwendungsgebiete eines +guten Vektorisierers reichen von der Bewegungsschaetzung in Video-Sequenzen +bis hin zur effektiven Bildkompression. + +Bitte wenden Sie sich an den Autor, wenn Sie Probleme mit dem Programm haben, +oder wenn Sie Fehler finden. +KVEC wurde so konzipiert, dass es auf mehreren Betriebssystemen (die +unterschiedliche Hardware und graphische Oberflaechen besitzen) laeuft. +Diese 'Release' ist deshalb eine (graphik-unabhaengige) Kommandozeilen-Version. + +Die Syntax ist sehr einfach: + + KVEC (Inputdatei) (Outputdatei) [optionale Parameter] + Zum Beispiel: + KVEC test.bmp test.dxf -format dxf + +Verschachtelte Unterverzeichnisse werden bei der Anwendung von Wildcards nicht erfasst. +Wenn der Name der Input Datei Wildcards enthlt, weden die Ausgabe-Dateinamen +aus den expandierten Input-Dateinamen abgeleitet und bekommen andere Dateiendungen. +Im Falle identischer Dateinamen fuegt KVEC am Anfang des Dateinames ein '_' +(Underscore) hinzu um ein Ueberschreiben der Dateien zu verhindern. Die Dateinamen +von Input- und Output-Dateien koennen vollstaendige Pfadangaben enthalten. + +Man kann KVEC auch mit Hilfe einer Parameter-Datei starten (KVEC.PAR): + +KVEC -readpar Parameterdatei + +Der Name der Parameter-Datei muss KVEC.PAR lauten (grossgeschrieben), falls +der (optionale) Name der Parameterdatei weggelassen wird. +Bitte beachten: Die letzte Zeile einer Parameter-Datei sollte mit einem +CR oder einem LF Zeichen beendet werden (die Datei wird sonst unter Linux oder +MAC-OS nicht richtig gelesen). + +Die Beispiele von Parameter-Dateien aus dem KVEC Paket koennen benutzt +werden. + +--------!-sequence-G------------------------ +Seit der Version 3.90 kann KVEC durch die Angabe zweier Parameter-Dateien im +'Sequenz-Modus' gestartet werden (der letzte Parameter 'nseq' ist optional). + + KVEC -readpar Parameterdatei1 Parameterdatei2 + +KVEC wird dann eine Sequenz von Einzelbildern erzeugen in dem stufenweise +alle Parameterwerte aus der ersten Datei in die Werte aus der zweiten Datei +interpoliert werden. Falls kein Wert fuer 'nseq' angegeben wird, gilt der +Default wert nseq = 100. +Wichtig: Die Eingabe/Ausgabe Dateinamen in der ersten Parameterdatei muessen mit +denen der zweiten Parameterdatei identisch sein. 'vnull' oder 'null' (siehe unten) +in Verbindung mit den internen 'Zufalls' und Demo-Bildern ist auch erlaubt. +Die erzeugten Ausgabedateien haben Indizes (6 Stellen). Existierende Dateien +werden ohne Abfrage ueberschrieben. +Man kann anschliessend andere Konvertierungssoftware dazu hernehmen um aus den +Bild-Sequenzen eine einzige Video-Datei zu erstellen und damit interessante +Animationen (z. Bsp. animierte Funktions-Zeichnungen) erstellen. +Zukuenftige KVEC-Versionen werden die Funktion von echtem 'Morphing' beinhalten, so +dass in beiden Parameterdateien unterschiedliche Inputdateien angegeben werden +koennen. + +--------!-intro_in-G------------------------ +Inputdatei ist der Name der Rastergraphik-Datei (Tiff, BMP, PCX, TGA, SGI, +IMG, PNM, JPEG, GIF, WPG, PNG oder FAX). +Falls der Name der Input-Datei 'null' lautet, erzeugt KVEC automatisch ein +Zufalls-Testbild (Raster-Bild). +Beim Plotten von benutzer-definierten Funktionen (siehe switch '-function') +muss der Input-Name auch 'vnull' lauten; + +Die Eigenschaften dieses Testbildes haengen von den Einstellungen des +Parameters 'random' ab. + +--------!-intro_out-G----------------------- +Outputdatei ist der Name der gewuenschten Vektorgraphik-Datei. +Bitte beachten Sie, dass der Dateiname auch das entsprechende File-Suffix +(z.B. WMF) enthalten muss. + +Wichtig: +Wenn die Input-Datei bereits ein Vektor-Format hat (WMF oder ART), dann +haben die meisten Eingabeparameter keine Wirkung. In diesem Fall fuehrt +KVEC nur eine Formatumwandlung vom einen Vektorformat ins andere durch. + + +Z. Zeit werden folgende Vektor-Formate unterstuetzt: + - Windows Metafile, Postscript, AutoCad DXF, HPGL, ART, XFIG, PCS, SVG, + SWF (Flash 6.x), Editable Adobe Illustrator Format, KVEC-Format (KVC). + DST (Tajiama stick format), HTML + +Die Parameter sind optional. Wenn Sie keine Parameter angeben, waehlt das +Programm automatisch einen Satz von Parametern aus, der optimal an die +Eigenschaften der Input-Datei angepasst ist. Die Schluesselwoerter fuer die +Parameter koennen abgekuerzt werden. +Die Dateinamen muessen in der Kommandozeile vor den optionalen Parametern +erscheinen. Einige Parameter koennen jedoch ohne Dateinamen direkt hinter +KVEC angegeben werden. Von diesen Parametern darf jeweils nur einer angegeben +werden: + +--------!-ehelp-G--------------------------- +KVEC -ehelp Zeigt Hilfe zum Parameter an (in Enlisch) + +--------!-ghelp-G--------------------------- +KVEC -ghelp Zeigt Hilfe zum Parameter an (in Deutsch) + +--------!-info-G---------------------------- +KVEC -info: Gibt ein paar nuetzliche Informationen auf dem Bildschirm + aus. + +--------!-printform-G----------------------- +KVEC -printform: Erzeugt automatisch ein Registrierungsformular. Dieses + Formular koennen Sie per FAX, E-Mail oder Briefpost an + den Programm-Autor senden, um einen Registrierungs- + schluessel zu erhalten. Der Registrierungsschluessel ist + eine max. 5-stellige Zahl, die dem Benutzer erlaubt, die + Software zu registrieren und den Zugriff auf die + erweiterten Funktionen von KVEC freigibt. + Sie koennen eine Sprache auswaehlen. Das Registrierungs- + formular wird dann in einer Sprache Ihrer Wahl erzeugt. + Das Registrierungsformular besteht aus reinem ASCII Text. + Wenn Sie es aus einem Textverarbeitungsprogramm heraus + ausdrucken moechten, achten Sie bitte darauf, dass Sie + einen Zeichensatz mit gleichmaessigem Zeichenabstand, und + keine Proportionalschrift ausgewaehlt haben. + + +--------!-register-G------------------------ +KVEC -register: Sobald Sie einen Registrierungsschluessel erhalten haben + koennen Sie mit dieser Option das Programm registrieren + lassen. Das Programm fragt Sie nach Ihrem Namen, der + Seriennummer und nach Ihrem Registrierungsschluessel. Bitte + geben Sie alle Buchstaben und Ziffern genau so ein, wie Sie + auf der Registrierungsbestaetigung, die Sie vom Autor + erhalten haben, abgedruckt sind. Wenn Sie die Informationen + richtig eingegeben haben, wird eine Meldung erscheinen, die + sich fuer die Registrierung bedankt. Ihr Registrierungs- + schluessel ist fuer alle 'Bugfixes' und Updates von KVEC + gueltig. + +--------!-readpar-G------------------------- +KVEC -readpar: KVEC liest die Dateinamen und zusaetzliche Parameter + aus einer Parameter-Datei ein (statt von der Kommando- + Zeile). Bitte beachten Sie, dass die Parameter-Datei im + aktuellen Verzeichnis stehen muss. Die Datei ist vom Typ + ASCI und kann mit jedem Texteditor bearbeitet werden. + Kommentare in der Parameter-Datei muessen mit einem + #-Zeichen beginnen und koennen ueberall nach einem + Parameter oder am Beginn einer Zeile erscheinen. + +KVEC -readpar [Datei]: + KVEC liest die Dateinamen und zusaetzliche Parameter + aus der Parameterdatei mit dem Namen [Datei]; + + +--------!-rename-G-------------------------- +KVEC *.jpg *.jpg -rename: (Nur Windows-Version). Diese spezielle Anweisung + dient zum Umbenennen von mehreren Dateien. Die + umbenannten Dateien haben das Prefix: "high_". Dies ist + nuetzlich in Vorbereitung zusammen mit dem Switch + "-html". Im Allgemeinen wird dieses Kommando fuer JPG- + Dateien angewendet werden. Hier ein Beispiel: + 'kvec bild*.jpg *.jpg -rename' + +--------!-writepar-G------------------------ +KVEC -writepar: Erzeugt eine KVEC Parameter-Datei. Der Benutzer wird + aufgefordert, Dateinamen und zusaetzliche Parameter + einzugeben. Der Name der Datei lautet immer 'KVEC.PAR' + und die Datei wird immer ins aktuelle Verzeichnis + geschrieben. Sie koennen Kommentare an die + eingegebenen Parameter anhaengen (siehe oben). Parameter + muessen immer mit einem '-'Zeichen beginnen. + Nach dem die Parameterdatei erzeugt wurde, muss das + Programm erneut mit der Option '-readpar' gestartet + werden. + +KVEC -writepar [Datei]: + Erzeugt eine KVEC Parameter-Datei mit dem Namen [Datei] + +--------!-end of writepar-G----------------- + +Die anderen Parameter muessen nach dem Dateinamen angegeben werden: + +--------!-antialiasing-G-------------------- +-antialiasing : (Nur fuer Vektor-Raster-Konvertierung): Anti-Aliasing + eingeschaltet beim Rendern. + : 0: Kein Antialiasing, 1: gute Qualitaet, 2: beste + <-N>: wie , erzeugt jedoch kompaktere Linien + +--------!-bezier-G-------------------------- +-bezier: Erzeugt in der Output-Datei Bezierkurven statt Geraden. + Vektorbilder aus Bezierkurven koennen beliebig ver- + groessert werden, ohne dass Ecken oder Kanten auftauchen. + Fuer Ausgabe-Formate, die keine Bezierkurven untersttzen + wird der Bezier-Algorithmus simuliert und durch Polygone + angenaehert. + +--------!-bkcolor-G------------------------- +-bkcolor : Setzt Hintergrundfarbe zum Zeichnen von benutzer- + definierten Funktionen (see switch '-function') + +--------!-black-G--------------------------- +-black: Ausgabe-Farbe fuer Vektor-Bilder ist immer schwarz + +--------!-centerline-G---------------------- +-centerline mixed: Die Wirkung dieses Parameters haengt vom Wert des Para- + meters -lwidth ab: (in Verbindung mit -centerline hat der + Parameter -lwidth eine etwas andere Bedeutung) + Vor der Vektorisierung werden alle gefundenen Objekte + auf Ihre maximale Dicke hin untersucht. Alle Objekte + mit einer Dicke kleiner als -lwidth werden als Linien- + objekte behandelt; alle anderen Objekte werden normal + vektorisiert. + Die Vektorisierung von Linienobjekten ergibt keine + Randlinien, die das Objekt umschliessen, sondern einzelne + Linien, die entlang einer Mittellinie durch das Objekt + gehen. Die tatsaechliche Liniendicke dieser aus der + Vektorisierung hervorgegangenen Linie wird so gewaehlt, + dass die Flaeche des Linienobjekts etwa mit der Flaeche + des urspruenglichen Objekts uebereinstimmt. + (Manche Ausgabe-Formate unterstuetzen leider keine variable + Liniendicke). Das ist der Default-Wert. + +-centerline lines: Wie bei 'centerline mixed', jedoch werden nur Linien- + objekte erzeugt. Alle anderen Objekte werden verworfen. +-centerline off: Schaltet Centerline Vektorisierung aus (Default) + +--------!-colspace-G------------------------ + Waehlt den internen Farbraum aus, der von KVEC benutzt wird. + Die Wahl des Farbraumes macht sich bemerkbar, wenn mit Farb- + separierung gearbeitet wird, oder wenn zusaetzliche + Bitmap-Verarbeitung durchgefuehrt wird ("process" Option). +-colspace rgb: RGB color space (Default). +-colspace rb: RB color space +-colspace gb: GB color space +-colspace gr: RG color space +-colspace cmyk: CMYK color space +-colspace cy: CY color space +-colspace my: MY color space +-colspace mc: CM color space + Achtung: Wenn ein anderer Farbraum als RGB oder CMYK ausge- + waehlt wurde, so werden die Farben so optimiert, dass der + optische Eindruck moeglichst nahe an den Originalfarben liegt. + +--------!-colseparation-G------------------- + Waehlt den Typ der Farbseparation. Die Ausgabedatei wird + nur die angegebenen Farbkomponenten enthalten. + Man beachte, dass fuer cmyk Separation auch der richtige + entsprechende Farbraum ausgewaehlt wurde. +-colsep rgb: keine Farbseparation (Default). +-colsep cmyk: keine Farbseparation +-colsep rb: R und B Komponenten +-colsep gb: G und B Komponenten +-colsep gr: R und G Komponenten +-colsep cy: C und Y Komponenten +-colsep my: M und Y Komponenten +-colsep mc: C und M Komponenten +-colsep rr: separiert R Farbe +-colsep gg: separiert G Farbe +-colsep bb: separiert B Farbe +-colsep cc: separiert C Farbe +-colsep mm: separiert M Farbe +-colsep yy: separiert Y Farbe + Achtung: Es ist praktisch, bei der Separierung von einzel- + nen Farbkomponenten eine Datei mit Graustufen zu erzeugen. + Das kann durch die gleichzeitige Angabe der Option "-black" + erreicht werden. + + +--------!-coord-G--------------------------- + Waehlt den Typ der internen Skalierung von Koordinaten +-coord optimize: Koordinaten werden evtl. neu skaliert um eine bessere + Aufloesung zu erzielen (Default) +-coord pixel: Das urspruengl. Pixel-Koordinatensystem wird benutzt. + + +--------!-dimension-G----------------------- +-dimension N: Gibt die maximale Ausdehnung (in X- oder y- Richtung) + des erzeugten (Raster)-Bildes an. Default: 512 Pixel. + WICHTIG: Dieser Parameter wird nur dann ausgewertet, falls + die Input-Datei vom Typ einer Vektorgrafik oder 'null' ist. + +--------!-xdim-G---------------------------- +-xdim N: Gibt die maximale Ausdehnung (in X- Richtung) + des erzeugten (Raster)-Bildes an. Default: Originalwert + +--------!-ydim-G---------------------------- +-ydim N: Gibt die maximale Ausdehnung (in Y- Richtung) + des erzeugten (Raster)-Bildes an. Default: Originalwert + +--------!-drcolor-G------------------------- +-drcolor : Setzt Linienfarbe zum Zeichnen von benutzer + definierten Funktionen (see switch '-function') + +--------!-dither-G-------------------------- +-dither off: Schaltet 'Dithering' aus (Default-Einstellung) +-dither linear: Schaltet 'Dithering' ein + Bitte beachten Sie, dass Dithering nur stattfindet, wenn + das Ausgabeformat vom Typ 'Raster' ist. + +--------!-dst-G----------------------------- +-dst dist : Gibt den Abstand zwischen zwei Stichen an (in 0.1 mm) +-dst width : Gibt die die Dicke des Fadens an (in 0.1 mm) +-dst fill hollow: Farbige Flchen werden nicht gefllt +-dst fill hatch: Erzeugt "schraffierte" Linien (simulierte Fllung,Default) +-dst fill zickzag: Erzeugt "Zickzack"-Linien als Fllung + +--------!-dxfopt-G-------------------------- +-dxfopt type 2dim: Erzeugt 2-dimensionale Koordinaten (falls als Ausgabe- + format das DXF-Format gewaehlt wurde (Default). +-dxfopt type 3dim: Erzeugt 3-dimensionale Koordinaten (falls als Ausgabe- + format das DXF-Format gewaehlt wurde. +-dxfopt form unix: Fuegt nur (line feed) an Zeilenenden ein (Default) +-dxfopt form dos: Fuegt an Zeilenenden ein + +--------!-fill-G---------------------------- +Die 'Fuell'-Paremeter geben an, wie die erzeugten Polylines/Polygone +interpretiert werden sollen: + +-fill solid: Polygone sind stets geschlossen, d.h. der letzte Punkt eines + Polygones ist identisch mit dem ersten. Die Flaecheninhalte + der Polygone werden mit individuellen Farben gefuellt. + (Das ist die Default-Fuelleinstellung). Der 'sort' + Parameter sollte in diesem Fall nicht 'min' sein, da die + groesseren Polygone die kleineren ueberdecken und + verstecken wuerden. + +-fill line: Es werden Polylines mit individuellen Farben erzeugt. Die + Polylines sind nicht geschlossen. Dies ist die bevorzugte + Einstellung wenn die Output-Datei fuer einen Plotter + bestimmt ist. Der Plotter-Stift wird keine Farben ueber- + einander zeichnen. Das 'Layout' haengt vom Sortierparameter + 'sort' ab. Mit den Parametern 'reduce' und 'smooth' koennen + Sie nochmals das Ergebnis der Vektorisierung verfeinern. + +-fill contour: Wie bei '-fill solid', jedoch wird das Innere der Polygone + nicht gefuellt. Linien mit unterschiedlicher Farbe koennen + sich evtl. ueberdecken. Das 'Layout' haengt vom Sortier- + parameter 'sort' ab. + +--------!-font-G---------------------------- +-font: Die Angabe dieses Parameters bewirkt, dass KVEC einen + optimierten Parametersatz erzeugt, der speziell fuer + die Vektorisierung von dunklem Text auf hellem Hinter- + grund optimiert ist. Allen Objekten wird eine einzige + 'dunkle' Farbe zugeordnet. Die Sortierreihenfolge "local" + wird hierbei automatisch eingeschaltet, so da Subpolygone + mit Transparenzfarbe erzeugt werden knnen. + +--------!-format-G-------------------------- +Die Format-Parameter geben das gewuenschte Output-Format an: +(Bitte beachten Sie, dass KVEC das Output-Format auch aus der Dateiendung der +Input-Date bestimmen kann, falls keine Formatangabe verwendet wird.) + +-format wmf: Outputformat ist Windows Metafile Format, *.WMF +-format amf: Outputformat ist ALDUS WMF Metafile, *.WMF +-format emf: Outputformat ist Enhanced Windows Metafile Format, *.EMF +-format ps: Outputformat ist Postscript Level 2, *.PS +-format eps: Outputformat ist Encapsulated Postscript Level 2, *.EPS +-format dxf: Outputformat ist AutoCad DXF, *.DXF +-format hpgl: Outputformat ist HPGL (nur Linien), *.HPG oder *.PLT +-format art: Outputformat ist ART LogoArt (OS/2-Graphikprogramm), *.ART +-format ai: Outputformat ist Adobe Illustrator Format *.AI +-format bmp: Outputformat ist Windows Bitmap, *.BMP +-format tiff: Outputformat ist Tiff, *.TIF +-format zyxel: Outputformat ist ZYXEL FAX +-format pfax: Outputformat ist PowerFax +-format kvc: Outputformat ist KVEC Vektor Format +-format xfig: Outputformat ist XFIG Vektor Format(Linux Zeichenprogramm) +-format pcs: Outputformat ist Pfaff PCS Format +-format dst: Outputformat ist Tajiama DST Format +-format wav: Outputformat ist WAV +-format svg: Outputformat ist SVG (scalable Vector Graphics) +-format svgz: Outputformat ist SVGZ (compressed scalable Vector Graphics) +-format swf: Outputformat ist SWF (Macromedia Flash MX, DEFAULT) + Der Macromedia Flash MX Editor akzeptiert nur bestimmte + Anordnung von Polygonen die mit dem switch + '-winding' eingestellt werden koennen. +-format png: Outputformat ist PNG (Portable Network Graphics) +-format jpeg: Outputformat ist JPEG +-format html: (Nur Windows-Version) + Hinweis: '-format html' ist ein Synonym fuer den folgenden + Satz von Parametern: + '-format jpg' '-hmtl source default','-html screen default', + '-html preview default', '-mode isotrop' + Dieses Format ist eigentlich kein richtiges Ausgabeformat, + sondern bietet die Moeglichkeit fuer eine sehr spezielle + Anwendung: Nehmen wir an, Sie haben viele JPG-Dateien und + Sie moechten einen Satz von html-Dateien erzeugen, mit denen + Sie mit einem Browser bequem alle Bilder betrachten koennen. + Beispiel: Sie mchten Hunderte oder Tausende von Bildern + auf einer Web-Seite verffentlichen und einen schnellen + Zugang zum Betrachten der Bilder bieten. + Kvec wird fuer jede einzelne Bild-Datei eine HTML Datei + erzeugen. Eine HTML Datei 'directory.htm' wird ebenfalls + erzeugt. Diese enthlt Links auf die einzelnen html-Dateien + durch 'Preview'-Bilder. Jedes Bild wird in drei Auflsungen + erzeugt: + niedrig (preview), mittel ('Screen-resolution') und hoch + (zum Download). Nehmen wir an, eine unserer Input-Dateien + heisst 'test01.bmp', dann werden folgende Dateien erzeugt: + 'source_test01.jpg', 'screen_test01.jpg', 'previe_test01.jpg' + + Der folgende Kommandozeilenaufruf wird dies alles bewirken: + + kvec source_dir\test*.bmp destination_dir\*.htm + + Nehmen wir an wir haben 100 Input Dateien eines beliebigen + lesbaren Input-Formates: + KVEC wird dann 300 JPEG Dateien im Zielverzeichnis erzeugen. + KVEC wird ebenso 100 HTML Dateien mit Links zu den + erzeugten Bilddateien generieren. + Die 'Preview' Bilder werden in der Datei 'directory.htm', + die ebenfalls im Ziel-Verzeichnis erzeugt wird, angezeigt. + + Siehe auch: '-html ...' + +--------!-function-G------------------------ +-function ...: (siehe auch: '-nstep', '-bkcolor', '-drcolor', '-xmin', + '-xmax', '-ymin', '-ymax', '-tmin', 'tmax', -lwidth') + Diese Funktion betrifft nicht die Bearbeitung von Bilddateien. + Der Parameter '-function' erzeugt Funktionsgraphen von math. + Funktionen, deren Formeln eingegeben werden knnen. + Die Definition von math. Funktionen beinhaltet auch die + Definition von benutzerspezifischen Konstanten. Da die Defi- + nition von Funktionen und Variablen sehr lang sein kann, wird + nicht empfohlen, die Parameter als Kommandozeilenparameter + einzugeben. Es ist wesentlich praktischer alle Definitionen + und Parameter in einer KVEC Parameterdatei anzugeben. + Alle Zeichenketten, die dem '-function' Schluesselwort folgen, + werden als 'C-style' Kommandos interpretiert, mit denen bis + zu 8 Funktionen und 100 Variablen definiert werden knnen. + Das Schluesselwort 'endfunc' (ohne ";") beendet diesen Defini- + tionsteil. Die zuweisungen von Variablen u. Konstanten muessen + der Definition der Funktionen vorausgehen! Folglich knnen + Variablen auch nicht mit Funktionsergebnissen oder Ausdruecken + initialisiert werden. + Es gelten folgende Einschraenkungen: + Alle Funktionen muessen den folgenden Namenskonventionen ent- + sprechen: + + f?(argument) ('?' ein beliebiges alphanumerisches Zeichen) + ('argument' kann eines von (x,y,z,t,i) sein) + x?(argument) y?(argument) ('?' belieb. alphanumerisches Zch.) + (Parameterdarstellung einer Funktion) + r?(phi-argument) ('?' ein beliebiges alphanumerisches Zeichen) + ('argument' muss 'p' lauten) + (Darstellung in Ploarkoordinaten) + Erlaubt ist ebenfalls: x?(), y?() or f?() + (ohne Funk.-Argument, Anwendung: Iterative Funktionen) + Wichtig: Funktionsnamen (zwei Zeichen lang) koennen auch als + Variablen benutzt werden. Das ist sinnvoll fuer Initialisierungen + in iterativen Funktionen oder Schleifen. + + Da Initialisierungen von Konstanten und Variablen den Funktions- + definitionen vorausgehen, sind Variablen immer 'global' und + gelten fuer jede der (max. 8 moeglichen) Funktionen. + + Ein paar Beispiele: f1(x)=sin(x); fa(t)=cos(t); (gueltig) + fabc(x)=x; (ungueltig) + f1(x) = cos(x); (ungueltig) + f2(x)=SUM(n=1,100,x^n/n!); (gueltig) + x3(t)=cos(t); y3(t)=sin(t); (gueltig) + y(x)=exp(x); (ungueltig) + x1(i)=KV_PRIMES[i]; y1(i)=i; (gueltig) + r1(p)=0.5*p; (gueltig) + + Jede Anweisung endet mit ";". Innerhalb einer Anweisung sollten + nach Moeglichkeit keine Leerzeichen oder andere "white-space" + Zeichen stehen. Anweisungen werden jedoch durch Leerzeichen oder + 'white-spaces' voneinander getrennt. + Insgesamt sind bis zu 8 verschiedene Funktionen erlaubt. + Die Funktionsnamen bestehen aus 2 Zeichen und muessen mit einem + der folgenden Zeichen beginnen: 'f', 'x', 'y' oder 'r'. Das + zweite Zeichen ist ein beliebiges alphanumerisches Zeichen. + Wenn eine Parameterdarstellung vorliegt z.Bsb. x1(t)=..,y1(t)=..) + muss die Definition der x1() Funktion der Definition der y1()-Funkt. + vorausgehen. Eine Parameterdarstellung zhlt als eine Funktion. + + Wenn die Definitionsreihenfolge in Parameterdarstellungen ver- + tauscht wird, ist das Ergebnis unvorhersagbar. + Das Funktionsargument muss eines der folgenden Zeichen sein: + 'x', 'y', 'z', 't' or 'p' (im Falle von Polarkoordinaten). + Ausdruecke koennen ineinander mit Klammern '(', ')' verschachtelt + werden. Konstanten koennen am Anfang wiefolgt definiert werden + (Beispiele): + ABC=1.234; SQ2=1.414; ... + Achtung: Konstanten koennen nicht durch Ausdruecke definiert werden + (nur durch Zahlenwerte). + + Folgende mathematische Operatoren sind erlaubt: + '+' Addition oder unitaeres (vorangestelltes) '+' + '-' Subtraktion or unitary (vorangestelltes) '-' + '*' Multiplikation + '/' Division + '%' Modulus + '^' Potenzierung + '!' Fakultaet (kann auch auf Ausdruecke angewendet werden) + 'SUM' Summation. Syntax: SUM(n=,,); + z. Bsp.: SUM(n=1,100,x^n/n!); + 'PROD' Produkte. Syntax: PROD(n=,,); + 'ITER' Iterations-Schleifen. Syntax: + ITER(n=,,,,); + 'iterate' (erweiterte Iterationsschleifen) Syntax: + iterate(n=,,,<(list of var-initializations>); + + In den SUM, PROD or ITER- Anweisungen kann jeweils nur eine Schleifen- + variable definiert werden; Schleifen-Variablen muessen durch (konstante) + Zahlenwerte initialisiert werden. + Die 'ITER'-Anweisung ist fuer einfache Funktionen einer Variablen + (z. Bsp. f1(x)=) geeignet. Der Funktionsterm + muss innerhalb der Anweisung als der letzte Ausdruck definiert werden. + Der Funktionsterm kann den Funktionsnamen selbst als Variable enthalten + (Iteration). Die Iteration startet mit einem Wert der Schleifen- + variablen und endet mit einem Wer groesser oder gleich dieser + Variablen. Die Iteration endet ebenfalls, wenn die Differenz des + Ergebnisses zwischen zwei aufeinander folgenden Iterationen kleiner + als ist. Iterationsschleifen fuer Funktionen in Parameter- + Darstellung (x(t), y(t) ist mit der 'ITER' Anweisung nicht moeglich. + Fuer diesen Zweck ist die erweiterte Anweisung 'iterate(...)' gedacht. + + Syntax: + iterate(n=,,,<(Liste v. Variablen-Initialisierungen>); + + Die 'iterate'-Anweisung beinhaltet selbst nicht die Funktionsdefinition. + Die Funktionsdefinition(en) muessen unmittelbar auf die 'iterate'- + Anweisung folgen. Mit dieser Anweisung koennen auch Funktionen in Parameter + darstellung oder iterative Funktionen von zwei Variablen behandelt werden. + Die Variablen-Definitionen und -Initialisierungen innerhalb der 'iterate'- + Anweisung sind nur fuer die der 'iterate'-Anweisung folgende Funktionen + gueltig (nicht global). + + Wichtig: Functionen koennen auch ohne Funktionsargumente definiert + werden (z. Bsp. 'x1() = ....'). Der Funktionsterm kann auch den Funktions- + namen als Parameter enthalten (Iteration). Die Anzahl der Iterationen + wird dann durch den Parameter '-nstep' gesteuert. (nstep ist global und + wird ausserhalb des durch die Schluesselwoerter '-function' und 'endfunc' + definierten Bereiches definiert. 'nstep' kann jedoch auch 'lokal' + definiert werden (ist dann nur fuer die folgende Funktion gueltig) + z. Bsp 'nstep ' (ohne fuehrendes '-' Zeichen). + Der aktuelle Wert der Iterations Schleifenvariablen kann innerhalb der + Funktion benutzt werden durch den Namen 'II' (interne Schleifenvariable). + Da II von KVEC verwaltet wird, sollten der Variablen 'II' keine Werte + zugewiesen werden. + + Alle mathematischen Funktion, die im 'ANSI' Standard definiert sind, + koennen verwendet werden. Damit sind die meisten elementaren mathematischen + Funktionen erfasst. Die folgenden hoeheren math. Funktionen koennen + ebenfalls verwendet werden (im Moment, diese Menge wird noch erweitert + werden) + + fakul(x) (Fakulttsfunktion) + bernoulli(x) (Bernoulli Funktion) + gamma_r(x); (relle Gamma Funktion) + PI_func(x); (Anzahl d. Primzahlen bis x) + nth_prime(x); (berechnet die n.te Primzahl) + nth_mprime(x); (Gibt den n-ten Mersenne Primzahl-Expnenten zurueck) + nur bis x=48, leider ;-) + nth_zzero(); (Gibt die n-th Nullstelle der Zeta-Funktion zurueck) + (nur in der erweiterten MATH-Version von KVEC verfuegbar) + IsPrime(x); (Ergibt 0.0 oder 1.0 je nach dem ob Primzahl) + riemann_r(x); (reelle Riemann-Funktion) + sigma(x); ('Anzahl von Teilern'-Funktion) + sigmaX(x); (wie sigma(), jedoch 'quadratfrei') + sigma4(x); (Anzahl von 4-dimensionalen Gitterpukten) + zeta_r(x); (Realteil d. Zeta-Funktion, entlang X-Achse) + zeta_cr(x); (Realteil d. Zeta-Funktion, entlang krit. Linie) + zeta_ci(x); (Imaginaerteil d. Zeta-Funktion, entlang krit. Linie) + primeSum2_2(x) (# Moeglichkeiten x als Summe v 2 Primz., start 2) + primeSum2_3(x) (# Moeglichkeiten x als Summe v 2 Primz., start 3) + primeSum2_5(x) (# Moeglichkeiten x als Summe v 2 Primz., start 5) + primeSum2_7(x) (# Moeglichkeiten x als Summe v 2 Primz., start 7) + primeSum2_11(x) (# Moeglichkeiten x als Summe v 2 Primz., start 11) + primeSum3_2(x) (# Moeglichkeiten x als Summe v 3 Primz., start 2) + primeSum3_11(x) (# Moeglichkeiten x als Summe v 3 Primz., start 11) + primeSum4_2(x) (# Moeglichkeiten x als Summe v 4 Prmz., start 2) + primeSum4_11(x) (# Moeglichkeite x als Summe v 4 Primz.., start 11) + getNextDigOfInvI(x) (gibt naechste Ziffer in Dezimalbr.-Entw. v. 1/N) + getPerLengthOfInvI(x) (gibt Periodenlnge der Dezimalbr.Entw. v. 1/N) + getDigitWithIndI(x) (gibt Ziffer mit Index x aus Dezim.ruch.entw. 1/N) + + + KVEC enthaelt auch einen vordefinierten Satz von mathematischen Konstanten + und Variablen, die benutzt werden koennen (alle in Grossbuchstaben): + M_PI + M_E (Euler-Konstante) + M_G (Gamma-Konstante) + M_LN2 (= log(2)) + M_Z3 (= zeta(3)) + + KV_PRIMES[n] (Primzahlen, n: 0-maxprime, siehe Parameter 'maxprime') + KV_MPRIMES[n] (Mersenne Primzahl-Exponenten, n: 0-48) + KV_ZETA_ZEROS[n] (Nullstellen der Zeta-function, entlang der 'kritischen + Linie', nur in der speziellen MATH KVEC Version verfuegbar + erlaubt n: 0-99999 ) + BN[n] (Bernoulli-Zahlen, n: 0-99) + BN_FAK[n] (=BN[n]/n!, n: 0-99) + ZETA[n] (= zeta_r(n), n: 0-99) + II (Interne KVEC Schleifen-Variable) + + Eckige Klammern ('[' and ']') muessen fuer die Indizierung dieser + vordefinierten Felder verwendet werden (an Stelle der runden Klammern + '(' or ')'). Bitte beachten Sie, dass die Indizes mit 0 starten, so ist + z. Bsp. die erste Primzahl in KV_PRIMES[0]. + + Spezielle Anweisungen f. getNextDigOfInvI(), getPerLengthOfInvI() + und etDigitWithIndI(): + numberbasis n: (Setzt die Basis fuer Dezimalbruchentw. Default: 10) + numberdenom n: (Setzt die Zahl n f. die Berechnung von 1/n) + + Graphische Anweisungen (zur Steuerung des Layouts der Ausgabe) koennen + ebanfalls nach der Variablen und Konstanten Defininion eingefuegt werden + (jedoch vor der entsprechenden Funktionsdefinition). Bitte beachten: + Diese Anweisungen enthalten kein '=' Zeichen und kein vorangestelltes + '-' Zeichen, da sie zur 'function'-Sektion gehoeren. + + bkcolor r g b; (Setzt die Hintergrundfarbe (rgb-Wert) + drcolor r g b; (Setzt aktuelle Zeichnungsfarbe (rgb-Wert) + lwidth n; (Setzt aktuelle Linienbreite auf den Wert n) + nstep n; (Setzt aktuelle Anzahl von Interpolationsschritten) + imin n; (Setzt den min-Wert f. das 'i'-Funktionsargument) + imax n; (Setzt den max-Wert f. das 'i'-Funktionsargument) + object ; (Setzt den Typ der generierten KVEC Objekte) + kann einer von folgenden sein: + 'polyline' (Default) + 'polygon' + 'markcircle', 'markfilledcircle' + 'markrect','markfilledrect' + 'markrbox','markfilledrbox' + 'hline', 'vline' + 'polyspline', 'filledpolyspline' + + msize n; (Setzt die Groesse von 'Markern' auf: % der Bildgroesse) + pmode : (Setzt den 'Zeichnungs-Modus' fuer Funktionen in + Parameter-Darstellung): + 'normal' (Zeichnet x-y plot, Default) + 'xt' (Zeichnet x-t plot) + 'yt' (Zeichnet y-t plot) + 'abs' (Zeichnet Absolutbetrag von (x,y) gegen t) + Die Modi 'xt/yt/abs' sind nuetzlich zum Zeichnen der Real- + bzw. Imaginaerteile von komplexen Funktionen in Abhaengigkeit + eines Parameters 't'. + + Wichtig: Grafische Einstellungen gelten nur fuer die aktuell + ausgewertete benutzerdefinierte (= aktive) Funktion (Ausnahme: + Farbeinstellung fuer den Hintergrund). Diese Einstellungen gelten + individuell fuer die jeweilige folgende Funktion. Falls keine + graphischen Einstellungen agegeben werden, gelten Deafaultwerte. + Die graphischen Anweisungen muessen der jeweiligen Funktion + vorausgehen. Die Einstellung 'polyline' oder 'polygon' erzeugt + kontinuierlich gezeichnete Linien zwischen Interpolationspunkten + mit dem eingestellten Abstand (der sich aus 'nstep' und den Werten + fuer 'xmin' und 'ymin' ergibt). Die Auswahl von 'Markern' erzeugt + 'Marker'Symbole (Kreise, Rechtecke, Linien segmente) an den jeweiligen + Plot-Positionen ohne dass Linien zwischen den Punkten gezeichnet + werden. + WICHTIG: Die absolute Groesse der Marker-Symbole haengt von der + 'Plot-Vorgeschichte' aller gezeichneten Objekte ab. Deshalb sollten + Marker als letzte Aktion gezeichnet werden (nach dem alle anderen + Funktionen gezeichnet wurden). + + Falls als Ausgabeformat 'SVG' oder 'SWF' gewhlt wurde, sollte + die Groesse und Dimension des Ausgabebildes mit folgenden Parametern + eingestellt werden: + + -paper user und/oder + -mode aniso oder -mode iso + + Siehe auch: '-nstep', '-bkcolor', '-drcolor', '-tmin', + '-xmin', '-xmax', '-ymin', '-ymax' + Hier sind ein paar Beispiele von KVEC Paremeterdateien die den + Gebrauch diese KVEC Funktionen zeigen: + + # KVEC Parameterdatei + # Bitte keine Kommentarzeileb zwischen "-func" und "endfunc" + # Das Beispiel zeigt wie zwei math. Funktionen mit zwei + # verschiedenen Farben geplottet werden + # Der Name der Input-Datei muss "vnull" lauten: + vnull + # Output Datei: Output-Format: SWF (Flash) + c:\test.swf + # Hier beginnt die Funktionsdefinition: + -func + c1=5.0; + drcolor 0 0 128; + f1(x)=zeta_cr(x); + drcolor 192 64 64; + f2(x)=c1+sin(x/M_PI)*exp(cos(sin(x))); + endfunc + # setzt die Hintergrundfarbe fuer die Funktionszeichnung + -bkcolor 220 220 255 + # Liniendicke: + -lwidth 10 + # Anzahl der Interpolationsschritte: + -nstep 4000 + # Bildgroesse (in mm) + -paper user 1000 100 + # setzt anisotropen Skalierungsmodus + -mode aniso + # x-Bereich zum Plotten + -xmin 1000 -xmax 1200 + -monitor + + ++++++++++++++++++++++++++++++++++++++++++++++++ + + # Dieses Beispiel zeigt die Verwendung des Summationssymboles + # f1(x) ist die Reihenentwicklung fuer 'cos(x)' + # wir benutzen unterschiedliche Farben + # Inputdatei muss 'vnull' lauten + vnull + test.swf + -func + c1=5.0; k=2; + drcolor 0 0 128; + f1(x)=1+SUM(n=1,25,(-1)^n*x^(2*n)/(2*n)!); + drcolor 128 0 64; + f2(x)=cos(x); + endfunc + -bkcolor 220 220 255 + -lwidth 1 + -nstep 1000 + -paper user 300 300 + -mode aniso + -xmin -20.5 -xmax 20.5 + -monitor + + Die geplotteten Koordinatenwerte koennen ebenfalls ausgegeben + werden (auf das angegebene Ausgabegert) durch die Angabe von: + + '-debug plot' + + +--------!-gapfill-G------------------------- +-gapfill N: Diese Parameter steuert, ob der Vektorisierer waehrend + der Vektorisierung eines Objekts ueber Luecken + 'hinwegspringen' kann. Der Wert N muss in Zehntel eines + Pixels angegeben werden. Erlaubte Werte: 0 bis 30. + +--------!-grit-G---------------------------- +-grit N: Mit diesem Parameter kann man angeben, ob kleine Details + bei der Vektorisierung erfasst werden sollen, oder nicht. + Polygone oder Polylines die eine Flaeche mit weniger als + N Pixels umfassen, werden 'weggefiltert'. Der Defaultwert + fuer 'grit' haengt von den Dimensionen und der Farbtiefe + des Bildes ab. Bei -grit 0 findet keine Filterung statt. + Die Benutzung eines Wertes N > 0 vergroessert die Rechen- + zeit und vergroessert auch erheblich den RAM Speicherbedarf. + Wenn Sie sparsam mit Speicher umgehen muessen sollten Sie + fuer -grit den Wert 0 und fuer -quantize einen kleineren + Wert waehlen. + +--------!-hatch-G--------------------------- +Die Schraffierungs-Parameter werden nur ausgewertet falls das Ausgabe-Format +DXF, PCS, DST oder HPGL ist. + +-hatch1 density N: Die max. Anzahl von horizontalen Schraffierungslinien wird + auf N begrenzt (der Wert 0 schaltet Schraffierung aus) +-hatch2 density N: Die max. Anzahl von vertikalen Schraffierungslinien wird + auf N begrenzt (der Wert 0 schaltet Schraffierung aus) +-hatch1 angle N: Winkel fuer horizontale Schraffierungs-Linien + (Default: 40 Grad) +-hatch2 angle N: Winkel fuer vertikale Schraffierungs-Linien + (Default: 40 Grad) + +--------!-html-G---------------------------- +Die html Parameter kontrollieren den Aufbau zustzliche erzeugter html Dateien, +die Links auf die erzeugten output-Dateien enthalten. (Siehe auch: '-format html') + +-html source none: Keine Generierung von hochauflsenden Bildern (Auflsung der + Quell-Dateien) findet statt. Individuelle Html Dateien erhalten + keine Links zu hoch-auflsenden (Original-Bildern). +-html source original: Kopien der Original Bild-Dateien (Umbenennung nach source_xxx..) + werden im Ziel-Verzeichnis erzeugt. Individuelle HTML-Dateien + erhalten Download-Links auf diese Dateien. +-html source format: Konvertierung und Erzeugung von hoch-auflsenden Dateien + bei Anwendung aller Parameter und des Ausgabe-Formates. Die + Dateien werden im Ziel-Verzeichnis erzeugt. Die Html Dateien + erhalten Download-Links auf diese Dateien. +-html source default: (Wie 'format'). Jedoch: Kopien (an Stelle von Konversionen) + werden erzeugt, falls die Quell- und Ziel-Formate identisch sind. + Falls die Bilddimensionen der Quell-Dateien kleiner als + dimx <=800 und dimy <= 600 sind werden keine hochauflsenden + Bilddateien erzeugt und auch keine entsprechenden Download Links. + (jedoch Einbettung der 'Screen-resolution" Dateien). + +-html screen none: keine Generierung von Bildern mit 'Bildschirm-Auflsung' + findet statt. Individuelle Html Dateien erhalten auch + keine Einbettungen der Bilder mit Bildschrim-Auflsung. +-html screen original: Kopien der Original Bild-Dateien (Umbenannt nach 'screen_xxx..") + werden im Ziel-Verzeichnis erzeugt. Individuelle HTML-Dateien + erhalten Einbettungen dieser Dateien. +-html screen format: Konvertierung und Erzeugung von 'Bildschirm-auflsenden' Dateien + bei Anwendung aller Parameter und des Ausgabe-Formates. Die + Dateien werden im Ziel-Verzeichnis erzeugt. Die Html Dateien + erhalten Einbettungen dieser Dateien. +-html screen default: (wie 'format'). Jedoch: Nur der Format-parameter + wird beruecksichtigt und 'Resampling' auf 800*600 pixel (isotrop). + + +-html preview none: Keine Konvertierung zu 'preview-resolution' Bildern. + 'directory.htm' wird nicht erzeugt. +-html preview original: Kopien der Original Bild-Dateien (umbenannt auf 'previe_xxx..") + werden im Ziel-Verzeichnis erzeugt. Die Bilder werden in die + Datei 'directory.htm' eingebettet. +-html preview format: Konvertierung und Erzeugung von 'preview resolution' Dateien + bei Anwendung aller Parameter und des Ausgabe-Formates. Die + Dateien werden im Ziel-Verzeichnis erzeugt. Die Datei 'diectory.htm' + erhaelt eine Einbettung dieser Dateien. +-html preview default: (wie 'format'). Jedoch: Das Ausgabe-Format ist 'JPEG' + und 'Resampling' auf 60*60 pixel (isotrop). + +--------!-jpg-G----------------------------- +-jpg quality : Gibt die Qualitt des JPEG Bildes an (output) + Erlaubte Werte: 1-100 (Default: 75) +-jpg grayscale on: Generiert JPEG Bilder mit Grauskala +-jpg grayscale off: Farbige JPEG Bilder (Default) + + +--------!-justify-G------------------------- +Die 'justify'-Parameter werden nur ausgewertet, falls das Input- und das +Output-Format beide vom Typ 'Raster' sind (keine Vektor-Formate). Die Farb- +tiefe der Input Datei muss 1 Bit betragen (S/W Bild). Die Hauptanwendung +fuer diese Option wird das Justieren (Zurechtruecken) und Saeubern von +'gescannten' S/W Bildern sein, um sie fuer die Einbettung in Dokumente +vorzubereiten. Die Defaultwerte fuer die 'justify' Parameter sind optimiert +fuer 300 dpi DIN A4 Bilder, die Text enthalten. +Kopien haben oft schmutzige schwarze Raender oder sind leicht verdreht, da +die Vorlage beim Kopieren etwas verrutscht wurde. KVEC kann diese Effekte +automatisch wieder korrigieren, wenn ein geeigneter Satz von Justierungs- +Parametern verwendet wird. + +-justify type off: Keine Bereinigung oder Justierung (Default). +-justify type rotate: Justierung wird durchgefuehrt (Nur Drehung) +-justify type all: Justierung wird durchgefuehrt (Drehung und Saeuberung + der 'schmutzigen' Raender durch Abschneiden). +-justify type angle: Keine Justierung wird durchgefuehrt (nur Bestimmung + des Drehwinkels) +-justify phimax N: Maximal erlaubter Drehwinkel. Dies ist der max. Ver- + drehungswinkel, der korrigiert werden kann. Achtung: + Die Rechenzeit waechst linear mit der Groesse dieses + Winkels. Default: 5.0 Grad. +-justify parameter N1 N2 N3: + Diese Werte steuern die Wirkung der internen Algorithmen. + (Detektierung von grossen rechteckigen Bloecken, von denen + widerum der Rotationswinkel abgeleitet wird). + N1: 'Verdickungs'-Faktor. Jedes Pixel wird um diesen Faktor + vergroessert, um enthaltene Block-Strukturen leichter + detektierbar zu machen. Default: 16 + N2: min. Filterwert. Zusammenhaengende Gebiete mit einer + Anzahl von Pixeln kleiner als N2 werden entfernt bevor + der interne 'Block-Detektierungsalgorithmus' startet. + Default: 50 + N3 max. Filterwert. Zusammenhaengende Gebiete mit einer + Anzahl von Pixeln groesser als N3 werden entfernt bevor + der interne 'Block-Detektierungsalgorithmus' startet. + Default: 400 + Bemerkung: Die Defaultwerte wurden fuer DIN A4 Bilder + (300 dpi), die einen Durchschnittstext enthalten, opti- + miert. Die durchschn. Anzahl von Pixeln liegt im Bereich + von 50 bis zu 400 Pixel pro Buchstaben). + Dies stellt sicher, dass nur die Teile des Bildes, die + Text-Information enthalten, fuer die Bestimmung des + Drehwinkels relevant sind. + + Fuer andere Arten von S/W Bildern (z.B. elektronische + Schaltplaene) koennen andere Parameterwerte evtl. zu + besseren Ergebnissen fuehren. +-justify fill ...: Durch Rotation erzeugte Raender u. Ecken werden gefuellt: +-justify fill black: schwarzer Farbe (bzw. der aehnlichsten schw. Farbe) +-justify fill white: weisser Farbe (bzw. der aehnlichsten weiss. Farbe), DEFAULT +-justify fill user : benutzer-spezifischen Farbe +-justify preserve off: Ausgabebild kann andere Dimensionen haben als Inputbild +-justify preserve on: Ausgabebild hat die gleichen Dimensionen wie Inputbild + +--------!-kvc-G----------------------------- +-kvc compress none: Schaltet jegliche Kompression fuer das KVC Format aus +-kvc compress lzw: Waehlt die LZW Kompressionstechnik fuer das KVC Format + (lzw ist die Default Kompression) +-kvc bufsize : Waehlt die Groesse der internen Pakete zur Kompression +-kvc byteorder i: Waehlt INTEL byteorder fuer die binaeren Daten (Default) +-kvc byteorder m: Waehlt MOTOROLA byteorder fuer die ninaeren Daten + +--------!-language-G------------------------ + (GUI-Parameter) Waehlt die Benutzersprache in der KVEC-GUI. + Hinweis: Wird von der KVEC Kommandozeilenversion ignoriert. +-language default: Benutzt die kompilierte Einstellung. +-language english: Englisch +-language german: Deutsch +-language czech: Tschechisch + +--------!-lwidth-G-------------------------- +-lwidth: Gibt die Dicke der Linien der erzeugten Ausgabevektoren an + (in Zehntel eines Pixels). + Erlaubte Werte: 0-1000. Defaultwert: 0. + Bitte beachten Sie die veraenderte Bedeutung dieses + Parameters, falls er zusammen mit der Option + -centerline gebraucht wird. In diesem Fall ist der + Defaultwert 100. + +--------!-maxpoints-G----------------------- +-maxpoints: Gibt die max. erlaubte Anzahl von Punkten fuer die + erzeugten Polylines und Polygone an. Das ist nuetzlich + wenn KVEC Vektoren mit einer Laenge von mehr als 32767 + Punkten erzeugt und als Ausgabe-Format WMF gewaehlt wurde. + +--------!-mode-G---------------------------- +-mode iso: Isotroper Modus. Dieser Modus bewahrt das Y/X-Verhaeltnis + des Bildes. (Ein Kreis wird auch im Ausgabebild ein Kreis + bleiben). Das ist die Default-Einstellung. + (Nur fuer Postscript-, AI-, SWF- und SVG-Format, sowie + bei Vektor-Raster Konvertierung). + +-mode aniso: Anisotroper Modus. Das Bild wird so skaliert, dass es die + Papierflaeche (bzw. den "Viewport") vollstaendig ausfuellt. + (Nur fuer Postscript- AI-, SWF- und SVG-Format, sowie + bei Vektor-Raster Konvertierung). + +--------!-monitor-G------------------------- +-monitor: Schaltet Fortschritts-Anzeige ein. Informationen ueber den + aktuellen Programm-Status und ueber den Programm- + Fortschritt (in %) werden angezeigt. + +--------!-nstep-G--------------------------- +-nstep : Setzt Anzahl der Schritte (Interpolationspunkte) zum + Zeichnen von benutzer-definierten Funktionen + (siehe switch '-function') + +--------!-overlapp-G------------------------ +-overlapp: Bei der Angabe dieses Parameters ueberlappen sich die + erzeugten Vektoren geringfuegig (um genau ein Pixel). + Der Defaultwert ist 'keine Ueberlappung'. + Falls Vektorgraphiken, nachdem sie gedreht worden sind, + schwarze oder andersfarbige Luecken aufweisen sollten, + (besonders entlang den Grenzlinien benachbarter Polygone) + dann sollten Sie diesen Parameter angeben. + +--------!-palette-G------------------------ +-palette optimize: KVEC benutzt intern eine optimierte Palette wenn eine + Farbreduzierung vorgenommen werden muss (Default) +-palette fixed: KVEC benutzt intern eine Standard Palette wenn eine + Farbreduzierung vorgenommen werden muss/soll. Diese + Einstellung liefert oftmals bessere Vektorisierungs- + Ergebnisse, besonders wenn die Farbanzahl kleiner als + 16 Farben ist. +-palette user R1,G1,B1, .... Rn,Gn,Bn: + Hier kann man eine benutzer-definierte Farb Palette an- + geben, die Farben enthaelt. Nach dem Wert folgen + die RGB Farbeintraege. Es ist einfacher, in diesem + Fall mit einer Parameter-Datei zu arbeiten, als alle RGB- + Werte in der Kommandozeile anzugeben. + Der Wert fuer n darf nicht groesser al 256 sein. +--------!-paper-G--------------------------- +-paper (format): Auswahl einer Papier-Groesse. Z. Zt. ist diese Option nur + fuer folgende Formate gltig: + Postscript, Adobe Illustrator, SWF und SVG-Format. + Die Format-Bezeichnung muss eine der folgenden sein: + + 'user' Breite Hoehe (Hoehe und Breite in mm angeben) + (Die Groesse von SVG bzw. SWF-Graphiken kann so angegeben + werden) + 'LETTER' (Letter 8 1/2 x 11 in) + 'TABLOID' (Tabloid 11 x 17 in) + 'LEDGER' (Ledger 17 x 11 in) + 'LEGAL' (Legal 8 1/2 x 14 in) + 'STATEMENT' (Statement 5 1/2 x 8 1/2 in) + 'EXECUTIVE' (Executive 7 1/4 x 10 1/2 in) + 'A3' (A3 297 x 420 mm) + 'A4' (A4 210 x 297 mm) + 'A5' (A5 148 x 210 mm) + 'B4' (B4 (JIS) 250 x 354) + 'B5' (B5 (JIS) 182 x 257 mm) + 'FOLIO' (Folio 8 1/2 x 13 in) + 'QUARTO' (Quarto 215 x 275 mm) + '10X14' (10x14 in) + 'NOTE' (Note 8 1/2 x 11 in) + 'ENV_9' (Envelope #9 3 7/8 x 8 7/8) + 'ENV_10' (Envelope #10 4 1/8 x 9 1/2) + 'ENV_11' (Envelope #11 4 1/2 x 10 3/8) + 'ENV_12' (Envelope #12 4 \276 x 11) + 'ENV_14' (Envelope #14 5 x 11 1/2) + 'ENV_DL' (Envelope DL 110 x 220 mm) + 'ENV_C5' (Envelope C5 162 x 229 mm) + 'ENV_C3' (Envelope C3 324 x 458 mm) + 'ENV_C4' (Envelope C4 229 x 324 mm) + 'ENV_C6' (Envelope C6 114 x 162 mm) + 'ENV_B4' (Envelope B4 250 x 353 mm) + 'ENV_B5' (Envelope B5 176 x 250 mm) + 'ENV_B6' (Envelope B6 176 x 125 mm) + 'ENV_ITALY' (Envelope 110 x 230 mm) + 'ENV_MONARCH' (Envelope Monarch 3.875 x 7.5 in) + 'ENV_PERSONAL' (6 3/4 Envelope 3 5/8 x 6 1/2 in) + 'FANFOLD_US' (US Std Fanfold 14 7/8 x 11 in) + 'FANFOLD_STD_GERMAN' (German Std Fanfold 8 1/2 x 12 in) + 'FANFOLD_LGL_GERMAN' (German Legal Fanfold 8 1/2 x 13 in) + 'ISO_B4' (B4 (ISO) 250 x 353 mm) + 'JAPANESE_POSTCARD' (Japanese Postcard 100 x 148 mm) + '9X11' (9 x 11 in) + '10X11' (10 x 11 in) + '15X11' (15 x 11 in) + 'ENV_INVITE' (Envelope Invite 220 x 220 mm) + 'A_PLUS' (SuperA/SuperA/A4 227 x 356 mm) + 'B_PLUS' (SuperB/SuperB/A3 305 x 487 mm) + 'A2' (A2 420 x 594 mm) + 'A1' (A1 594 x 840 mm) + 'A0' (A0 840 * 1188 mm) + +--------!-pattern-G------------------------- +Dieser Parameter wirkt nur auf Vektor-Objekte und ist daher fuer eine reine +Raster-Raster Formatumwandlung wirkungslos. +Die letzten drei Parameter DR, DG und DB geben jeweils die max. Farbdifferenz +fuer Farbverlaeufe bzw. Zufalls-Farbmuster an. Erlaubte Werte: 0 bis 255. +-pattern nodither D1 D2 D3: Kein Farbverlauf (Default) +-pattern left2right D1 D2 D3: Farbverlauf von links nach rechts +-pattern right2left D1 D2 D3: Farbverlauf von rechts nach links +-pattern top2bottom D1 D2 D3: Farbverlauf von oben nach unten +-pattern bottom2top D1 D2 D3: Farbverlauf von unten nach oben +-pattern inout D1 D2 D3: Farbverlauf von innen nach aussen +-pattern outin D1 D2 D3: Farbverlauf von aussen nach innen +-pattern randrgb D1 D2 D3: Zufallsfarbmuster (Dithering) + +Wichtig: Bitte beachten Sie, dass das angegebene Vektor Ausgabeformat Farb- +verlaeufe unterstuetzt. Z. Zt. gilt dies nur fuer das ART und KVC Format. +Farbverlaeufe werden jedoch immer durchgefuehrt falls das Ausgabeformat ein +Raster-Format ist (und das Eingabeformat vom Typ Vektor). + +--------!-png-G----------------------------- + +Die PNG-Parameter werden nur ausgewertet falls das Output-Format PNG ist: + +-png bitdepth : Bittiefe des PNG-Bildes. Erlaubt sind: 1,4,8,24 Bit. + Paletten-Bilder koennen bis 8 Bits, RGB nur 24 bit. + Default: 24 Bit +-png coltype gray: Erzeugt ein Graustufen-Bild +-png coltype pal: Erzeugt ein Paletten-Bild +-png coltype rgb: Erzeugt RGB Bild mit 24 Bit Aufloesung +-png coltype alpha2: Erzeugt Graustufen-Bild mit Alpha-Kanal +-png coltype alpha4: Erzeugt RGB-Bild mit Alpha-Kanal + Default: RGB (True Color) +-png tcolor : Waehlt eine Transparenzfarbe + Default: Keine Transparenzfarbe +-png interlace: Schltet Interlacing ein (noch nicht verfuegbar) + Default: Kein Interlacing +-png gamma : Waehlt einen Gamma-Wert Default: 0.45 + Bitte Ganzzahl eingeben. 100000 entspricht einem Wert von 1.0 +-png addpalette: Fuegt einem RGB-Bild eine Farbpalette hinzu (noch nicht verfuegbar) + Default: PNG RGB Dateien enthalten keine Farbpaletten +-png bkcolor : Waehlt eine Hintergrungfarbe fuer das PNG Bild + Default: Keine Hintergrundfarbe +-png ppx : Setzt den "pixels per unit"-Wert fuer X-Richtung +-png ppy : Setzt den "pixels per unit"-Wert fuer Y-Richtung +-png pixunit meter: Waehlt die Unit fuer die ppx und ppy Werte: 1 meter. +-png pixunit none: Waehlt fuer die Unit den Wert "unbekannt" (Default) + +KVEC bestimmt die Werte fuer 'bitdepth' und 'coltype' aus der Input-Datei und +benutzt Default-Werte fuer die PNG-Parameter, falls keine angegeben werden. +Im Fall einer Vektor-Raster Konvertierung mit PNG als Ausgabe-Format versucht +KVEC den groesst-moeglichen Wert fuer 'bitdepth' zu verwenden. Das ist normalerweise +24 Bit, es sei denn ein anderer Wert wurde angegeben. + + +--------!-primes-G-------------------------- +-primes : Initialisiert interne Primzahlen bis zum Wert N. + (Default, falls nicht angegeben : 1000000) + + +--------!-quantize-G------------------------ +-quantize N: Die Inputdatei wird vor Beginn der Vektorisierung auf + N Farben quantisiert (falls diese mehr als N Farben + enthalten sollte). Der Defaultwert ist 32 Farben. + Fuer DXF und HPGL Format gilt der Defaultwert 8 Farben. + +--------!-reduce-G-------------------------- +Die 'reduce'-Parameter geben an, ob alle die Punkte eines Vektors, die auf +einer Geraden liegen, durch zwei Punkte (den Start- und den Endpunkt des +Geradenabschnittes) ersetzt (= reduziert) werden. Das verringert die Groesse +der Ausgabedatei. Da Geraden horizontal, vertikal oder schraeg liegen koennen, +haben wir folgende Moeglichkeiten: + +-reduce orthogonal:gerade horizontale und vertikale Vektorabschnitte werden + reduziert. Das ist der Default-Wert. +-reduce all: Alle geraden Abschnitte (auch die schraeg liegenden) + werden reduziert. Bei dieser Parameterwahl koennen + gelegentlich kleine Luecken im Layout erscheinen. +-reduce off: Vektoren werden, auch wenn sie Geradenabschnitte enthalten, + nicht reduziert. Der einzige Fall, in dem man evtl. diese + Einstellung waehlen wird, ist, wenn man die Geschwindigkeit + eines Plotterstiftes entlang langer Geradenabschnitte herab- + setzen moechte. + +--------!-resolution-G---------------------- +Die 'resolution'-Parameter haben Einfluss auf die interne Auswertung: + +-resolution low: Sehr kleine Details koennen verloren gehen (Default) +-resolution high: Alle Details koennen erfasst werden (braucht mehr Speicher) + +--------!-rotate-G-------------------------- +-rotate N: Setzt den Rotationswinkel (Wert N in Grad) + Die Rotation findet nur statt, wenn sich in der Befehlsliste + (definiert duch '-process...') ein 'rotate' Befehl befindet. + Der Default Rotationswinkel betraegt 40 Grad. + Hinweis: Die Rotation betrifft nur ein Input Rasterbild und + findet vor einer eventuellen Vektorisierung statt. + +--------!-scale-G--------------------------- +Die Skalierungs-Parameter werden nur ausgewertet falls das Ausgabe-Format +DXF oder HPGL ist. + +-scale hpgl N: Das ausgegebene HPGL-Bild wird um einen Faktor N skaliert. +-scale dxf N: Das ausgegebene DXF-Bild wird um einen Faktor N skaliert. + Siehe auch -xyscale hpgl / -xyscale dxf + WICHTIG: scale dxf skaliert ebenfalls SWF Output! +--------!-sort-G---------------------------- +Die Sortier-Parameter geben an, in welcher Reihenfolge die Vektoren in der +Output-Datei erscheinen: + +-sort nosort: Vektoren werden nicht sortiert. Konturen oder Linien + mit unterschiedlichen Farben koennen sich ueberdecken, + die inneren Gebiete der Vektoren jedoch nicht. + +-sort max: Dieser Parameter haengt von der Einstellung des Parameters + 'fill' ab: Beim Fuelltyp 'solid' werden die Polygone + nach der Groesse der umschlossenen Flaeche sortiert. Beim + Typ 'line' oder 'contour' wird nach der Laenge der Vektoren + sortiert. Die Sortierreihenfolge ist vom Maximum zum + Minimum. Das ist die Default-Einstellung. + +-sort min: Wie bei '-sort min', jedoch ist die Sortierreihenfolge + vom Minimum zum Maximum. Diese Einstellung ergibt nur einen + Sinn, wenn der Fuelltyp nicht auf 'solid' eingestellt ist. + +-sort local: Die erzeugte Sortierreihenfolge erhaelt nimmt Ruecksicht + auf die lokalen topologischen Gegebenheiten. + D.h. Objekte werden in der Reihenfolge gezeichnet, wie sie + in einander verschachtelt sind. Die Sortierreihenfolge + innerhalb einer Gruppe von in sich verschachtelten Objekten + ist vom Maximum zum Minimum. + Benoetigt mehr Rechenzeit. + Wenn die Sortierreihenfolge auf "local" steht, versucht + KVEC Subpolygone mit Transparenzfarbe zu erzeugen. Das + ist ntzlich beim Vektorisieren von Text. Die "-font" + Option schaltet automatisch diese Sortierreihenfolge ein. + +-sort color: Polygone/Polylines werden nach ihrer Farbe sortiert. + Diese Einstellung ist nuetzlich fuer das HPGL-Format. + +--------!-subsampling-G--------------------- +-subsampling: Die erzeugten Ouput-Vektoren werden mit einem Faktor 2 + 'unter-abgetastet'. Dadurch wird die Groesse der Output- + Datei reduziert. Dies fuehrt ausserdem zu einer Glaettung + der Vektoren. + +--------!-swf-G----------------------------- +-swf format mx: Erzeugt Flash format MX (Default, komprimierte Ausgabe) +-swf format 6: Flash format MX (komprimierte Ausgabe) +-swf format 5: Flash format 5.x (unkomprimiert, kompatibel zu 5.0) +-swf compression zlib: Benutzt zlib Kompression (Default, fuer Format MX) +-swf compression none: Keine Kompression + +--------!-sysmalloc-G----------------------- +-sysmalloc on: (Default) KVEC benutzt die Speicher-Allokierungsroutinen + des Betriebssystems. + +-sysmalloc off: KVEC verwendet eigene Routinen zur Verwaltung des + Speichers. Falls die Performance von KVEC bei bestimmten + Bilderen abnimmt, sollte dieser Switch ausprobiert werden. + +--------!-tcolor-G-------------------------- +Die Transparenz Parameter werden nur ausgewertet, falls das Ausgabe-Format +gefuellte Flaechen behandeln kann. +Die Transparenz-Farbe wird im ausgegebenen Vektor-Bild unterdrueckt. +Einige Formate unterstuetzen keine Sub-Polygone. Fuer diese Formate kann +die Transparenz Option in einigen Faellen nicht richtig arbeiten. +Default: Transparenz-Option ist ausgeschaltet. + +-tcolor auto: Automatische Bestimmung der Transparenz Farbe +-tcolor color R G B: Benutzer-definierte Transparenz-Farbe (RGB Werte) + + +--------!-text-G---------------------------- +-text on/off: Erzeugung / Unterdrueckung von Text-Objekten in der Ausgabe- + Datei. Das betrifft nur die Formate, die Textobjekte + unterstuetzen: Default: -text on + + +--------!-tiff-G---------------------------- +Die Tiff-Parameter werden nur ausgewertet falls als Ausgabe-Format das +Tiff Format gewaehlt wurde. Sie steuern die Erzeugung des Tiff-Files. + +-tiff append: Bild wird als subimage angehngt (Default: ueberschreiben) +-tiff FillOrder msb2lsb: (Fuer S/W Bilder) Default +-tiff FillOrder lsb2msb: (Fuer S/W Bilder) +-tiff byteorder I: byte-order im Tiff-File wird 'INTEL' (DEFAULT) +-tiff byteorder M: byte-order im Tiff-File wird 'MOTOROLA' +-tiff compress none: Es wird keine Kompression durchgefuehrt (DEFAULT) +-tiff compress huffman: 'Huffman-Komprimierung' (Schwarz-Weiss Bilder) +-tiff compress fax3: Fax Gruppe 3 Komprimierung (Schwarz-Weiss Bilder) +-tiff compress fax4: Fax Gruppe 4 Komprimierung (Schwarz-Weiss Bilder) +-tiff compress lzw: LZW Komprimierung (vor allem fuer RGB-Bilder) +-tiff compress packbits: 'packbits-Komprimierung' +-tiff Group3Opt fill: Fuellbits vor EOL (Fax Format) +-tiff xres : X-Auflsung in pixels per inch (Default: 300) +-tiff yres : Y-Auflsung in pixels per inch (Default: 300) +-tiff SubFileType normal: (Default) +-tiff SubFileType mask: Transparent Maske +-tiff SubfileType page: multi page File (fax) +-tiff predictor: Das Tiff-Predictor Feld wird auf 2 gesetzt (fuer LZW + Komprimierung) DEFAULT: Kein Predictor +-tiff photo white: Photometrische Interpretation: 'MINISWHITE' + Das Tiff-File wird vom Typ 'S/W' oder 'Grauskala' + (Tiff Klasse 'B' oder 'G') +-tiff photo black: Photometrische Interpretation: 'MINISBLACK' + Das Tiff-File wird vom Typ 'S/W' oder 'Grauskala' + (Tiff Klasse 'B' oder 'G') +-tiff photo rgb: Das Tiff-File bekommt 3 Farb-Komponenten (RGB) + (Tiff Klasse 'R') (DEFAULT) +-tiff photo separated: Das Tiff-File bekommt 4 Farb-Komponenten (CMYK) + +-tiff photo pal: Das Tiff-File bekommt eine Farb-Palette. + (Tiff Klasse 'P') +-tiff photo ycbcr: Das Tiff-File bekommt Luminanz und Chrominanz Komponenten + (Tiff Klasse 'Y') +-tiff stripsize N: Der 'Stripsize-Wert' des Tiff-Files hat eine Groesse von + N Bytes (DEFAULT: 32000). + +--------!-trim-G---------------------------- +-trim: Bild optimieren. (Nur WMF Ausgabe Format) + +--------!-vblack-G-------------------------- +-vblack: Es wird nur die Farbe mit den 'schwaerzesten' RGB-Werten + vektorisiert (holt die 'schwarzen Linien' aus dem Bild). + Alle Objekte mit einer anderen Farbe werden als 'helle' + Objekte behandelt. Alle Regionen die aus dieser 'hellen' + Farbe bestehen, werden ebenfalls vektorisiert. + Helle Gebiete, die innerhalb von schwarzen Gebieten + liegen werden richtig dargestellt. Man beachte, dass ein + kleinerer 'quantize' Wert mehr dunkle Linien erfasst. + Wenn der 'quantize' Wert zu groos ist, werden evtl. + nicht alle dunklen Linien erfasst. + +--------!-voblack-G------------------------ +-voblack dark: Wie bei vblack, jedoch werden nur 'dunkle' Objekte vek- + torisiert. Helle Gebiete, die innerhalb von 'schwarzen' + Gebieten liegen werden evtl. nicht dargestellt, falls das + 'schwarze' Gebiet vom Typ eines gefuellten Polygons ist. +-voblack nwhite: Wie bei vblack, jedoch werden keine 'hellen' Objekte vek- + torisiert. Helle Gebiete, die innerhalb von anderen + Gebieten liegen werden evtl. nicht dargestellt, falls das + Gebiet vom Typ eines gefuellten Polygons ist. + +--------!-viewtype-G------------------------ + (GUI-Parameter) Waehlt den 'Viewer' fuer die KVEC-GUI. + Hinweis: Wird von der Kommandozeilenversion ignoriert. +-viewtype SWF: (default) Macromedia Shockwave (Flash) +-viewtype SVG: Adobe SVG Format (Scalable vector graphics) + +--------!-winding-G------------------------- +-winding original: (Default) Der Umlaufsinn von Polygonen bleibt unver- + aendert (wie von der Quelle oder dem Vektorisierer) + uebernommen wurde. +-winding reversed: Umgekehrter Umlaufsinn. Diese Einstellung ist fuer + einige Typen von Input Dateien ntig. +-winding optimized: KVEC setzt einen alternierendenden Umlaufsinn fuer + fuer Haupt- und Subpolygone, in Abhaengigkeit von der + Verschachtelungstiefe. + Diese Einstellungen sind nur fuer das SWF Output- + Format relevant (und speziell nur dann, wenn die SWF- + Daten im Macromedia Flash Editor weiter bearbeitet + werden sollen). Die gngigen Flash Player kommen mit + allen Kombinationen von Umlaufsinn in Polygonen + zurecht. +--------!-xmin-G--------------------------- +-xmin : Setzt X-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-xmax-G--------------------------- +-xmax : Setzt X-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-ymin-G--------------------------- +-ymin : Setzt Y-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-ymax-G--------------------------- +-ymax : Setzt Y-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-zmin-G--------------------------- +-zmin : Setzt Z-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-zmax-G--------------------------- +-zmax : Setzt z-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-tmin-G--------------------------- +-tmin : Setzt t-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-tmax-G--------------------------- +-tmax : Setzt t-Bereich fuer benutzerdefinierte Funktion + (in beliebigen Einheiten) + (siehe switch '-function') + +--------!-phimin-G-------------------------- +-phimin : Setzt Phi-Bereich fuer benutzerdefinierte Funktion + (Fuer Darstellung in Polarkoordinaten) + (siehe switch '-function') + +--------!-phimin-G-------------------------- +-phimax : Setzt Phi-Bereich fuer benutzerdefinierte Funktion + (Fuer Darstellung in Ploarkoordinaten) + (siehe switch '-function') + +--------!-zlib-G--------------------------- +-zlib bufsize : Buffergroesse fuer die zlib input/output Buffer. Default: 32768 +-zlib clevel : Komprimierungslevel fuer zlib Routinen (Default: 6) + Erlaubte Werte: 1 bis to 9 + (Die zlib Kompressionsmethode wird fuer SVG und SWF Formate verwendet) + + +Auf die folgenden Parameter haben nur registrierte Benutzer Zugriff: + +Die Debug-Parameter geben den Grad (d.h. die Ausfuehrlichkeit) des +Debug-Outputs an. Debug-Output bedeutet, dass ein Protokoll ueber den Fort- +schritt der Vektorisierung auf dem Bildschirm ausgegeben wird. +(Grosses N bedeutet ausfuehrliches Protokoll, kleines N ein sparsames Protokoll. + +--------!-debug-G--------------------------- +-debug N: Erzeugt Protokoll-Ausgabe level N (1-8) + (Default: Debug ausgeschaltet) +-debug all: Erzeugt sehr ausfuehrliches Protokoll + +--------!-delta-G--------------------------- +-delta N: Das ist die maximal erlaubte Farbabweichung zwischen der + ersten Ebene (dem 'rohen' Bild und der zweiten Ebene (dem + 'Detail'-Bild). Die 'Detail-Ebene enthaelt eine Vektor- + darstellung nur jener Gebiete, die eine Farbabweichung + von mehr als N Einheiten zur 1.ten Ebene aufweisen. + Achtung: 'delta' hat zwei verschiedene Bedeutungen: + In Verbindung mit der 'progressive' - Option bedeutet + der Wert die max. Farbabweichung zwischen 2 Ebenen. In + Verbindung mit der 'vcolor' - Option bedeutet der Wert + eine max. zulaessige Farb-Toleranz. + Werte: 0 bis 128. Default: 0 + +--------!-errbez-G-------------------------- +-errbez N: Gibt den Wert N fuer den Bezier Error-Parameter an. + Erlaubte Werte sind: 1 - 20. Groessere Werte fuer errbez + fuehren zu groesseren Differenzen zwischen dem Original- + und dem Vektor-Bild, reduzieren jedoch die Groesse der + Ausgabe-Datei. Der Default-Wert betraegt 3. + +--------!-group-G--------------------------- +-group: Erzeugt rekursiv verschachtelte Gruppen von Objekten. + Dieser Parameter gilt nur fuer Das LogoArt-Format. + +--------!-lossless-G------------------------ +-lossless: Die Vektorisierung soll ohne Informationsverlust erfolgen. + Die Angabe dieser Option kann enorme Speicheranforderungen + zur Folge haben. + Diese Option ist identisch mit der Einstellung: + -resolution high -grit 0 -reduce orth. -quantize (Unendlich) + +--------!-process-G------------------------- +-process : KVEC hat einige Bildverarbeitungs Features eingebaut, die + kaum in anderen Bildverarbeitungs-Programmen gefunden + werden. Sie koennen eine Liste von Befehlen nach dem + 'process' keyword angeben. Diese Befehle muessen entweder + als Zeichenketten oder als Funktionsnummern angegeben + werden und muessen voneinander durch eines der folgenden + Zeichen getrennt werdens: ',',':','.','-'. + Die Zeichenketten koennen abgekuerzt werden. + Die Befehle werden ausgefuehrt, sobald das Bild eingelesen + (oder automatisch durch den 'random' Switch erzeugt) + wurde. Hier einige Beispiele: + +(Bsp. 1: Gauss Hochpass-Filter) +KVEC x.bmp y.tif -for tif -proc fft_bm,gausshighpass,ifft_bm +KVEC x.bmp y.tif -for tif -proc 14,39,15 + +(Bsp. 2: Spektrum) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,log_bm,norm_byt,center_or +KVEC x.bmp y.tif -for tif -proc 11,14,12,8,33 + +(Bsp. 3: Spektrale Leistungsdichte) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,abs_bm,log_bm,norm_rby,center_or +KVEC x.bmp y.tif -for tif -proc 11,14,7,12,9,33 + +(Bsp. 4: Autokorrelationsfunktion) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,abs_bm,ifft_bm,log_bm,norm_byt,center_or +KVEC x.bmp y.tif -for tif -proc 11,14,7,15,12,8,33 + +(Bsp. 5: 1.te Ableitung) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,derive1,ifft_bm,abs_bm,norm_byt +KVEC x.bmp y.tif -for tif -proc 11,14,34,15,7,8 + +(Bsp. 6: 1.tes Integral) +KVEC x.bmp y.tif -for tif -proc norm_flo,fft_bm,integral1,ifft_bm,abs_bm,norm_byt +KVEC x.bmp y.tif -for tif -proc 11,14,35,15,7,8 + +(Bsp. 7: Versuch einer Rekonstruktion des Originalbildes aus einer Bitmap, die +ein logarithm. Spektrum enthaelt) +KVEC x.bmp y.tif -for tif -proc center_or,norm_flo,exp_bm,ifft_bm,abs_bm,log_bm,norm_byt +KVEC x.bmp y.tif -for tif -proc 33,11,13,15,7,12,8 + +(Bsp. 8: Zufalls-Testbild (24 Bit Farbe) mit 1/(F*F) Spektrum) +KVEC null y.tif -for tif -proc norm_flo,fft_bm,spect_2_f,ifft_bm,norm_byt -random 24 2 +KVEC null y.tif -for tif -proc 11,14,23,15,8 -random 24 2 + + + + Die (erste) Anweisung 'byte2complex' und die (letzte) An- + weisung 'complex2byte' brauchen nicht angegeben zu werden, + da sie von KVEC automatisch ausgefuehrt werden. + Bsp. 2: + Dies weist KVEC an, eine Fourier-Transformation des Bildes + auszufuehren, die Logarithmus Funktion anzuwenden, die + Werte auf den Bereich [0..255] zu normieren und den Bild- + Ursprung in die Mitte des Bildes zu legen (was fuer + Frequenz-Darstellungen sehr viel besser geeignet ist). + Danach faehrt KVEC mit der Auswertung der anderen Parameter + fort. + + BITTE BEACHTEN SIE, DASS DIE BITMAP IN EINE KOMPLEXE + BITMAP UMGEWANDELT WERDEN MUSS. DAS KANN ZU RIESIGEN + SPEICHERANFORDERUNGEN FUEHREN! + + Hier ein Beispiel: Eine 500 * 500 Bitmap mit einer + Farbtiefe von 4 Bit (Paletten Bitmap) belegt einen Speicher + von 500*500*1/2 *sizeof(BYTE) = 125 KByte. Die konvertierte + komplexe Bitmap belegt + 500*500*(3 Farbebenen)*sizeof(COMPLEX) = 6 MByte! + + Hier ist die Befehlsliste und die entsprechenden Funktions + Nummern (manche Funktionen koennen evtl. noch nicht + implementiert sein). + Bitte geben Sie die Zeichenketten in Kleinbuchstaben ein. + Befehl: Funktionsnummer: + ========================================================= + NOOP 0 Keine Operation + BYTE2COMPLEX 1 Erzeugt komplexes Bild einer Bitmap + COMPLEX2BYTE 2 Erzeugt Bitmap aus komplexem Bild + BYTE2REAL 3 Fuellt Real-Anteil eines komplexen Bildes + REAL2BYTE 4 Erzeugt Bitmap aus dem Real-Anteil + BYTE2IMAGINARY 5 Fuellt Imaginaer-Anteil + IMAGINARY2BYTE 6 Erzeugt Bitmap aus dem Real-Anteil + ABS_BM_COMPLEX 7 Bildet die Absolut-Betraege Abs(z) + NORM_BYTE 8 Normiert alle Werte auf [0...255] + NORM_RBYTE 9 Normierte reelle Werte auf [0...255] + NORM_IBYTE 10 Normiert imaginaere Werte auf [0...255] + NORM_FLOAT 11 Normiert alle Werte auf [-1.0,1.0] + LOG_BM_COMPLEX 12 Wendet die Logarithmus Funktion an + EXP_BM_COMPLEX 13 Wendet die Exponential Funktion an + FFT_BM_COMPLEX 14 Fuehrt eine Fourier Transformation aus + IFFT_BM_COMPLEX 15 Fuehrt inverse Fourier Transform aus. + SUPPRESS_DC 16 Unterdrueckt den DC Anteil im Spektrum + SET_ZERO 17 Setzt alle Werte auf 0 + SET_IM_ZERO 18 Setzt alle reellen Werte auf 0 + SET_RE_ZERO 19 Setzt alle imaginaeren Werte auf 0 + MAKE_RAND_PHASE 20 Erzeugt eine Fufalls-Phase f. alle Werte + SPECT_LIN 21 gibt dem Spektrum eine lineare Form + SPECT_1_F 22 Formt das Spektrum nach 1/f + SPECT_2_F 23 Formt das Spektrum nach 1/f*f + SPECT_RE_EVEN 24 Erzwingt gerade Symmetrie f. rell. Spek. + SPECT_RE_ODD 25 Erzwingt gerade Symmetrie f. imag. Spek. + SPECT_IM_EVEN 26 Erzwingt unger. Symmetrie f. rell. Spek. + SPECT_IM_ODD 27 Erzwingt unger. Symmetrie f. imag. Spek. + CAR2POL 28 Konvertiert in Polarkorrdinaten + POL2CAR 29 Konvertiert in kartesische Koordinaten + LOWPASS 30 Low Pass Filter + HIGHPASS 31 High Pass Filter + ROTATE 32 Rotation + CENTER_ORIGIN 33 Legt den Bildursprung in die Bildmitte + DERIVE1 34 Berchnet die erste Ableitung + INTEGRAL1 35 Berechnet das erste Integral + DERIVE2 36 Berchnet die zweite Ableitung + INTEGRAL2 37 Berechnet das zweite Integral + GAUSSLOWPASS 38 Tiefpass Filter (Gauss) + GAUSSHIGHPASS 39 Hoch Pass Filter (Gauss) + GRAY2COLOR 40 Umwandlung von Grau in Farbwerte + MAKE16MCOLOR 41 Konvertierung in ein Bild, das 16M Farben enthlt + (Achtung: bentigt 150 - 200 MB RAM und luft 12 - 100 Stunden!!) + + + +GRAY2COLOR: Die Farbtiefe des erzeugten Farbbildes (Default: 8 Bit) kann mit + Hilfe der Option '-random eingestellt werden. + In diesem Fall wird der Wert ignoriert. + +--------!-progressive-G--------------------- +KVEC bietet die Moeglichkeit, einen progressiven Bildaufbau zu erzeugen. +Der Ausdruck 'progressiv' bedeutet, dass das Bild aus zwei aufeinander +folgenden Ebenen (einem 'groben' Bild ohne Details und einem 'feinem' Bild, +das nur Datails enthaelt) aufgebaut wird. Die beiden Ebenen folgen in dieser +Reihenfolge beim Zeichnen. Diese Art des Bildaufbaues ist sehr robust gegen +alle Arten von Rotationen, Dehnungen oder lokalen Deformationen. Die Unter- +schiede dieser beiden Ebenen in Bezug auf Farbquantisierung und dem 'grit'- +Wert werden durch den 'colorfactor' und dem 'gritfactor' ausgedrueckt. + +-progressive gritfactor N: Erzeugt ein progressives Bild aus zwei Ebenen + Die erste Ebene hat einen mit N multiplizierten + 'grit'-Wert +-progressive colorfactor N: Erzeugt ein progressives Bild aus zwei Ebenen + Die erste Ebene hat einen durch N dividierten + 'quantize'-Wert + +--------!-random-G-------------------------- +-random N1 N2: Erzeugt ein Zufalls-Testbild als Input. Der Name der + Input Datei sollte in diesem Fall 'null' oder 'vnull'sein. + Der Parameter N1 gibt die Farbtiefe des Testbildes an. + Gueltige Werte: 1,4,8,24. + N2 gibt den Typ des Bildes an. + Erlaubte Werte fuer N2 fuer Raster-Bilder ('null'): + 0 or 1 (SW oder Grau), 2 (farbiges Bild) + Die Werte 0,1, oder 2 fuer N2 erzeugen jeweils 'weisses' + Rauschen und sind deshalb fuer Vektorisierung ungeeignet. + Werte 3 oder 4 fuer N2 (erzeugt ein Testbild...) sind + zum Testen der Vektorisierung besser geeignet. + N2 = 3: Bekanntes Logo + N2 = 4: Space-Shuttle + N2 = 5: Testbild mit 16777216 versch. Farben + Erlaubte Werte fuer N2 fuer Vektor-Bilder ('vnull'): + 0: Zufalls-Polylines, 1: gefuellte Zufalls-Polygone + 2: Alle moeglichen KVEC Objekte + Werte 3 oder 4 fuer N2 erzeugt ein Testbild + N2 = 3: Schmetterling + N2 = 4: Tigerkopf + +--------!-scmode-G-------------------------- + (GUI-Parameter) Waehlt den Skalierungsmodus in der KVEC-GUI. + Hinweis: Wird von der KVEC Kommandozeilenversion ignoriert. +-scmode N: 0: Isotrop, 1: Isotrop, 2: Anisotrop, 3: Keine Skalierung + +--------!-smooth-G-------------------------- +-smooth on: Glaettung von Polylines und Polygonen. Das Programm + versucht, Vektoren zu glaetten. Diese Einstellung ist mit + einem gewissen Bild-Informationsverlust verbunden. + Default: haengt vom Ausgabe-Format ab. + Wird 'smooth on' beim Format WMF oder EMF verwendet, so + erhoeht sich die Aufloesung um den Faktor 4. +-smooth off: Schaltet die Glaettungsfunktion aus + +--------!-subimage-G------------------------ +-subimage N: Waehlt das Bild Nr. N in einer Graphik-Datei aus, die mehr + als ein Bild enthaelt (Tiff, OS/2 Bitmaps oder FAX Formate) + Das erste Bild beginnt mit Nr. 0. Falls kein subimage Wert + angegeben wurde, erzeugt KVEC ein einziges Bild, in dem + alle Subimages aneinander 'gehaengt' werden (Nur fuer FAX) + +--------!-xyscale-G------------------------- +KVEC bietet die Mglichkeit einer anisotropen Skalierung / Translation fuer +DXF und HPGL output: +-xyscale hpgl X Y: Skaliere hpgl Koordinaten mit Faktor X (x-Richtung) und + Y (y-Richtung) +-xyscale dxf X Y: Skaliere dxf Koordinaten mit Faktor X (x-Richtung) und + Y (y-Richtung) +-xyoffset X Y: Addiere X und Y Offsets zu den Ausgabekoordinaten + (Die Option '-coord pixel' sollte dann angegeben werden!) + +--------!-vcolor-G-------------------------- +-vcolor R G B: Diese Option kann benutzt werden, um aus einem Bild + bestimmte Bereiche, naemlich die mit den RGB- + Farbkomponenten R,G,B, 'herauszuholen'. + Die Werte fuer R,G,B koennen zwischen 0 und 255 liegen. + Die Vektor-Outputdatei wird nur Bereiche mit dieser Farbe + enthalten. + Achtung: Falls ein Delta Wert > 0 angegeben wurde + ('-delta Option) werden alle Farben vektorisiert, die im + Bereich (RGB +/- delta) liegen. +-vcolor -R -G -B: Die Vektor-Outputdatei keine Bereiche mit dieser Farbe + enthalten. + Achtung: Falls ein Delta Wert > 0 angegeben wurde + ('-delta Option) werden keine Farben vektorisiert, die im + Bereich (RGB +/- delta) liegen. + +--------!-end-G----------------------------- + +Die neueste Version von KVEC und eine aktuelle Preisliste ist stets verfuegbar +in http://www.kvec.de diff --git a/extensions/fablabchemnitz/kvec/meta.json b/extensions/fablabchemnitz/kvec/meta.json new file mode 100644 index 0000000..46b9725 --- /dev/null +++ b/extensions/fablabchemnitz/kvec/meta.json @@ -0,0 +1,20 @@ +[ + { + "name": "KVEC", + "id": "fablabchemnitz.de.kvec", + "path": "kvec", + "dependent_extensions": null, + "original_name": "KVEC", + "original_id": "fablabchemnitz.de.kvec", + "license": "GNU GPL v3", + "license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/LICENSE", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/kvec", + "fork_url": null, + "documentation_url": "https://stadtfabrikanten.org/display/IFM/KVEC", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/line_shading/line_shading.inx b/extensions/fablabchemnitz/line_shading/line_shading.inx new file mode 100644 index 0000000..0dac1c5 --- /dev/null +++ b/extensions/fablabchemnitz/line_shading/line_shading.inx @@ -0,0 +1,43 @@ + + + Line Shading + fablabchemnitz.de.line_shading + + + + + + + + 20 + 0.1 + 2.0 + 0.0 + 1.0 + 2.2 + + + + + + 0.25 + + + + + + + + false + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/line_shading/line_shading.py b/extensions/fablabchemnitz/line_shading/line_shading.py new file mode 100644 index 0000000..0213b0f --- /dev/null +++ b/extensions/fablabchemnitz/line_shading/line_shading.py @@ -0,0 +1,320 @@ +#!/usr/bin/env python3 +''' +Created by Danylo Horbatenko 2018, dnkxyz@gmail.com +Copyright (C) 2018 George Fomitchev, gf@endurancerobots.com + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +''' +#Version control: last edited by 01.03.2018 8:20 +import os +import tempfile +import shutil +import subprocess +import math +import inkex +import sys +import png +from lxml import etree +from inkex.paths import Path + +def saw(x): + #The function returns a symmetric triangle wave with period 4 and varying between -1 and 1 + x = math.fmod(x, 4.0) + x = math.fabs(x) + if x > 2.0: + y = 3 - x + else: + y = x - 1 + return y + +def square(x): + #The function returns a square wave with period 4 and varying between -1 and 1 + x = math.fmod(x, 4.0) + if 1.0 < x < 3.0: + y = 1.0 + else: + y = -1.0 + return y + +class LineShading(inkex.EffectExtension): + + def add_arguments(self, pars): + pars.add_argument('--palette', help='Choose the colors...') + pars.add_argument("--waveform", help="Select the shape of the curve") + pars.add_argument("--num_lines", type=int, help="Number of lines") + pars.add_argument("--min_period", type=float, help="Minimum period (corresponds to black pixels)") + pars.add_argument("--max_period", type=float, help="Maximum period (corresponds to white pixels)") + pars.add_argument("--min_amplitude", type=float, help="Minimum amplitude (corresponds to white pixels)") + pars.add_argument("--max_amplitude", type=float, help="Maximum amplitude (corresponds to black pixels)") + pars.add_argument("--gamma", type=float, help="Maximum amplitude (corresponds to black pixels)") + pars.add_argument("--line_width", type=float, help="Line width") + pars.add_argument("--units", help="Units for line thickness") + pars.add_argument("--remove", type=inkex.Boolean, help="If True, source image is removed") + pars.add_argument("--active-tab", help="The selected UI-tab when OK was pressed") + + def drawfunction(self, image_w, image_h, file): + reader = png.Reader(file) + w, h, pixels, metadata = reader.read_flat() + matrice = [[1.0 for i in range(w)]for j in range(h)] + if metadata['alpha']: + n = 4 + else: + n = 3 + #RGB convert to grayscale 0.21R + 0.72G + 0.07B + for y in range(h): + for x in range(w): + pixel_pos = (x + y * w)*n + p = 1.0 - (pixels[pixel_pos]*0.21 + pixels[(pixel_pos+1)]*0.72 + pixels[(pixel_pos+2)]*0.07)/255.0 + matrice[y][x] = math.pow(p, 1.0/self.options.gamma) + + points = [] + step_y = image_h/h + step_x = image_w/(w-1) + min_amplitude = self.options.min_amplitude*step_y/2 + max_amplitude = self.options.max_amplitude*step_y/2 + min_period = self.options.min_period*step_y + max_period = self.options.max_period*step_y + min_frequency = 1.0/max_period + max_frequency = 1.0/min_period + + #Sinusoidal wave (optimized) + if self.options.waveform == 'sin': + for y in range(h): + pi = math.pi + phase = 0.0 + coord_x = 0.0 + amplitude = 0.0 + n_step = 0 + x0 = 0.0 + y0 = math.sin(phase)*(min_amplitude + (max_amplitude - min_amplitude)*matrice[y][x]) + (y+0.5)*step_y + points.append(['M',[x0, y0]]) + for x in range(w): + period = min_period + (max_period - min_period)*(1-matrice[y][x]) + #period = 1.0/(min_frequency + (max_frequency - min_frequency)*(matrice[y][x])) + d_phase = 2.0*pi/period*step_x + #calculate y + if phase > 2.0*pi: + if n_step > 0: + x3 = coord_x + y3 = -amplitude/n_step + (y+0.5)*step_y + x2 = x3 - (x3-x0)*0.32 + y2 = y3 + x1 = x0 + (x3-x0)*0.34 + y1 = y0 + x0 = x3 + y0 = y3 + points.append(['C',[x1, y1, x2, y2, x3, y3]]) + n_step = 0 + amplitude = 0 + elif phase < pi < (phase + d_phase): + if n_step > 0: + x3 = coord_x + y3 = amplitude/n_step + (y+0.5)*step_y + x2 = x3 - (x3-x0)*0.34 + y2 = y3 + x1 = x0 + (x3-x0)*0.32 + y1 = y0 + x0 = x3 + y0 = y3 + points.append(['C',[x1, y1, x2, y2, x3, y3]]) + n_step = 0 + amplitude = 0 + phase = math.fmod(phase, 2.0*pi) + #calculate x + if phase < 0.5*pi < (phase + d_phase): + coord_x = (x - (phase - 0.5*pi)/d_phase)*step_x + elif phase < 1.5*pi < (phase + d_phase): + coord_x = (x - (phase - 1.5*pi)/d_phase)*step_x + phase += d_phase + amplitude += (min_amplitude + (max_amplitude - min_amplitude)*matrice[y][x]) + n_step += 1 + #add last point + if n_step > 0: + phase = math.fmod(phase, 2.0*pi) + if (0 < phase < 0.5*pi) or (pi < phase < 1.5*pi): + x3 = (w-1)*step_x + y3 = amplitude*math.sin(phase)/n_step + (y+0.5)*step_y + x2 = x3 + y2 = y3 + x1 = x0 + (x3-x0)*0.33 + y1 = y0 + points.append(['C',[x1, y1, x2, y2, x3, y3]]) + else: + if coord_x > (w-1)*step_x: + coord_x = (w-1)*step_x + x3 = coord_x + y3 = math.copysign( amplitude , math.sin(phase))/n_step + (y+0.5)*step_y + x2 = x3 - (x3-x0)*0.32 + y2 = y3 + x1 = x0 + (x3-x0)*0.34 + y1 = y0 + points.append(['C',[x1, y1, x2, y2, x3, y3]]) + if coord_x < (w-1)*step_x: + x0 = x3 + y0 = y3 + x3 = (w-1)*step_x + y3 = amplitude*math.sin(phase)/n_step + (y+0.5)*step_y + x2 = x3 + y2 = y3 + x1 = x0 + (x3-x0)*0.33 + y1 = y0 + points.append(['C',[x1, y1, x2, y2, x3, y3]]) + + #Sinusoidal wave (Brute-force) + elif self.options.waveform == 'sin_b': + pi2 = math.pi*2.0 + for y in range(h): + phase = - pi2/4.0 + for x in range(w): + period = min_period + (max_period - min_period)*(1-matrice[y][x]) + amplitude = min_amplitude + (max_amplitude - min_amplitude)*matrice[y][x] + phase += pi2*step_x/period + phase = math.fmod(phase, pi2) + if x == 0: + points.append(['M',[x*step_x, amplitude*math.sin(phase) + (y+0.5)*step_y]]) + else: + points.append(['L',[x*step_x, amplitude*math.sin(phase) + (y+0.5)*step_y]]) + + #Saw wave + elif self.options.waveform == 'saw': + for y in range(h): + phase = 0.0 + coord_x = 0.0 + amplitude = 0.0 + n_step = 0.0 + for x in range(w): + period = min_period + (max_period - min_period)*(1-matrice[y][x]) + #period = 1.0/(min_frequency + (max_frequency - min_frequency)*(matrice[y][x])) + d_phase = 4.0/period*step_x + if phase > 4.0: + coord_x = (x - (phase - 4.0)/d_phase)*step_x + elif phase < 2.0 < (phase + d_phase): + coord_x = (x - (phase - 2.0)/d_phase)*step_x + phase = math.fmod(phase, 4.0) + if (phase < 1.0 < (phase + d_phase)) or (phase < 3.0 < (phase + d_phase)): + if n_step > 0: + if coord_x == 0.0: + points.append(['M',[coord_x, amplitude*square(phase - 1.0)/n_step + (y+0.5)*step_y]]) + else: + points.append(['L',[coord_x, amplitude*square(phase - 1.0)/n_step + (y+0.5)*step_y]]) + n_step = 0 + amplitude = 0 + phase += d_phase + n_step += 1.0 + amplitude += (min_amplitude + (max_amplitude - min_amplitude)*matrice[y][x]) + if n_step > 0: + points.append(['L',[(w-1)*step_x, amplitude*saw(phase - 1.0)/n_step + (y+0.5)*step_y]]) + + #Square wave + else: + for y in range(h): + phase = 0.0 + coord_x = 0.0 + amplitude = 0.0 + n_step = 0 + for x in range(w): + period = min_period + (max_period - min_period)*(1-matrice[y][x]) + #period = 1.0/(min_frequency + (max_frequency - min_frequency)*(matrice[y][x])) + d_phase = 4.0/period*step_x + if phase > 4.0: + coord_x = (x - (phase - 4.0)/d_phase)*step_x + elif phase < 2.0 < (phase + d_phase): + coord_x = (x - (phase - 2.0)/d_phase)*step_x + phase = math.fmod(phase, 4.0) + if phase < 1.0 < (phase + d_phase): + if n_step > 0: + if coord_x == 0.0: + points.append(['M',[coord_x, amplitude/n_step + (y+0.5)*step_y]]) + else: + points.append(['L',[coord_x, -amplitude/n_step + (y+0.5)*step_y]]) + points.append(['L',[coord_x, amplitude/n_step + (y+0.5)*step_y]]) + n_step = 0 + amplitude = 0 + elif phase < 3.0 < (phase + d_phase): + if n_step > 0: + if coord_x == 0.0: + points.append(['M',[coord_x, -amplitude/n_step + (y+0.5)*step_y]]) + else: + points.append(['L',[coord_x, amplitude/n_step + (y+0.5)*step_y]]) + points.append(['L',[coord_x, -amplitude/n_step + (y+0.5)*step_y]]) + n_step = 0 + amplitude = 0 + phase += d_phase + n_step += 1 + amplitude += (min_amplitude + (max_amplitude - min_amplitude)*matrice[y][x]) + if n_step > 0: + if 3.0 > phase > 1.0: + points.append(['L',[(w-1)*step_x, amplitude/n_step + (y+0.5)*step_y]]) + else: + points.append(['L',[(w-1)*step_x, -amplitude/n_step + (y+0.5)*step_y]]) + return points + + def draw_path(self, node, file): + newpath = etree.Element(inkex.addNS('path','svg')) + line_width = self.options.line_width + units = self.options.units + s = {'stroke': '#000000', 'fill': 'none', 'stroke-linejoin': 'round', 'stroke-linecap': 'round', 'stroke-width': str(self.svg.unittouu(str(line_width) + units))} + newpath.set('style', str(inkex.Style(s))) + x = node.get('x') + y = node.get('y') + t = 'translate('+ x +','+ y +')' + newpath.set('transform', t) + image_w = float(node.get('width')) + image_h = float(node.get('height')) + newpath.set('d', str(Path(self.drawfunction(image_w, image_h, file)))) + newpath.set('title', 'Line_Shading') + node.getparent().append(newpath) + newpath.set('x', x) + + def export_png(self, node, file): + image_w = float(node.get('width')) + image_h = float(node.get('height')) + min_period = self.options.min_period + max_period = self.options.min_period + poinnt_per_min_period = 8.0 + current_file = self.options.input_file + h_png = str(self.options.num_lines) + if min_period < max_period: + w_png = str(round(poinnt_per_min_period*image_w*float(h_png)/min_period/image_h)) + else: + w_png = str(round(poinnt_per_min_period*image_w*float(h_png)/max_period/image_h)) + id = node.get('id') + cmd = "inkscape " + current_file + " --export-type=\"png\" --export-filename=" + file + " --actions=\"export-width:"+w_png+";export-height:"+h_png+";export-background:rgb(255,255,255);export-background-opacity:255;export-id:"+id+"\"" + #inkex.errormsg(cmd) + proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + #inkex.utils.debug(cmd) + #inkex.utils.debug(proc.communicate()) + #sys.exit(0) + #return_code = proc.wait() + #sys.exit(0) + f = proc.stdout + err = proc.stderr + f.close() + err.close() + proc.wait() + #inkex.errormsg(proc.stdout.read()) + + def effect(self): + image_selected_flag = False + for id, node in self.svg.selected.items(): + if node.tag == inkex.addNS('image','svg'): + image_selected_flag = True + tmp_dir = tempfile.mkdtemp() + png_temp_file = os.path.join(tmp_dir, "LineShading.png") + self.export_png(node, png_temp_file) + self.draw_path(node, png_temp_file) + shutil.rmtree(tmp_dir) + if self.options.remove: + node.delete() + return + if not image_selected_flag: + inkex.errormsg("Please select an image") + +if __name__ == '__main__': + LineShading().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/line_shading/meta.json b/extensions/fablabchemnitz/line_shading/meta.json new file mode 100644 index 0000000..156d6c3 --- /dev/null +++ b/extensions/fablabchemnitz/line_shading/meta.json @@ -0,0 +1,22 @@ +[ + { + "name": "Line Shading", + "id": "fablabchemnitz.de.line_shading", + "path": "line_shading", + "dependent_extensions": null, + "original_name": "Endurance Line Shading", + "original_id": "org.ekips.filter.line_shading", + "license": "MIT License", + "license_url": "https://endurancelasers.com/download/Endurance_Line_Shading.rar", + "comment": "", + "source_url": "ported to Inkscape v1 manually by Mario Voigt", + "fork_url": "https://endurancelasers.com/download/Endurance_Line_Shading.rar", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Line+Shading", + "inkscape_gallery_url": null, + "main_authors": [ + "dnkxyz@gmail.com", + "gf@endurancerobots.com", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/line_shading/png.py b/extensions/fablabchemnitz/line_shading/png.py new file mode 100644 index 0000000..42dadd5 --- /dev/null +++ b/extensions/fablabchemnitz/line_shading/png.py @@ -0,0 +1,2751 @@ +#!/usr/bin/env python3 + +# png.py - PNG encoder/decoder in pure Python +# +# Copyright (C) 2006 Johann C. Rocholl +# Portions Copyright (C) 2009 David Jones +# And probably portions Copyright (C) 2006 Nicko van Someren +# +# Original concept by Johann C. Rocholl. +# +# LICENCE (MIT) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +""" +Pure Python PNG Reader/Writer + +This Python module implements support for PNG images (see PNG +specification at http://www.w3.org/TR/2003/REC-PNG-20031110/ ). It reads +and writes PNG files with all allowable bit depths +(1/2/4/8/16/24/32/48/64 bits per pixel) and colour combinations: +greyscale (1/2/4/8/16 bit); RGB, RGBA, LA (greyscale with alpha) with +8/16 bits per channel; colour mapped images (1/2/4/8 bit). +Adam7 interlacing is supported for reading and +writing. A number of optional chunks can be specified (when writing) +and understood (when reading): ``tRNS``, ``bKGD``, ``gAMA``. + +For help, type ``import png; help(png)`` in your python interpreter. + +A good place to start is the :class:`Reader` and :class:`Writer` +classes. + +Requires Python 2.3. Limited support is available for Python 2.2, but +not everything works. Best with Python 2.4 and higher. Installation is +trivial, but see the ``README.txt`` file (with the source distribution) +for details. + +This file can also be used as a command-line utility to convert +`Netpbm `_ PNM files to PNG, and the +reverse conversion from PNG to PNM. The interface is similar to that +of the ``pnmtopng`` program from Netpbm. Type ``python png.py --help`` +at the shell prompt for usage and a list of options. + +A note on spelling and terminology +---------------------------------- + +Generally British English spelling is used in the documentation. So +that's "greyscale" and "colour". This not only matches the author's +native language, it's also used by the PNG specification. + +The major colour models supported by PNG (and hence by PyPNG) are: +greyscale, RGB, greyscale--alpha, RGB--alpha. These are sometimes +referred to using the abbreviations: L, RGB, LA, RGBA. In this case +each letter abbreviates a single channel: *L* is for Luminance or Luma +or Lightness which is the channel used in greyscale images; *R*, *G*, +*B* stand for Red, Green, Blue, the components of a colour image; *A* +stands for Alpha, the opacity channel (used for transparency effects, +but higher values are more opaque, so it makes sense to call it +opacity). + +A note on formats +----------------- + +When getting pixel data out of this module (reading) and presenting +data to this module (writing) there are a number of ways the data could +be represented as a Python value. Generally this module uses one of +three formats called "flat row flat pixel", "boxed row flat pixel", and +"boxed row boxed pixel". Basically the concern is whether each pixel +and each row comes in its own little tuple (box), or not. + +Consider an image that is 3 pixels wide by 2 pixels high, and each pixel +has RGB components: + +Boxed row flat pixel:: + + list([R,G,B, R,G,B, R,G,B], + [R,G,B, R,G,B, R,G,B]) + +Each row appears as its own list, but the pixels are flattened so +that three values for one pixel simply follow the three values for +the previous pixel. This is the most common format used, because it +provides a good compromise between space and convenience. PyPNG regards +itself as at liberty to replace any sequence type with any sufficiently +compatible other sequence type; in practice each row is an array (from +the array module), and the outer list is sometimes an iterator rather +than an explicit list (so that streaming is possible). + +Flat row flat pixel:: + + [R,G,B, R,G,B, R,G,B, + R,G,B, R,G,B, R,G,B] + +The entire image is one single giant sequence of colour values. +Generally an array will be used (to save space), not a list. + +Boxed row boxed pixel:: + + list([ (R,G,B), (R,G,B), (R,G,B) ], + [ (R,G,B), (R,G,B), (R,G,B) ]) + +Each row appears in its own list, but each pixel also appears in its own +tuple. A serious memory burn in Python. + +In all cases the top row comes first, and for each row the pixels are +ordered from left-to-right. Within a pixel the values appear in the +order, R-G-B-A (or L-A for greyscale--alpha). + +There is a fourth format, mentioned because it is used internally, +is close to what lies inside a PNG file itself, and has some support +from the public API. This format is called packed. When packed, +each row is a sequence of bytes (integers from 0 to 255), just as +it is before PNG scanline filtering is applied. When the bit depth +is 8 this is essentially the same as boxed row flat pixel; when the +bit depth is less than 8, several pixels are packed into each byte; +when the bit depth is 16 (the only value more than 8 that is supported +by the PNG image format) each pixel value is decomposed into 2 bytes +(and `packed` is a misnomer). This format is used by the +:meth:`Writer.write_packed` method. It isn't usually a convenient +format, but may be just right if the source data for the PNG image +comes from something that uses a similar format (for example, 1-bit +BMPs, or another PNG file). + +And now, my famous members +-------------------------- +""" + +# http://www.python.org/doc/2.2.3/whatsnew/node5.html +from __future__ import generators + +__version__ = "0.0.16" + +from array import array +try: # See :pyver:old + import itertools +except ImportError: + pass +import math +# http://www.python.org/doc/2.4.4/lib/module-operator.html +import operator +import struct +import sys +import zlib +# http://www.python.org/doc/2.4.4/lib/module-warnings.html +import warnings +try: + # `cpngfilters` is a Cython module: it must be compiled by + # Cython for this import to work. + # If this import does work, then it overrides pure-python + # filtering functions defined later in this file (see `class + # pngfilters`). + import cpngfilters as pngfilters +except ImportError: + pass + + +__all__ = ['Image', 'Reader', 'Writer', 'write_chunks', 'from_array'] + + +# The PNG signature. +# http://www.w3.org/TR/PNG/#5PNG-file-signature +_signature = struct.pack('8B', 137, 80, 78, 71, 13, 10, 26, 10) + +_adam7 = ((0, 0, 8, 8), + (4, 0, 8, 8), + (0, 4, 4, 8), + (2, 0, 4, 4), + (0, 2, 2, 4), + (1, 0, 2, 2), + (0, 1, 1, 2)) + +def group(s, n): + # See http://www.python.org/doc/2.6/library/functions.html#zip + return zip(*[iter(s)]*n) + +def isarray(x): + """Same as ``isinstance(x, array)`` except on Python 2.2, where it + always returns ``False``. This helps PyPNG work on Python 2.2. + """ + + try: + return isinstance(x, array) + except TypeError: + # Because on Python 2.2 array.array is not a type. + return False + +try: + array.tobytes +except AttributeError: + try: # see :pyver:old + array.tostring + except AttributeError: + def tostring(row): + l = len(row) + return struct.pack('%dB' % l, *row) + else: + def tostring(row): + """Convert row of bytes to string. Expects `row` to be an + ``array``. + """ + return row.tostring() +else: + def tostring(row): + """ Python3 definition, array.tostring() is deprecated in Python3 + """ + return row.tobytes() + +# Conditionally convert to bytes. Works on Python 2 and Python 3. +try: + bytes('', 'ascii') + def strtobytes(x): return bytes(x, 'iso8859-1') + def bytestostr(x): return str(x, 'iso8859-1') +except (NameError, TypeError): + # We get NameError when bytes() does not exist (most Python + # 2.x versions), and TypeError when bytes() exists but is on + # Python 2.x (when it is an alias for str() and takes at most + # one argument). + strtobytes = str + bytestostr = str + +def interleave_planes(ipixels, apixels, ipsize, apsize): + """ + Interleave (colour) planes, e.g. RGB + A = RGBA. + + Return an array of pixels consisting of the `ipsize` elements of + data from each pixel in `ipixels` followed by the `apsize` elements + of data from each pixel in `apixels`. Conventionally `ipixels` + and `apixels` are byte arrays so the sizes are bytes, but it + actually works with any arrays of the same type. The returned + array is the same type as the input arrays which should be the + same type as each other. + """ + + itotal = len(ipixels) + atotal = len(apixels) + newtotal = itotal + atotal + newpsize = ipsize + apsize + # Set up the output buffer + # See http://www.python.org/doc/2.4.4/lib/module-array.html#l2h-1356 + out = array(ipixels.typecode) + # It's annoying that there is no cheap way to set the array size :-( + out.extend(ipixels) + out.extend(apixels) + # Interleave in the pixel data + for i in range(ipsize): + out[i:newtotal:newpsize] = ipixels[i:itotal:ipsize] + for i in range(apsize): + out[i+ipsize:newtotal:newpsize] = apixels[i:atotal:apsize] + return out + +def check_palette(palette): + """Check a palette argument (to the :class:`Writer` class) + for validity. Returns the palette as a list if okay; raises an + exception otherwise. + """ + + # None is the default and is allowed. + if palette is None: + return None + + p = list(palette) + if not (0 < len(p) <= 256): + raise ValueError("a palette must have between 1 and 256 entries") + seen_triple = False + for i,t in enumerate(p): + if len(t) not in (3,4): + raise ValueError( + "palette entry %d: entries must be 3- or 4-tuples." % i) + if len(t) == 3: + seen_triple = True + if seen_triple and len(t) == 4: + raise ValueError( + "palette entry %d: all 4-tuples must precede all 3-tuples" % i) + for x in t: + if int(x) != x or not(0 <= x <= 255): + raise ValueError( + "palette entry %d: values must be integer: 0 <= x <= 255" % i) + return p + +def check_sizes(size, width, height): + """Check that these arguments, in supplied, are consistent. + Return a (width, height) pair. + """ + + if not size: + return width, height + + if len(size) != 2: + raise ValueError( + "size argument should be a pair (width, height)") + if width is not None and width != size[0]: + raise ValueError( + "size[0] (%r) and width (%r) should match when both are used." + % (size[0], width)) + if height is not None and height != size[1]: + raise ValueError( + "size[1] (%r) and height (%r) should match when both are used." + % (size[1], height)) + return size + +def check_color(c, greyscale, which): + """Checks that a colour argument for transparent or + background options is the right form. Returns the colour + (which, if it's a bar integer, is "corrected" to a 1-tuple). + """ + + if c is None: + return c + if greyscale: + try: + l = len(c) + except TypeError: + c = (c,) + if len(c) != 1: + raise ValueError("%s for greyscale must be 1-tuple" % + which) + if not isinteger(c[0]): + raise ValueError( + "%s colour for greyscale must be integer" % which) + else: + if not (len(c) == 3 and + isinteger(c[0]) and + isinteger(c[1]) and + isinteger(c[2])): + raise ValueError( + "%s colour must be a triple of integers" % which) + return c + +class Error(Exception): + def __str__(self): + return self.__class__.__name__ + ': ' + ' '.join(self.args) + +class FormatError(Error): + """Problem with input file format. In other words, PNG file does + not conform to the specification in some way and is invalid. + """ + +class ChunkError(FormatError): + pass + + +class Writer: + """ + PNG encoder in pure Python. + """ + + def __init__(self, width=None, height=None, + size=None, + greyscale=False, + alpha=False, + bitdepth=8, + palette=None, + transparent=None, + background=None, + gamma=None, + compression=None, + interlace=False, + bytes_per_sample=None, # deprecated + planes=None, + colormap=None, + maxval=None, + chunk_limit=2**20): + """ + Create a PNG encoder object. + + Arguments: + + width, height + Image size in pixels, as two separate arguments. + size + Image size (w,h) in pixels, as single argument. + greyscale + Input data is greyscale, not RGB. + alpha + Input data has alpha channel (RGBA or LA). + bitdepth + Bit depth: from 1 to 16. + palette + Create a palette for a colour mapped image (colour type 3). + transparent + Specify a transparent colour (create a ``tRNS`` chunk). + background + Specify a default background colour (create a ``bKGD`` chunk). + gamma + Specify a gamma value (create a ``gAMA`` chunk). + compression + zlib compression level: 0 (none) to 9 (more compressed); + default: -1 or None. + interlace + Create an interlaced image. + chunk_limit + Write multiple ``IDAT`` chunks to save memory. + + The image size (in pixels) can be specified either by using the + `width` and `height` arguments, or with the single `size` + argument. If `size` is used it should be a pair (*width*, + *height*). + + `greyscale` and `alpha` are booleans that specify whether + an image is greyscale (or colour), and whether it has an + alpha channel (or not). + + `bitdepth` specifies the bit depth of the source pixel values. + Each source pixel value must be an integer between 0 and + ``2**bitdepth-1``. For example, 8-bit images have values + between 0 and 255. PNG only stores images with bit depths of + 1,2,4,8, or 16. When `bitdepth` is not one of these values, + the next highest valid bit depth is selected, and an ``sBIT`` + (significant bits) chunk is generated that specifies the + original precision of the source image. In this case the + supplied pixel values will be rescaled to fit the range of + the selected bit depth. + + The details of which bit depth / colour model combinations the + PNG file format supports directly, are somewhat arcane + (refer to the PNG specification for full details). Briefly: + "small" bit depths (1,2,4) are only allowed with greyscale and + colour mapped images; colour mapped images cannot have bit depth + 16. + + For colour mapped images (in other words, when the `palette` + argument is specified) the `bitdepth` argument must match one of + the valid PNG bit depths: 1, 2, 4, or 8. (It is valid to have a + PNG image with a palette and an ``sBIT`` chunk, but the meaning + is slightly different; it would be awkward to press the + `bitdepth` argument into service for this.) + + The `palette` option, when specified, causes a colour mapped + image to be created: the PNG colour type is set to 3; greyscale + must not be set; alpha must not be set; transparent must not be + set; the bit depth must be 1,2,4, or 8. When a colour mapped + image is created, the pixel values are palette indexes and + the `bitdepth` argument specifies the size of these indexes + (not the size of the colour values in the palette). + + The palette argument value should be a sequence of 3- or + 4-tuples. 3-tuples specify RGB palette entries; 4-tuples + specify RGBA palette entries. If both 4-tuples and 3-tuples + appear in the sequence then all the 4-tuples must come + before all the 3-tuples. A ``PLTE`` chunk is created; if there + are 4-tuples then a ``tRNS`` chunk is created as well. The + ``PLTE`` chunk will contain all the RGB triples in the same + sequence; the ``tRNS`` chunk will contain the alpha channel for + all the 4-tuples, in the same sequence. Palette entries + are always 8-bit. + + If specified, the `transparent` and `background` parameters must + be a tuple with three integer values for red, green, blue, or + a simple integer (or singleton tuple) for a greyscale image. + + If specified, the `gamma` parameter must be a positive number + (generally, a float). A ``gAMA`` chunk will be created. + Note that this will not change the values of the pixels as + they appear in the PNG file, they are assumed to have already + been converted appropriately for the gamma specified. + + The `compression` argument specifies the compression level to + be used by the ``zlib`` module. Values from 1 to 9 specify + compression, with 9 being "more compressed" (usually smaller + and slower, but it doesn't always work out that way). 0 means + no compression. -1 and ``None`` both mean that the default + level of compession will be picked by the ``zlib`` module + (which is generally acceptable). + + If `interlace` is true then an interlaced image is created + (using PNG's so far only interace method, *Adam7*). This does + not affect how the pixels should be presented to the encoder, + rather it changes how they are arranged into the PNG file. + On slow connexions interlaced images can be partially decoded + by the browser to give a rough view of the image that is + successively refined as more image data appears. + + .. note :: + + Enabling the `interlace` option requires the entire image + to be processed in working memory. + + `chunk_limit` is used to limit the amount of memory used whilst + compressing the image. In order to avoid using large amounts of + memory, multiple ``IDAT`` chunks may be created. + """ + + # At the moment the `planes` argument is ignored; + # its purpose is to act as a dummy so that + # ``Writer(x, y, **info)`` works, where `info` is a dictionary + # returned by Reader.read and friends. + # Ditto for `colormap`. + + width, height = check_sizes(size, width, height) + del size + + if width <= 0 or height <= 0: + raise ValueError("width and height must be greater than zero") + if not isinteger(width) or not isinteger(height): + raise ValueError("width and height must be integers") + # http://www.w3.org/TR/PNG/#7Integers-and-byte-order + if width > 2**32-1 or height > 2**32-1: + raise ValueError("width and height cannot exceed 2**32-1") + + if alpha and transparent is not None: + raise ValueError( + "transparent colour not allowed with alpha channel") + + if bytes_per_sample is not None: + warnings.warn('please use bitdepth instead of bytes_per_sample', + DeprecationWarning) + if bytes_per_sample not in (0.125, 0.25, 0.5, 1, 2): + raise ValueError( + "bytes per sample must be .125, .25, .5, 1, or 2") + bitdepth = int(8*bytes_per_sample) + del bytes_per_sample + if not isinteger(bitdepth) or bitdepth < 1 or 16 < bitdepth: + raise ValueError("bitdepth (%r) must be a postive integer <= 16" % + bitdepth) + + self.rescale = None + if palette: + if bitdepth not in (1,2,4,8): + raise ValueError("with palette, bitdepth must be 1, 2, 4, or 8") + if transparent is not None: + raise ValueError("transparent and palette not compatible") + if alpha: + raise ValueError("alpha and palette not compatible") + if greyscale: + raise ValueError("greyscale and palette not compatible") + else: + # No palette, check for sBIT chunk generation. + if alpha or not greyscale: + if bitdepth not in (8,16): + targetbitdepth = (8,16)[bitdepth > 8] + self.rescale = (bitdepth, targetbitdepth) + bitdepth = targetbitdepth + del targetbitdepth + else: + assert greyscale + assert not alpha + if bitdepth not in (1,2,4,8,16): + if bitdepth > 8: + targetbitdepth = 16 + elif bitdepth == 3: + targetbitdepth = 4 + else: + assert bitdepth in (5,6,7) + targetbitdepth = 8 + self.rescale = (bitdepth, targetbitdepth) + bitdepth = targetbitdepth + del targetbitdepth + + if bitdepth < 8 and (alpha or not greyscale and not palette): + raise ValueError( + "bitdepth < 8 only permitted with greyscale or palette") + if bitdepth > 8 and palette: + raise ValueError( + "bit depth must be 8 or less for images with palette") + + transparent = check_color(transparent, greyscale, 'transparent') + background = check_color(background, greyscale, 'background') + + # It's important that the true boolean values (greyscale, alpha, + # colormap, interlace) are converted to bool because Iverson's + # convention is relied upon later on. + self.width = width + self.height = height + self.transparent = transparent + self.background = background + self.gamma = gamma + self.greyscale = bool(greyscale) + self.alpha = bool(alpha) + self.colormap = bool(palette) + self.bitdepth = int(bitdepth) + self.compression = compression + self.chunk_limit = chunk_limit + self.interlace = bool(interlace) + self.palette = check_palette(palette) + + self.color_type = 4*self.alpha + 2*(not greyscale) + 1*self.colormap + assert self.color_type in (0,2,3,4,6) + + self.color_planes = (3,1)[self.greyscale or self.colormap] + self.planes = self.color_planes + self.alpha + # :todo: fix for bitdepth < 8 + self.psize = (self.bitdepth/8) * self.planes + + def make_palette(self): + """Create the byte sequences for a ``PLTE`` and if necessary a + ``tRNS`` chunk. Returned as a pair (*p*, *t*). *t* will be + ``None`` if no ``tRNS`` chunk is necessary. + """ + + p = array('B') + t = array('B') + + for x in self.palette: + p.extend(x[0:3]) + if len(x) > 3: + t.append(x[3]) + p = tostring(p) + t = tostring(t) + if t: + return p,t + return p,None + + def write(self, outfile, rows): + """Write a PNG image to the output file. `rows` should be + an iterable that yields each row in boxed row flat pixel + format. The rows should be the rows of the original image, + so there should be ``self.height`` rows of ``self.width * + self.planes`` values. If `interlace` is specified (when + creating the instance), then an interlaced PNG file will + be written. Supply the rows in the normal image order; + the interlacing is carried out internally. + + .. note :: + + Interlacing will require the entire image to be in working + memory. + """ + + if self.interlace: + fmt = 'BH'[self.bitdepth > 8] + a = array(fmt, itertools.chain(*rows)) + return self.write_array(outfile, a) + else: + nrows = self.write_passes(outfile, rows) + if nrows != self.height: + raise ValueError( + "rows supplied (%d) does not match height (%d)" % + (nrows, self.height)) + + def write_passes(self, outfile, rows, packed=False): + """ + Write a PNG image to the output file. + + Most users are expected to find the :meth:`write` or + :meth:`write_array` method more convenient. + + The rows should be given to this method in the order that + they appear in the output file. For straightlaced images, + this is the usual top to bottom ordering, but for interlaced + images the rows should have already been interlaced before + passing them to this function. + + `rows` should be an iterable that yields each row. When + `packed` is ``False`` the rows should be in boxed row flat pixel + format; when `packed` is ``True`` each row should be a packed + sequence of bytes. + """ + + # http://www.w3.org/TR/PNG/#5PNG-file-signature + outfile.write(_signature) + + # http://www.w3.org/TR/PNG/#11IHDR + write_chunk(outfile, 'IHDR', + struct.pack("!2I5B", self.width, self.height, + self.bitdepth, self.color_type, + 0, 0, self.interlace)) + + # See :chunk:order + # http://www.w3.org/TR/PNG/#11gAMA + if self.gamma is not None: + write_chunk(outfile, 'gAMA', + struct.pack("!L", int(round(self.gamma*1e5)))) + + # See :chunk:order + # http://www.w3.org/TR/PNG/#11sBIT + if self.rescale: + write_chunk(outfile, 'sBIT', + struct.pack('%dB' % self.planes, + *[self.rescale[0]]*self.planes)) + + # :chunk:order: Without a palette (PLTE chunk), ordering is + # relatively relaxed. With one, gAMA chunk must precede PLTE + # chunk which must precede tRNS and bKGD. + # See http://www.w3.org/TR/PNG/#5ChunkOrdering + if self.palette: + p,t = self.make_palette() + write_chunk(outfile, 'PLTE', p) + if t: + # tRNS chunk is optional. Only needed if palette entries + # have alpha. + write_chunk(outfile, 'tRNS', t) + + # http://www.w3.org/TR/PNG/#11tRNS + if self.transparent is not None: + if self.greyscale: + write_chunk(outfile, 'tRNS', + struct.pack("!1H", *self.transparent)) + else: + write_chunk(outfile, 'tRNS', + struct.pack("!3H", *self.transparent)) + + # http://www.w3.org/TR/PNG/#11bKGD + if self.background is not None: + if self.greyscale: + write_chunk(outfile, 'bKGD', + struct.pack("!1H", *self.background)) + else: + write_chunk(outfile, 'bKGD', + struct.pack("!3H", *self.background)) + + # http://www.w3.org/TR/PNG/#11IDAT + if self.compression is not None: + compressor = zlib.compressobj(self.compression) + else: + compressor = zlib.compressobj() + + # Choose an extend function based on the bitdepth. The extend + # function packs/decomposes the pixel values into bytes and + # stuffs them onto the data array. + data = array('B') + if self.bitdepth == 8 or packed: + extend = data.extend + elif self.bitdepth == 16: + # Decompose into bytes + def extend(sl): + fmt = '!%dH' % len(sl) + data.extend(array('B', struct.pack(fmt, *sl))) + else: + # Pack into bytes + assert self.bitdepth < 8 + # samples per byte + spb = int(8/self.bitdepth) + def extend(sl): + a = array('B', sl) + # Adding padding bytes so we can group into a whole + # number of spb-tuples. + l = float(len(a)) + extra = math.ceil(l / float(spb))*spb - l + a.extend([0]*int(extra)) + # Pack into bytes + l = group(a, spb) + l = map(lambda e: reduce(lambda x,y: + (x << self.bitdepth) + y, e), l) + data.extend(l) + if self.rescale: + oldextend = extend + factor = \ + float(2**self.rescale[1]-1) / float(2**self.rescale[0]-1) + def extend(sl): + oldextend(map(lambda x: int(round(factor*x)), sl)) + + # Build the first row, testing mostly to see if we need to + # changed the extend function to cope with NumPy integer types + # (they cause our ordinary definition of extend to fail, so we + # wrap it). See + # http://code.google.com/p/pypng/issues/detail?id=44 + enumrows = enumerate(rows) + del rows + + # First row's filter type. + data.append(0) + # :todo: Certain exceptions in the call to ``.next()`` or the + # following try would indicate no row data supplied. + # Should catch. + i, row = next(enumrows) + try: + # If this fails... + extend(row) + except: + # ... try a version that converts the values to int first. + # Not only does this work for the (slightly broken) NumPy + # types, there are probably lots of other, unknown, "nearly" + # int types it works for. + def wrapmapint(f): + return lambda sl: f(map(int, sl)) + extend = wrapmapint(extend) + del wrapmapint + extend(row) + + for i,row in enumrows: + # Add "None" filter type. Currently, it's essential that + # this filter type be used for every scanline as we do not + # mark the first row of a reduced pass image; that means we + # could accidentally compute the wrong filtered scanline if + # we used "up", "average", or "paeth" on such a line. + data.append(0) + extend(row) + if len(data) > self.chunk_limit: + compressed = compressor.compress(tostring(data)) + if len(compressed): + write_chunk(outfile, 'IDAT', compressed) + # Because of our very witty definition of ``extend``, + # above, we must re-use the same ``data`` object. Hence + # we use ``del`` to empty this one, rather than create a + # fresh one (which would be my natural FP instinct). + del data[:] + if len(data): + compressed = compressor.compress(tostring(data)) + else: + compressed = '' + flushed = compressor.flush() + if len(compressed) or len(flushed): + write_chunk(outfile, 'IDAT', compressed + flushed) + # http://www.w3.org/TR/PNG/#11IEND + write_chunk(outfile, 'IEND') + return i+1 + + def write_array(self, outfile, pixels): + """ + Write an array in flat row flat pixel format as a PNG file on + the output file. See also :meth:`write` method. + """ + + if self.interlace: + self.write_passes(outfile, self.array_scanlines_interlace(pixels)) + else: + self.write_passes(outfile, self.array_scanlines(pixels)) + + def write_packed(self, outfile, rows): + """ + Write PNG file to `outfile`. The pixel data comes from `rows` + which should be in boxed row packed format. Each row should be + a sequence of packed bytes. + + Technically, this method does work for interlaced images but it + is best avoided. For interlaced images, the rows should be + presented in the order that they appear in the file. + + This method should not be used when the source image bit depth + is not one naturally supported by PNG; the bit depth should be + 1, 2, 4, 8, or 16. + """ + + if self.rescale: + raise Error("write_packed method not suitable for bit depth %d" % + self.rescale[0]) + return self.write_passes(outfile, rows, packed=True) + + def convert_pnm(self, infile, outfile): + """ + Convert a PNM file containing raw pixel data into a PNG file + with the parameters set in the writer object. Works for + (binary) PGM, PPM, and PAM formats. + """ + + if self.interlace: + pixels = array('B') + pixels.fromfile(infile, + (self.bitdepth/8) * self.color_planes * + self.width * self.height) + self.write_passes(outfile, self.array_scanlines_interlace(pixels)) + else: + self.write_passes(outfile, self.file_scanlines(infile)) + + def convert_ppm_and_pgm(self, ppmfile, pgmfile, outfile): + """ + Convert a PPM and PGM file containing raw pixel data into a + PNG outfile with the parameters set in the writer object. + """ + pixels = array('B') + pixels.fromfile(ppmfile, + (self.bitdepth/8) * self.color_planes * + self.width * self.height) + apixels = array('B') + apixels.fromfile(pgmfile, + (self.bitdepth/8) * + self.width * self.height) + pixels = interleave_planes(pixels, apixels, + (self.bitdepth/8) * self.color_planes, + (self.bitdepth/8)) + if self.interlace: + self.write_passes(outfile, self.array_scanlines_interlace(pixels)) + else: + self.write_passes(outfile, self.array_scanlines(pixels)) + + def file_scanlines(self, infile): + """ + Generates boxed rows in flat pixel format, from the input file + `infile`. It assumes that the input file is in a "Netpbm-like" + binary format, and is positioned at the beginning of the first + pixel. The number of pixels to read is taken from the image + dimensions (`width`, `height`, `planes`) and the number of bytes + per value is implied by the image `bitdepth`. + """ + + # Values per row + vpr = self.width * self.planes + row_bytes = vpr + if self.bitdepth > 8: + assert self.bitdepth == 16 + row_bytes *= 2 + fmt = '>%dH' % vpr + def line(): + return array('H', struct.unpack(fmt, infile.read(row_bytes))) + else: + def line(): + scanline = array('B', infile.read(row_bytes)) + return scanline + for y in range(self.height): + yield line() + + def array_scanlines(self, pixels): + """ + Generates boxed rows (flat pixels) from flat rows (flat pixels) + in an array. + """ + + # Values per row + vpr = self.width * self.planes + stop = 0 + for y in range(self.height): + start = stop + stop = start + vpr + yield pixels[start:stop] + + def array_scanlines_interlace(self, pixels): + """ + Generator for interlaced scanlines from an array. `pixels` is + the full source image in flat row flat pixel format. The + generator yields each scanline of the reduced passes in turn, in + boxed row flat pixel format. + """ + + # http://www.w3.org/TR/PNG/#8InterlaceMethods + # Array type. + fmt = 'BH'[self.bitdepth > 8] + # Value per row + vpr = self.width * self.planes + for xstart, ystart, xstep, ystep in _adam7: + if xstart >= self.width: + continue + # Pixels per row (of reduced image) + ppr = int(math.ceil((self.width-xstart)/float(xstep))) + # number of values in reduced image row. + row_len = ppr*self.planes + for y in range(ystart, self.height, ystep): + if xstep == 1: + offset = y * vpr + yield pixels[offset:offset+vpr] + else: + row = array(fmt) + # There's no easier way to set the length of an array + row.extend(pixels[0:row_len]) + offset = y * vpr + xstart * self.planes + end_offset = (y+1) * vpr + skip = self.planes * xstep + for i in range(self.planes): + row[i::self.planes] = \ + pixels[offset+i:end_offset:skip] + yield row + +def write_chunk(outfile, tag, data=strtobytes('')): + """ + Write a PNG chunk to the output file, including length and + checksum. + """ + + # http://www.w3.org/TR/PNG/#5Chunk-layout + outfile.write(struct.pack("!I", len(data))) + tag = strtobytes(tag) + outfile.write(tag) + outfile.write(data) + checksum = zlib.crc32(tag) + checksum = zlib.crc32(data, checksum) + checksum &= 2**32-1 + outfile.write(struct.pack("!I", checksum)) + +def write_chunks(out, chunks): + """Create a PNG file by writing out the chunks.""" + + out.write(_signature) + for chunk in chunks: + write_chunk(out, *chunk) + +def filter_scanline(type, line, fo, prev=None): + """Apply a scanline filter to a scanline. `type` specifies the + filter type (0 to 4); `line` specifies the current (unfiltered) + scanline as a sequence of bytes; `prev` specifies the previous + (unfiltered) scanline as a sequence of bytes. `fo` specifies the + filter offset; normally this is size of a pixel in bytes (the number + of bytes per sample times the number of channels), but when this is + < 1 (for bit depths < 8) then the filter offset is 1. + """ + + assert 0 <= type < 5 + + # The output array. Which, pathetically, we extend one-byte at a + # time (fortunately this is linear). + out = array('B', [type]) + + def sub(): + ai = -fo + for x in line: + if ai >= 0: + x = (x - line[ai]) & 0xff + out.append(x) + ai += 1 + def up(): + for i,x in enumerate(line): + x = (x - prev[i]) & 0xff + out.append(x) + def average(): + ai = -fo + for i,x in enumerate(line): + if ai >= 0: + x = (x - ((line[ai] + prev[i]) >> 1)) & 0xff + else: + x = (x - (prev[i] >> 1)) & 0xff + out.append(x) + ai += 1 + def paeth(): + # http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth + ai = -fo # also used for ci + for i,x in enumerate(line): + a = 0 + b = prev[i] + c = 0 + + if ai >= 0: + a = line[ai] + c = prev[ai] + p = a + b - c + pa = abs(p - a) + pb = abs(p - b) + pc = abs(p - c) + if pa <= pb and pa <= pc: Pr = a + elif pb <= pc: Pr = b + else: Pr = c + + x = (x - Pr) & 0xff + out.append(x) + ai += 1 + + if not prev: + # We're on the first line. Some of the filters can be reduced + # to simpler cases which makes handling the line "off the top" + # of the image simpler. "up" becomes "none"; "paeth" becomes + # "left" (non-trivial, but true). "average" needs to be handled + # specially. + if type == 2: # "up" + type = 0 + elif type == 3: + prev = [0]*len(line) + elif type == 4: # "paeth" + type = 1 + if type == 0: + out.extend(line) + elif type == 1: + sub() + elif type == 2: + up() + elif type == 3: + average() + else: # type == 4 + paeth() + return out + + +def from_array(a, mode=None, info={}): + """Create a PNG :class:`Image` object from a 2- or 3-dimensional + array. One application of this function is easy PIL-style saving: + ``png.from_array(pixels, 'L').save('foo.png')``. + + .. note : + + The use of the term *3-dimensional* is for marketing purposes + only. It doesn't actually work. Please bear with us. Meanwhile + enjoy the complimentary snacks (on request) and please use a + 2-dimensional array. + + Unless they are specified using the *info* parameter, the PNG's + height and width are taken from the array size. For a 3 dimensional + array the first axis is the height; the second axis is the width; + and the third axis is the channel number. Thus an RGB image that is + 16 pixels high and 8 wide will use an array that is 16x8x3. For 2 + dimensional arrays the first axis is the height, but the second axis + is ``width*channels``, so an RGB image that is 16 pixels high and 8 + wide will use a 2-dimensional array that is 16x24 (each row will be + 8*3==24 sample values). + + *mode* is a string that specifies the image colour format in a + PIL-style mode. It can be: + + ``'L'`` + greyscale (1 channel) + ``'LA'`` + greyscale with alpha (2 channel) + ``'RGB'`` + colour image (3 channel) + ``'RGBA'`` + colour image with alpha (4 channel) + + The mode string can also specify the bit depth (overriding how this + function normally derives the bit depth, see below). Appending + ``';16'`` to the mode will cause the PNG to be 16 bits per channel; + any decimal from 1 to 16 can be used to specify the bit depth. + + When a 2-dimensional array is used *mode* determines how many + channels the image has, and so allows the width to be derived from + the second array dimension. + + The array is expected to be a ``numpy`` array, but it can be any + suitable Python sequence. For example, a list of lists can be used: + ``png.from_array([[0, 255, 0], [255, 0, 255]], 'L')``. The exact + rules are: ``len(a)`` gives the first dimension, height; + ``len(a[0])`` gives the second dimension; ``len(a[0][0])`` gives the + third dimension, unless an exception is raised in which case a + 2-dimensional array is assumed. It's slightly more complicated than + that because an iterator of rows can be used, and it all still + works. Using an iterator allows data to be streamed efficiently. + + The bit depth of the PNG is normally taken from the array element's + datatype (but if *mode* specifies a bitdepth then that is used + instead). The array element's datatype is determined in a way which + is supposed to work both for ``numpy`` arrays and for Python + ``array.array`` objects. A 1 byte datatype will give a bit depth of + 8, a 2 byte datatype will give a bit depth of 16. If the datatype + does not have an implicit size, for example it is a plain Python + list of lists, as above, then a default of 8 is used. + + The *info* parameter is a dictionary that can be used to specify + metadata (in the same style as the arguments to the + :class:``png.Writer`` class). For this function the keys that are + useful are: + + height + overrides the height derived from the array dimensions and allows + *a* to be an iterable. + width + overrides the width derived from the array dimensions. + bitdepth + overrides the bit depth derived from the element datatype (but + must match *mode* if that also specifies a bit depth). + + Generally anything specified in the + *info* dictionary will override any implicit choices that this + function would otherwise make, but must match any explicit ones. + For example, if the *info* dictionary has a ``greyscale`` key then + this must be true when mode is ``'L'`` or ``'LA'`` and false when + mode is ``'RGB'`` or ``'RGBA'``. + """ + + # We abuse the *info* parameter by modifying it. Take a copy here. + # (Also typechecks *info* to some extent). + info = dict(info) + + # Syntax check mode string. + bitdepth = None + try: + # Assign the 'L' or 'RGBA' part to `gotmode`. + if mode.startswith('L'): + gotmode = 'L' + mode = mode[1:] + elif mode.startswith('RGB'): + gotmode = 'RGB' + mode = mode[3:] + else: + raise Error() + if mode.startswith('A'): + gotmode += 'A' + mode = mode[1:] + + # Skip any optional ';' + while mode.startswith(';'): + mode = mode[1:] + + # Parse optional bitdepth + if mode: + try: + bitdepth = int(mode) + except (TypeError, ValueError): + raise Error() + except Error: + raise Error("mode string should be 'RGB' or 'L;16' or similar.") + mode = gotmode + + # Get bitdepth from *mode* if possible. + if bitdepth: + if info.get('bitdepth') and bitdepth != info['bitdepth']: + raise Error("mode bitdepth (%d) should match info bitdepth (%d)." % + (bitdepth, info['bitdepth'])) + info['bitdepth'] = bitdepth + + # Fill in and/or check entries in *info*. + # Dimensions. + if 'size' in info: + # Check width, height, size all match where used. + for dimension,axis in [('width', 0), ('height', 1)]: + if dimension in info: + if info[dimension] != info['size'][axis]: + raise Error( + "info[%r] should match info['size'][%r]." % + (dimension, axis)) + info['width'],info['height'] = info['size'] + if 'height' not in info: + try: + l = len(a) + except TypeError: + raise Error( + "len(a) does not work, supply info['height'] instead.") + info['height'] = l + # Colour format. + if 'greyscale' in info: + if bool(info['greyscale']) != ('L' in mode): + raise Error("info['greyscale'] should match mode.") + info['greyscale'] = 'L' in mode + if 'alpha' in info: + if bool(info['alpha']) != ('A' in mode): + raise Error("info['alpha'] should match mode.") + info['alpha'] = 'A' in mode + + planes = len(mode) + if 'planes' in info: + if info['planes'] != planes: + raise Error("info['planes'] should match mode.") + + # In order to work out whether we the array is 2D or 3D we need its + # first row, which requires that we take a copy of its iterator. + # We may also need the first row to derive width and bitdepth. + a,t = itertools.tee(a) + row = t.next() + del t + try: + row[0][0] + threed = True + testelement = row[0] + except (IndexError, TypeError): + threed = False + testelement = row + if 'width' not in info: + if threed: + width = len(row) + else: + width = len(row) // planes + info['width'] = width + + # Not implemented yet + assert not threed + + if 'bitdepth' not in info: + try: + dtype = testelement.dtype + # goto the "else:" clause. Sorry. + except AttributeError: + try: + # Try a Python array.array. + bitdepth = 8 * testelement.itemsize + except AttributeError: + # We can't determine it from the array element's + # datatype, use a default of 8. + bitdepth = 8 + else: + # If we got here without exception, we now assume that + # the array is a numpy array. + if dtype.kind == 'b': + bitdepth = 1 + else: + bitdepth = 8 * dtype.itemsize + info['bitdepth'] = bitdepth + + for thing in 'width height bitdepth greyscale alpha'.split(): + assert thing in info + return Image(a, info) + +# So that refugee's from PIL feel more at home. Not documented. +fromarray = from_array + +class Image: + """A PNG image. You can create an :class:`Image` object from + an array of pixels by calling :meth:`png.from_array`. It can be + saved to disk with the :meth:`save` method. + """ + + def __init__(self, rows, info): + """ + .. note :: + + The constructor is not public. Please do not call it. + """ + + self.rows = rows + self.info = info + + def save(self, file): + """Save the image to *file*. If *file* looks like an open file + descriptor then it is used, otherwise it is treated as a + filename and a fresh file is opened. + + In general, you can only call this method once; after it has + been called the first time and the PNG image has been saved, the + source data will have been streamed, and cannot be streamed + again. + """ + + w = Writer(**self.info) + + try: + file.write + def close(): pass + except AttributeError: + file = open(file, 'wb') + def close(): file.close() + + try: + w.write(file, self.rows) + finally: + close() + +class _readable: + """ + A simple file-like interface for strings and arrays. + """ + + def __init__(self, buf): + self.buf = buf + self.offset = 0 + + def read(self, n): + r = self.buf[self.offset:self.offset+n] + if isarray(r): + r = r.tostring() + self.offset += n + return r + + +class Reader: + """ + PNG decoder in pure Python. + """ + + def __init__(self, _guess=None, **kw): + """ + Create a PNG decoder object. + + The constructor expects exactly one keyword argument. If you + supply a positional argument instead, it will guess the input + type. You can choose among the following keyword arguments: + + filename + Name of input file (a PNG file). + file + A file-like object (object with a read() method). + bytes + ``array`` or ``string`` with PNG data. + + """ + if ((_guess is not None and len(kw) != 0) or + (_guess is None and len(kw) != 1)): + raise TypeError("Reader() takes exactly 1 argument") + + # Will be the first 8 bytes, later on. See validate_signature. + self.signature = None + self.transparent = None + # A pair of (len,type) if a chunk has been read but its data and + # checksum have not (in other words the file position is just + # past the 4 bytes that specify the chunk type). See preamble + # method for how this is used. + self.atchunk = None + + if _guess is not None: + if isarray(_guess): + kw["bytes"] = _guess + elif isinstance(_guess, str): + kw["filename"] = _guess + elif hasattr(_guess, 'read'): + kw["file"] = _guess + + if "filename" in kw: + self.file = open(kw["filename"], "rb") + elif "file" in kw: + self.file = kw["file"] + elif "bytes" in kw: + self.file = _readable(kw["bytes"]) + else: + raise TypeError("expecting filename, file or bytes array") + + + def chunk(self, seek=None, lenient=False): + """ + Read the next PNG chunk from the input file; returns a + (*type*,*data*) tuple. *type* is the chunk's type as a string + (all PNG chunk types are 4 characters long). *data* is the + chunk's data content, as a string. + + If the optional `seek` argument is + specified then it will keep reading chunks until it either runs + out of file or finds the type specified by the argument. Note + that in general the order of chunks in PNGs is unspecified, so + using `seek` can cause you to miss chunks. + + If the optional `lenient` argument evaluates to True, + checksum failures will raise warnings rather than exceptions. + """ + + self.validate_signature() + + while True: + # http://www.w3.org/TR/PNG/#5Chunk-layout + if not self.atchunk: + self.atchunk = self.chunklentype() + length,type = self.atchunk + self.atchunk = None + data = self.file.read(length) + if len(data) != length: + raise ChunkError('Chunk %s too short for required %i octets.' + % (type, length)) + checksum = self.file.read(4) + if len(checksum) != 4: + raise ValueError('Chunk %s too short for checksum.', tag) + if seek and type != seek: + continue + verify = zlib.crc32(strtobytes(type)) + verify = zlib.crc32(data, verify) + # Whether the output from zlib.crc32 is signed or not varies + # according to hideous implementation details, see + # http://bugs.python.org/issue1202 . + # We coerce it to be positive here (in a way which works on + # Python 2.3 and older). + verify &= 2**32 - 1 + verify = struct.pack('!I', verify) + if checksum != verify: + (a, ) = struct.unpack('!I', checksum) + (b, ) = struct.unpack('!I', verify) + message = "Checksum error in %s chunk: 0x%08X != 0x%08X." % (type, a, b) + if lenient: + warnings.warn(message, RuntimeWarning) + else: + raise ChunkError(message) + return type, data + + def chunks(self): + """Return an iterator that will yield each chunk as a + (*chunktype*, *content*) pair. + """ + + while True: + t,v = self.chunk() + yield t,v + if t == 'IEND': + break + + def undo_filter(self, filter_type, scanline, previous): + """Undo the filter for a scanline. `scanline` is a sequence of + bytes that does not include the initial filter type byte. + `previous` is decoded previous scanline (for straightlaced + images this is the previous pixel row, but for interlaced + images, it is the previous scanline in the reduced image, which + in general is not the previous pixel row in the final image). + When there is no previous scanline (the first row of a + straightlaced image, or the first row in one of the passes in an + interlaced image), then this argument should be ``None``. + + The scanline will have the effects of filtering removed, and the + result will be returned as a fresh sequence of bytes. + """ + + # :todo: Would it be better to update scanline in place? + # Yes, with the Cython extension making the undo_filter fast, + # updating scanline inplace makes the code 3 times faster + # (reading 50 images of 800x800 went from 40s to 16s) + result = scanline + + if filter_type == 0: + return result + + if filter_type not in (1,2,3,4): + raise FormatError('Invalid PNG Filter Type.' + ' See http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters .') + + # Filter unit. The stride from one pixel to the corresponding + # byte from the previous pixel. Normally this is the pixel + # size in bytes, but when this is smaller than 1, the previous + # byte is used instead. + fu = max(1, self.psize) + + # For the first line of a pass, synthesize a dummy previous + # line. An alternative approach would be to observe that on the + # first line 'up' is the same as 'null', 'paeth' is the same + # as 'sub', with only 'average' requiring any special case. + if not previous: + previous = array('B', [0]*len(scanline)) + + def sub(): + """Undo sub filter.""" + + ai = 0 + # Loop starts at index fu. Observe that the initial part + # of the result is already filled in correctly with + # scanline. + for i in range(fu, len(result)): + x = scanline[i] + a = result[ai] + result[i] = (x + a) & 0xff + ai += 1 + + def up(): + """Undo up filter.""" + + for i in range(len(result)): + x = scanline[i] + b = previous[i] + result[i] = (x + b) & 0xff + + def average(): + """Undo average filter.""" + + ai = -fu + for i in range(len(result)): + x = scanline[i] + if ai < 0: + a = 0 + else: + a = result[ai] + b = previous[i] + result[i] = (x + ((a + b) >> 1)) & 0xff + ai += 1 + + def paeth(): + """Undo Paeth filter.""" + + # Also used for ci. + ai = -fu + for i in range(len(result)): + x = scanline[i] + if ai < 0: + a = c = 0 + else: + a = result[ai] + c = previous[ai] + b = previous[i] + p = a + b - c + pa = abs(p - a) + pb = abs(p - b) + pc = abs(p - c) + if pa <= pb and pa <= pc: + pr = a + elif pb <= pc: + pr = b + else: + pr = c + result[i] = (x + pr) & 0xff + ai += 1 + + # Call appropriate filter algorithm. Note that 0 has already + # been dealt with. + (None, + pngfilters.undo_filter_sub, + pngfilters.undo_filter_up, + pngfilters.undo_filter_average, + pngfilters.undo_filter_paeth)[filter_type](fu, scanline, previous, result) + return result + + def deinterlace(self, raw): + """ + Read raw pixel data, undo filters, deinterlace, and flatten. + Return in flat row flat pixel format. + """ + + # Values per row (of the target image) + vpr = self.width * self.planes + + # Make a result array, and make it big enough. Interleaving + # writes to the output array randomly (well, not quite), so the + # entire output array must be in memory. + fmt = 'BH'[self.bitdepth > 8] + a = array(fmt, [0]*vpr*self.height) + source_offset = 0 + + for xstart, ystart, xstep, ystep in _adam7: + if xstart >= self.width: + continue + # The previous (reconstructed) scanline. None at the + # beginning of a pass to indicate that there is no previous + # line. + recon = None + # Pixels per row (reduced pass image) + ppr = int(math.ceil((self.width-xstart)/float(xstep))) + # Row size in bytes for this pass. + row_size = int(math.ceil(self.psize * ppr)) + for y in range(ystart, self.height, ystep): + filter_type = raw[source_offset] + source_offset += 1 + scanline = raw[source_offset:source_offset+row_size] + source_offset += row_size + recon = self.undo_filter(filter_type, scanline, recon) + # Convert so that there is one element per pixel value + flat = self.serialtoflat(recon, ppr) + if xstep == 1: + assert xstart == 0 + offset = y * vpr + a[offset:offset+vpr] = flat + else: + offset = y * vpr + xstart * self.planes + end_offset = (y+1) * vpr + skip = self.planes * xstep + for i in range(self.planes): + a[offset+i:end_offset:skip] = \ + flat[i::self.planes] + return a + + def iterboxed(self, rows): + """Iterator that yields each scanline in boxed row flat pixel + format. `rows` should be an iterator that yields the bytes of + each row in turn. + """ + + def asvalues(raw): + """Convert a row of raw bytes into a flat row. Result may + or may not share with argument""" + + if self.bitdepth == 8: + return raw + if self.bitdepth == 16: + raw = tostring(raw) + return array('H', struct.unpack('!%dH' % (len(raw)//2), raw)) + assert self.bitdepth < 8 + width = self.width + # Samples per byte + spb = 8//self.bitdepth + out = array('B') + mask = 2**self.bitdepth - 1 + shifts = map(self.bitdepth.__mul__, reversed(range(spb))) + for o in raw: + out.extend(map(lambda i: mask&(o>>i), shifts)) + return out[:width] + + return map(asvalues, rows) + + def serialtoflat(self, bytes, width=None): + """Convert serial format (byte stream) pixel data to flat row + flat pixel. + """ + + if self.bitdepth == 8: + return bytes + if self.bitdepth == 16: + bytes = tostring(bytes) + return array('H', + struct.unpack('!%dH' % (len(bytes)//2), bytes)) + assert self.bitdepth < 8 + if width is None: + width = self.width + # Samples per byte + spb = 8//self.bitdepth + out = array('B') + mask = 2**self.bitdepth - 1 + shifts = map(self.bitdepth.__mul__, reversed(range(spb))) + l = width + for o in bytes: + out.extend([(mask&(o>>s)) for s in shifts][:l]) + l -= spb + if l <= 0: + l = width + return out + + def iterstraight(self, raw): + """Iterator that undoes the effect of filtering, and yields + each row in serialised format (as a sequence of bytes). + Assumes input is straightlaced. `raw` should be an iterable + that yields the raw bytes in chunks of arbitrary size. + """ + + # length of row, in bytes + rb = self.row_bytes + a = array('B') + # The previous (reconstructed) scanline. None indicates first + # line of image. + recon = None + for some in raw: + a.extend(some) + while len(a) >= rb + 1: + filter_type = a[0] + scanline = a[1:rb+1] + del a[:rb+1] + recon = self.undo_filter(filter_type, scanline, recon) + yield recon + if len(a) != 0: + # :file:format We get here with a file format error: + # when the available bytes (after decompressing) do not + # pack into exact rows. + raise FormatError( + 'Wrong size for decompressed IDAT chunk.') + assert len(a) == 0 + + def validate_signature(self): + """If signature (header) has not been read then read and + validate it; otherwise do nothing. + """ + + if self.signature: + return + self.signature = self.file.read(8) + if self.signature != _signature: + raise FormatError("PNG file has invalid signature.") + + def preamble(self, lenient=False): + """ + Extract the image metadata by reading the initial part of + the PNG file up to the start of the ``IDAT`` chunk. All the + chunks that precede the ``IDAT`` chunk are read and either + processed for metadata or discarded. + + If the optional `lenient` argument evaluates to True, checksum + failures will raise warnings rather than exceptions. + """ + + self.validate_signature() + + while True: + if not self.atchunk: + self.atchunk = self.chunklentype() + if self.atchunk is None: + raise FormatError( + 'This PNG file has no IDAT chunks.') + if self.atchunk[1] == 'IDAT': + return + self.process_chunk(lenient=lenient) + + def chunklentype(self): + """Reads just enough of the input to determine the next + chunk's length and type, returned as a (*length*, *type*) pair + where *type* is a string. If there are no more chunks, ``None`` + is returned. + """ + + x = self.file.read(8) + if not x: + return None + if len(x) != 8: + raise FormatError( + 'End of file whilst reading chunk length and type.') + length,type = struct.unpack('!I4s', x) + type = bytestostr(type) + if length > 2**31-1: + raise FormatError('Chunk %s is too large: %d.' % (type,length)) + return length,type + + def process_chunk(self, lenient=False): + """Process the next chunk and its data. This only processes the + following chunk types, all others are ignored: ``IHDR``, + ``PLTE``, ``bKGD``, ``tRNS``, ``gAMA``, ``sBIT``. + + If the optional `lenient` argument evaluates to True, + checksum failures will raise warnings rather than exceptions. + """ + + type, data = self.chunk(lenient=lenient) + method = '_process_' + type + m = getattr(self, method, None) + if m: + m(data) + + def _process_IHDR(self, data): + # http://www.w3.org/TR/PNG/#11IHDR + if len(data) != 13: + raise FormatError('IHDR chunk has incorrect length.') + (self.width, self.height, self.bitdepth, self.color_type, + self.compression, self.filter, + self.interlace) = struct.unpack("!2I5B", data) + + check_bitdepth_colortype(self.bitdepth, self.color_type) + + if self.compression != 0: + raise Error("unknown compression method %d" % self.compression) + if self.filter != 0: + raise FormatError("Unknown filter method %d," + " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ." + % self.filter) + if self.interlace not in (0,1): + raise FormatError("Unknown interlace method %d," + " see http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods ." + % self.interlace) + + # Derived values + # http://www.w3.org/TR/PNG/#6Colour-values + colormap = bool(self.color_type & 1) + greyscale = not (self.color_type & 2) + alpha = bool(self.color_type & 4) + color_planes = (3,1)[greyscale or colormap] + planes = color_planes + alpha + + self.colormap = colormap + self.greyscale = greyscale + self.alpha = alpha + self.color_planes = color_planes + self.planes = planes + self.psize = float(self.bitdepth)/float(8) * planes + if int(self.psize) == self.psize: + self.psize = int(self.psize) + self.row_bytes = int(math.ceil(self.width * self.psize)) + # Stores PLTE chunk if present, and is used to check + # chunk ordering constraints. + self.plte = None + # Stores tRNS chunk if present, and is used to check chunk + # ordering constraints. + self.trns = None + # Stores sbit chunk if present. + self.sbit = None + + def _process_PLTE(self, data): + # http://www.w3.org/TR/PNG/#11PLTE + if self.plte: + warnings.warn("Multiple PLTE chunks present.") + self.plte = data + if len(data) % 3 != 0: + raise FormatError( + "PLTE chunk's length should be a multiple of 3.") + if len(data) > (2**self.bitdepth)*3: + raise FormatError("PLTE chunk is too long.") + if len(data) == 0: + raise FormatError("Empty PLTE is not allowed.") + + def _process_bKGD(self, data): + try: + if self.colormap: + if not self.plte: + warnings.warn( + "PLTE chunk is required before bKGD chunk.") + self.background = struct.unpack('B', data) + else: + self.background = struct.unpack("!%dH" % self.color_planes, + data) + except struct.error: + raise FormatError("bKGD chunk has incorrect length.") + + def _process_tRNS(self, data): + # http://www.w3.org/TR/PNG/#11tRNS + self.trns = data + if self.colormap: + if not self.plte: + warnings.warn("PLTE chunk is required before tRNS chunk.") + else: + if len(data) > len(self.plte)/3: + # Was warning, but promoted to Error as it + # would otherwise cause pain later on. + raise FormatError("tRNS chunk is too long.") + else: + if self.alpha: + raise FormatError( + "tRNS chunk is not valid with colour type %d." % + self.color_type) + try: + self.transparent = \ + struct.unpack("!%dH" % self.color_planes, data) + except struct.error: + raise FormatError("tRNS chunk has incorrect length.") + + def _process_gAMA(self, data): + try: + self.gamma = struct.unpack("!L", data)[0] / 100000.0 + except struct.error: + raise FormatError("gAMA chunk has incorrect length.") + + def _process_sBIT(self, data): + self.sbit = data + if (self.colormap and len(data) != 3 or + not self.colormap and len(data) != self.planes): + raise FormatError("sBIT chunk has incorrect length.") + + def read(self, lenient=False): + """ + Read the PNG file and decode it. Returns (`width`, `height`, + `pixels`, `metadata`). + + May use excessive memory. + + `pixels` are returned in boxed row flat pixel format. + + If the optional `lenient` argument evaluates to True, + checksum failures will raise warnings rather than exceptions. + """ + + def iteridat(): + """Iterator that yields all the ``IDAT`` chunks as strings.""" + while True: + try: + type, data = self.chunk(lenient=lenient) + except ValueError as e: + raise ChunkError(e.args[0]) + if type == 'IEND': + # http://www.w3.org/TR/PNG/#11IEND + break + if type != 'IDAT': + continue + # type == 'IDAT' + # http://www.w3.org/TR/PNG/#11IDAT + if self.colormap and not self.plte: + warnings.warn("PLTE chunk is required before IDAT chunk") + yield data + + def iterdecomp(idat): + """Iterator that yields decompressed strings. `idat` should + be an iterator that yields the ``IDAT`` chunk data. + """ + + # Currently, with no max_length paramter to decompress, this + # routine will do one yield per IDAT chunk. So not very + # incremental. + d = zlib.decompressobj() + # Each IDAT chunk is passed to the decompressor, then any + # remaining state is decompressed out. + for data in idat: + # :todo: add a max_length argument here to limit output + # size. + yield array('B', d.decompress(data)) + yield array('B', d.flush()) + + self.preamble(lenient=lenient) + raw = iterdecomp(iteridat()) + + if self.interlace: + raw = array('B', itertools.chain(*raw)) + arraycode = 'BH'[self.bitdepth>8] + # Like :meth:`group` but producing an array.array object for + # each row. + pixels = itertools.imap(lambda *row: array(arraycode, row), + *[iter(self.deinterlace(raw))]*self.width*self.planes) + else: + pixels = self.iterboxed(self.iterstraight(raw)) + meta = dict() + for attr in 'greyscale alpha planes bitdepth interlace'.split(): + meta[attr] = getattr(self, attr) + meta['size'] = (self.width, self.height) + for attr in 'gamma transparent background'.split(): + a = getattr(self, attr, None) + if a is not None: + meta[attr] = a + if self.plte: + meta['palette'] = self.palette() + return self.width, self.height, pixels, meta + + + def read_flat(self): + """ + Read a PNG file and decode it into flat row flat pixel format. + Returns (*width*, *height*, *pixels*, *metadata*). + + May use excessive memory. + + `pixels` are returned in flat row flat pixel format. + + See also the :meth:`read` method which returns pixels in the + more stream-friendly boxed row flat pixel format. + """ + + x, y, pixel, meta = self.read() + arraycode = 'BH'[meta['bitdepth']>8] + pixel = array(arraycode, itertools.chain(*pixel)) + self.file.close() + return x, y, pixel, meta + + def palette(self, alpha='natural'): + """Returns a palette that is a sequence of 3-tuples or 4-tuples, + synthesizing it from the ``PLTE`` and ``tRNS`` chunks. These + chunks should have already been processed (for example, by + calling the :meth:`preamble` method). All the tuples are the + same size: 3-tuples if there is no ``tRNS`` chunk, 4-tuples when + there is a ``tRNS`` chunk. Assumes that the image is colour type + 3 and therefore a ``PLTE`` chunk is required. + + If the `alpha` argument is ``'force'`` then an alpha channel is + always added, forcing the result to be a sequence of 4-tuples. + """ + + if not self.plte: + raise FormatError( + "Required PLTE chunk is missing in colour type 3 image.") + plte = group(array('B', self.plte), 3) + if self.trns or alpha == 'force': + trns = array('B', self.trns or '') + trns.extend([255]*(len(plte)-len(trns))) + plte = map(operator.add, plte, group(trns, 1)) + return plte + + def asDirect(self): + """Returns the image data as a direct representation of an + ``x * y * planes`` array. This method is intended to remove the + need for callers to deal with palettes and transparency + themselves. Images with a palette (colour type 3) + are converted to RGB or RGBA; images with transparency (a + ``tRNS`` chunk) are converted to LA or RGBA as appropriate. + When returned in this format the pixel values represent the + colour value directly without needing to refer to palettes or + transparency information. + + Like the :meth:`read` method this method returns a 4-tuple: + + (*width*, *height*, *pixels*, *meta*) + + This method normally returns pixel values with the bit depth + they have in the source image, but when the source PNG has an + ``sBIT`` chunk it is inspected and can reduce the bit depth of + the result pixels; pixel values will be reduced according to + the bit depth specified in the ``sBIT`` chunk (PNG nerds should + note a single result bit depth is used for all channels; the + maximum of the ones specified in the ``sBIT`` chunk. An RGB565 + image will be rescaled to 6-bit RGB666). + + The *meta* dictionary that is returned reflects the `direct` + format and not the original source image. For example, an RGB + source image with a ``tRNS`` chunk to represent a transparent + colour, will have ``planes=3`` and ``alpha=False`` for the + source image, but the *meta* dictionary returned by this method + will have ``planes=4`` and ``alpha=True`` because an alpha + channel is synthesized and added. + + *pixels* is the pixel data in boxed row flat pixel format (just + like the :meth:`read` method). + + All the other aspects of the image data are not changed. + """ + + self.preamble() + + # Simple case, no conversion necessary. + if not self.colormap and not self.trns and not self.sbit: + return self.read() + + x,y,pixels,meta = self.read() + + if self.colormap: + meta['colormap'] = False + meta['alpha'] = bool(self.trns) + meta['bitdepth'] = 8 + meta['planes'] = 3 + bool(self.trns) + plte = self.palette() + def iterpal(pixels): + for row in pixels: + row = map(plte.__getitem__, row) + yield array('B', itertools.chain(*row)) + pixels = iterpal(pixels) + elif self.trns: + # It would be nice if there was some reasonable way + # of doing this without generating a whole load of + # intermediate tuples. But tuples does seem like the + # easiest way, with no other way clearly much simpler or + # much faster. (Actually, the L to LA conversion could + # perhaps go faster (all those 1-tuples!), but I still + # wonder whether the code proliferation is worth it) + it = self.transparent + maxval = 2**meta['bitdepth']-1 + planes = meta['planes'] + meta['alpha'] = True + meta['planes'] += 1 + typecode = 'BH'[meta['bitdepth']>8] + def itertrns(pixels): + for row in pixels: + # For each row we group it into pixels, then form a + # characterisation vector that says whether each + # pixel is opaque or not. Then we convert + # True/False to 0/maxval (by multiplication), + # and add it as the extra channel. + row = group(row, planes) + opa = map(it.__ne__, row) + opa = map(maxval.__mul__, opa) + opa = zip(opa) # convert to 1-tuples + yield array(typecode, + itertools.chain(*map(operator.add, row, opa))) + pixels = itertrns(pixels) + targetbitdepth = None + if self.sbit: + sbit = struct.unpack('%dB' % len(self.sbit), self.sbit) + targetbitdepth = max(sbit) + if targetbitdepth > meta['bitdepth']: + raise Error('sBIT chunk %r exceeds bitdepth %d' % + (sbit,self.bitdepth)) + if min(sbit) <= 0: + raise Error('sBIT chunk %r has a 0-entry' % sbit) + if targetbitdepth == meta['bitdepth']: + targetbitdepth = None + if targetbitdepth: + shift = meta['bitdepth'] - targetbitdepth + meta['bitdepth'] = targetbitdepth + def itershift(pixels): + for row in pixels: + yield map(shift.__rrshift__, row) + pixels = itershift(pixels) + return x,y,pixels,meta + + def asFloat(self, maxval=1.0): + """Return image pixels as per :meth:`asDirect` method, but scale + all pixel values to be floating point values between 0.0 and + *maxval*. + """ + + x,y,pixels,info = self.asDirect() + sourcemaxval = 2**info['bitdepth']-1 + del info['bitdepth'] + info['maxval'] = float(maxval) + factor = float(maxval)/float(sourcemaxval) + def iterfloat(): + for row in pixels: + yield map(factor.__mul__, row) + return x,y,iterfloat(),info + + def _as_rescale(self, get, targetbitdepth): + """Helper used by :meth:`asRGB8` and :meth:`asRGBA8`.""" + + width,height,pixels,meta = get() + maxval = 2**meta['bitdepth'] - 1 + targetmaxval = 2**targetbitdepth - 1 + factor = float(targetmaxval) / float(maxval) + meta['bitdepth'] = targetbitdepth + def iterscale(): + for row in pixels: + yield map(lambda x: int(round(x*factor)), row) + if maxval == targetmaxval: + return width, height, pixels, meta + else: + return width, height, iterscale(), meta + + def asRGB8(self): + """Return the image data as an RGB pixels with 8-bits per + sample. This is like the :meth:`asRGB` method except that + this method additionally rescales the values so that they + are all between 0 and 255 (8-bit). In the case where the + source image has a bit depth < 8 the transformation preserves + all the information; where the source image has bit depth + > 8, then rescaling to 8-bit values loses precision. No + dithering is performed. Like :meth:`asRGB`, an alpha channel + in the source image will raise an exception. + + This function returns a 4-tuple: + (*width*, *height*, *pixels*, *metadata*). + *width*, *height*, *metadata* are as per the + :meth:`read` method. + + *pixels* is the pixel data in boxed row flat pixel format. + """ + + return self._as_rescale(self.asRGB, 8) + + def asRGBA8(self): + """Return the image data as RGBA pixels with 8-bits per + sample. This method is similar to :meth:`asRGB8` and + :meth:`asRGBA`: The result pixels have an alpha channel, *and* + values are rescaled to the range 0 to 255. The alpha channel is + synthesized if necessary (with a small speed penalty). + """ + + return self._as_rescale(self.asRGBA, 8) + + def asRGB(self): + """Return image as RGB pixels. RGB colour images are passed + through unchanged; greyscales are expanded into RGB + triplets (there is a small speed overhead for doing this). + + An alpha channel in the source image will raise an + exception. + + The return values are as for the :meth:`read` method + except that the *metadata* reflect the returned pixels, not the + source image. In particular, for this method + ``metadata['greyscale']`` will be ``False``. + """ + + width,height,pixels,meta = self.asDirect() + if meta['alpha']: + raise Error("will not convert image with alpha channel to RGB") + if not meta['greyscale']: + return width,height,pixels,meta + meta['greyscale'] = False + typecode = 'BH'[meta['bitdepth'] > 8] + def iterrgb(): + for row in pixels: + a = array(typecode, [0]) * 3 * width + for i in range(3): + a[i::3] = row + yield a + return width,height,iterrgb(),meta + + def asRGBA(self): + """Return image as RGBA pixels. Greyscales are expanded into + RGB triplets; an alpha channel is synthesized if necessary. + The return values are as for the :meth:`read` method + except that the *metadata* reflect the returned pixels, not the + source image. In particular, for this method + ``metadata['greyscale']`` will be ``False``, and + ``metadata['alpha']`` will be ``True``. + """ + + width,height,pixels,meta = self.asDirect() + if meta['alpha'] and not meta['greyscale']: + return width,height,pixels,meta + typecode = 'BH'[meta['bitdepth'] > 8] + maxval = 2**meta['bitdepth'] - 1 + maxbuffer = struct.pack('=' + typecode, maxval) * 4 * width + def newarray(): + return array(typecode, maxbuffer) + + if meta['alpha'] and meta['greyscale']: + # LA to RGBA + def convert(): + for row in pixels: + # Create a fresh target row, then copy L channel + # into first three target channels, and A channel + # into fourth channel. + a = newarray() + pngfilters.convert_la_to_rgba(row, a) + yield a + elif meta['greyscale']: + # L to RGBA + def convert(): + for row in pixels: + a = newarray() + pngfilters.convert_l_to_rgba(row, a) + yield a + else: + assert not meta['alpha'] and not meta['greyscale'] + # RGB to RGBA + def convert(): + for row in pixels: + a = newarray() + pngfilters.convert_rgb_to_rgba(row, a) + yield a + meta['alpha'] = True + meta['greyscale'] = False + return width,height,convert(),meta + +def check_bitdepth_colortype(bitdepth, colortype): + """Check that `bitdepth` and `colortype` are both valid, + and specified in a valid combination. Returns if valid, + raise an Exception if not valid. + """ + + if bitdepth not in (1,2,4,8,16): + raise FormatError("invalid bit depth %d" % bitdepth) + if colortype not in (0,2,3,4,6): + raise FormatError("invalid colour type %d" % colortype) + # Check indexed (palettized) images have 8 or fewer bits + # per pixel; check only indexed or greyscale images have + # fewer than 8 bits per pixel. + if colortype & 1 and bitdepth > 8: + raise FormatError( + "Indexed images (colour type %d) cannot" + " have bitdepth > 8 (bit depth %d)." + " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ." + % (bitdepth, colortype)) + if bitdepth < 8 and colortype not in (0,3): + raise FormatError("Illegal combination of bit depth (%d)" + " and colour type (%d)." + " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ." + % (bitdepth, colortype)) + +def isinteger(x): + try: + return int(x) == x + except (TypeError, ValueError): + return False + + +# === Legacy Version Support === + +# :pyver:old: PyPNG works on Python versions 2.3 and 2.2, but not +# without some awkward problems. Really PyPNG works on Python 2.4 (and +# above); it works on Pythons 2.3 and 2.2 by virtue of fixing up +# problems here. It's a bit ugly (which is why it's hidden down here). +# +# Generally the strategy is one of pretending that we're running on +# Python 2.4 (or above), and patching up the library support on earlier +# versions so that it looks enough like Python 2.4. When it comes to +# Python 2.2 there is one thing we cannot patch: extended slices +# http://www.python.org/doc/2.3/whatsnew/section-slices.html. +# Instead we simply declare that features that are implemented using +# extended slices will not work on Python 2.2. +# +# In order to work on Python 2.3 we fix up a recurring annoyance involving +# the array type. In Python 2.3 an array cannot be initialised with an +# array, and it cannot be extended with a list (or other sequence). +# Both of those are repeated issues in the code. Whilst I would not +# normally tolerate this sort of behaviour, here we "shim" a replacement +# for array into place (and hope no-one notices). You never read this. +# +# In an amusing case of warty hacks on top of warty hacks... the array +# shimming we try and do only works on Python 2.3 and above (you can't +# subclass array.array in Python 2.2). So to get it working on Python +# 2.2 we go for something much simpler and (probably) way slower. +try: + array('B').extend([]) + array('B', array('B')) +# :todo:(drj) Check that TypeError is correct for Python 2.3 +except TypeError: + # Expect to get here on Python 2.3 + try: + class _array_shim(array): + true_array = array + def __new__(cls, typecode, init=None): + super_new = super(_array_shim, cls).__new__ + it = super_new(cls, typecode) + if init is None: + return it + it.extend(init) + return it + def extend(self, extension): + super_extend = super(_array_shim, self).extend + if isinstance(extension, self.true_array): + return super_extend(extension) + if not isinstance(extension, (list, str)): + # Convert to list. Allows iterators to work. + extension = list(extension) + return super_extend(self.true_array(self.typecode, extension)) + array = _array_shim + except TypeError: + # Expect to get here on Python 2.2 + def array(typecode, init=()): + if type(init) == str: + return map(ord, init) + return list(init) + +# Further hacks to get it limping along on Python 2.2 +try: + enumerate +except NameError: + def enumerate(seq): + i=0 + for x in seq: + yield i,x + i += 1 + +try: + reversed +except NameError: + def reversed(l): + l = list(l) + l.reverse() + for x in l: + yield x + +try: + itertools +except NameError: + class _dummy_itertools: + pass + itertools = _dummy_itertools() + def _itertools_imap(f, seq): + for x in seq: + yield f(x) + itertools.imap = _itertools_imap + def _itertools_chain(*iterables): + for it in iterables: + for element in it: + yield element + itertools.chain = _itertools_chain + + +# === Support for users without Cython === + +try: + pngfilters +except NameError: + class pngfilters(object): + def undo_filter_sub(filter_unit, scanline, previous, result): + """Undo sub filter.""" + + ai = 0 + # Loops starts at index fu. Observe that the initial part + # of the result is already filled in correctly with + # scanline. + for i in range(filter_unit, len(result)): + x = scanline[i] + a = result[ai] + result[i] = (x + a) & 0xff + ai += 1 + undo_filter_sub = staticmethod(undo_filter_sub) + + def undo_filter_up(filter_unit, scanline, previous, result): + """Undo up filter.""" + + for i in range(len(result)): + x = scanline[i] + b = previous[i] + result[i] = (x + b) & 0xff + undo_filter_up = staticmethod(undo_filter_up) + + def undo_filter_average(filter_unit, scanline, previous, result): + """Undo up filter.""" + + ai = -filter_unit + for i in range(len(result)): + x = scanline[i] + if ai < 0: + a = 0 + else: + a = result[ai] + b = previous[i] + result[i] = (x + ((a + b) >> 1)) & 0xff + ai += 1 + undo_filter_average = staticmethod(undo_filter_average) + + def undo_filter_paeth(filter_unit, scanline, previous, result): + """Undo Paeth filter.""" + + # Also used for ci. + ai = -filter_unit + for i in range(len(result)): + x = scanline[i] + if ai < 0: + a = c = 0 + else: + a = result[ai] + c = previous[ai] + b = previous[i] + p = a + b - c + pa = abs(p - a) + pb = abs(p - b) + pc = abs(p - c) + if pa <= pb and pa <= pc: + pr = a + elif pb <= pc: + pr = b + else: + pr = c + result[i] = (x + pr) & 0xff + ai += 1 + undo_filter_paeth = staticmethod(undo_filter_paeth) + + def convert_la_to_rgba(row, result): + for i in range(3): + result[i::4] = row[0::2] + result[3::4] = row[1::2] + convert_la_to_rgba = staticmethod(convert_la_to_rgba) + + def convert_l_to_rgba(row, result): + """Convert a grayscale image to RGBA. This method assumes + the alpha channel in result is already correctly + initialized. + """ + for i in range(3): + result[i::4] = row + convert_l_to_rgba = staticmethod(convert_l_to_rgba) + + def convert_rgb_to_rgba(row, result): + """Convert an RGB image to RGBA. This method assumes the + alpha channel in result is already correctly initialized. + """ + for i in range(3): + result[i::4] = row[i::3] + convert_rgb_to_rgba = staticmethod(convert_rgb_to_rgba) + + +# === Command Line Support === + +def read_pam_header(infile): + """ + Read (the rest of a) PAM header. `infile` should be positioned + immediately after the initial 'P7' line (at the beginning of the + second line). Returns are as for `read_pnm_header`. + """ + + # Unlike PBM, PGM, and PPM, we can read the header a line at a time. + header = dict() + while True: + l = infile.readline().strip() + if l == strtobytes('ENDHDR'): + break + if not l: + raise EOFError('PAM ended prematurely') + if l[0] == strtobytes('#'): + continue + l = l.split(None, 1) + if l[0] not in header: + header[l[0]] = l[1] + else: + header[l[0]] += strtobytes(' ') + l[1] + + required = ['WIDTH', 'HEIGHT', 'DEPTH', 'MAXVAL'] + required = [strtobytes(x) for x in required] + WIDTH,HEIGHT,DEPTH,MAXVAL = required + present = [x for x in required if x in header] + if len(present) != len(required): + raise Error('PAM file must specify WIDTH, HEIGHT, DEPTH, and MAXVAL') + width = int(header[WIDTH]) + height = int(header[HEIGHT]) + depth = int(header[DEPTH]) + maxval = int(header[MAXVAL]) + if (width <= 0 or + height <= 0 or + depth <= 0 or + maxval <= 0): + raise Error( + 'WIDTH, HEIGHT, DEPTH, MAXVAL must all be positive integers') + return 'P7', width, height, depth, maxval + +def read_pnm_header(infile, supported=('P5','P6')): + """ + Read a PNM header, returning (format,width,height,depth,maxval). + `width` and `height` are in pixels. `depth` is the number of + channels in the image; for PBM and PGM it is synthesized as 1, for + PPM as 3; for PAM images it is read from the header. `maxval` is + synthesized (as 1) for PBM images. + """ + + # Generally, see http://netpbm.sourceforge.net/doc/ppm.html + # and http://netpbm.sourceforge.net/doc/pam.html + + supported = [strtobytes(x) for x in supported] + + # Technically 'P7' must be followed by a newline, so by using + # rstrip() we are being liberal in what we accept. I think this + # is acceptable. + type = infile.read(3).rstrip() + if type not in supported: + raise NotImplementedError('file format %s not supported' % type) + if type == strtobytes('P7'): + # PAM header parsing is completely different. + return read_pam_header(infile) + # Expected number of tokens in header (3 for P4, 4 for P6) + expected = 4 + pbm = ('P1', 'P4') + if type in pbm: + expected = 3 + header = [type] + + # We have to read the rest of the header byte by byte because the + # final whitespace character (immediately following the MAXVAL in + # the case of P6) may not be a newline. Of course all PNM files in + # the wild use a newline at this point, so it's tempting to use + # readline; but it would be wrong. + def getc(): + c = infile.read(1) + if not c: + raise Error('premature EOF reading PNM header') + return c + + c = getc() + while True: + # Skip whitespace that precedes a token. + while c.isspace(): + c = getc() + # Skip comments. + while c == '#': + while c not in '\n\r': + c = getc() + if not c.isdigit(): + raise Error('unexpected character %s found in header' % c) + # According to the specification it is legal to have comments + # that appear in the middle of a token. + # This is bonkers; I've never seen it; and it's a bit awkward to + # code good lexers in Python (no goto). So we break on such + # cases. + token = strtobytes('') + while c.isdigit(): + token += c + c = getc() + # Slight hack. All "tokens" are decimal integers, so convert + # them here. + header.append(int(token)) + if len(header) == expected: + break + # Skip comments (again) + while c == '#': + while c not in '\n\r': + c = getc() + if not c.isspace(): + raise Error('expected header to end with whitespace, not %s' % c) + + if type in pbm: + # synthesize a MAXVAL + header.append(1) + depth = (1,3)[type == strtobytes('P6')] + return header[0], header[1], header[2], depth, header[3] + +def write_pnm(file, width, height, pixels, meta): + """Write a Netpbm PNM/PAM file. + """ + + bitdepth = meta['bitdepth'] + maxval = 2**bitdepth - 1 + # Rudely, the number of image planes can be used to determine + # whether we are L (PGM), LA (PAM), RGB (PPM), or RGBA (PAM). + planes = meta['planes'] + # Can be an assert as long as we assume that pixels and meta came + # from a PNG file. + assert planes in (1,2,3,4) + if planes in (1,3): + if 1 == planes: + # PGM + # Could generate PBM if maxval is 1, but we don't (for one + # thing, we'd have to convert the data, not just blat it + # out). + fmt = 'P5' + else: + # PPM + fmt = 'P6' + file.write('%s %d %d %d\n' % (fmt, width, height, maxval)) + if planes in (2,4): + # PAM + # See http://netpbm.sourceforge.net/doc/pam.html + if 2 == planes: + tupltype = 'GRAYSCALE_ALPHA' + else: + tupltype = 'RGB_ALPHA' + file.write('P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\n' + 'TUPLTYPE %s\nENDHDR\n' % + (width, height, planes, maxval, tupltype)) + # Values per row + vpr = planes * width + # struct format + fmt = '>%d' % vpr + if maxval > 0xff: + fmt = fmt + 'H' + else: + fmt = fmt + 'B' + for row in pixels: + file.write(struct.pack(fmt, *row)) + file.flush() + +def color_triple(color): + """ + Convert a command line colour value to a RGB triple of integers. + FIXME: Somewhere we need support for greyscale backgrounds etc. + """ + if color.startswith('#') and len(color) == 4: + return (int(color[1], 16), + int(color[2], 16), + int(color[3], 16)) + if color.startswith('#') and len(color) == 7: + return (int(color[1:3], 16), + int(color[3:5], 16), + int(color[5:7], 16)) + elif color.startswith('#') and len(color) == 13: + return (int(color[1:5], 16), + int(color[5:9], 16), + int(color[9:13], 16)) + +def _add_common_options(parser): + """Call *parser.add_option* for each of the options that are + common between this PNG--PNM conversion tool and the gen + tool. + """ + parser.add_option("-i", "--interlace", + default=False, action="store_true", + help="create an interlaced PNG file (Adam7)") + parser.add_option("-t", "--transparent", + action="store", type="string", metavar="#RRGGBB", + help="mark the specified colour as transparent") + parser.add_option("-b", "--background", + action="store", type="string", metavar="#RRGGBB", + help="save the specified background colour") + parser.add_option("-g", "--gamma", + action="store", type="float", metavar="value", + help="save the specified gamma value") + parser.add_option("-c", "--compression", + action="store", type="int", metavar="level", + help="zlib compression level (0-9)") + return parser + +def _main(argv): + """ + Run the PNG encoder with options from the command line. + """ + + # Parse command line arguments + from optparse import OptionParser + import re + version = '%prog ' + __version__ + parser = OptionParser(version=version) + parser.set_usage("%prog [options] [imagefile]") + parser.add_option('-r', '--read-png', default=False, + action='store_true', + help='Read PNG, write PNM') + parser.add_option("-a", "--alpha", + action="store", type="string", metavar="pgmfile", + help="alpha channel transparency (RGBA)") + _add_common_options(parser) + + (options, args) = parser.parse_args(args=argv[1:]) + + # Convert options + if options.transparent is not None: + options.transparent = color_triple(options.transparent) + if options.background is not None: + options.background = color_triple(options.background) + + # Prepare input and output files + if len(args) == 0: + infilename = '-' + infile = sys.stdin + elif len(args) == 1: + infilename = args[0] + infile = open(infilename, 'rb') + else: + parser.error("more than one input file") + outfile = sys.stdout + if sys.platform == "win32": + import msvcrt, os + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + + if options.read_png: + # Encode PNG to PPM + png = Reader(file=infile) + width,height,pixels,meta = png.asDirect() + write_pnm(outfile, width, height, pixels, meta) + else: + # Encode PNM to PNG + format, width, height, depth, maxval = \ + read_pnm_header(infile, ('P5','P6','P7')) + # When it comes to the variety of input formats, we do something + # rather rude. Observe that L, LA, RGB, RGBA are the 4 colour + # types supported by PNG and that they correspond to 1, 2, 3, 4 + # channels respectively. So we use the number of channels in + # the source image to determine which one we have. We do not + # care about TUPLTYPE. + greyscale = depth <= 2 + pamalpha = depth in (2,4) + supported = map(lambda x: 2**x-1, range(1,17)) + try: + mi = supported.index(maxval) + except ValueError: + raise NotImplementedError( + 'your maxval (%s) not in supported list %s' % + (maxval, str(supported))) + bitdepth = mi+1 + writer = Writer(width, height, + greyscale=greyscale, + bitdepth=bitdepth, + interlace=options.interlace, + transparent=options.transparent, + background=options.background, + alpha=bool(pamalpha or options.alpha), + gamma=options.gamma, + compression=options.compression) + if options.alpha: + pgmfile = open(options.alpha, 'rb') + format, awidth, aheight, adepth, amaxval = \ + read_pnm_header(pgmfile, 'P5') + if amaxval != '255': + raise NotImplementedError( + 'maxval %s not supported for alpha channel' % amaxval) + if (awidth, aheight) != (width, height): + raise ValueError("alpha channel image size mismatch" + " (%s has %sx%s but %s has %sx%s)" + % (infilename, width, height, + options.alpha, awidth, aheight)) + writer.convert_ppm_and_pgm(infile, pgmfile, outfile) + else: + writer.convert_pnm(infile, outfile) + + +if __name__ == '__main__': + try: + _main(sys.argv) + except Error as e: + print(sys.stderr, e) \ No newline at end of file diff --git a/extensions/fablabchemnitz/living_hinge_size_input/living_hinge_size_input.inx b/extensions/fablabchemnitz/living_hinge_size_input/living_hinge_size_input.inx new file mode 100644 index 0000000..faf16e8 --- /dev/null +++ b/extensions/fablabchemnitz/living_hinge_size_input/living_hinge_size_input.inx @@ -0,0 +1,31 @@ + + + Living Hinge (Size Input) + fablabchemnitz.de.living_hinge_size_input + 10 + 100 + 1.0 + 3.0 + 30 + 1.0 + + + + + + + + false + true + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/living_hinge_size_input/living_hinge_size_input.py b/extensions/fablabchemnitz/living_hinge_size_input/living_hinge_size_input.py new file mode 100644 index 0000000..fed5717 --- /dev/null +++ b/extensions/fablabchemnitz/living_hinge_size_input/living_hinge_size_input.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 + +""" +A Inkscape extension to generate a pattern that allows to bend wood or MDF one it is laser cut. +""" + +import inkex +import math +from lxml import etree + +class LivingHingeSizeInput(inkex.EffectExtension): + height = -1.0 + + def add_arguments(self, pars): + pars.add_argument('--width', type=float, default=10, help='Width (mm)') + pars.add_argument('--height', type=float, default=100, help='Height (mm)') + pars.add_argument('--horizontalLineSeparation', type=float, default=1, help='Horizontal Line Separation (mm)') + pars.add_argument('--verticalLineSeparation', type=float, default=3, help='Vertical Line Separation (mm)') + pars.add_argument('--maxLineLength', type=float, default=30, help='Max Line Length (mm)') + pars.add_argument("--line_width", type=float, help="Line width") + pars.add_argument("--units", help="Units for line thickness") + pars.add_argument('--addInitMarks', type=inkex.Boolean, default=False, help='Add Init Marks') + pars.add_argument('--groupLines', type=inkex.Boolean, default=True, help='Group Lines') + +#draw an SVG line segment between the given (raw) points + def draw_SVG_line(self, x1, y1, x2, y2, parent): + + if self.height < 0: + svg = self.document.getroot() + self.height = self.svg.unittouu(svg.attrib['height']) + + line_style = { 'stroke-width':str(self.svg.unittouu(str(self.options.line_width) + self.options.units)), 'stroke':'#000000'} + + line_attribs = {'style' : str(inkex.Style(line_style)), + 'd' : 'M '+str(x1)+','+str(self.height - y1)+' L '+str(x2)+','+str(self.height - y2)} + + line = etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) + + def effect(self): + width = self.options.width + height = self.options.height + horizontalLineSeparation = self.options.horizontalLineSeparation + verticalLineSeparation = self.options.verticalLineSeparation + parent = self.svg.get_current_layer() + + if self.options.groupLines is True: + parent = etree.SubElement(parent, 'g') + + xLines = int(width / horizontalLineSeparation) + maxLineLength = self.options.maxLineLength + + linesPerColumn = int(math.ceil(height / self.options.maxLineLength)) + ll = height / linesPerColumn + + for x in range(0, xLines): + if self.options.addInitMarks is True: + self.draw_SVG_line(x * horizontalLineSeparation, -3, x * horizontalLineSeparation, -2, parent) + + if x % 2 == 0: + for y in range(0, linesPerColumn): + self.draw_SVG_line(x * horizontalLineSeparation, y * ll + verticalLineSeparation / 2, x * horizontalLineSeparation, (y + 1) * ll - verticalLineSeparation / 2, parent) + + else: + for y in range(-1, linesPerColumn): + incy = ll / 2 + + y0 = y * ll + verticalLineSeparation / 2 + incy + if y0 < 0: + y0 = -1 + + y1 = (y + 1) * ll - verticalLineSeparation / 2 + incy + + if y1 > height: + y1 = height + 1 + + self.draw_SVG_line(x * horizontalLineSeparation, y0, x * horizontalLineSeparation, y1, parent) + +if __name__ == '__main__': + LivingHingeSizeInput().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/living_hinge_size_input/meta.json b/extensions/fablabchemnitz/living_hinge_size_input/meta.json new file mode 100644 index 0000000..07b536b --- /dev/null +++ b/extensions/fablabchemnitz/living_hinge_size_input/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Living Hinge (Size Input)", + "id": "fablabchemnitz.de.living_hinge_size_input", + "path": "living_hinge_size_input", + "dependent_extensions": null, + "original_name": "Bend Wood Cuts Pattern", + "original_id": "com.zerjio.inkscape.bwcp", + "license": "GNU GPL v3", + "license_url": "https://github.com/zerjillo/laserCutInkscapeExtensions/blob/master/LICENSE", + "comment": "ported to Inkscape v1 by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/living_hinge_size_input", + "fork_url": "https://github.com/zerjillo/laserCutInkscapeExtensions", + "documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=55019631", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/zerjillo", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/longest_continuous_path/longest_continuous_path.inx b/extensions/fablabchemnitz/longest_continuous_path/longest_continuous_path.inx new file mode 100644 index 0000000..c70b06e --- /dev/null +++ b/extensions/fablabchemnitz/longest_continuous_path/longest_continuous_path.inx @@ -0,0 +1,24 @@ + + + Longest Continuous Path + fablabchemnitz.de.optimize_path + 0.10 + + + + + + false + false + + path + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/longest_continuous_path/longest_continuous_path.py b/extensions/fablabchemnitz/longest_continuous_path/longest_continuous_path.py new file mode 100644 index 0000000..4bad4b1 --- /dev/null +++ b/extensions/fablabchemnitz/longest_continuous_path/longest_continuous_path.py @@ -0,0 +1,624 @@ +#!/usr/bin/env python3 +''' +Copyright (C) 2017 Romain Testuz + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St Fifth Floor, Boston, MA 02139 +''' +import inkex +import sys +import math +import random +import colorsys +import os +import numpy +import timeit + +import networkx as nx + +MAX_CONSECUTIVE_OVERWRITE_EDGE = 3 +STOP_SHORTEST_PATH_IF_SMALLER_OR_EQUAL_TO = 1 +OVERWRITE_ALLOW = 0 +OVERWRITE_ALLOW_SOME = 1 +OVERWRITE_ALLOW_NONE = 2 + +""" +class Graph: + def __init__(self): + self.__adj = {} + self.__data = {} + + def __str__(self): + return str(self.__adj) + + def nodes(self): + nodes = [] + for n in self.__adj: + nodes.append(n) + return nodes + + def edges(self): + edges = [] + for n1 in self.__adj: + for n2 in self.neighbours(n1): + if((n2, n1) not in edges): + edges.append((n1, n2)) + return edges + + def node(self, n): + if n in self.__adj: + return self.__data[n] + else: + raise ValueError('Inexistant node') + + def neighbours(self, n): + if n in self.__adj: + return self.__adj[n] + else: + raise ValueError('Inexistant node') + + def outEdges(self, n): + edges = [] + for n2 in self.neighbours(n): + edges.append((n, n2)) + return edges + + def degree(self, n): + if n in self.__adj: + return len(self.__adj[n]) + else: + raise ValueError('Inexistant node') + + def addNode(self, n, data): + if n not in self.__adj: + self.__adj[n] = [] + self.__data[n] = data + else: + raise ValueError('Node already exists') + + def removeNode(self, n): + if n in self.__adj: + #Remove all edges pointing to node + for n2 in self.__adj: + neighbours = self.__adj[n2] + if n in neighbours: + neighbours.remove(n) + del self.__adj[n] + del self.__data[n] + else: + raise ValueError('Removing inexistant node') + + def addEdge(self, n1, n2): + if(n1 in self.__adj and n2 in self.__adj): + self.__adj[n1].append(n2) + self.__adj[n2].append(n1) + else: + raise ValueError('Adding edge to inexistant node') + + def removeEdge(self, n1, n2): + if(n1 in self.__adj and n2 in self.__adj and + n2 in self.__adj[n1] and n1 in self.__adj[n2]): + self.__adj[n1].remove(n2) + self.__adj[n2].remove(n1) + else: + raise ValueError('Removing inexistant edge') + + def __sortedEdgesByAngle(self, previousEdge, edges): + previousEdgeVectNormalized = numpy.array(self.node(previousEdge[1])) - numpy.array(self.node(previousEdge[0])) + previousEdgeVectNormalized = previousEdgeVectNormalized/numpy.linalg.norm(previousEdgeVectNormalized) + #previousEdgeVectNormalized = numpy.array((0,1)) + def angleKey(outEdge): + edgeVectNormalized = numpy.array(self.node(outEdge[1])) - numpy.array(self.node(outEdge[0])) + edgeVectNormalized = edgeVectNormalized/numpy.linalg.norm(edgeVectNormalized) + return -numpy.dot(previousEdgeVectNormalized, edgeVectNormalized) + + return sorted(edges, key=angleKey) + + def dfsEdges(self): + nodes = self.nodes() + visitedEdges = set() + visitedNodes = set() + edges = {} + dfsEdges = [] + + for startNode in nodes: + #if self.degree(startNode) != 1: + #continue#Makes sure we don't start in the middle of a path + stack = [startNode] + prevEdge = None + while stack: + currentNode = stack[-1] + if currentNode not in visitedNodes: + edges[currentNode] = self.outEdges(currentNode) + visitedNodes.add(currentNode) + + if edges[currentNode]: + if(prevEdge): + edges[currentNode] = self.__sortedEdgesByAngle(prevEdge, edges[currentNode]) + edge = edges[currentNode][0] + if edge not in visitedEdges and (edge[1], edge[0]) not in visitedEdges: + visitedEdges.add(edge) + # Mark the traversed "to" node as to-be-explored. + stack.append(edge[1]) + dfsEdges.append(edge) + prevEdge = edge + edges[currentNode].pop(0) + else: + # No more edges from the current node. + stack.pop() + prevEdge = None + + return dfsEdges +""" + +class LongestContinuousPath(inkex.GenerateExtension): + + def add_arguments(self, pars): + pars.add_argument("-t", "--tolerance", type=float, default=0.1, help="the distance below which 2 nodes will be merged") + pars.add_argument("-l", "--enableLog", type=inkex.Boolean, default=False, help="Enable logging") + pars.add_argument("-o", "--overwriteRule", type=int, default=1, help="Options to control edge overwrite rules") + pars.add_argument("-k", "--keepSelected", type=inkex.Boolean, default=False, help="Keep selected elements") + + def parseSVG(self): + vertices = [] + edges = [] + + objects = self.svg.selection.filter(inkex.PathElement).values() + + for node in objects: + if node.tag == inkex.addNS('path', 'svg'): + node.apply_transform() + superpath = node.path.to_absolute().to_superpath() + for subpath in superpath: + subpathList = list(subpath) + + # We only work with lines, not curves, so we ignore the a and c in [a, b, c] + newVertices = list(map(lambda x: x[1], subpathList)) + # self.log(newVertices) + + newEdges = range(len(vertices), len(vertices) + len(newVertices) - 1) + newEdges = list(map(lambda x: (x, x + 1), newEdges)) + # self.log(newEdges) + + edges.extend(newEdges) + vertices.extend(newVertices) + else: + self.log("This extension only works with paths and currently doesn't support groups") + + if self.options.keepSelected is False: + for object in objects: + if object.getparent() is not None: + #inkex.utils.debug(object.get('id')) + object.getparent().remove(object) + + return (vertices, edges) + + # Also computes edge weight + def buildGraph(self, vertices, edges): + G = nx.Graph() + for i, v in enumerate(vertices): + G.add_node(i, x=v[0], y=v[1]) + # self.log("N "+ str(i) + " (" + str(v[0]) + "," + str(v[1]) + ")") + for e in edges: + dist = self.dist(G.nodes[e[0]], G.nodes[e[1]]) + G.add_edge(e[0], e[1], weight=dist) + # self.log("E "+str(e[0]) + " " + str(e[1])) + return G + + @staticmethod + def dist(a, b): + return math.sqrt((a['x'] - b['x']) ** 2 + (a['y'] - b['y']) ** 2) + + def log(self, message): + if self.options.enableLog: + inkex.utils.debug(message) + + def mergeWithTolerance(self, G, tolerance): + mergeTo = {} + for ni in G.nodes(): + for nj in G.nodes(): + if nj <= ni: + continue + # self.log("Test " + str(ni) + " with " + str(nj)) + dist_ij = self.dist(G.nodes[ni], G.nodes[nj]) + if (dist_ij < tolerance) and (nj not in mergeTo) and (ni not in mergeTo): + # self.log("Merge " + str(nj) + " with " + str(ni) + " (dist=" + str(dist_ij) + ")") + mergeTo[nj] = ni + + for n in mergeTo: + newEdges = [] + for neigh_n in G[n]: + newEdge = None + if neigh_n in mergeTo: + newEdge = (mergeTo[n], mergeTo[neigh_n]) + else: + newEdge = (mergeTo[n], neigh_n) + + if newEdge[0] != newEdge[1]: # Don't add self-loops + newEdges.append(newEdge) + + for e in newEdges: + G.add_edge(*e) + # self.log("Added edge: "+str(e[0]) + " " + str(e[1])) + G.remove_node(n) + # self.log("Removed node: " + str(n)) + + @staticmethod + def rgbToHex(rgb): + return '#%02x%02x%02x' % rgb + + # Color should be in hex format ("#RRGGBB"), if not specified a random color will be generated + def addPathToInkscape(self, path, parent, color): + elem = parent.add(inkex.PathElement()) + elem.style = {'stroke': color, 'stroke-width': 2, 'fill': 'none'} + elem.path = inkex.Path(path) + + def removeSomeEdges(self, G, edges): + visitedEdges = set() + + # Contains a list of [start, end] where start is the start index of a duplicate path + # and end is the end index of the duplicate path + edgeRangeToRemove = [] + isPrevEdgeDuplicate = False + duplicatePathStartIndex = -1 + for i, e in enumerate(edges): + isEdgeDuplicate = e in visitedEdges or (e[1], e[0]) in visitedEdges + + if isEdgeDuplicate: + if duplicatePathStartIndex == -1: + duplicatePathStartIndex = i + else: + if duplicatePathStartIndex >= 0: + edgeRangeToRemove.append((duplicatePathStartIndex, i - 1)) + duplicatePathStartIndex = -1 + + visitedEdges.add(e) + + if isEdgeDuplicate and i == len(edges) - 1: + edgeRangeToRemove.append((duplicatePathStartIndex, i)) + + if self.options.overwriteRule == OVERWRITE_ALLOW: + # The last duplicate path can always be removed + edgeRangeToRemove = [edgeRangeToRemove[-1]] if edgeRangeToRemove else [] + elif self.options.overwriteRule == OVERWRITE_ALLOW_SOME: # Allow overwrite except for long paths + edgeRangeToRemove = [x for x in edgeRangeToRemove if x[1] - x[0] > MAX_CONSECUTIVE_OVERWRITE_EDGE] + + indicesToRemove = set() + for start, end in edgeRangeToRemove: + indicesToRemove.update(range(start, end + 1)) + + cleanedEdges = [e for i, e in enumerate(edges) if i not in indicesToRemove] + + return cleanedEdges + + # Find the first break and rotate the edges to align to this break + # this allows to avoid an extra path + # Return the rotated edges + def shiftEdgesToBreak(self, edges): + if not edges: + return edges + # Only useful if the last edge connects to the first + if edges[0][0] != edges[-1][1]: + return edges + + for i, e in enumerate(edges): + if i == 0: + continue + if edges[i - 1][1] != e[0]: + return edges[i:] + edges[:i] + + return edges + + def edgesToPaths(self, edges): + paths = [] + path = [] + + for i, e in enumerate(edges): + if e[0] == -1: # Start with extra node, ignore it + assert not path + elif e[1] == -1: # End with extra node, ignore it + if path: + paths.append(path) + path = [] + + else: + # Path ends either at the last edge or when the next edge starts somewhere else + endPath = (i == len(edges) - 1 or e[1] != edges[i + 1][0]) + + if not path: + path.append(e[0]) + path.append(e[1]) + else: + path.append(e[1]) + + if endPath: + paths.append(path) + path = [] + + if self.options.overwriteRule == OVERWRITE_ALLOW: + assert len(paths) == 1 + + # paths.sort(key=len, reverse=True) + return paths + + def pathsToSVG(self, G, paths): + svgPaths = [] + for path in paths: + svgPath = [] + for nodeIndex, n in enumerate(path): + command = None + if nodeIndex == 0: + command = 'M' + else: + command = 'L' + svgPath.append([command, (G.nodes[n]['x'], G.nodes[n]['y'])]) + svgPaths.append(svgPath) + + # Create a group + group = inkex.Group.new("OptimizedPaths") + + for pathIndex, svgPath in enumerate(svgPaths): + # Generate a different color for every path + color = colorsys.hsv_to_rgb(pathIndex / float(len(svgPaths)), 1.0, 1.0) + color = tuple(int(x * 255) for x in color) + color = self.rgbToHex(color) + self.addPathToInkscape(svgPath, group, color) + return group + + # Computes the physical path length (it ignores the edge weight) + def pathLength(self, G, path): + length = 0.0 + for i, n in enumerate(path): + if i > 0: + length += self.dist(G.nodes[path[i - 1]], G.nodes[path[i]]) + return length + + # Eulerization algorithm: + # 1. Find all vertices with odd valence. + # 2. Pair them up with their nearest neighbor. + # 3. Find the shortest path between each pair. + # 4. Duplicate these edges. + # Doesn't modify input graph + def makeEulerianGraph(self, G): + oddNodes = [] + for n in G.nodes: + if G.degree(n) % 2 != 0: + oddNodes.append(n) + # self.log("Number of nodes with odd degree: " + str(len(oddNodes))) + + if len(oddNodes) == 0: + return G + + # self.computeEdgeWeights(G) + + pathsToDuplicate = [] + + while (oddNodes): + n1 = oddNodes[0] + + shortestPaths = [] + # For every other node, find the shortest path to the closest node + for n2 in oddNodes: + if n2 != n1: + # self.log(str(n1) + " " + str(n2)) + shortestPath = nx.astar_path(G, n1, n2, + lambda n1, n2: self.dist(G.nodes[n1], G.nodes[n2]), 'weight') + # self.log(str(len(shortestPath))) + shortestPaths.append(shortestPath) + if len(shortestPath) <= STOP_SHORTEST_PATH_IF_SMALLER_OR_EQUAL_TO: + # If we find a path of length <= STOP_SHORTEST_PATH_IF_SMALLER_OR_EQUAL_TO, + # we assume it's good enough (to speed up calculation) + break + # For all the shortest paths from n1, we take the shortest one and therefore get the closest odd node + shortestShortestPath = min(shortestPaths, key=lambda x: self.pathLength(G, x)) + closestNode = shortestShortestPath[-1] + pathsToDuplicate.append(shortestShortestPath) + oddNodes.pop(0) + oddNodes.remove(closestNode) + + numberOfDuplicatedEdges = 0 + lenghtOfDuplicatedEdges = 0.0 + + for path in pathsToDuplicate: + numberOfDuplicatedEdges += len(path) - 1 + pathLength = self.pathLength(G, path) + # self.log("Path length: " + str(pathLength)) + lenghtOfDuplicatedEdges += pathLength + # self.log("Number of duplicated edges: " + str(numberOfDuplicatedEdges)) + # self.log("Length of duplicated edges: " + str(lenghtOfDuplicatedEdges)) + + # Convert the graph to a MultiGraph to allow parallel edges + G2 = nx.MultiGraph(G) + for path in pathsToDuplicate: + nx.add_path(G2, path) + + return G2 + + # Doesn't modify input graph + # faster than makeEulerianGraph but creates an extra node + def makeEulerianGraphExtraNode(self, G): + oddNodes = [] + for n in G.nodes: + if G.degree(n) % 2 != 0: + oddNodes.append(n) + if len(oddNodes) == 0: + return G + + G2 = nx.Graph(G) + G2.add_node(-1, x=0, y=0) + for n in oddNodes: + G2.add_edge(n, -1) + + return G2 + + """def computeEdgeWeights(self, G): + for n1, n2 in G.edges(): + dist = self.dist(G.nodes[n1], G.nodes[n2]) + G.add_edge(n1, n2, weight=dist)""" + + def _getNodePosition(self, G, n): + return (G.nodes[n]['x'], G.nodes[n]['y']) + + def _getBestEdge(self, G, previousEdge, edges): + previousEdgeVectNormalized = numpy.array(self._getNodePosition(G, previousEdge[1])) - numpy.array( + self._getNodePosition(G, previousEdge[0])) + # self.log(str(numpy.linalg.norm(previousEdgeVectNormalized)) + " " + str(previousEdge[1]) + " " + str(previousEdge[0])) + previousEdgeVectNormalized = previousEdgeVectNormalized / numpy.linalg.norm(previousEdgeVectNormalized) + + # previousEdgeVectNormalized = numpy.array((0,1)) + def angleKey(outEdge): + edgeVectNormalized = numpy.array(self._getNodePosition(G, outEdge[1])) - numpy.array( + self._getNodePosition(G, outEdge[0])) + edgeVectNormalized = edgeVectNormalized / numpy.linalg.norm(edgeVectNormalized) + return numpy.dot(previousEdgeVectNormalized, edgeVectNormalized) + + return max(edges, key=angleKey) + + """def eulerian_circuit(self, G): + g = G.__class__(G)#G.copy() + v = next(g.nodes()) + + degree = g.degree + edges = g.edges + + circuit = [] + vertex_stack = [v] + last_vertex = None + while vertex_stack: + current_vertex = vertex_stack[-1] + if degree(current_vertex) == 0: + if last_vertex is not None: + circuit.append((last_vertex, current_vertex)) + self.log(str(last_vertex) + " " + str(current_vertex)) + last_vertex = current_vertex + vertex_stack.pop() + else: + if circuit: + arbitrary_edge = self._getBestEdge(g, circuit[-1], edges(current_vertex)) + else:#For the first iteration we arbitrarily take the first edge + arbitrary_edge = next(edges(current_vertex)) + #self.log(str(arbitrary_edge) + "::" + str(edges[current_vertex])) + + #self.log(str(edges[current_vertex])) + #self.log(" ") + + vertex_stack.append(arbitrary_edge[1]) + g.remove_edge(*arbitrary_edge) + + return circuit""" + + # Walk as straight as possible from node until stuck + def walk(self, node, G): + n = node + e = None + path = [n] + + while G.degree[n]: # Continue until there no unvisited edges from n + if e: + e = self._getBestEdge(G, e, G.edges(n)) + else: # For the first iteration we arbitrarily take the first edge + e = (n, next(iter(G[n]))) + n = e[1] + G.remove_edge(*e) + path.append(n) + + return path + + def eulerian_circuit_hierholzer(self, G): + g = G.copy() + v = next(iter(g.nodes)) # First vertex, arbitrary + + cycle = self.walk(v, g) + assert cycle[0] == cycle[-1] + notvisited = set(cycle) + + while len(notvisited) != 0: + v = notvisited.pop() + if g.degree(v) != 0: + i = cycle.index(v) + sub = self.walk(v, g) + assert sub[0] == sub[-1] + cycle = cycle[:i] + sub[:-1] + cycle[i:] + notvisited.update(sub) + + cycleEdges = [] + prevNode = None + for n in cycle: + if prevNode != None: + cycleEdges.append((prevNode, n)) + prevNode = n + return cycleEdges + + def generate(self): + self.log("NetworkX version: " + nx.__version__) + if int(nx.__version__[0]) < 2: + inkex.utils.debug("NetworkX version is: {} but should be >= 2.0.".format(nx.__version__)) + return + self.log("Python version: " + sys.version) + + totalTimerStart = timeit.default_timer() + (vertices, edges) = self.parseSVG() + G = self.buildGraph(vertices, edges) + + timerStart = timeit.default_timer() + self.mergeWithTolerance(G, self.options.tolerance) + timerStop = timeit.default_timer() + mergeDuration = timerStop - timerStart + initialEdgeCount = nx.number_of_edges(G) + finalEdgeCount = 0 + + """for e in G.edges(): + self.log("E "+str(e[0]) + " " + str(e[1])) + for n in G.nodes(): + self.log("Degree of "+str(n) + ": " + str(G.degree(n)))""" + # Split disjoint graphs + connectedGraphs = [G.subgraph(c).copy() for c in nx.connected_components(G)] + self.log("Number of disconnected graphs: " + str(len(connectedGraphs))) + + paths = [] + makeEulerianDuration = 0 + for connectedGraph in connectedGraphs: + timerStart = timeit.default_timer() + if self.options.overwriteRule == OVERWRITE_ALLOW_NONE: + connectedGraph = self.makeEulerianGraphExtraNode(connectedGraph) + #connectedGraph = nx.eulerize(connectedGraph) + else: + connectedGraph = self.makeEulerianGraph(connectedGraph) + #connectedGraph = nx.eulerize(connectedGraph) + timerStop = timeit.default_timer() + makeEulerianDuration += timerStop - timerStart + # connectedGraph is now likely a multigraph + + finalEdgeCount = finalEdgeCount + nx.number_of_edges(connectedGraph) + #pathEdges = list(nx.eulerian_path(connectedGraph)) + pathEdges = self.eulerian_circuit_hierholzer(connectedGraph) + pathEdges = self.removeSomeEdges(connectedGraph, pathEdges) + pathEdges = self.shiftEdgesToBreak(pathEdges) + + paths.extend(self.edgesToPaths(pathEdges)) + + self.log("Path number: " + str(len(paths))) + self.log("Total path length: {:.2f}".format(sum(self.pathLength(G, x) for x in paths))) + self.log("Number of duplicated edges: {:d}".format(finalEdgeCount-initialEdgeCount)) + + group = self.pathsToSVG(G, paths) + totalTimerStop = timeit.default_timer() + totalDuration = totalTimerStop - totalTimerStart + self.log("Merge duration: {:.0f} sec ({:.1f} min)".format(mergeDuration, mergeDuration / 60)) + self.log("Make Eulerian duration: {:.0f} sec ({:.1f} min)".format(makeEulerianDuration, makeEulerianDuration / 60)) + self.log("Total duration: {:.0f} sec ({:.1f} min)".format(totalDuration, totalDuration / 60)) + return group + +if __name__ == '__main__': + LongestContinuousPath().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/longest_continuous_path/meta.json b/extensions/fablabchemnitz/longest_continuous_path/meta.json new file mode 100644 index 0000000..793e168 --- /dev/null +++ b/extensions/fablabchemnitz/longest_continuous_path/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Longest Continuous Path", + "id": "fablabchemnitz.de.longest_continuous_path", + "path": "longest_continuous_path", + "dependent_extensions": null, + "original_name": "Optimize Paths", + "original_id": "org.daekkyn.filter.optimizePaths", + "license": "GNU GPL v3", + "license_url": "https://github.com/Daekkyn/inkscapeOptimizePath/blob/master/LICENSE", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/longest_continuous_path", + "fork_url": "https://github.com/Daekkyn/inkscapeOptimizePath", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Longest+Continuous+Path", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/Daekkyn", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/netting/netting.inx b/extensions/fablabchemnitz/netting/netting.inx index 5b4d1f5..64274a2 100644 --- a/extensions/fablabchemnitz/netting/netting.inx +++ b/extensions/fablabchemnitz/netting/netting.inx @@ -15,7 +15,7 @@ - + diff --git a/extensions/fablabchemnitz/offset_paths/offset_paths.inx b/extensions/fablabchemnitz/offset_paths/offset_paths.inx index 3f330d2..78c7249 100644 --- a/extensions/fablabchemnitz/offset_paths/offset_paths.inx +++ b/extensions/fablabchemnitz/offset_paths/offset_paths.inx @@ -42,7 +42,7 @@ - + diff --git a/extensions/fablabchemnitz/pixel2svg/meta.json b/extensions/fablabchemnitz/pixel2svg/meta.json new file mode 100644 index 0000000..f3d49da --- /dev/null +++ b/extensions/fablabchemnitz/pixel2svg/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Pixel2SVG", + "id": "fablabchemnitz.de.pixel2svg", + "path": "pixel2svg", + "dependent_extensions": null, + "original_name": "Pixel2SVG (contrib)", + "original_id": "su-v/org.inkscape.effect.pixel2svg", + "license": "GNU GPL v2", + "license_url": "https://gitlab.com/su-v/inx-pixel2svg/-/blob/master/COPYING", + "comment": "ported to Inkscape v1 manually by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/pixel2svg", + "fork_url": "ttps://gitlab.com/su-v/inx-pixel2svg", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Pixel2SVG", + "inkscape_gallery_url": null, + "main_authors": [ + "gitlab.com/su-v", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/pixel2svg/pixel2svg.inx b/extensions/fablabchemnitz/pixel2svg/pixel2svg.inx new file mode 100644 index 0000000..7e84f6c --- /dev/null +++ b/extensions/fablabchemnitz/pixel2svg/pixel2svg.inx @@ -0,0 +1,45 @@ + + + Pixel2SVG + fablabchemnitz.de.pixel2svg + + + 5 + true + true + false + + + true + false + false + 256 + + + + + + + + FFFFFF + + + + + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/pixel2svg/pixel2svg.py b/extensions/fablabchemnitz/pixel2svg/pixel2svg.py new file mode 100644 index 0000000..9d31684 --- /dev/null +++ b/extensions/fablabchemnitz/pixel2svg/pixel2svg.py @@ -0,0 +1,336 @@ +#!/usr/bin/env python3 +""" +Pixel2SVG - Convert the pixels of bitmap images to SVG rects + +Idea and original implementation as standalone script: +Copyright (C) 2011 Florian Berger +Homepage: + +Rewritten as Inkscape extension: +Copyright (C) 2012 ~suv + +'getFilePath()' is based on code from 'extractimages.py': +Copyright (C) 2005 Aaron Spike, aaron@ekips.org + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import os +import sys +import base64 +from io import StringIO, BytesIO +import urllib.request as urllib +import inkex +from PIL import Image +from lxml import etree + +DEBUG = False + +# int r = ( hexcolor >> 16 ) & 0xFF; +# int g = ( hexcolor >> 8 ) & 0xFF; +# int b = hexcolor & 0xFF; +# int hexcolor = (r << 16) + (g << 8) + b; + +def hex_to_int_color(v): + if (v[0] == '#'): + v = v[1:] + assert(len(v) == 6) + return int(v[:2], 16), int(v[2:4], 16), int(v[4:6], 16) + +class Pixel2SVG(inkex.EffectExtension): + + def add_arguments(self, pars): + pars.add_argument("-s", "--squaresize", type=int, default="5", help="Width and height of vector squares in pixels") + pars.add_argument("--same_like_original", type=inkex.Boolean, default=True, help="Same size as original") + pars.add_argument("--transparency", type=inkex.Boolean, default=True, help="Convert transparency to 'fill-opacity'") + pars.add_argument("--overlap", type=inkex.Boolean, default=False, help="Overlap vector squares by 1px") + pars.add_argument("--offset_image", type=inkex.Boolean, default=True, help="Offset traced image") + pars.add_argument("--delete_image", type=inkex.Boolean, default=False, help="Delete bitmap image") + pars.add_argument("--maxsize", type=int, default="256", help="Max. image size (width or height)") + pars.add_argument("--verbose", type=inkex.Boolean, default=False) + pars.add_argument("--color_mode", default="all", help="Which colors to trace.") + pars.add_argument("--color", default="FFFFFF", help="Special color") + pars.add_argument("--tab") + + def checkImagePath(self, node): + """Embed the data of the selected Image Tag element""" + 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 drawFilledRect(self, parent, svgpx): + """ + Draw rect based on ((x, y), (width,height), ((r,g,b),a)), add to parent + """ + style = {} + pos = svgpx[0] + dim = svgpx[1] + rgb = svgpx[2][0] + alpha = svgpx[2][1] + + style['stroke'] = 'none' + + if len(rgb) == 3: + # fill: rgb tuple + style['fill'] = '#%02x%02x%02x' % (rgb[0], rgb[1], rgb[2]) + elif len(rgb) == 1: + # fill: color name, or 'none' + style['fill'] = rgb[0] + else: + # fill: 'Unset' (no fill defined) + pass + + if alpha < 255: + # only write 'fill-opacity' for non-default value + style['fill-opacity'] = '%s' % round(alpha/255.0, 8) + + rect_attribs = {'x': str(pos[0]), + 'y': str(pos[1]), + 'width': str(dim[0]), + 'height': str(dim[1]), + 'style': str(inkex.Style(style)), } + + rect = etree.SubElement(parent, inkex.addNS('rect', 'svg'), rect_attribs) + + return rect + + def vectorizeImage(self, node): + """ + Parse RGBA values of linked bitmap image, create a group and + draw the rectangles (SVG pixels) inside the new group + """ + 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) + + if image: + # init, set limit (default: 256) + pixel2svg_max = self.options.maxsize + + if self.options.verbose: + inkex.utils.debug("ID: %s" % node.get('id')) + inkex.utils.debug("Image size:\t%dx%d" % image.size) + inkex.utils.debug("Image format:\t%s" % image.format) + inkex.utils.debug("Image mode:\t%s" % image.mode) + inkex.utils.debug("Image info:\t%s" % image.info) + + if (image.mode == 'P' and 'transparency' in image.info): + inkex.utils.debug( + "Note: paletted image with an alpha channel is handled badly with " + + "current PIL:\n" + + "") + elif not image.mode in ('RGBA', 'LA'): + inkex.utils.debug("No alpha channel or transparency found") + + image = image.convert("RGBA") + (width, height) = image.size + + if width <= pixel2svg_max and height <= pixel2svg_max: + + # color trace modes + trace_color = [] + if self.options.color: + trace_color = hex_to_int_color(self.options.color) + + # get RGBA data + rgba_values = list(image.getdata()) + + # create group + nodeParent = node.getparent() + nodeIndex = nodeParent.index(node) + pixel2svg_group = etree.Element(inkex.addNS('g', 'svg')) + pixel2svg_group.set('id', "%s_pixel2svg" % node.get('id')) + nodeParent.insert(nodeIndex + 1, pixel2svg_group) + + # draw bbox rectangle at the bottom of group + pixel2svg_bbox_fill = ('none', ) + pixel2svg_bbox_alpha = 255 + pixel2svg_bbox = ((0, 0), + (width * self.options.squaresize, + height * self.options.squaresize), + (pixel2svg_bbox_fill, pixel2svg_bbox_alpha)) + self.drawFilledRect(pixel2svg_group, pixel2svg_bbox) + + img_w = node.get('width') + img_h = node.get('height') + img_x = node.get('x') + img_y = node.get('y') + if img_w is not None and img_h is not None and img_x is not None and img_y is not None: + #if width/height are not unitless but end with px, mm, in etc. we have to convert to a float number + if img_w[-1].isdigit() is False: + img_w = self.svg.uutounit(img_w) + if img_h[-1].isdigit() is False: + img_h = self.svg.uutounit(img_h) + if self.options.same_like_original is True: + scale_x = float(img_w) / pixel2svg_bbox[1][0] #px + scale_y = float(img_h) / pixel2svg_bbox[1][1] #px + else: + scale_x = 1.0 + scale_y = 1.0 + # move group beside original image + if self.options.offset_image: + pixel2svg_offset = float(img_w) + else: + pixel2svg_offset = 0.0 + # add transformation to fit previous XY coordinates and width/height + # image might also be influenced by other transformations from parent: + if nodeParent is not None and nodeParent != self.document.getroot(): + tpc = nodeParent.composed_transform() + x_offset = tpc.e + pixel2svg_offset + y_offset = tpc.f + else: + x_offset = 0.0 + pixel2svg_offset + y_offset = 0.0 + transform = "matrix({:1.6f}, 0, 0, {:1.6f}, {:1.6f}, {:1.6f})"\ + .format(scale_x, scale_y, float(img_x) + x_offset, float(img_y) + y_offset) + else: + t = node.composed_transform() + img_w = t.a + img_h = t.d + img_x = t.e + img_y = t.f + if self.options.same_like_original is True: + scale_x = float(img_w) / pixel2svg_bbox[1][0] #px + scale_y = float(img_h) / pixel2svg_bbox[1][1] #px + else: + scale_x = 1.0 + scale_y = 1.0 + # move group beside original image + if self.options.offset_image: + pixel2svg_offset = float(img_w) + else: + pixel2svg_offset = 0.0 + # add transformation to fit previous XY coordinates and width/height + # image might also be influenced by other transformations from parent: + if nodeParent is not None and nodeParent != self.document.getroot(): + tpc = nodeParent.composed_transform() + x_offset = tpc.e + pixel2svg_offset + y_offset = tpc.f + else: + x_offset = 0.0 + pixel2svg_offset + y_offset = 0.0 + transform = "matrix({:1.6f}, 0, 0, {:1.6f}, {:1.6f}, {:1.6f})"\ + .format(scale_x, scale_y, float(img_x) + x_offset, float(img_y) + y_offset) + pixel2svg_group.attrib['transform'] = transform + + # reverse list (performance), pop last one instead of first + rgba_values.reverse() + # loop through pixels (per row) + rowcount = 0 + while rowcount < height: + colcount = 0 + while colcount < width: + rgba_tuple = rgba_values.pop() + # Omit transparent pixels + if rgba_tuple[3] > 0: + # color options + do_trace = True + if (self.options.color_mode != "all"): + if (trace_color == rgba_tuple[:3]): + # colors match + if (self.options.color_mode == "other"): + do_trace = False + else: + # colors don't match + if (self.options.color_mode == "this"): + do_trace = False + if do_trace: + # position + svgpx_x = colcount * self.options.squaresize + svgpx_y = rowcount * self.options.squaresize + # dimension + overlap + svgpx_size = self.options.squaresize + self.options.overlap + # get color, ignore alpha + svgpx_rgb = rgba_tuple[:3] + svgpx_a = 255 + # transparency + if self.options.transparency: + svgpx_a = rgba_tuple[3] + svgpx = ((svgpx_x, svgpx_y), + (svgpx_size, svgpx_size), + (svgpx_rgb, svgpx_a) + ) + # draw square in group + self.drawFilledRect(pixel2svg_group, svgpx) + colcount = colcount + 1 + rowcount = rowcount + 1 + + # all done + if DEBUG: + inkex.utils.debug("All rects drawn.") + + if self.options.delete_image: + nodeParent.remove(node) + + else: + # bail out with larger images + inkex.errormsg( + "Bailing out: this extension is not intended for large images.\n" + + "The current limit is %spx for either dimension of the bitmap image." + % pixel2svg_max) + sys.exit(0) + + # clean-up? + if DEBUG: + inkex.utils.debug("Done.") + + else: + inkex.errormsg("Bailing out: No supported image file or data found") + sys.exit(1) + + def effect(self): + """ + Pixel2SVG - Convert the pixels of bitmap images to SVG rects + """ + found_image = False + if (self.options.ids): + for node in self.svg.selected.values(): + if node.tag == inkex.addNS('image', 'svg'): + found_image = True + self.vectorizeImage(node) + + if not found_image: + inkex.errormsg("Please select one or more bitmap image(s) for Pixel2SVG") + sys.exit(0) + +if __name__ == '__main__': + Pixel2SVG().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/psd_export/meta.json b/extensions/fablabchemnitz/psd_export/meta.json new file mode 100644 index 0000000..ea1d31a --- /dev/null +++ b/extensions/fablabchemnitz/psd_export/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Photoshop PSD Export", + "id": "fablabchemnitz.de.psd_export", + "path": "psd_export", + "dependent_extensions": null, + "original_name": "GIMP PSD", + "original_id": "org.ekips.output.gimp_psd", + "license": "GNU GPL v2", + "license_url": "https://github.com/junichi11/gimp_psd/blob/master/gimp_psd.py", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/psd_export", + "fork_url": "https://github.com/junichi11/gimp_psd", + "documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=120525412", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/junichi11", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/psd_export/psd_export.inx b/extensions/fablabchemnitz/psd_export/psd_export.inx new file mode 100755 index 0000000..ec4853d --- /dev/null +++ b/extensions/fablabchemnitz/psd_export/psd_export.inx @@ -0,0 +1,20 @@ + + + Photoshop PSD Export + fablabchemnitz.de.psd_export + false + false + false + 96 + + .psd + application/x-psd + Photoshop PSD (*.psd) + Photoshop PSD (*.psd) + true + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/psd_export/psd_export.py b/extensions/fablabchemnitz/psd_export/psd_export.py new file mode 100755 index 0000000..027f74f --- /dev/null +++ b/extensions/fablabchemnitz/psd_export/psd_export.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2006 Aaron Spike, aaron@ekips.org +# Copyright (C) 2010-2012 Nicolas Dufour, nicoduf@yahoo.fr +# (Windows support and various fixes) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +""" +Export to Gimp's XCF file format including Grids and Guides. +""" + +import os +from collections import OrderedDict + +import inkex +from inkex.base import TempDirMixin +from inkex.command import take_snapshot, call +from inkex.localization import inkex_gettext as _ + +class PSDExport(TempDirMixin, inkex.OutputExtension): + """ + Provide a quick and dirty way of using gimp to output an xcf from Inkscape. + + Both Inkscape and Gimp must be installed for this extension to work. + """ + dir_prefix = 'gimp-out-' + + def add_arguments(self, pars): + pars.add_argument("--tab") + pars.add_argument("-d", "--guides", type=inkex.Boolean, help="Save Guides") + pars.add_argument("-r", "--grid", type=inkex.Boolean, help="Save Grid") + pars.add_argument("-b", "--background", type=inkex.Boolean, help="Save background color") + pars.add_argument("-i", "--dpi", type=float, default=96.0, help="File resolution") + + def get_guides(self): + """Generate a list of horzontal and vertical only guides""" + horz_guides = [] + vert_guides = [] + # Grab all guide tags in the namedview tag + for guide in self.svg.namedview.get_guides(): + if guide.is_horizontal: + # GIMP doesn't like guides that are outside of the image + if 0 < guide.point.y < self.svg.height: + # The origin is at the top in GIMP land + horz_guides.append(str(guide.point.y)) + elif guide.is_vertical: + # GIMP doesn't like guides that are outside of the image + if 0 < guide.point.x < self.svg.width: + vert_guides.append(str(guide.point.x)) + + return ('h', ' '.join(horz_guides)), ('v', ' '.join(vert_guides)) + + def get_grid(self): + """Get the grid if asked for and return as gimpfu script""" + scale = (self.svg.scale) * (self.options.dpi / 96.0) + # GIMP only allows one rectangular grid + xpath = "sodipodi:namedview/inkscape:grid[@type='xygrid' and (not(@units) or @units='px')]" + if self.svg.xpath(xpath): + node = self.svg.getElement(xpath) + for attr, default, target in (('spacing', 1, 'spacing'), ('origin', 0, 'offset')): + fmt = {'target': target} + for dim in 'xy': + # These attributes could be nonexistent + unit = float(node.get(attr + dim, default)) + unit = self.svg.uutounit(unit, "px") * scale + fmt[dim] = int(round(float(unit))) + yield '(gimp-image-grid-set-{target} img {x} {y})'.format(**fmt) + + @property + def docname(self): + """Get the document name suitable for export""" + return self.svg.get('sodipodi:docname') or 'document' + + def save(self, stream): + + pngs = OrderedDict() + valid = False + + for node in self.svg.xpath("/svg:svg/*[name()='g' or @style][@id]"): + if not len(node): # pylint: disable=len-as-condition + # Ignore empty layers + continue + + valid = True + node_id = node.get('id') + name = node.get("inkscape:label", node_id) + + pngs[name] = take_snapshot( + self.document, + dirname=self.tempdir, + name=name, + dpi=int(self.options.dpi), + export_id=node_id, + export_id_only=True, + export_area_page=True, + export_background_opacity=int(bool(self.options.background)) + ) + + if not valid: + inkex.errormsg(_('This extension requires at least one non empty layer.')) + return + + xcf = os.path.join(self.tempdir, "{}.psd".format(self.docname)) + script_fu = """ +(tracing 1) +(define + (png-to-layer img png_filename layer_name) + (let* + ( + (png (car (file-png-load RUN-NONINTERACTIVE png_filename png_filename))) + (png_layer (car (gimp-image-get-active-layer png))) + (xcf_layer (car (gimp-layer-new-from-drawable png_layer img))) + ) + (gimp-image-add-layer img xcf_layer -1) + (gimp-drawable-set-name xcf_layer layer_name) + ) +) +(let* + ( + (img (car (gimp-image-new 200 200 RGB))) + ) + (gimp-image-set-resolution img {dpi} {dpi}) + (gimp-image-undo-disable img) + (for-each + (lambda (names) + (png-to-layer img (car names) (cdr names)) + ) + (map cons '("{files}") '("{names}")) + ) + + (gimp-image-resize-to-layers img) +""".format( + dpi=self.options.dpi, + files='" "'.join(pngs.values()), + names='" "'.join(list(pngs)) +) + + if self.options.guides: + for dim, guides in self.get_guides(): + script_fu += """ + (for-each + (lambda ({d}Guide) + (gimp-image-add-{d}guide img {d}Guide) + ) + '({g}) + )""".format(d=dim, g=guides) + + # Grid + if self.options.grid: + for fu_let in self.get_grid(): + script_fu += "\n" + fu_let + "\n" + + script_fu += """ + (gimp-image-undo-enable img) + (file-psd-save RUN-NONINTERACTIVE img (car (gimp-image-get-active-layer img)) "{xcf}" "{xcf}" 0 0)) +(gimp-quit 0) + """.format(xcf=xcf) + + #please install with apt/dnf to install gimp. Do not use snap or flatpak installations + call('gimp', "-b", "-", i=True, batch_interpreter="plug-in-script-fu-eval", stdin=script_fu) + + with open(xcf, 'rb') as fhl: + stream.write(fhl.read()) + +if __name__ == '__main__': + PSDExport().run() diff --git a/extensions/fablabchemnitz/purge_pointy_paths/meta.json b/extensions/fablabchemnitz/purge_pointy_paths/meta.json new file mode 100644 index 0000000..2f2a918 --- /dev/null +++ b/extensions/fablabchemnitz/purge_pointy_paths/meta.json @@ -0,0 +1,20 @@ +[ + { + "name": "Purge Pointy Paths", + "id": "fablabchemnitz.de.purge_pointy_paths", + "path": "purge_pointy_paths", + "dependent_extensions": null, + "original_name": "Purge Pointy Paths", + "original_id": "fablabchemnitz.de.purge_pointy_paths", + "license": "GNU GPL v3", + "license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/LICENSE", + "comment": "Written by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/purge_pointy_paths", + "fork_url": null, + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Purge+Pointy+Paths", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.inx b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.inx new file mode 100644 index 0000000..dd6c399 --- /dev/null +++ b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.inx @@ -0,0 +1,16 @@ + + + Purge Pointy Paths + fablabchemnitz.de.purge_pointy_paths + + path + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py new file mode 100644 index 0000000..25383cc --- /dev/null +++ b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +""" +This filter deletes paths which render as point only + +More usesless and/or redundant filters for removing duplicate nodes and segments are provided by the following extension: +- https://stadtfabrikanten.org/display/IFM/Purge+Duplicate+Path+Segments +- https://stadtfabrikanten.org/display/IFM/Purge+Duplicate+Path+Nodes + +Extension for InkScape 1.X +Author: Mario Voigt / FabLab Chemnitz +Mail: mario.voigt@stadtfabrikanten.org +Date: 21.04.2021 +Last patch: 03.10.2022 +License: GNU GPL v3 +""" + +import inkex +from lxml import etree + +class PurgePointyPaths(inkex.EffectExtension): + + def effect(self): + + selected = [] #list of items to parse + if len(self.svg.selected) == 0: + for element in self.document.getroot().iter("*"): + selected.append(element) + else: + selected = self.svg.selected.values() + + for element in selected: + if isinstance(element, inkex.PathElement): + p = element.path + commandsCoords = p.to_arrays() + # "m 45.250809,91.692739" - this path contains onyl one command - a single point + if len(commandsCoords) == 1: + element.delete() + inkex.utils.debug("Element {} was deleted".format(element.get('id'))) + # "m 45.250809,91.692739 z" - this path contains two commands, but only one coordinate. + # It's a single point, the path is closed by a Z command + elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]: + element.delete() + inkex.utils.debug("Element {} was deleted".format(element.get('id'))) + # "m 45.250809,91.692739 l 45.250809,91.692739" - this path contains two commands, + # but the first and second coordinate are the same. It will render as point + elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z': + element.delete() + inkex.utils.debug("Element {} was deleted".format(element.get('id'))) + # "m 45.250809,91.692739 l 45.250809,91.692739 z" - this path contains three commands, + # but the first and second coordinate are the same. It will render as point, the path is closed by a Z command + elif len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z': + element.delete() + inkex.utils.debug("Element {} was deleted".format(element.get('id'))) + +if __name__ == '__main__': + PurgePointyPaths().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/set_css_class/meta.json b/extensions/fablabchemnitz/set_css_class/meta.json new file mode 100644 index 0000000..84e2047 --- /dev/null +++ b/extensions/fablabchemnitz/set_css_class/meta.json @@ -0,0 +1,21 @@ +[ + { + "name": "Set CSS Class On Elements", + "id": "fablabchemnitz.de.set_css_class", + "path": "set_css_class", + "dependent_extensions": null, + "original_name": "Set CSS class on elements", + "original_id": "org.inkscape.stylesheet.set", + "license": "GNU GPL", + "license_url": "https://github.com/monomon/inkscape-set-css-class/blob/master/set_css_class.py", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/set_css_class", + "fork_url": "https://github.com/monomon/inkscape-set-css-class", + "documentation_url": "https://stadtfabrikanten.org/display/IFM/Set+CSS+Class+On+Elements", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/monomon", + "github.com/eridur-de" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/set_css_class/set_css_class.inx b/extensions/fablabchemnitz/set_css_class/set_css_class.inx new file mode 100644 index 0000000..422e25c --- /dev/null +++ b/extensions/fablabchemnitz/set_css_class/set_css_class.inx @@ -0,0 +1,19 @@ + + + Set CSS Class On Elements + fablabchemnitz.de.set_css_class + + class1 + true + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/set_css_class/set_css_class.py b/extensions/fablabchemnitz/set_css_class/set_css_class.py new file mode 100644 index 0000000..60a271b --- /dev/null +++ b/extensions/fablabchemnitz/set_css_class/set_css_class.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +""" +Sets a css class on selected elements, while optionally removing the elements' styling. +If inline styles are not removed, the css class might not have effect. + +Inspired by MergeStyles (and best used together with it). +""" + +__author__ = "Mois Moshev" +__email__ = "mois@monomon.me" +__copyright__ = "Copyright (C) 2017 Mois Moshev" +__license__ = "GPL" + +import inkex +import sys + +class SetCSSClass(inkex.EffectExtension): + + def add_arguments(self, pars): + pars.add_argument("--name", help="Name of css class to apply") + pars.add_argument("--clear_styles", type=inkex.Boolean, default=True, help="Name of css class to apply") + + def effect(self): + newclass = self.options.name + elements = self.svg.selected.values() + + for el in elements: + current_classes = el.attrib.has_key("class") and el.attrib["class"].split() or [] + + if newclass not in current_classes: + current_classes.append(newclass) + + if self.options.clear_styles: + el.attrib.pop("style", None) + + el.attrib["class"] = " ".join(current_classes) + +if __name__ == "__main__": + SetCSSClass().run()