adding back several more extensions

This commit is contained in:
Mario Voigt 2022-10-03 13:42:30 +02:00
parent 58ed243ac0
commit 196337a7bc
78 changed files with 8084 additions and 26 deletions

View File

@ -7,14 +7,14 @@
"original_name": "Convert Vertical/Horizontal To Line",
"original_id": "fablabchemnitz.de.convert_vertical_horizontal_to_line",
"license": "GNU GPL v3",
"license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE",
"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.X/src/branch/master/extensions/fablabchemnitz/convert_vertical_horizontal_to_line",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/convert_vertical_horizontal_to_line",
"fork_url": null,
"documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=79626259",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -9,13 +9,13 @@
"license": "GNU GPL v3",
"license_url": "https://github.com/chrille69/Inkscape-Extension-pathpoints2dots/blob/master/LICENSE",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/dots_to_path_points",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/dots_to_path_points",
"fork_url": "https://github.com/chrille69/Inkscape-Extension-pathpoints2dots",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Dots+To+Path+Points",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/chrille69",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -9,13 +9,13 @@
"license": "GNU LGPL v2",
"license_url": "https://inkscape.org/~MatheM/%E2%98%85simple-attribute-editor+1",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/edit_attributes",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/edit_attributes",
"fork_url": "https://inkscape.org/~MatheM/%E2%98%85simple-attribute-editor+1",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Edit+Attributes",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/MatheM",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -10,14 +10,14 @@
"original_name": "Filter By Length/Area",
"original_id": "com.filter_by_length_area",
"license": "GNU GPL v3",
"license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE",
"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.X/src/branch/master/extensions/fablabchemnitz/filter_by_length_area",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/filter_by_length_area",
"fork_url": null,
"documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=74645969",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Filter To Layer</name>
<id>fablabchemnitz.de.filter_to_layer</id>
<param name="type" type="optiongroup" appearance="radio" gui-text="Filter to current layer:">
<option>Add</option>
<option>Remove</option>
</param>
<label>Filter from selected item: Apply only for the future draws and for selected item. Problem: you can't add more live effects to elements.</label>
<effect needs-document="true">
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Groups and Layers"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">filter_to_layer.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,82 @@
#!/usr/bin/env python3
'''
This extension adds filters to current layer or removes filters from current layer
Copyright (C) 2012 Jabiertxo Arraiza, jabier.arraiza@marker.es
Version 0.3
TODO:
Comment Better!!!
CHANGE LOG
0.1 Start 30/07/2012
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
import re
class FilterToLayer(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument('--type', default = 'Add', help = 'Add or remove filters to current layer')
def selectTop(self):
selectedSorted = None
if self.svg.selected is not None:
for element in self.document.getroot().iter():
if element.get("id") in self.svg.selection:
selectedSorted = element
return selectedSorted
def effect(self):
svg = self.document.getroot()
typeOperation = self.options.type
xpathStr = '//sodipodi:namedview'
namedview = svg.xpath(xpathStr, namespaces=inkex.NSS)
idLayer = namedview[0].get('{http://www.inkscape.org/namespaces/inkscape}current-layer');
xpathStr = '//svg:g[@id="'+idLayer+'"]'
layer = svg.xpath(xpathStr, namespaces=inkex.NSS)
if typeOperation == "Add": #Add action
element = self.selectTop()
if element is not None:
if element.get('style'):
matchObj = re.search( r'filter:url\(#.*?[^\)]\)', element.get('style'), re.M|re.I)
if matchObj:
filter = matchObj.group()
element.set('style',element.get('style').replace(filter,"").replace(";;",";"))
if layer[0].get('style'):
matchObj = re.search( r'filter:url\(#.*?[^\)]\)', layer[0].get('style'), re.M|re.I)
if matchObj:
element.set('style',element.get('style').replace(matchObj.group(),"").replace(";;",";"))
style = layer[0].get('style')+ ";" + filter;
layer[0].set('style',style.replace(";;",";"))
else:
layer[0].set('style',filter)
else:
inkex.utils.debug("Nothing selected")
else: #Remove action
if layer[0].get('style'):
matchObj = re.search( r'filter:url\(#.*?[^\)]\)', layer[0].get('style'), re.M|re.I)
if matchObj:
layer[0].set('style',layer[0].get('style').replace(matchObj.group(),"").replace(";;",";"))
if __name__ == '__main__':
FilterToLayer().run()

View File

@ -0,0 +1,21 @@
[
{
"name": "Filter To Layer",
"id": "fablabchemnitz.de.filter_to_layer",
"path": "filter_to_layer",
"dependent_extensions": null,
"original_name": "Filter to layer",
"original_id": "org.inkscape.filter.layer",
"license": "GNU GPL v2",
"license_url": "https://inkscape.org/~jabiertxof/%E2%98%85filter-layer",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/filter_to_layer",
"fork_url": "https://inkscape.org/~jabiertxof/%E2%98%85filter-layer",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Filter+To+Layer",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/jabiertxof",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>GPX Import</name>
<id>fablabchemnitz.de.gpx_import</id>
<param name="tab" type="notebook">
<page name="options" gui-text="Options">
<param name="m" type="int" gui-text="Maximum width or height of the SVG in pixels" min="0" max="100000">3000</param>
<param name="d" type="bool" gui-text="Drop single points" gui-description="Default: draw a circle with 1px diameter">true</param>
<param name="r" type="bool" gui-text="Raw conversion" gui-description="Create on SVG path per track segment, don't try to combine paths that end with the starting piont of another path">true</param>
<param name="j" type="bool" gui-text="Join all segments" gui-description="Join all segments to a big one in the order of the gpx file. This can create an oun-scattered path if the default combining algorthm does not work because there are no matching pints across segments (implies raw conversion)">true</param>
</page>
<page name="help" gui-text="Help">
<label appearance="header">Homepage</label>
<label appearance="url">https://efossils.somxslibres.net/fossil/user/mono/repository/inkgpx2svg/index</label>
<label appearance="header">based on gpx2svg</label>
<label appearance="url">https://nasauber.de/opensource/gpx2svg/</label>
</page>
</param>
<input>
<extension>.gpx</extension>
<mimetype>application/gpx+xml</mimetype>
<filetypename>GPS eXchange Format (*.gpx)</filetypename>
<filetypetooltip>Import GPX Format</filetypetooltip>
</input>
<script>
<command location="inx" interpreter="python">gpx_import.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,379 @@
#!/usr/bin/env python3
# Copyright (c) 2012-2018 Tobias Leupold <tobias.leupold@gmx.de>
#
# gpx2svg - Convert GPX formatted geodata to Scalable Vector Graphics (SVG)
#
# 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 in version 2 of the License.
#
# 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.
#
# modified by monomono@disroot.org at 2019-08-05 for use on inkscape extension,
# 3to2 python converter and adjust parser_options for inkscape compatibility.
from __future__ import division
from __future__ import absolute_import
from io import open
__version__ = u'@VERSION@'
import argparse
import sys
import math
from xml.dom.minidom import parse as parseXml
from os.path import abspath
def parseGpx(gpxFile):
u"""Get the latitude and longitude data of all track segments in a GPX file"""
if gpxFile == u'/dev/stdin':
gpxFile = sys.stdin
# Get the XML information
try:
gpx = parseXml(gpxFile)
except IOError as error:
print (sys.stderr, u'Error while reading file: {}. Terminating.'.format(error))
sys.exit(1)
except:
print (sys.stderr, u'Error while parsing XML data:')
print (sys.stderr, sys.exc_info())
print (sys.stderr, u'Terminating.')
sys.exit(1)
# Iterate over all tracks, track segments and points
gpsData = []
for track in gpx.getElementsByTagName(u'trk'):
for trackseg in track.getElementsByTagName(u'trkseg'):
trackSegData = []
for point in trackseg.getElementsByTagName(u'trkpt'):
trackSegData.append(
(float(point.attributes[u'lon'].value), float(point.attributes[u'lat'].value))
)
# Leave out empty segments
if(trackSegData != []):
gpsData.append(trackSegData)
return gpsData
def calcProjection(gpsData):
u"""Calculate a plane projection for a GPS dataset"""
projectedData = []
for segment in gpsData:
projectedSegment = []
for coord in segment:
# At the moment, we only have the Mercator projection
projectedSegment.append(mercatorProjection(coord))
projectedData.append(projectedSegment)
return projectedData
def mercatorProjection(coord):
u"""Calculate the Mercator projection of a coordinate pair"""
# Assuming we're on earth, we have (according to GRS 80):
r = 6378137.0
# As long as meridian = 0 and can't be changed, we don't need:
# meridian = meridian * math.pi / 180.0
# x = r * ((coord[0] * math.pi / 180.0) - meridian)
# Instead, we use this simplified version:
x = r * coord[0] * math.pi / 180.0
y = r * math.log(math.tan((math.pi / 4.0) + ((coord[1] * math.pi / 180.0) / 2.0)))
return x, y
def moveProjectedData(gpsData):
u"""Move a dataset to 0,0 and return it with the resulting width and height"""
# Find the minimum and maximum x and y coordinates
minX = maxX = gpsData[0][0][0]
minY = maxY = gpsData[0][0][1]
for segment in gpsData:
for coord in segment:
if coord[0] < minX:
minX = coord[0]
if coord[0] > maxX:
maxX = coord[0]
if coord[1] < minY:
minY = coord[1]
if coord[1] > maxY:
maxY = coord[1]
# Move the GPS data to 0,0
movedGpsData = []
for segment in gpsData:
movedSegment = []
for coord in segment:
movedSegment.append((coord[0] - minX, coord[1] - minY))
movedGpsData.append(movedSegment)
# Return the moved data and it's width and height
return movedGpsData, maxX - minX, maxY - minY
def searchCircularSegments(gpsData):
u"""Splits a GPS dataset to tracks that are circular and other tracks"""
circularSegments = []
straightSegments = []
for segment in gpsData:
if segment[0] == segment[len(segment) - 1]:
circularSegments.append(segment)
else:
straightSegments.append(segment)
return circularSegments, straightSegments
def combineSegmentPairs(gpsData):
u"""Combine segment pairs to one bigger segment"""
combinedData = []
# Walk through the GPS data and search for segment pairs
# that end with the starting point of another track
while len(gpsData) > 0:
# Get one segment from the source GPS data
firstTrackData = gpsData.pop()
foundMatch = False
# Try to find a matching segment
for i in xrange(len(gpsData)):
if firstTrackData[len(firstTrackData) - 1] == gpsData[i][0]:
# There is a matching segment, so break here
foundMatch = True
break
if foundMatch == True:
# We found a pair of segments with one shared point, so pop the data of the second
# segment from the source GPS data and create a new segment containing all data, but
# without the overlapping point
firstTrackData.pop()
combinedData.append(firstTrackData + gpsData[i])
gpsData.pop(i)
else:
# No segment with a shared point was found, so just append the data to the output
combinedData.append(firstTrackData)
return searchCircularSegments(combinedData)
def combineSegments(gpsData):
u"""Combine all segments of a GPS dataset that can be combined"""
# Search for circular segments. We can't combine them with any other segment.
circularSegments, remainingSegments = searchCircularSegments(gpsData)
# Search for segments that can be combined
while True:
# Look how many tracks we have now
segmentsBefore = len(remainingSegments)
# Search for segments that can be combined
newCircularSegments, remainingSegments = combineSegmentPairs(remainingSegments)
# Add newly found circular segments to processedSegments -- they can't be used anymore
circularSegments = circularSegments + newCircularSegments
if segmentsBefore == len(remainingSegments):
# combineSegmentPairs() did not reduce the number of tracks anymore,
# so we can't combine more tracks and can stop here
break
return circularSegments + remainingSegments
def chronologyJoinSegments(gpsData):
u"""Join all segments to a big one in the order defined by the GPX file."""
joinedSegment = []
for segment in gpsData:
joinedSegment += segment
return [joinedSegment]
def scaleCoords(coord, height, scale):
u"""Return a scaled pair of coordinates"""
return coord[0] * scale, (coord[1] * -1 + height) * scale
def generateScaledSegment(segment, height, scale):
u"""Create the coordinate part of an SVG path string from a GPS data segment"""
for coord in segment:
yield scaleCoords(coord, height, scale)
def writeSvgData(gpsData, width, height, maxPixels, dropSinglePoints, outfile):
u"""Output the SVG data -- quick 'n' dirty, without messing around with dom stuff ;-)"""
# Calculate the scale factor we need to fit the requested maximal output size
if width <= maxPixels and height <= maxPixels:
scale = 1
elif width > height:
scale = maxPixels / width
else:
scale = maxPixels / height
# Open the requested output file or map to /dev/stdout
if outfile != u'/dev/stdout':
try:
fp = open(outfile, u'w')
except IOError as error:
print (sys.stderr, u"Can't open output file: {}. Terminating.".format(error))
sys.exit(1)
else:
fp = sys.stdout
# Header data
fp.write( u'<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n')
fp.write((u'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" '
u'"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'))
fp.write( u'<!-- Created with gpx2svg {} -->\n'.format(__version__))
fp.write((u'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" '
u'width="{}px" height="{}px">\n').format(width * scale, height * scale))
# Process all track segments and generate ids and path drawing commands for them
# First, we split the data to circular and straight segments
circularSegments, straightSegments = searchCircularSegments(gpsData)
realCircularSegments = []
singlePoints = []
for segment in circularSegments:
# We can leave out the last point, because it's equal to the first one
segment.pop()
if len(segment) == 1:
# It's a single point
if dropSinglePoints == False:
# We want to keep single points, so add it to singlePoints
singlePoints.append(segment)
else:
realCircularSegments.append(segment)
circularSegments = realCircularSegments
# Draw single points if requested
if len(singlePoints) > 0:
fp.write(u'<g>\n')
for segment in singlePoints:
x, y = scaleCoords(segment[0], height, scale)
fp.write(
u'<circle cx="{}" cy="{}" r="0.5" style="stroke:none;fill:black"/>\n'.format(x, y)
)
fp.write(u'</g>\n')
# Draw all circular segments
if len(circularSegments) > 0:
fp.write(u'<g>\n')
for segment in circularSegments:
fp.write(u'<path d="M')
for x, y in generateScaledSegment(segment, height, scale):
fp.write(u' {} {}'.format(x, y))
fp.write(u' Z" style="fill:none;stroke:black"/>\n')
fp.write(u'</g>\n')
# Draw all un-closed paths
if len(straightSegments) > 0:
fp.write(u'<g>\n')
for segment in straightSegments:
fp.write(u'<path d="M')
for x, y in generateScaledSegment(segment, height, scale):
fp.write(u' {} {}'.format(x, y))
fp.write(u'" style="fill:none;stroke:black"/>\n')
fp.write(u'</g>\n')
# Close the XML
fp.write(u'</svg>\n')
# Close the file if necessary
if fp != sys.stdout:
fp.close()
def main():
# Setup the command line argument parser
cmdArgParser = argparse.ArgumentParser(
description = u'Convert GPX formatted geodata to Scalable Vector Graphics (SVG)',
epilog = u'gpx2svg {} - http://nasauber.de/opensource/gpx2svg/'.format(__version__)
)
cmdArgParser.add_argument(
u'i', metavar = u'FILE', nargs = u'?', default = u'/dev/stdin',
help = u'GPX input file (default: read from STDIN)'
)
cmdArgParser.add_argument(
u'--o', metavar = u'FILE', nargs = u'?', default = u'/dev/stdout',
help = u'SVG output file (default: write to STDOUT)'
)
cmdArgParser.add_argument(
u'--m', metavar = u'PIXELS', nargs = u'?', type = int, default = 3000,
help = u'Maximum width or height of the SVG output in pixels (default: 3000)'
)
cmdArgParser.add_argument(
u'--d',
help = u'Drop single points (default: draw a circle with 1px diameter)'
)
cmdArgParser.add_argument(
u'--r',
help = (u'"Raw" conversion: Create one SVG path per track segment, don\'t try to combine '
u'paths that end with the starting point of another path')
)
cmdArgParser.add_argument(
u'--j',
help = (u'Join all segments to a big one in the order of the GPX file. This can create an '
u'un-scattered path if the default combining algorithm does not work because there '
u'are no matching points across segments (implies -r)')
)
cmdArgParser.add_argument(
u'--tab',
help = (u'inkscape option')
)
# Get the given arguments
cmdArgs = cmdArgParser.parse_args()
# Map "-" to STDIN or STDOUT
if cmdArgs.i == u'-':
cmdArgs.i = u'/dev/stdin'
if cmdArgs.o == u'-':
cmdArgs.o = u'/dev/stdout'
# Check if a given input or output file name is a relative representation of STDIN or STDOUT
if cmdArgs.i != u'/dev/stdin':
if abspath(cmdArgs.i) == u'/dev/stdin':
cmdArgs.i = u'/dev/stdin'
if cmdArgs.o != u'/dev/stdout':
if abspath(cmdArgs.o) == u'/dev/stdout':
cmdArgs.o = u'/dev/stdout'
# Get the latitude and longitude data from the given GPX file or STDIN
gpsData = parseGpx(cmdArgs.i)
# Check if we actually _have_ data
if gpsData == []:
print (sys.stderr, u'No data to convert. Terminating.')
sys.exit(1)
# Join all segments if requested by "-j"
if bool(cmdArgs.j):
gpsData = chronologyJoinSegments(gpsData)
# Try to combine all track segments that can be combined if not requested otherwise
# Don't execute if all segments are already joined with "-j"
if not bool(cmdArgs.r) and not bool(cmdArgs.j):
gpsData = combineSegments(gpsData)
# Calculate a plane projection for a GPS dataset
# At the moment, we only have the Mercator projection
gpsData = calcProjection(gpsData)
# Move the projected data to the 0,0 origin of a cartesial coordinate system
# and get the raw width and height of the resulting vector data
gpsData, width, height = moveProjectedData(gpsData)
# Write the resulting SVG data to the requested output file or STDOUT
writeSvgData(gpsData, width, height, cmdArgs.m, bool(cmdArgs.d), cmdArgs.o)
if __name__ == u'__main__':
main()

View File

@ -0,0 +1,21 @@
[
{
"name": "GPX Import",
"id": "fablabchemnitz.de.gpx_import",
"path": "gpx_import",
"dependent_extensions": null,
"original_name": "GPX Import",
"original_id": "mono.inkscape.pgx_input",
"license": "GNU GPL v2",
"license_url": "https://inkscape.org/de/~mono/%E2%98%85inkgpx2svg",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/gpx_import",
"fork_url": "https://git.disroot.org/monomono/inkgpx2svg",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/GPX+Import",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/mono",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,667 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Gradient Saver</property>
<property name="resizable">False</property>
<property name="window_position">center</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<property name="icon">icon.svg</property>
<property name="gravity">north</property>
<signal name="destroy" handler="onDestroy" swapped="no"/>
<child>
<placeholder/>
</child>
<child>
<object class="GtkNotebook" id="active_page">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="switch-page" handler="onSwitchPage" swapped="no"/>
<child>
<object class="GtkLayout">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="width">400</property>
<property name="height">250</property>
<child>
<object class="GtkScrolledWindow">
<property name="width_request">600</property>
<property name="height_request">180</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox" id="save_gradients_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">30</property>
<property name="margin_top">10</property>
<property name="border_width">2</property>
<property name="orientation">vertical</property>
<property name="spacing">20</property>
<child>
<object class="GtkBox" id="save_gradient1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">10</property>
<property name="spacing">18</property>
<child>
<object class="GtkDrawingArea" id="save_gradient_draw">
<property name="width_request">150</property>
<property name="height_request">42</property>
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="save_gradient_name">
<property name="width_request">325</property>
<property name="height_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">25</property>
<property name="placeholder_text" translatable="yes">e.g Beautiful Color</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="y">130</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="width_request">580</property>
<property name="height_request">32</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">20</property>
<property name="spacing">10</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="save_btn_cancel">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="onDestroy" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_btn_apply">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="onSaveGradientClicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="y">318</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="width_request">600</property>
<property name="height_request">100</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">10</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkImage">
<property name="width_request">55</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">30</property>
<property name="margin_top">21</property>
<property name="stock">gtk-info</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="width_request">250</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">30</property>
<property name="margin_top">14</property>
<property name="label" translatable="yes">&lt;b&gt;Hint:&lt;/b&gt;
Select at least one object that use gradient color in order to add those gradient to your library. Selected gradient object will appear below. You can give a name for your gradients to help you recognize it later.</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="width_request">550</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">45</property>
<property name="margin_right">50</property>
<property name="margin_bottom">10</property>
<property name="spacing">100</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Preview&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Gradient Name&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="y">100</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Add New</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkLayout">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButtonBox">
<property name="width_request">580</property>
<property name="height_request">32</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">20</property>
<property name="spacing">6</property>
<property name="baseline_position">bottom</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="load_gradient_remove1">
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="onRemoveGradientClicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="load_gradient_add1">
<property name="label" translatable="yes">Load</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="onLoadGradientClicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="y">318</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="width_request">600</property>
<property name="height_request">100</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">10</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkImage">
<property name="width_request">55</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">30</property>
<property name="margin_top">21</property>
<property name="stock">gtk-info</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="width_request">250</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">30</property>
<property name="margin_top">14</property>
<property name="label" translatable="yes">&lt;b&gt;Hint:&lt;/b&gt;
Select at least one object that use gradient color in order to add those gradient to your library. Selected gradient object will appear below. You can give a name for your gradients to help you recognize it later.</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="width_request">550</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">45</property>
<property name="margin_right">50</property>
<property name="margin_bottom">10</property>
<property name="spacing">100</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Your Current Gradient&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="y">100</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="width_request">600</property>
<property name="height_request">180</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkFlowBox" id="load_gradients_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="column_spacing">30</property>
<property name="row_spacing">10</property>
<property name="min_children_per_line">2</property>
<property name="max_children_per_line">2</property>
<property name="selection_mode">none</property>
<property name="activate_on_single_click">False</property>
<child>
<object class="GtkFlowBoxChild" id="load_gradient1">
<property name="width_request">60</property>
<property name="height_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">start</property>
<property name="valign">start</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkCheckButton" id="load_gradient_select">
<property name="height_request">42</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="load_gradient_draw">
<property name="width_request">100</property>
<property name="height_request">42</property>
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="load_gradient_text">
<property name="height_request">42</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">ijo trans</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
<property name="max_width_chars">25</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="y">130</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Load or Remove</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkLayout">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="extension_version">
<property name="width_request">317</property>
<property name="height_request">300</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;span font="12"&gt;&lt;b&gt;Version $VERSION&lt;/b&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="x">137</property>
<property name="y">-84</property>
</packing>
</child>
<child>
<object class="GtkImage">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixbuf">icon.svg</property>
</object>
<packing>
<property name="x">10</property>
<property name="y">32</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;span font="12"&gt;&lt;b&gt;Gradient Saver&lt;/b&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="x">69</property>
<property name="y">225</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="width_request">307</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;span&gt;Gradient Saver is an extension for Inkscape that will help you to organize your favorite gradients. This extension created with love by &lt;a href="#"&gt;Sofyan&lt;/a&gt; &amp;amp; &lt;a href="https://raniaamina.id"&gt;Rania Amina&lt;/a&gt; and fully supported by Gimpscape ID Community.
Project Repository:
&lt;a href="#"&gt;&lt;b&gt;https://github.com/artemtech/inkscape-gradient-saver&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="x">243</property>
<property name="y">82</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="width_request">580</property>
<property name="height_request">32</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">20</property>
<property name="spacing">10</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="about_btn_close">
<property name="label" translatable="yes">Close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="onDestroy" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="y">318</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">About</property>
</object>
<packing>
<property name="position">2</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkDialog" id="information_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Information</property>
<property name="icon_name">dialog-information</property>
<property name="type_hint">dialog</property>
<property name="attached_to">window</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="layout_style">center</property>
<child>
<object class="GtkButton" id="information_button">
<property name="label" translatable="yes">Close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="onDestroy" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage">
<property name="width_request">55</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-info</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="information_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Gradient Saver</name>
<id>fablabchemnitz.de.gradient_saver</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Colors/Gradients/Filters"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">gradient_saver.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,386 @@
#! /usr/bin/env python3
# OS modules
import os
import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
# inkscape extension files
import cairo
from lxml import etree
import inkex # required
from inkex.elements import NSS
from inkex.utils import errormsg as show_errormsg
from inkex.styles import Style
from inkex.colors import Color
__version__ = '1.0.0'
saved_gradient_path = "../my-gradients.svg"
def create_new_file(gradient_data):
root = etree.Element("svg", nsmap=NSS)
def_tree = etree.SubElement(root, "defs")
for i, item in enumerate(gradient_data):
gradient = etree.SubElement(def_tree, item.tag, attrib=item.attrib)
for j, gradient_stop in enumerate(item):
etree.SubElement(gradient, gradient_stop.tag, attrib=gradient_stop.attrib, id="stop%d%d" % (i, j))
with open(saved_gradient_path, "w") as f:
f.write(etree.tostring(
root, encoding="utf-8", xml_declaration=True, pretty_print=True).decode("utf-8"))
def save_to_file(data):
""" Wrapper for saving gradients to file. """
if len(data) == 0:
return 1
else:
try:
# read previous data then append it with current data
if os.path.exists(saved_gradient_path):
previous_data = load_gradients_from_file()
data = previous_data + data
create_new_file(data)
return 0
except Exception as e:
import traceback
show_errormsg(e)
show_errormsg(traceback.print_exc())
return -1
def load_gradients_from_file():
""" Load gradients from saved gradient, returned as List """
if os.path.exists(saved_gradient_path) and os.stat(saved_gradient_path).st_size != 0:
root = etree.parse(saved_gradient_path)
mygradients = root.xpath("//linearGradient", namespaces=NSS)
else:
mygradients = []
return mygradients
def read_stop_gradient(gradient):
stop_data = {
"id": gradient.attrib.get("id"),
"stops": []
}
for stop in gradient:
offset = stop.attrib.get("offset")
style = Style(Style.parse_str(stop.attrib['style']))
color = Color.parse_str(style.get("stop-color"))[1]
opacity = style.get("stop-opacity")
stop_data.get("stops").append(
tuple([float(offset)] + [x/256.0 for x in color] + [float(opacity)]))
return stop_data
class MainWindow(Gtk.Builder):
def __init__(self, gradientSaver):
Gtk.Builder.__init__(self)
self.gradientSaver = gradientSaver
self.add_from_file("GUI.glade")
self.window = self.get_object("window")
self.app_version = self.get_object("extension_version")
self.app_version.set_label(self.app_version.get_label().replace("$VERSION",__version__))
self.information_dialog = self.get_object("information_dialog")
# parsing components
# save gradient components
self.save_container = self.get_object("save_gradients_container")
save_template = self.get_object("save_gradient1")
self.save_container.remove(save_template)
for idx, item in enumerate(self.gradientSaver.doc_selected_gradients):
new_save_template = self.SaveGradientTemplate(item)
new_save_template.set_name("gradient%d" % idx)
self.save_container.add(new_save_template)
self.save_container.show_all()
# - end save gradient components
# load gradient components
self.load_container = self.get_object("load_gradients_container")
load_template = self.get_object("load_gradient1")
self.load_container.remove(load_template)
# - end load gradient components
# show the GUI
self.connect_signals(self.Handler(self))
self.window.show()
class SaveGradientTemplate(Gtk.HBox):
"""
Template for generating gradient name
and preview of selected object in the save page.
"""
def __init__(self, gradient_data):
Gtk.HBox.__init__(self)
self.gradient_data = gradient_data
self.set_spacing(20)
preview = Gtk.DrawingArea()
preview.set_size_request(150, 42)
preview.set_app_paintable(True)
preview.connect("draw", self.on_draw, gradient_data)
self.pack_start(preview, False, True, 0)
self.input_entry = Gtk.Entry()
self.input_entry.set_placeholder_text("e.g Beautiful Color")
self.input_entry.set_size_request(250, 42)
self.input_entry.set_text(gradient_data.get("id"))
self.input_entry.set_max_length(25)
self.pack_start(self.input_entry, False, True, 1)
def on_draw(self, wid, cr, data):
"""
Calllback for draw signal for rendering gradient.
params:
- wid :GtkWidget
- cr :Cairo
- data :list -> gradient data
"""
lg = cairo.LinearGradient(0.0, 20.0, 150.0, 20.0)
for stop in data["stops"]:
lg.add_color_stop_rgba(
stop[0], stop[1], stop[2], stop[3], stop[4])
cr.rectangle(10.0, 0.0, 150.0, 42.0)
cr.set_source(lg)
cr.fill()
def get_save_gradient_text(self):
return self.input_entry.get_text()
def get_compiled_gradient(self, new_id):
# compiling gradient stops
root = etree.Element("linearGradient", id=new_id)
for idx, stop in enumerate(self.gradient_data["stops"]):
stop_id = self.get_name() + str(idx)
offset = stop[0]
color = Color([stop[1], stop[2], stop[3]],"rgb")
opacity = stop[4]
tmp_stops = {
"id": stop_id,
"offset": str(offset),
"style": Style({
"stop-color": str(color),
"stop-opacity": str(opacity)
}).to_str()
}
current_stop = etree.SubElement(root, "stop", attrib=tmp_stops)
return root
class LoadGradientTemplate(Gtk.FlowBoxChild):
"""
Template for generating gradient name
and preview of saved gradient in the load page.
"""
def __init__(self, gradient_data):
Gtk.FlowBoxChild.__init__(self)
self.gradient_data = gradient_data
self.set_size_request(60,32)
self.set_halign(Gtk.Align.START)
self.set_valign(Gtk.Align.START)
container = Gtk.HBox()
container.set_spacing(5)
container.set_baseline_position(Gtk.BaselinePosition.TOP)
self.checkbox = Gtk.CheckButton()
self.checkbox.draw_indicator = True
container.pack_start(self.checkbox,False,True,0)
preview = Gtk.DrawingArea()
preview.set_size_request(100, 32)
preview.set_app_paintable(True)
preview.connect("draw", self.on_draw, gradient_data)
container.pack_start(preview,False,True,0)
self.text_gradient = Gtk.Label()
self.text_gradient.set_text(gradient_data.get("id"))
self.text_gradient.set_line_wrap(True)
self.text_gradient.set_line_wrap_mode(1)
self.text_gradient.set_max_width_chars(25)
container.pack_start(self.text_gradient,False,True,0)
self.add(container)
def on_draw(self, wid, cr, data):
"""
Calllback for draw signal for rendering gradient.
params:
- wid :GtkWidget
- cr :Cairo
- data :list -> gradient data
"""
lg = cairo.LinearGradient(0.0, 20.0, 100.0, 20.0)
for stop in data["stops"]:
lg.add_color_stop_rgba(
stop[0], stop[1], stop[2], stop[3], stop[4])
cr.rectangle(10.0, 0.0, 110.0, 32.0)
cr.set_source(lg)
cr.fill()
class Handler:
""" Signal Handler for GUI """
def __init__(self, main_window):
self.main_window = main_window
def onDestroy(self, *args):
Gtk.main_quit()
def onSwitchPage(self, notebook, page, page_num):
if page_num == 0: # save tab
pass
elif page_num == 1: # load/remove tab
self.main_window.gradients_to_load = []
for children in self.main_window.load_container.get_children():
self.main_window.load_container.remove(children)
loaded_gradients = load_gradients_from_file()
# TODO render with disabled checkbox if it already exists in current project doc
for idx,gradient in enumerate(loaded_gradients):
# parse gradient stops
stop_data = read_stop_gradient(gradient)
gradient_info = self.main_window.LoadGradientTemplate(stop_data)
gradient_info.checkbox.connect("toggled",self.onLoadGradientToggled, gradient)
gradient_info.set_name("gradient%d" % idx)
self.main_window.load_container.add(gradient_info)
self.main_window.load_container.show_all()
else:
pass
def onSaveGradientClicked(self, button):
text = ""
gradient_to_save = []
# get all gradient data in save_container
for item in self.main_window.save_container.get_children():
# get new gradient name
new_name_gradient = item.get_save_gradient_text()
# strip all special chars
if not new_name_gradient.isalnum():
new_name_gradient = ''.join(e for e in new_name_gradient if e.isalnum())
# get gradient data
gradient_data = item.get_compiled_gradient(new_name_gradient)
text += "{0}\n-----\n".format(etree.tostring(gradient_data))
gradient_to_save.append(gradient_data)
# save to file
status = save_to_file(gradient_to_save)
if status == 0:
info = "%d gradients saved successfully!" % len(gradient_to_save)
# reload current document info with saved gradients
self.main_window.gradientSaver.reload_current_gradients(gradient_to_save)
elif status == 1:
info = "Nothing to save, there is no object with gradient selected. Exiting..."
elif status == -1:
info = "Internal Error (-1)! "
# showing popup information
self.main_window.get_object("information_text").set_text(info)
self.main_window.information_dialog.set_title("Save Gradient Information")
self.main_window.information_dialog.show_all()
def onLoadGradientToggled(self, togglebutton, gradient):
# if active, queue gradient, otherwise pop it
if togglebutton.get_active():
self.main_window.gradients_to_load.append(gradient)
else:
self.main_window.gradients_to_load.remove(gradient)
def onLoadGradientClicked(self, button):
if len(self.main_window.gradients_to_load) > 0:
self.main_window.gradientSaver.insert_new_gradients_to_current_doc(self.main_window.gradients_to_load)
teks = "Successfully loading these gradients:\n"
teks += "".join(["- "+gradient.attrib["id"]+"\n" for gradient in self.main_window.gradients_to_load])
else:
teks = "No gradient(s) selected to load. Exiting..."
self.main_window.get_object("information_text").set_text(teks)
self.main_window.information_dialog.set_title("Load Gradient Information")
self.main_window.information_dialog.show_all()
def onRemoveGradientClicked(self, button):
loaded_gradients = load_gradients_from_file()
if len(self.main_window.gradients_to_load) > 0:
gradient_to_remove = [gradient.attrib["id"] for gradient in self.main_window.gradients_to_load]
new_gradient_after = [gradient for gradient in loaded_gradients if gradient.attrib["id"] not in gradient_to_remove]
create_new_file(new_gradient_after)
teks = "Successfully removing these gradients:\n"
teks += "".join(["- "+gradient+"\n" for gradient in gradient_to_remove])
else:
teks = "No gradient(s) selected to load. Exiting..."
self.main_window.get_object("information_text").set_text(teks)
self.main_window.information_dialog.set_title("Remove Gradient Information")
self.main_window.information_dialog.show_all()
class GradientSaver(inkex.Effect):
def __init__(self):
" define how the options are mapped from the inx file "
inkex.Effect.__init__(self) # initialize the super class
try:
self.tty = open("/dev/tty", 'w')
except:
self.tty = open(os.devnull, 'w')
self.doc_selected_gradients = []
def insert_new_gradients_to_current_doc(self, gradients):
defs_node = self.svg.getElement("//svg:defs")
for item in gradients:
gradient = etree.SubElement(defs_node,item.tag,attrib=item.attrib)
for stop in item:
etree.SubElement(gradient,stop.tag,attrib=stop.attrib)
def reload_current_gradients(self, new_data):
" reload gradients information in current project with stored gradient "
for idx,gradient in enumerate(self.doc_selected_gradients):
# set old gradient id to new id
real_node = self.svg.getElement("//*[@id='%s']" % gradient["id"])
# remove inkscape collect first
real_node.attrib.pop("{"+NSS["inkscape"]+"}collect", None)
real_node.attrib["id"] = new_data[idx].attrib["id"]
# set old xlink:href to new id
node_href = self.svg.getElement("//*[@xlink:href='#%s']" % gradient["id"])
node_href.attrib["{"+NSS["xlink"]+"}href"] = "#"+new_data[idx].attrib["id"]
# last set up inkscape collect again
real_node.attrib["{"+NSS["inkscape"]+"}collect"] = "always"
def get_all_doc_gradients(self):
"""TODO
retrieve all gradient sources of current project document
"""
pass
def get_selected_gradients_data(self):
selected_objects = self.svg.selected
gradient_list = []
if len(selected_objects) > 0:
for item in selected_objects.values():
style = Style(Style.parse_str(item.get('style')))
fill = stroke = "None"
if style.get("fill"):
fill = style.get("fill")[5:-1] if "url" in style.get("fill") else "None"
if style.get("stroke"):
stroke = style("stroke")[5:-1] if "url" in style.get("stroke") else "None"
if fill == "None" and stroke == "None":
continue
# read fill data
if "radialGradient" in fill or "linearGradient" in fill:
real_fill = self.svg.getElementById(fill).attrib["{"+NSS["xlink"]+"}href"][1:]
real_fill_node = self.svg.getElementById(real_fill)
if real_fill_node not in gradient_list:
gradient_list.append(real_fill_node)
# read stroke data
if "radialGradient" in stroke or "linearGradient" in stroke:
real_stroke = self.svg.getElementById(stroke).attrib["{"+NSS["xlink"]+"}href"][1:]
real_stroke_node = self.svg.getElementById(real_stroke)
if real_stroke_node not in gradient_list:
gradient_list.append(real_stroke_node)
data = []
# read gradients data
for gradient in gradient_list:
# parse gradient stops
stop_data = read_stop_gradient(gradient)
inkex.utils.debug(gradient)
data.append(stop_data)
return data
# called when the extension is running.
def effect(self):
self.doc_selected_gradients = self.get_selected_gradients_data()
try:
app = MainWindow(self)
Gtk.main()
except Exception as e:
import traceback
show_errormsg(e)
show_errormsg(traceback.print_exc())
if __name__ == '__main__':
GradientSaver().run()

View File

@ -0,0 +1,678 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="icon.svg">
<title
id="title239">Gradient Saver Icon</title>
<defs
id="defs2">
<linearGradient
id="linearGradient5327"
inkscape:collect="always">
<stop
id="stop5323"
offset="0"
style="stop-color:#35f600;stop-opacity:1" />
<stop
id="stop5325"
offset="1"
style="stop-color:#f0f600;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4992">
<stop
style="stop-color:#00bfa5;stop-opacity:1"
offset="0"
id="stop4988" />
<stop
style="stop-color:#29ff8a;stop-opacity:1"
offset="1"
id="stop4990" />
</linearGradient>
<linearGradient
id="linearGradient4978"
inkscape:collect="always">
<stop
id="stop4974"
offset="0"
style="stop-color:#6200ea;stop-opacity:1" />
<stop
id="stop4976"
offset="1"
style="stop-color:#f50048;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4972">
<stop
style="stop-color:#00c853;stop-opacity:1"
offset="0"
id="stop4968" />
<stop
style="stop-color:#2196f3;stop-opacity:1"
offset="1"
id="stop4970" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4977">
<stop
style="stop-color:#fdd835;stop-opacity:1"
offset="0"
id="stop4973" />
<stop
style="stop-color:#f50057;stop-opacity:1"
offset="1"
id="stop4975" />
</linearGradient>
<linearGradient
id="linearGradient4851"
inkscape:collect="always">
<stop
id="stop4847"
offset="0"
style="stop-color:#1de9b6;stop-opacity:1" />
<stop
id="stop4849"
offset="1"
style="stop-color:#2962ff;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4753">
<stop
style="stop-color:#d500f9;stop-opacity:1"
offset="0"
id="stop4749" />
<stop
style="stop-color:#6200ea;stop-opacity:1"
offset="1"
id="stop4751" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4753"
id="linearGradient4755"
x1="114.52679"
y1="122.37501"
x2="85.328125"
y2="153.12674"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(8.3154762)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient4845"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(8.3154762)"
x1="115.28274"
y1="124.26488"
x2="75.122765"
y2="157.66246" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient4834"
x1="-372.85895"
y1="77.110123"
x2="-317.53687"
y2="46.030495"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7490779,0,0,0.7490779,-28.486614,89.363651)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4977"
id="linearGradient4932"
x1="-81.856453"
y1="213.70543"
x2="-83.746712"
y2="278.80466"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.63636261,0,0,0.63636261,-11.36592,145.37946)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4977"
id="linearGradient4940"
x1="-101.17622"
y1="231.34521"
x2="-115.24634"
y2="199.42558"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4977"
id="linearGradient4952"
x1="-61.471992"
y1="208.40015"
x2="-50.513939"
y2="218.02187"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,-10.503224,0)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4978"
id="linearGradient4958"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,77.718339,5.7980475)"
x1="-61.359409"
y1="232.67445"
x2="-53.959938"
y2="206.80617" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient4962"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,157.24809,-18.087736)"
x1="-61.471992"
y1="208.40015"
x2="-50.513939"
y2="218.02187" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4972"
id="linearGradient4966"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,226.92887,-70.453899)"
x1="-61.471992"
y1="208.40015"
x2="-52.248871"
y2="224.28619" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4992"
id="linearGradient4986"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,225.00896,-68.355136)"
x1="-47.505936"
y1="221.68723"
x2="-56.489384"
y2="202.32527" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4977"
id="linearGradient5011"
gradientUnits="userSpaceOnUse"
x1="-131.41586"
y1="199.4256"
x2="-125.32622"
y2="216.22539"
gradientTransform="matrix(0.40495803,0,0,0.40495803,146.66448,176.80023)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient5305"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.40495803,0,0,0.40495803,71.206797,177.92807)"
x1="-134.1552"
y1="187.01805"
x2="-125.32622"
y2="216.22539" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4978"
id="linearGradient5309"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,77.145743,4.2945512)"
x1="-53.819473"
y1="237.63091"
x2="-52.285004"
y2="209.06267" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient5311"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8245614,0,0,1,156.2106,-19.317359)"
x1="-52.407578"
y1="211.81105"
x2="-56.196835"
y2="236.80499" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient5315"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.40495803,0,0,0.40495803,71.206797,177.92807)"
x1="-43.361553"
y1="209.01698"
x2="-84.406708"
y2="287.03156" />
<linearGradient
inkscape:collect="always"
id="linearGradient3883">
<stop
style="stop-color:#dddbd8;stop-opacity:1"
offset="0"
id="stop3879" />
<stop
style="stop-color:#f5f4f2;stop-opacity:1"
offset="1"
id="stop3881" />
</linearGradient>
<linearGradient
id="linearGradient3094"
inkscape:collect="always">
<stop
id="stop3090"
offset="0"
style="stop-color:#0b394d;stop-opacity:1;" />
<stop
id="stop3092"
offset="1"
style="stop-color:#0b394d;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient2639"
inkscape:collect="always">
<stop
id="stop2635"
offset="0"
style="stop-color:#fe6a2d;stop-opacity:1" />
<stop
id="stop2637"
offset="1"
style="stop-color:#9b0101;stop-opacity:1" />
</linearGradient>
<clipPath
id="clipPath2609"
clipPathUnits="userSpaceOnUse">
<rect
ry="10.056858"
rx="10.056858"
y="-85.398689"
x="1592.8157"
height="58.391529"
width="90.441025"
id="rect2611"
style="opacity:1;vector-effect:none;fill:#3d83cf;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers" />
</clipPath>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="246.60634"
x2="643.51672"
y1="257.47424"
x1="643.51672"
id="linearGradient1561-1"
xlink:href="#linearGradient3883"
inkscape:collect="always" />
<filter
height="1.1218587"
y="-0.060929373"
width="1.0463915"
x="-0.02319574"
id="filter3130-5"
style="color-interpolation-filters:sRGB"
inkscape:collect="always">
<feGaussianBlur
id="feGaussianBlur3132-3"
stdDeviation="0.45051951"
inkscape:collect="always" />
</filter>
<linearGradient
gradientTransform="matrix(1,0,-0.26717917,-0.37367534,29.058353,152.44235)"
gradientUnits="userSpaceOnUse"
y2="166.3714"
x2="1384.7688"
y1="-3.469604"
x1="1362.2035"
id="linearGradient3096-8"
xlink:href="#linearGradient3094"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="-94.958282"
x2="1617.5334"
y1="-135.36632"
x1="1615.9795"
id="linearGradient2641-1"
xlink:href="#linearGradient2639"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="-549.33533"
x2="1543.2006"
y1="-489.51007"
x1="1540.6981"
id="linearGradient2649-6"
xlink:href="#linearGradient4977"
inkscape:collect="always"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-545.58139,422.10485)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="-869.45026"
x2="1369.0061"
y1="-928.71313"
x1="1365.6919"
id="linearGradient2657-3"
xlink:href="#linearGradient4851"
inkscape:collect="always"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-417.74238,548.92883)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="-1259.3573"
x2="1095.538"
y1="-1193.1265"
x1="1094.515"
id="linearGradient2665-6"
xlink:href="#linearGradient4851"
inkscape:collect="always"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-261.43492,638.34422)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="-1459.3491"
x2="748.05066"
y1="-1503.9033"
x1="745.37823"
id="linearGradient2673-8"
xlink:href="#linearGradient5327"
inkscape:collect="always"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-87.311101,684.2575)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="-1645.3777"
x2="352.32254"
y1="-1596.4655"
x1="361.24866"
id="linearGradient2681-9"
xlink:href="#linearGradient5327"
inkscape:collect="always"
gradientTransform="matrix(0.39357722,0,0,0.39357722,92.762826,683.53977)" />
<clipPath
id="clipPath2609-4"
clipPathUnits="userSpaceOnUse">
<rect
ry="10.056858"
rx="10.056858"
y="-85.398689"
x="1592.8157"
height="58.391529"
width="90.441025"
id="rect2611-0"
style="opacity:1;vector-effect:none;fill:#3d83cf;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4977"
id="linearGradient5566"
gradientUnits="userSpaceOnUse"
x1="1615.9795"
y1="-135.36632"
x2="1617.5334"
y2="-94.958282"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-636.23993,266.51512)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient5674"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-417.74238,548.92883)"
x1="1365.6919"
y1="-928.71313"
x2="1368.8816"
y2="-878.95062" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient5676"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-261.43492,638.34422)"
x1="1094.515"
y1="-1193.1265"
x2="1098.1172"
y2="-1263.8123" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5327"
id="linearGradient5678"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39357722,0,0,0.39357722,92.762826,683.53977)"
x1="361.24866"
y1="-1596.4655"
x2="352.32254"
y2="-1645.3777" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4851"
id="linearGradient5694"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.39357722,0,0,0.39357722,-261.43492,638.34422)"
x1="1094.515"
y1="-1193.1265"
x2="1098.1172"
y2="-1263.8123" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.0273438"
inkscape:cx="34.014139"
inkscape:cy="85.816088"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1366"
inkscape:window-height="712"
inkscape:window-x="0"
inkscape:window-y="28"
inkscape:window-maximized="1"
inkscape:snap-global="false"
units="px" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gradient Saver Icon</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Hadiid Pratama</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-nc/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-nc/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:prohibits
rdf:resource="http://creativecommons.org/ns#CommercialUse" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<g
id="g226"
transform="translate(-4.7231367,-1.696596)">
<path
style="opacity:0.66799999;vector-effect:none;fill:none;fill-opacity:1;stroke:none;stroke-width:1.62901139;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;filter:url(#filter3130-5)"
d="m 1365.4604,94.01541 c -0.7804,0 -1.241,0.234791 -1.0325,0.526396 l 4.7725,6.674764 -3.582,0.3862 c -0.8145,0.0879 -1.363,0.36813 -1.4493,0.69362 -0.027,0.0194 -0.053,0.0388 -0.075,0.0593 -0.1454,0.13326 -0.1905,0.28935 -0.115,0.45823 0,0 2e-4,1.9e-4 2e-4,1.9e-4 0.013,0.0337 0.034,0.0681 0.06,0.10273 l 5.6074,7.84226 c 0.05,0.0694 0.1169,0.13701 0.1986,0.20238 0,0 2e-4,1.9e-4 2e-4,1.9e-4 0.1644,0.13066 0.3904,0.25203 0.6592,0.35859 0.2019,0.08 0.424,0.15162 0.6691,0.2128 0.5654,0.14275 1.2217,0.22825 1.8718,0.22825 h 35.4505 c 0.093,-10e-6 0.1828,-0.002 0.2714,-0.005 0.2636,-0.0102 0.5048,-0.0355 0.7186,-0.0734 0.071,-0.0126 0.1394,-0.0267 0.2044,-0.0421 0.065,-0.0153 0.1267,-0.0323 0.1852,-0.0502 0.117,-0.0359 0.2203,-0.077 0.3091,-0.12223 0.2664,-0.13583 0.4003,-0.31088 0.3673,-0.5069 -0.01,-0.0327 -0.016,-0.0659 -0.031,-0.0996 -0.013,-0.0338 -0.034,-0.068 -0.06,-0.10273 l -1.7115,-2.39388 -2.1839,-3.05449 -1.7117,-2.39389 c -0.025,-0.0347 -0.049,-0.0692 -0.087,-0.10292 -0.033,-0.0338 -0.071,-0.067 -0.1115,-0.0996 -0.1645,-0.13073 -0.3903,-0.25198 -0.6593,-0.35859 -0.1345,-0.0533 -0.2798,-0.10301 -0.4344,-0.1483 -0.1537,-0.0453 -0.3151,-0.0863 -0.4838,-0.12224 0,0 -5e-4,0 -5e-4,0 -0.085,-0.0179 -0.1699,-0.0346 -0.2563,-0.05 0,0 -6e-4,0 -6e-4,0 -0.087,-0.0154 -0.1754,-0.0295 -0.2642,-0.0421 0,0 -6e-4,0 -6e-4,0 -0.2676,-0.0379 -0.5445,-0.0631 -0.823,-0.0734 0,0 -5e-4,0 -5e-4,0 -0.091,-0.003 -0.1849,-0.005 -0.2776,-0.005 h -5e-4 -1.3436 l -0.4127,-0.28792 -1.2344,-0.8622 c -0.2629,-0.18344 -0.7316,-0.31729 -1.2196,-0.36786 0.1127,-0.15515 -0.014,-0.34839 -0.3868,-0.512876 l -3.3931,-1.501175 c -0.3716,-0.164436 -0.8912,-0.257825 -1.3664,-0.263004 0,-0.01412 -0.01,-0.02836 -0.011,-0.04268 8e-4,-0.0059 0,-0.01166 0,-0.01757 10e-5,-7.23e-4 10e-5,-0.0011 -0.01,-0.0019 -0.062,-0.153559 -0.3058,-0.313129 -0.7073,-0.431393 l -4.1571,-1.225809 c -0.4553,-0.13428 -0.9904,-0.180421 -1.4201,-0.139807 -0.01,-0.0087 -0.012,-0.01741 -0.018,-0.02608 -0.03,-0.0287 -0.06,-0.05691 -0.099,-0.08477 -0.01,-0.0071 -0.019,-0.01405 -0.029,-0.02104 -0.041,-0.02773 -0.086,-0.05499 -0.1391,-0.0811 -0.1806,-0.09206 -0.4333,-0.172313 -0.7282,-0.227476 l -4.6375,-0.866642 c -0.5082,-0.09498 -1.0223,-0.09104 -1.3778,-0.0073 -0.019,-0.0099 -0.031,-0.01951 -0.047,-0.02915 -0.042,-0.02496 -0.089,-0.04916 -0.1403,-0.07241 -0.012,-0.0039 -0.013,-0.0081 -0.024,-0.01196 -0.063,-0.02608 -0.1242,-0.0504 -0.1935,-0.07357 -0.052,-0.01835 -0.113,-0.03595 -0.1693,-0.05214 -3e-4,-3.74e-4 10e-5,-7.23e-4 2e-4,-0.0015 -0.1984,-0.0536 -0.4223,-0.09456 -0.6608,-0.116829 l -4.8017,-0.448769 c -0.5254,-0.04909 -0.9827,0.0045 -1.2396,0.125132 -0.01,-0.0026 -0.015,-0.0052 -0.023,-0.0079 -0.01,-0.0068 -0.037,-0.01312 -0.046,-0.01969 -0.059,-0.02074 -0.1157,-0.04038 -0.1681,-0.05871 -0.018,-0.0065 -0.046,-0.01255 -0.064,-0.01872 -0.056,-0.01555 -0.1122,-0.02975 -0.1713,-0.04306 -0.038,-0.0086 -0.076,-0.0173 -0.1133,-0.02492 -0.02,-0.0033 -0.033,-0.0065 -0.049,-0.0095 -0.07,-0.0127 -0.1414,-0.02354 -0.2141,-0.03284 -0.014,-0.0015 -0.025,-0.003 -0.036,-0.0045 -0.078,-0.0092 -0.1542,-0.01629 -0.2326,-0.02123 -3e-4,-1.83e-4 -0.012,-7.23e-4 -0.012,-7.23e-4 v 0 c 0,0 -5e-4,1.91e-4 -5e-4,1.91e-4 -0.08,-0.0048 -0.1603,-0.0079 -0.2406,-0.0079 z"
id="path140"
inkscape:connector-curvature="0"
inkscape:transform-center-y="-7.3219625"
inkscape:transform-center-x="3.5474848"
transform="matrix(-1.0159411,0,0,0.83457554,1450.0893,194.42636)" />
<g
id="g108">
<path
inkscape:connector-curvature="0"
id="path5277"
d="m 32.026687,256.94379 c 1.01979,0.89055 2.70444,2.74573 4.10309,4.082 h 11.51227 c 0.95662,0 1.72654,0.92699 1.72654,2.07834 v 20.76027 c 0,1.15134 -0.76992,2.078 -1.72654,2.078 h -29.96732 c -0.95661,0 -1.72681,-0.92666 -1.72681,-2.078 v -4.08201 -16.67826 -4.08202 c 0,-1.15134 0.7702,-2.07832 1.72681,-2.07832 z"
style="opacity:1;fill:url(#linearGradient5305);fill-opacity:1;stroke:none;stroke-width:5.29166698;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke" />
<g
id="g5672"
transform="translate(21.664226,27.145537)">
<g
id="g5692"
transform="matrix(1.0615763,0,0,1.0615763,0.14058954,-15.029605)"
style="stroke-width:0.94199538">
<rect
style="opacity:1;vector-effect:none;fill:url(#linearGradient5566);fill-opacity:1;stroke:none;stroke-width:1.41299284;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect2615-1"
width="7.575388"
height="30.240459"
x="-2.1066508"
y="212.28931"
rx="1.4310507"
ry="1.4310507" />
<path
id="rect2771-2"
d="m 4.2772194,212.31071 c -0.1958741,0.17826 -0.3454332,0.41238 -0.4193576,0.68827 l -5.9644127,22.25932 v 5.8405 c 0,0.0437 0.00255,0.0867 0.00643,0.12936 l 4.4366992,1.1889 c 0.7657856,0.2052 1.5473532,-0.24613 1.7525436,-1.01191 l 1.3796344,-5.14891 v -22.53582 c 0,-0.71093 -0.5138192,-1.29614 -1.1915118,-1.40971 z"
style="opacity:0.072;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.41299295;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:connector-curvature="0" />
<rect
ry="1.4310507"
rx="1.4310507"
y="203.67245"
x="59.982849"
height="30.240459"
width="7.575388"
id="rect2617-8"
style="opacity:1;vector-effect:none;fill:url(#linearGradient2649-6);fill-opacity:1;stroke:none;stroke-width:1.41299284;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:transform-center-y="-31.186035"
transform="rotate(15)"
inkscape:transform-center-x="-8.3563328" />
<path
id="rect2773-9"
d="m 11.572926,214.03246 c -0.393519,0.0754 -0.753243,0.31411 -0.970224,0.68993 l -11.26801895,19.51689 -1.56632555,5.84571 c -0.042118,0.15715 -0.055255,0.31455 -0.045017,0.46793 l 3.23713258,1.86888 1.68906372,0.45253 c 0.3353405,-0.10159 0.6346651,-0.32511 0.8244981,-0.65392 l 2.9198911,-5.05721 5.77771,-21.56299 c 0.164698,-0.61466 -0.09438,-1.23894 -0.59871,-1.56775 z"
style="opacity:0.072;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.41299295;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:connector-curvature="0" />
<rect
inkscape:transform-center-x="-16.143173"
transform="rotate(30)"
inkscape:transform-center-y="-27.960618"
style="opacity:1;vector-effect:none;fill:url(#linearGradient5674);fill-opacity:1;stroke:none;stroke-width:1.41299284;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect2619-3"
width="7.575388"
height="30.240459"
x="117.72649"
y="179.27925"
rx="1.4310507"
ry="1.4310507" />
<path
id="rect2775-6"
d="m 17.683283,217.71241 c -0.365801,0 -0.731626,0.14025 -1.011917,0.42055 l -15.78529029,15.78528 -2.97627451,5.15507 c -0.1559156,0.27006 -0.2130632,0.5686 -0.1848109,0.85578 l 1.63243777,1.63243 2.79905733,1.61608 c 0.1863394,-0.0697 0.3616641,-0.17828 0.5119996,-0.32862 l 4.279619,-4.27962 11.211405,-19.4188 c 0.246508,-0.42696 0.248885,-0.92538 0.05069,-1.33674 -0.169005,-0.0671 -0.347896,-0.10141 -0.52692,-0.10141 z"
style="opacity:0.072;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.41299295;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:connector-curvature="0" />
<rect
ry="1.4310507"
rx="1.4310507"
y="140.77209"
x="167.18912"
height="30.240459"
width="7.575388"
id="rect2621-8"
style="opacity:1;vector-effect:none;fill:url(#linearGradient5694);fill-opacity:1;stroke:none;stroke-width:1.41299284;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:transform-center-y="-22.829713"
transform="rotate(45)"
inkscape:transform-center-x="-22.829829" />
<path
id="rect2777-0"
d="m 22.328484,222.8054 c -0.230592,0.006 -0.463295,0.0685 -0.67785,0.19239 l -19.4190475,11.21164 -3.9232803,3.92328 c -0.3915541,0.39155 -0.5086758,0.94976 -0.3532575,1.44194 l 0.3056446,0.52906 c 0.015928,0.0176 0.030654,0.0359 0.047613,0.0528 l 3.1947359,3.19473 c 0.076472,-0.0281 0.1519974,-0.0616 0.2250726,-0.10378 l 5.1550659,-2.97628 16.1411553,-16.14115 c 0.237871,-0.23787 0.373637,-0.53753 0.409641,-0.8463 -0.283955,-0.31965 -0.691327,-0.48954 -1.105493,-0.47836 z"
style="opacity:0.072;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.41299295;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:connector-curvature="0" />
<rect
inkscape:transform-center-x="-27.960727"
transform="rotate(60)"
inkscape:transform-center-y="-16.143018"
style="opacity:1;vector-effect:none;fill:url(#linearGradient2673-8);fill-opacity:1;stroke:none;stroke-width:1.41299284;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect2623-2"
width="7.575388"
height="30.240459"
x="204.99998"
y="90.775146"
rx="1.4310507"
ry="1.4310507" />
<path
id="rect2779-1"
d="m 25.629824,228.93732 c -0.1408,-0.005 -0.28501,0.01 -0.428601,0.0483 l -22.0494031,5.90826 -4.2151809,2.43348 c -0.6865843,0.3964 -0.9200029,1.2683 -0.5236086,1.95489 l 2.35648161,4.08178 c 0.00182,0.003 0.004124,0.006 0.005944,0.009 l 5.30053709,-1.42014 20.3587019,-11.7542 c 0.18213,-0.10516 0.331531,-0.24423 0.446603,-0.40396 -0.220815,-0.50756 -0.710664,-0.83658 -1.251449,-0.85744 z"
style="opacity:0.072;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.41299295;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:connector-curvature="0" />
<rect
ry="1.4310507"
rx="1.4310507"
y="32.695652"
x="228.58229"
height="30.240459"
width="7.575388"
id="rect2625-0"
style="opacity:1;vector-effect:none;fill:url(#linearGradient5678);fill-opacity:1;stroke:none;stroke-width:1.41299284;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:transform-center-y="-8.3562031"
transform="rotate(75)"
inkscape:transform-center-x="-31.186109" />
<path
id="rect2810-5"
d="m 14.997144,233.2388 c 0,0 -1.018353,0.10729 -2.407435,0.81561 -1.013978,0.51705 -2.306717,1.63862 -3.1433504,1.86637 -3.1283181,0.85159 -9.69421033,0.79155 -9.69421033,0.79155 -0.76578557,0.20519 -1.21710747,0.98676 -1.01191707,1.75255 l 1.21993397,4.55279 c 0.20519045,0.76579 0.98677017,1.21711 1.75255573,1.01192 l 26.4455981,-7.08626 c 0.765786,-0.20519 1.217108,-0.98676 1.011917,-1.75255 l -0.591856,-2.2084 z"
style="opacity:0.07099998;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.41299295;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscccccccc" />
</g>
</g>
<path
style="opacity:0.66799999;vector-effect:none;fill:url(#linearGradient3096-8);fill-opacity:1;stroke:none;stroke-width:1.62901139;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;filter:url(#filter3130-5)"
d="m 1365.4604,94.01541 c -0.7804,0 -1.241,0.234791 -1.0325,0.526396 l 4.7725,6.674764 -3.582,0.3862 c -0.8145,0.0879 -1.363,0.36813 -1.4493,0.69362 -0.027,0.0194 -0.053,0.0388 -0.075,0.0593 -0.1454,0.13326 -0.1905,0.28935 -0.115,0.45823 0,0 2e-4,1.9e-4 2e-4,1.9e-4 0.013,0.0337 0.034,0.0681 0.06,0.10273 l 5.6074,7.84226 c 0.05,0.0694 0.1169,0.13701 0.1986,0.20238 0,0 2e-4,1.9e-4 2e-4,1.9e-4 0.1644,0.13066 0.3904,0.25203 0.6592,0.35859 0.2019,0.08 0.424,0.15162 0.6691,0.2128 0.5654,0.14275 1.2217,0.22825 1.8718,0.22825 h 35.4505 c 0.093,-10e-6 0.1828,-0.002 0.2714,-0.005 0.2636,-0.0102 0.5048,-0.0355 0.7186,-0.0734 0.071,-0.0126 0.1394,-0.0267 0.2044,-0.0421 0.065,-0.0153 0.1267,-0.0323 0.1852,-0.0502 0.117,-0.0359 0.2203,-0.077 0.3091,-0.12223 0.2664,-0.13583 0.4003,-0.31088 0.3673,-0.5069 -0.01,-0.0327 -0.016,-0.0659 -0.031,-0.0996 -0.013,-0.0338 -0.034,-0.068 -0.06,-0.10273 l -1.7115,-2.39388 -2.1839,-3.05449 -1.7117,-2.39389 c -0.025,-0.0347 -0.049,-0.0692 -0.087,-0.10292 -0.033,-0.0338 -0.071,-0.067 -0.1115,-0.0996 -0.1645,-0.13073 -0.3903,-0.25198 -0.6593,-0.35859 -0.1345,-0.0533 -0.2798,-0.10301 -0.4344,-0.1483 -0.1537,-0.0453 -0.3151,-0.0863 -0.4838,-0.12224 0,0 -5e-4,0 -5e-4,0 -0.085,-0.0179 -0.1699,-0.0346 -0.2563,-0.05 0,0 -6e-4,0 -6e-4,0 -0.087,-0.0154 -0.1754,-0.0295 -0.2642,-0.0421 0,0 -6e-4,0 -6e-4,0 -0.2676,-0.0379 -0.5445,-0.0631 -0.823,-0.0734 0,0 -5e-4,0 -5e-4,0 -0.091,-0.003 -0.1849,-0.005 -0.2776,-0.005 h -5e-4 -1.3436 l -0.4127,-0.28792 -1.2344,-0.8622 c -0.2629,-0.18344 -0.7316,-0.31729 -1.2196,-0.36786 0.1127,-0.15515 -0.014,-0.34839 -0.3868,-0.512876 l -3.3931,-1.501175 c -0.3716,-0.164436 -0.8912,-0.257825 -1.3664,-0.263004 0,-0.01412 -0.01,-0.02836 -0.011,-0.04268 8e-4,-0.0059 0,-0.01166 0,-0.01757 10e-5,-7.23e-4 10e-5,-0.0011 -0.01,-0.0019 -0.062,-0.153559 -0.3058,-0.313129 -0.7073,-0.431393 l -4.1571,-1.225809 c -0.4553,-0.13428 -0.9904,-0.180421 -1.4201,-0.139807 -0.01,-0.0087 -0.012,-0.01741 -0.018,-0.02608 -0.03,-0.0287 -0.06,-0.05691 -0.099,-0.08477 -0.01,-0.0071 -0.019,-0.01405 -0.029,-0.02104 -0.041,-0.02773 -0.086,-0.05499 -0.1391,-0.0811 -0.1806,-0.09206 -0.4333,-0.172313 -0.7282,-0.227476 l -4.6375,-0.866642 c -0.5082,-0.09498 -1.0223,-0.09104 -1.3778,-0.0073 -0.019,-0.0099 -0.031,-0.01951 -0.047,-0.02915 -0.042,-0.02496 -0.089,-0.04916 -0.1403,-0.07241 -0.012,-0.0039 -0.013,-0.0081 -0.024,-0.01196 -0.063,-0.02608 -0.1242,-0.0504 -0.1935,-0.07357 -0.052,-0.01835 -0.113,-0.03595 -0.1693,-0.05214 -3e-4,-3.74e-4 10e-5,-7.23e-4 2e-4,-0.0015 -0.1984,-0.0536 -0.4223,-0.09456 -0.6608,-0.116829 l -4.8017,-0.448769 c -0.5254,-0.04909 -0.9827,0.0045 -1.2396,0.125132 -0.01,-0.0026 -0.015,-0.0052 -0.023,-0.0079 -0.01,-0.0068 -0.037,-0.01312 -0.046,-0.01969 -0.059,-0.02074 -0.1157,-0.04038 -0.1681,-0.05871 -0.018,-0.0065 -0.046,-0.01255 -0.064,-0.01872 -0.056,-0.01555 -0.1122,-0.02975 -0.1713,-0.04306 -0.038,-0.0086 -0.076,-0.0173 -0.1133,-0.02492 -0.02,-0.0033 -0.033,-0.0065 -0.049,-0.0095 -0.07,-0.0127 -0.1414,-0.02354 -0.2141,-0.03284 -0.014,-0.0015 -0.025,-0.003 -0.036,-0.0045 -0.078,-0.0092 -0.1542,-0.01629 -0.2326,-0.02123 -3e-4,-1.83e-4 -0.012,-7.23e-4 -0.012,-7.23e-4 v 0 c 0,0 -5e-4,1.91e-4 -5e-4,1.91e-4 -0.08,-0.0048 -0.1603,-0.0079 -0.2406,-0.0079 z"
id="rect2977-7"
inkscape:connector-curvature="0"
inkscape:transform-center-y="-7.3219625"
inkscape:transform-center-x="3.5474848"
transform="matrix(1.0159411,0,0,0.83457554,-1376.5639,194.42636)" />
<path
inkscape:connector-curvature="0"
id="path5289"
d="m 36.115727,260.49398 c -0.86895,0.59707 -1.34094,1.48038 -3.428115,2.87126 -0.380703,0.2537 -2.981025,0.21653 -3.746995,0.21176 h -10.91469 c -1.15136,0 -2.07801,0.92699 -2.07801,2.07833 v 20.76027 c 0,1.15135 0.92665,2.078 2.07801,2.078 h 36.06755 c 1.15135,0 2.07833,-0.92665 2.07833,-2.078 v -4.08201 -16.67826 -4.08201 c 0,-1.15135 -0.92698,-2.07832 -2.07833,-2.07832 H 39.945486 c -1.68704,0 -2.960809,0.40188 -3.829759,0.99898 z"
style="opacity:1;fill:url(#linearGradient5315);fill-opacity:1;stroke:none;stroke-width:5.29166698;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
sodipodi:nodetypes="zscssssssccsscz" />
<path
inkscape:connector-curvature="0"
id="path5275-0"
d="m 38.745599,266.74442 a 1.346382,1.346382 0 0 0 -1.32602,1.36425 v 9.59839 l -1.68724,-1.67484 a 1.346382,1.346382 0 0 0 -0.96686,-0.40462 1.346382,1.346382 0 0 0 -0.93018,2.31458 l 3.78272,3.75533 a 1.346382,1.346382 0 0 0 0.68885,0.53537 1.346382,1.346382 0 0 0 0.92087,-0.001 1.346382,1.346382 0 0 0 0.68678,-0.53537 l 3.7822,-3.75428 a 1.346382,1.346382 0 0 0 -0.96997,-2.31459 1.346382,1.346382 0 0 0 -0.92759,0.40463 l -1.68724,1.67535 v -9.5989 a 1.346382,1.346382 0 0 0 -1.36632,-1.36426 z m 9.32759,0 a 1.346382,1.346382 0 0 0 -0.43408,0.0806 1.346382,1.346382 0 0 0 -0.65009,0.4837 l -3.82612,3.79821 a 1.346405,1.346405 0 1 0 1.89704,1.911 l 1.68775,-1.67535 v 9.59786 a 1.346382,1.346382 0 1 0 2.69183,0 v -9.59786 l 1.68775,1.67535 a 1.3464068,1.3464068 0 1 0 1.89704,-1.911 l -3.82871,-3.80028 a 1.346382,1.346382 0 0 0 -0.59737,-0.46457 1.346382,1.346382 0 0 0 -0.52504,-0.0977 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.29166651;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
<rect
style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4254"
width="67.733337"
height="67.733337"
x="-119.13585"
y="205.91806"
rx="1.3047903"
ry="1.3047903" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,21 @@
[
{
"name": "Gradient Saver",
"id": "fablabchemnitz.de.gradient_saver",
"path": "gradient_saver",
"dependent_extensions": null,
"original_name": "Gradient Saver",
"original_id": "id.artemtech.gradient_saver",
"license": "GNU GPL v3",
"license_url": "https://github.com/artemtech/inkscape-gradient-saver/blob/inkscape-1.0/LICENSE",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/gradient_saver",
"fork_url": "https://github.com/artemtech/inkscape-gradient-saver/",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Gradient+Saver",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/artemtech",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Grey to MonoAlpha</name>
<id>fablabchemnitz.de.grey_to_monoalpha</id>
<param name="tab" type="notebook">
<page name="main_page" gui-text="Settings">
<vbox>
<hbox>
<param name="color_picker_mono" type="color" appearance="colorbutton" gui-text="Mono Color">0x000000ff</param>
</hbox>
<hbox>
<param name="apply_to_type_radio" type="optiongroup" appearance="radio" gui-text="Apply To">
<option value="fill_and_stroke">Fill and Stroke</option>
<option value="fill">Fill Only</option>
<option value="stroke">Stroke Only</option>
</param>
</hbox>
<hbox>
<label>Opacity Threshold</label>
<param name="opacity_lower_threshold" type="float" min="0" max="0.9" gui-text="Lower" gui-description="opacity_lower_threshold">0</param>
<param name="opacity_upper_threshold" type="float" min="0.05" max="1" gui-text="Upper" gui-description="opacity_upper_threshold">1</param>
</hbox>
</vbox>
</page>
<page name="about_page" gui-text="About">
<label>Grey To MonoAlpha - An Inkscape Extension</label>
<label>Inkscape 1.1 +</label>
<label appearance="url">https://gitlab.com/inklinea/</label>
<label xml:space="preserve">
▶ Converts a greyscale image to monochrome with variable opacity
▶ Threshold setting to avoid solid color
▶ Can be applied to stroke, fill or both
</label>
</page>
</param>
<effect>
<object-type>path</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Colors/Gradients/Filters"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">grey_to_monoalpha.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python3
#
# Copyright (C) [2021] [Matt Cottam], [mpcottam@raincloud.co.uk]
#
# 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.
#
##############################################################################
# Grey To Mono Alpha *** Convert Greys to Monochrome with varying Opacity
##############################################################################
import math
import inkex
from inkex import Color
# Python Standard Libary
from statistics import mean
def get_attributes(self):
for att in dir(self):
inkex.errormsg((att, getattr(self, att)))
def rgba_to_bw_rgba(self, my_objects):
apply_to = self.options.apply_to_type_radio
mono_color = self.options.color_picker_mono.to_rgba()
opacity_lower_threshold = self.options.opacity_lower_threshold
opacity_upper_threshold = self.options.opacity_upper_threshold
opacity_range = opacity_upper_threshold - opacity_lower_threshold
for my_object in my_objects:
if 'fill' in apply_to and ('fill:none' not in str(my_object.style)):
my_fill_color = my_object.style.get_color(name='fill').to_rgba()
my_fill_color_red = my_fill_color[0]
my_fill_color_green = my_fill_color[1]
my_fill_color_blue = my_fill_color[2]
mean_fill_component_value = mean([my_fill_color_red, my_fill_color_blue, my_fill_color_green])
if mean_fill_component_value > 0:
mono_opacity = (1 - (mean_fill_component_value / 256)) * opacity_range
mono_opacity = mono_opacity + opacity_lower_threshold
else:
mono_opacity = opacity_upper_threshold
my_object.style['fill'] = str(mono_color)
my_object.style['fill-opacity'] = str(mono_opacity)
if 'stroke' in apply_to and (';stroke:none' not in str(my_object.style)) and ('stroke:' in str(my_object.style)):
my_stroke_color = my_object.style.get_color(name='stroke').to_rgba()
my_stroke_color_red = my_stroke_color[0]
my_stroke_color_green = my_stroke_color[1]
my_stroke_color_blue = my_stroke_color[2]
mean_stroke_component_value = mean([my_stroke_color_red, my_stroke_color_blue, my_stroke_color_green])
if mean_stroke_component_value > 0:
mono_opacity = (1 - (mean_stroke_component_value / 256)) * opacity_range
mono_opacity = mono_opacity + opacity_lower_threshold
else:
mono_opacity = opacity_upper_threshold
my_object.style['stroke'] = str(mono_color)
my_object.style['stroke-opacity'] = str(mono_opacity)
class GreyToMonoAlpha(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--tab")
pars.add_argument("--color_picker_mono", type=inkex.colors.Color, default=0)
pars.add_argument("--apply_to_type_radio", default=None)
pars.add_argument("--opacity_lower_threshold", type=float, default=0)
pars.add_argument("--opacity_upper_threshold", type=float, default=1)
def effect(self):
my_objects = self.svg.selected
if len(my_objects) < 1:
self.msg('Please select some paths first.')
return
rgba_to_bw_rgba(self, my_objects)
if __name__ == '__main__':
GreyToMonoAlpha().run()

View File

@ -0,0 +1,21 @@
[
{
"name": "Grey To MonoAlpha",
"id": "fablabchemnitz.de.grey_to_monoalpha",
"path": "grey_to_monoalpha",
"dependent_extensions": null,
"original_name": "Grey to MonoAlpha",
"original_id": "org.inkscape.grey_to_monoalpha",
"license": "GNU GPL v3",
"license_url": "https://gitlab.com/inklinea/grey-to-mono-alpha/-/blob/main/LICENSE",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/grey_to_monoalpha",
"fork_url": "https://gitlab.com/inklinea/grey-to-mono-alpha",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Grey+to+MonoAlpha",
"inkscape_gallery_url": null,
"main_authors": [
"gitlab.com/inklinea",
"github.com/eridur-de"
]
}
]

View File

@ -9,13 +9,13 @@
"license": "GNU GPL v2",
"license_url": "https://github.com/nicolaromano/triangulate/blob/master/triangulation.py",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/image_triangulation",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/image_triangulation",
"fork_url": "https://github.com/nicolaromano/triangulate",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Image+Triangulation",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/nicolaromano",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -9,13 +9,13 @@
"license": "GNU GPL v2",
"license_url": "https://sourceforge.net/p/razorfoss/svn/HEAD/tree/trunk/Inkscape/InsetAlignmentExtension/InsetAlignment.py",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/inset_alignment",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/inset_alignment",
"fork_url": "https://sourceforge.net/p/razorfoss/svn/HEAD/tree/trunk/Inkscape/InsetAlignmentExtension/",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Inset+Alignment",
"inkscape_gallery_url": null,
"main_authors": [
"Luke Phillips:lukerazor@hotmail.com",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,17 @@
<?xml version='1.0' encoding='utf-8'?>
<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://creativecommons.org/ns#" xmlns:ccOLD="http://web.resource.org/cc/" xmlns:svg="http://www.w3.org/2000/svg" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="test">
<stop id="stop00" offset="0.0" style="stop-color:#cc20c1;stop-opacity:1.0"/>
<stop id="stop01" offset="1.0" style="stop-color:#cc20c1;stop-opacity:0.0"/>
</linearGradient>
<linearGradient id="test">
<stop id="stop10" offset="0.0" style="stop-color:#cc20c1;stop-opacity:1.0"/>
<stop id="stop11" offset="1.0" style="stop-color:#cc20c1;stop-opacity:0.0"/>
</linearGradient>
<linearGradient id="test">
<stop id="stop20" offset="0.0" style="stop-color:#cc20c1;stop-opacity:1.0"/>
<stop id="stop21" offset="1.0" style="stop-color:#cc20c1;stop-opacity:0.0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,21 @@
[
{
"name": "Inkscape Output Pro",
"id": "fablabchemnitz.de.output_pro",
"path": "output_pro",
"dependent_extensions": null,
"original_name": "Inkscape Output Pro",
"original_id": "org.inkscape.outputpro",
"license": "GNU GPL v2",
"license_url": "https://github.com/jonata/Inkscape-OUTPUT-PRO/blob/master/LICENSE.txt",
"comment": "ported to Inkscape v1 by Mario Voigt",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/output_pro",
"fork_url": "https://github.com/jonata/Inkscape-OUTPUT-PRO",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Output+Pro+for+Inkscape",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/jonata",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Inkscape Output Pro</name>
<id>fablabchemnitz.de.output_pro</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Import/Export/Transfer"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">output_pro.py</command>
</script>
</inkscape-extension>

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

View File

@ -0,0 +1,118 @@
#!/usr/bin/env python3
import re
import os
import inkex
from inkex.command import inkscape
def calculateCMYK(red, green, blue):
C = float()
M = float()
Y = float()
K = float()
if 1.00 - red < 1.00 - green:
K = 1.00 - red
else:
K = 1.00 - green
if 1.00 - blue < K:
K = 1.00 - blue
if K != 1.00:
C = ( 1.00 - red - K ) / ( 1.00 - K )
M = ( 1.00 - green - K ) / ( 1.00 - K )
Y = ( 1.00 - blue - K ) / ( 1.00 - K )
return [C, M, Y, K]
def clean_svg_color_definitions(svg):
def change_colors(origin, color_type):
for i in range(len(str(origin).split(color_type + ':'))):
if str(str(origin).split(color_type + ':')[i].split(';')[0]) in inkex.colors.SVG_COLOR.keys():
color_numbers = str(inkex.Color(inkex.Color(str(str(origin).split(color_type + ':')[i].split(';')[0])).to_rgb()))
origin = str(origin).replace(':' + str(str(origin).split(color_type + ':')[i].split(';')[0]) + ';', ':' + color_numbers + ';')
return origin
colortypes = ['fill', 'stop-color', 'flood-color', 'lighting-color', 'stroke']
for i in range(len(colortypes)):
svg = change_colors(svg, colortypes[i])
return svg
def removeK(origin):
def reset_opacity(value):
return str(value.group()).split('opacity:')[0] + "opacity:0;"
#return re.sub("#000000;fill-opacity:[0-9.]+;", reset_opacity, re.sub("#000000;stop-opacity:[0-9.]+;", reset_opacity, re.sub("#000000;stroke-opacity:[0-9.]+;", reset_opacity, re.sub("#000000;flood-opacity:[0-9.]+;", reset_opacity, re.sub("#000000;lighting-opacity:[0-9.]+;", reset_opacity, origin)))))
return re.sub("#000000;fill-opacity:[0-9.?]+", reset_opacity, re.sub("#000000;stop-opacity:[0-9.?]+", reset_opacity, re.sub("#000000;stroke-opacity:[0-9.?]+", reset_opacity, re.sub("#000000;flood-opacity:[0-9.?]+", reset_opacity, re.sub("#000000;lighting-opacity:[0-9.?]+", reset_opacity, origin)))))
def representC(value):
# returns CMS color if available
if (re.search("icc-color", value.group())):
return str(inkex.Color((float(1.00 - float(re.split(r'[,\)\s]+',value.group())[2])), float(1.00), float(1.00))))
else:
red = float(inkex.Color(str(value.group())).to_rgb()[0]/255.00)
green = float(inkex.Color(str(value.group())).to_rgb()[1]/255.00)
blue = float(inkex.Color(str(value.group())).to_rgb()[2]/255.00)
return str(inkex.Color((float(1.00 - calculateCMYK(red, green, blue)[0]), float(1.00), float(1.00))))
def representM(value):
# returns CMS color if available
if ( re.search("icc-color", value.group()) ):
return str(inkex.Color((float(1.00), float(1.00 - float(re.split(r'[,\)\s]+',value.group())[3])), float(1.00))))
else:
red = float(inkex.Color(str(value.group())).to_rgb()[0]/255.00)
green = float(inkex.Color(str(value.group())).to_rgb()[1]/255.00)
blue = float(inkex.Color(str(value.group())).to_rgb()[2]/255.00)
return str(inkex.Color((float(1.00), float(1.00 - calculateCMYK(red, green, blue)[1]), float(1.00))))
def representY(value):
# returns CMS color if available
if (re.search("icc-color", value.group()) ):
return str(inkex.Color((float(1.00), float(1.00), float(1.00 - float(re.split(r'[,\)\s]+',value.group())[4])))))
else:
red = float(inkex.Color(str(value.group())).to_rgb()[0]/255.00)
green = float(inkex.Color(str(value.group())).to_rgb()[1]/255.00)
blue = float(inkex.Color(str(value.group())).to_rgb()[2]/255.00)
return str(inkex.Color((float(1.00), float(1.00), float(1.00 - calculateCMYK(red, green, blue)[2]))))
def representK(value):
# returns CMS color if available
if (re.search("icc-color", value.group()) ):
return str(inkex.Color((float(1.00 - float(re.split(r'[,\)\s]+',value.group())[5])), float(1.00 - float(re.split(r'[,\)\s]+',value.group())[5])), float(1.00 - float(re.split(r'[,\)\s]+',value.group())[5])))))
else:
red = float(inkex.Color(str(value.group())).to_rgb()[0]/255.00)
green = float(inkex.Color(str(value.group())).to_rgb()[1]/255.00)
blue = float(inkex.Color(str(value.group())).to_rgb()[2]/255.00)
return str(inkex.Color((float(1.00 - calculateCMYK(red, green, blue)[3]), float(1.00 - calculateCMYK(red, green, blue)[3]), float(1.00 - calculateCMYK(red, green, blue)[3]))))
def generate_svg_separations(temp_dir, original_source, overblack):
svg_ready = clean_svg_color_definitions(original_source)
with open(os.path.join(temp_dir, "separationK.svg"), "w") as f:
f.write(re.sub(r"#[a-fA-F0-9]{6}( icc-color\(.*?\))?", representK, svg_ready))
if overblack:
svg_ready = removeK(svg_ready)
with open(os.path.join(temp_dir, "separationC.svg"), "w") as f:
f.write(re.sub(r"#[a-fA-F0-9]{6}( icc-color\(.*?\))?", representC, svg_ready))
with open(os.path.join(temp_dir, "separationM.svg"), "w") as f:
f.write(re.sub(r"#[a-fA-F0-9]{6}( icc-color\(.*?\))?", representM, svg_ready))
with open(os.path.join(temp_dir, "separationY.svg"), "w") as f:
f.write(re.sub(r"#[a-fA-F0-9]{6}( icc-color\(.*?\))?", representY, svg_ready))
def generate_png_separations(temp_dir, area_to_export, resolution, alpha):
if alpha:
alpha_command = ""
else:
alpha_command = ";export-background:white"
for color in ['C', 'M', 'Y', 'K']:
cmd = area_to_export + alpha_command + ';export-dpi:' + str(resolution) + ';export-background-opacity:1;export-filename:' + os.path.join(temp_dir, "separated" + area_to_export.replace(' ', '') + color + ".png") + ';export-do'
#inkex.utils.debug(cmd)
cli_output = inkscape(os.path.join(temp_dir, "separation" + color + ".svg"), actions=cmd)
if len(cli_output) > 0:
inkex.utils.debug(cli_output)
#inkex.utils.debug(os.listdir(temp_dir))

View File

@ -0,0 +1,84 @@
#!/usr/bin/env python3
import subprocess
import os
def generate_final_file(isvector, hide_inside_marks, colormode, width, height, space, strokewidth, bleedsize, marksize, temp_dir):
if not isvector:
if "nt" in os.name:
shell = True
else:
shell = False
command = []
final_command = ['convert']
for color in colormode:
command.append('convert')
command.append('-size')
command.append(str(sum(width) + (marksize*2) + (space * (len(width) -1))) + 'x' + str(sum(height) + (marksize*2) + (space * (len(height) -1))))
command.append('xc:white')
command.append('-stroke')
command.append('black')
command.append('-strokewidth')
command.append(str(strokewidth))
width_value = 0
number_of_column = 1
for column in width:
height_value = 0
number_of_line = 1
for line in height:
with open(os.path.join(temp_dir, 'str.txt'), 'a') as f:
f.write(str(width.index(column)))
if not hide_inside_marks or (hide_inside_marks and number_of_column == 1):
command.append('-draw')
command.append('line ' + str(width_value + marksize) + ',' + str(height_value + marksize + bleedsize) + ', ' + str(width_value) + ',' + str(height_value + marksize + bleedsize))
command.append('-draw')
command.append('line ' + str(width_value + marksize) + ',' + str(height_value + line + marksize - bleedsize) + ', ' + str(width_value) + ',' + str(height_value + line + marksize - bleedsize))
if not hide_inside_marks or (hide_inside_marks and number_of_line == 1):
command.append('-draw')
command.append('line ' + str(width_value + marksize + bleedsize) + ',' + str(height_value + marksize) + ', ' + str(width_value + marksize + bleedsize) + ',' + str(height_value))
command.append('-draw')
command.append('line ' + str(width_value + column + marksize - bleedsize) + ',' + str(height_value + marksize) + ', ' + str(width_value + column + marksize - bleedsize) + ',' + str(height_value))
if not hide_inside_marks or (hide_inside_marks and number_of_column == len(width)):
command.append('-draw')
command.append('line ' + str(width_value + marksize + column) + ',' + str(height_value + marksize + bleedsize) + ', ' + str(width_value + (marksize*2) + column) + ',' + str(height_value + marksize + bleedsize))
command.append('-draw')
command.append('line ' + str(width_value + marksize + column) + ',' + str(height_value + line + marksize - bleedsize) + ', ' + str(width_value + (marksize*2) + column) + ',' + str(height_value + marksize + line - bleedsize))
if not hide_inside_marks or (hide_inside_marks and number_of_line == len(height)):
command.append('-draw')
command.append('line ' + str(width_value + marksize + bleedsize) + ',' + str(height_value + line + marksize) + ', ' + str(width_value + marksize + bleedsize) + ',' + str(height_value + line + (marksize*2)))
command.append('-draw')
command.append('line ' + str(width_value + column + marksize - bleedsize) + ',' + str(height_value + line + marksize) + ', ' + str(width_value + marksize + column - bleedsize) + ',' + str(height_value + line + (marksize*2)))
height_value += line + space
number_of_line += 1
width_value += column + space
number_of_column += 1
command.append(os.path.join(temp_dir, 'cut_mark_' + color + '.png'))
subprocess.Popen(command, shell=shell).wait()
del command[:]
command.append('convert')
command.append(os.path.join(temp_dir, 'cut_mark_' + color + '.png'))
command.append('-colorspace')
command.append(str(colormode).lower())
command.append('-channel')
command.append('K')
command.append('-separate')
command.append(os.path.join(temp_dir, 'cut_mark_' + color + '.png'))
subprocess.Popen(command, shell=shell).wait()
del command[:]
final_command.append(os.path.join(temp_dir, 'cut_mark_' + color + '.png'))
final_command.extend(['-set', 'colorspace', colormode, '-combine', os.path.join(temp_dir, 'cut_mark.tiff')])
subprocess.Popen(final_command, shell=shell).wait()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

View File

@ -0,0 +1,22 @@
[
{
"name": "Paths To OpenSCAD",
"id": "fablabchemnitz.de.paths_to_openscad",
"path": "paths_to_openscad",
"dependent_extensions": null,
"original_name": "aths to OpenSCAD<",
"original_id": "command.extrude.openscad",
"license": "GNU GPL v2",
"license_url": "https://github.com/fablabnbg/inkscape-paths2openscad/blob/master/LICENSE",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/paths_to_openscad",
"fork_url": "https://github.com/fablabnbg/inkscape-paths2openscad",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Paths+to+OpenSCAD",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/l0b0",
"github.com/fablabnbg",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Paths To OpenSCAD</name>
<id>fablabchemnitz.de.paths_to_openscad</id>
<param name="tab" type="notebook">
<page name="splash" gui-text="Paths to OpenSCAD">
<param type="path" name="fname" gui-text="Output file" mode="file_new" filetypes="scad" gui-description="Use '{NAME}.scad' here to use the name from svg.">{NAME}.scad</param>
<param name="zsize" type="float" min="0" max="1000" precision="2" gui-text="Depth (Z) [mm]" gui-description="Default 3D extrude depth (when no zsize is parsed from an svg object).">5.0</param>
<param name="parsedesc" type="bool" gui-text="Description parsing" gui-description="Read the extruded zsize, zoffset, scale per svg object from its description or ID. See the Extrusion Syntax tab for details.">true</param>
<param name="scadview" type="bool" gui-text="View in OpenSCAD" gui-description="Start OpenSCAD to view the 3D-model.">false</param>
<param name="scad2stl" type="bool" gui-text="Convert to STL" gui-description="Also save an .stl file next to the specified output file.">false</param>
<param name="stlpost" type="bool" gui-text="STL post processing" gui-description="Start e.g. a slicer after converting to STL. See the Commands tab for details.">false</param>
<param name="stlmodule" type="bool" gui-text="Only create a module">false</param>
</page>
<page name="tuning" gui-text="Tuning">
<param name="smoothness" type="float" min="0.0001" max="5" precision="4" gui-text="Smoothing" gui-description="Used when rendering curves. Smaller values are smoother. Range: 0.0001 to 5">0.2</param>
<param type="float" name="chamfer" min="0.0" gui-text="Add chamfer radius [mm]">0</param>
<param name="chamfer_fn" type="optiongroup" appearance="combo" gui-text="Chamfer precision ($fn)">
<option value="4">4: Rough (fast)</option>
<option value="12">12: Medium (slow)</option>
<option value="16">16: Fine (slower)</option>
<option value="32">32: Perfekt (slowest)</option>
</param>
<label appearance="header">Outline Mode</label>
<label>Objects are extruded into 3D either in normal mode, or in outline mode. Normally filled areas are extruded, ignoring the line width. Objects with no fill are rendered in outline mode. Note: the 'Scale: XX %' instruction has no effect in outline mode.</label>
<param name="min_line_width" type="float" min="0.1" max="10" gui-text="Minimum line width [mm]">1.0</param>
<param type="float" name="line_width_scale_perc" min="1" max="10000" gui-text="Scale line width [%]">100.0</param>
<param name="line_fn" type="optiongroup" appearance="combo" gui-text="Line width precision ($fn)">
<option value="4">4: Rough (fast)</option>
<option value="8">8: Medium (slow)</option>
<option value="16">16: Fine (slower)</option>
<option value="32">32: Perfekt (slowest)</option>
</param>
<param name="force_line" type="bool" gui-text="Force outline mode, ignore fill">false</param>
<spacer/>
</page>
<page name="commands" gui-text="Commands">
<label>Placeholders: You can use "{NAME}.scad" for the OpenSCAD file to read as specified as 'Output file' in the main tab. You can use "{NAME}.stl" for an STL file to write.</label>
<param name="scadviewcmd" type="string" gui-text="View in OpenSCAD:" gui-description="Is only started, if no command of the same name is running. Always started non-blocking. A running OpenSCAD automatically picks up changed file content">openscad "{NAME}.scad"</param>
<param name="scad2stlcmd" type="string" gui-text="Convert to STL:" gui-description="Automatically run, when STL postprocessing is requested.">openscad "{NAME}.scad" -o "{NAME}.stl"</param>
<param name="stlpostcmd" type="string" gui-text="STL postprocessing:" gui-description="Append an '&amp;' for non-blocking.">cura "{NAME}.stl" &amp;</param>
</page>
<page name="extrusion" gui-text="Extrusion Syntax">
<label xml:space="preserve">The depth (Z-Axis) and other parameters can be defined through an svg object's description. The menu 'Object-&gt;Object Properties ...' (Shift-Ctrl-O) shows details of one selected object.
If an object's ID is in either name_XXX_mm or name_XXXmm
format, then XXX is translated into zsize in millimeters.
Use . or _ as separator for a decimal number.
Note that all whitespace or comma are saved as '_' in ID.
</label>
<label appearance="header">Syntax for the object property description</label>
<label xml:space="preserve">Depth: 10 mm
Linear extrusion length (or Z-Size)) of the object.
Antimatter: true
Object is part of the difference set, which is
cut away from all other objects.
Offset: 4.5 mm
Move an object upwards to create a balcony (or window).
Taper: 90 % or Taper: 120,60 %
Scale the object along its Z-axis. The bottom surface always
is as drawn, but the top surface is scaled to this value.
If two values are given (separated by Komma), different
scaling applies along X- and Y-axis.
Parameters in the objects take precedence over groups.</label>
</page>
<page name="info" gui-text="About ...">
<label xml:space="preserve">
This extension converts Inkscape paths to extruded polygons in OpenSCAD. Before using, some objects must firat be converted to paths with the "Path &gt; Object to Path" menu item.
Inkscape's units of pixels are converted to millimeters using the SVG standard's definition of 96 px = 1 inch = 25.4 mm. (Before inkscape 0.92 the standard was 90 px per inch, Adobe products often use 75 px per inch)
Dan Newman (dan newman @ mtbaldy us)
Josef Skladanka (jskladan @ redhat com)
Juergen Weigert (juergen @ fabmail org)
Find updates at</label>
<label appearance="url">https://github.com/fablabnbg/inkscape-paths2openscad/releases</label>
</page>
</param>
<effect needs-live-preview="false">
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Import/Export/Transfer"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">paths_to_openscad.py</command>
</script>
</inkscape-extension>

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,13 @@
"license": "GNU GPL v3",
"license_url": "https://inkscape.org/~pakin/%E2%98%85pixels-to-objects",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/pixels2objects",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/pixels2objects",
"fork_url": "https://inkscape.org/~pakin/%E2%98%85pixels-to-objects",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Pixels+To+Objects",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/pakin",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -7,14 +7,14 @@
"original_name": "Primitive (Michael Fogleman)",
"original_id": "fablabchemnitz.de.primitive",
"license": "GNU GPL v3",
"license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE",
"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.X/src/branch/master/extensions/fablabchemnitz/primitive",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/primitive",
"fork_url": "https://github.com/fogleman/primitive",
"documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=78807580",
"inkscape_gallery_url": "https://inkscape.org/~MarioVoigt/%E2%98%85primitive-for-inkscape",
"main_authors": [
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,21 @@
[
{
"name": "Printing Marks Dotted",
"id": "fablabchemnitz.de.printing_marks_dotted",
"path": "printing_marks_dotted",
"dependent_extensions": null,
"original_name": "Printing Marks Dotted",
"original_id": "org.inkscape.printing.marks.dotted",
"license": "GNU GPL v2",
"license_url": "https://inkscape.org/~jabiertxof/%E2%98%85printing-marks-dotted",
"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/printing_marks_dotted",
"fork_url": "https://inkscape.org/~jabiertxof/%E2%98%85printing-marks-dotted",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Printing+Marks+Dotted",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/jabiertxof",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Printing Marks Dotted</name>
<id>fablabchemnitz.de.printing_marks_dotted</id>
<param name="tab" type="notebook">
<page name="marks" gui-text="Marks">
<param name="crop_marks" type="bool" gui-text="Crop Marks">true</param>
<param name="dotted_crop_marks" type="bool" gui-text="Dotted Crop Marks">false</param>
<param name="bleed_marks" type="bool" gui-text="Bleed Marks">false</param>
<param name="registration_marks" type="bool" gui-text="Registration Marks">true</param>
<param name="star_target" type="bool" gui-text="Star Target">false</param>
<param name="colour_bars" type="bool" gui-text="Color Bars">true</param>
<param name="page_info" type="bool" gui-text="Page Information">false</param>
</page>
<page name="pos" gui-text="Positioning">
<param name="where" type="optiongroup" appearance="combo" gui-text="Set crop marks to:">
<option value="canvas">Canvas</option>
<option value="selection">Selection</option>
</param>
<param name="unit" type="optiongroup" appearance="combo" gui-text="Unit:" >
<option value="px">px</option>
<option value="pt">pt</option>
<option value="in">in</option>
<option value="cm">cm</option>
<option value="mm">mm</option>
</param>
<param name="crop_offset" type="float" min="0.0" max="9999.0" precision="3" gui-text="Offset:">5</param>
<label appearance="header">Bleed Margin</label>
<param name="bleed_top" type="float" indent="1" min="0.0" max="9999.0" precision="3" gui-text="Top:">5</param>
<param name="bleed_bottom" type="float" indent="1" min="0.0" max="9999.0" precision="3" gui-text="Bottom:">5</param>
<param name="bleed_left" type="float" indent="1" min="0.0" max="9999.0" precision="3" gui-text="Left:">5</param>
<param name="bleed_right" type="float" indent="1" min="0.0" max="9999.0" precision="3" gui-text="Right:">5</param>
</page>
</param>
<effect needs-live-preview="true">
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Cutting/Plotting/Printing"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">printing_marks_dotted.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,475 @@
#!/usr/bin/env python3
'''
This extension allows you to draw crop, registration and other
printing marks in Inkscape.
Authors:
Nicolas Dufour - Association Inkscape-fr
Aurelio A. Heckert <aurium(a)gmail.com>
Copyright (C) 2008 Authors
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
'''
from subprocess import Popen, PIPE, STDOUT
import math
import inkex
from lxml import etree
class PrintingMarksDotted(inkex.EffectExtension):
# Default parameters
stroke_width = 0.25
def add_arguments(self, pars):
pars.add_argument("--where_to_crop", default=True, help="Apply crop marks to...")
pars.add_argument("--crop_marks", type=inkex.Boolean, default=True, help="Draw crop Marks?")
pars.add_argument("--dotted_crop_marks", type=inkex.Boolean, default=True, help="Draw dotted crop Marks?")
pars.add_argument("--bleed_marks", type=inkex.Boolean, default=False, help="Draw Bleed Marks?")
pars.add_argument("--registration_marks", type=inkex.Boolean, default=False, help="Draw Registration Marks?")
pars.add_argument("--star_target", type=inkex.Boolean, default=False, help="Draw Star Target?")
pars.add_argument("--colour_bars", type=inkex.Boolean, default=False, help="Draw Colour Bars?")
pars.add_argument("--page_info", type=inkex.Boolean, default=False, help="Draw Page Information?")
pars.add_argument("--unit",default="px", help="Draw measurment")
pars.add_argument("--crop_offset", type=float, default=0, help="Offset")
pars.add_argument("--bleed_top", type=float, default=0, help="Bleed Top Size")
pars.add_argument("--bleed_bottom", type=float, default=0, help="Bleed Bottom Size")
pars.add_argument("--bleed_left", type=float, default=0, help="Bleed Left Size")
pars.add_argument("--bleed_right",type=float, default=0, help="Bleed Right Size")
pars.add_argument("--tab", help="The selected UI-tab when OK was pressed")
def addMarker(self):
svg = self.document.getroot()
xpathStr = '//marker[@id="scissorsCroper"]'
maskElement = svg.xpath(xpathStr, namespaces=inkex.NSS)
if maskElement == []:
xpathStr = '//svg:defs'
defs = svg.xpath(xpathStr, namespaces=inkex.NSS)
line_attribs = {'markerWidth': "8.2212915",
'markerHeight': "4.8983894",
'orient': "auto",
'id':"scissorsCroper"}
markerElement = etree.SubElement(defs[0],inkex.addNS('marker','svg'), line_attribs)
line_attribs = {'style': "fill:#000000;stroke:#ffffff;stroke-width:0.2;stroke-miterlimit:4;stroke-opacity:1",
'id': "scissorsCroperPath",
'd': "m -3.09375,-2.59375 c -0.2875213,-0.019086 -0.5530997,0.080418 -0.78125,0.25 -0.2281503,0.1695818 -0.4212781,0.4427198 -0.4375,0.75 -0.014236,0.2696628 0.032949,0.4281517 0.09375,0.53125 0.011692,0.019827 0.022314,0.017924 0.03125,0.03125 -0.074992,0.019409 -0.1886388,0.0360237 -0.34375,0.0625 -0.3217609,0.0549221 -0.7596575,0.13825127 -1.21875,0.375 l -3.03125,-1.125 c -0.2710413,-0.1042898 -0.5662791,-0.1829987 -0.875,-0.15625 -0.3087209,0.026749 -0.621076,0.1687088 -0.84375,0.4375 a 0.20792008,0.20792008 0 0 0 -0.03125,0.03125 0.20792008,0.20792008 0 0 0 -0.03125,0.0625 0.20792008,0.20792008 0 0 0 0,0.0625 0.20792008,0.20792008 0 0 0 0.03125,0.0625 0.20792008,0.20792008 0 0 0 0.03125,0.03125 0.20792008,0.20792008 0 0 0 0.09375,0.0625 l 2.9375,1.15625 -2.96875,1.125 a 0.20792008,0.20792008 0 0 0 -0.09375,0.0625 0.20792008,0.20792008 0 0 0 -0.03125,0.03125 0.20792008,0.20792008 0 0 0 -0.03125,0.0625 0.20792008,0.20792008 0 0 0 0,0.0625 0.20792008,0.20792008 0 0 0 0.03125,0.0625 0.20792008,0.20792008 0 0 0 0.03125,0.03125 C -10.094168,1.9539272 -9.4699318,1.9749423 -9,1.84375 L -5.71875,0.6875 c 0.481754,0.20541523 0.912658,0.3186677 1.1875,0.375 0.1483249,0.030401 0.2392409,0.045912 0.3125,0.0625 0.03663,0.00829 0.024599,-0.00324 0.03125,0 -0.0079,0.02335 -0.010635,0.041757 -0.03125,0.09375 -0.053917,0.1359822 -0.1506131,0.3500538 -0.09375,0.625 0.074929,0.3622982 0.3561361,0.6217769 0.65625,0.75 0.3001139,0.1282231 0.6300895,0.1440646 0.9375,0.03125 0.6444683,-0.175589 0.9014775,-0.9349259 0.625,-1.5 C -2.2324842,0.83910622 -2.4880622,0.66240891 -2.75,0.5625 -3.0119378,0.46259109 -3.2717529,0.42256233 -3.53125,0.4375 c -0.2805605,0.0161501 -0.5796777,0.0351178 -0.8125,-0.03125 -0.1944918,-0.0554414 -0.3308104,-0.18103045 -0.46875,-0.375 0.1925418,-0.25215792 0.4169804,-0.350782 0.71875,-0.375 0.3394341,-0.0272407 0.7247815,0.0434012 1.0625,0 0.010025,-6.5986e-4 0.021283,9.2632e-4 0.03125,0 0.5937358,-0.0551819 1.1050788,-0.57908524 1.0625,-1.1875 -0.00523,-0.6217326 -0.5853909,-1.0659264 -1.15625,-1.0625 z M -2.9375,-1.875 c 0.1401777,0.04894 0.2268596,0.139783 0.25,0.25 a 0.20792008,0.20792008 0 0 0 0.03125,0.03125 c 0.046997,0.1597651 -0.018243,0.2935457 -0.15625,0.40625 -0.1380068,0.1127043 -0.3531142,0.176154 -0.5,0.125 -0.1652738,-0.046651 -0.2408416,-0.1796945 -0.25,-0.34375 -0.00916,-0.1640555 0.046643,-0.3414062 0.21875,-0.4375 0.104863,-0.058549 0.2664752,-0.08005 0.40625,-0.03125 z m -0.21875,3.03125 c 0.2392165,0.047351 0.4697735,0.2941069 0.4375,0.53125 -0.010405,0.1211995 -0.066062,0.2235316 -0.1875,0.28125 C -3.0276883,2.0264684 -3.2009829,2.0387215 -3.3125,2 A 0.20792008,0.20792008 0 0 0 -3.34375,2 C -3.6474031,1.9320987 -3.710744,1.2999504 -3.40625,1.1875 a 0.20792008,0.20792008 0 0 0 0.03125,0 c 0.072689,-0.036572 0.1390112,-0.047034 0.21875,-0.03125 z"}
pathElement = etree.SubElement(markerElement, inkex.addNS('path','svg'), line_attribs)
def draw_crop_line(self, x1, y1, x2, y2, name, parent):
if self.options.dotted_crop_marks == True:
self.addMarker()
style = { 'stroke': '#FFFFFF', 'stroke-width': str(self.stroke_width),
'fill': 'none'}
else:
style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width),
'fill': 'none'}
line_attribs = {'style': str(inkex.Style(style)),
'id': name,
'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
etree.SubElement(parent, 'path', line_attribs)
if self.options.dotted_crop_marks == True:
style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width),
'fill': 'none' , 'marker-end':'url(#scissorsCroper)',
'stroke-dasharray' :'0.5,0.25', 'stroke-miterlimit':"4"}
line_attribs = {'style': str(inkex.Style(style)),
'id': name + "_dotted",
'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
etree.SubElement(parent, 'path', line_attribs)
def draw_bleed_line(self, x1, y1, x2, y2, name, parent):
style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width),
'fill': 'none',
'stroke-miterlimit': '4', 'stroke-dasharray': '4, 2, 1, 2',
'stroke-dashoffset': '0' }
line_attribs = {'style': str(inkex.Style(style)),
'id': name,
'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
etree.SubElement(parent, 'path', line_attribs)
def draw_reg_circles(self, cx, cy, r, name, colours, parent):
for i in range(len(colours)):
style = {'stroke':colours[i], 'stroke-width':str(r / len(colours)),
'fill':'none'}
circle_attribs = {'style':str(inkex.Style(style)),
inkex.addNS('label','inkscape'):name,
'cx':str(cx), 'cy':str(cy),
'r':str((r / len(colours)) * (i + 0.5))}
etree.SubElement(parent, inkex.addNS('circle','svg'),
circle_attribs)
def draw_registration_marks(self, cx, cy, rotate, name, parent):
colours = ['#000000','#00ffff','#ff00ff','#ffff00','#000000']
g = etree.SubElement(parent, 'g', { 'id': name })
for i in range(len(colours)):
style = {'fill':colours[i], 'fill-opacity':'1', 'stroke':'none'}
r = (self.mark_size/2)
step = r
stroke = r / len(colours)
regoffset = stroke * i
regmark_attribs = {'style': str(inkex.Style(style)),
'd': 'm' +\
' '+str(-regoffset)+','+str(r) +\
' '+str(-stroke) +',0' +\
' '+str(step) +','+str(-r) +\
' '+str(-step) +','+str(-r) +\
' '+str(stroke) +',0' +\
' '+str(step) +','+str(r) +\
' '+str(-step) +','+str(r) +\
' z',
'transform': 'translate('+str(cx)+','+str(cy)+ \
') rotate('+str(rotate)+')'}
etree.SubElement(g, 'path', regmark_attribs)
def draw_star_target(self, cx, cy, name, parent):
r = (self.mark_size/2)
style = {'fill':'#000 device-cmyk(1,1,1,1)', 'fill-opacity':'1', 'stroke':'none'}
d = ' M 0,0'
i = 0
while i < ( 2 * math.pi ):
i += math.pi / 16
d += ' L 0,0 ' +\
' L '+ str(math.sin(i)*r) +','+ str(math.cos(i)*r) +\
' L '+ str(math.sin(i+0.09)*r) +','+ str(math.cos(i+0.09)*r)
regmark_attribs = {'style':str(inkex.Style(style)),
inkex.addNS('label','inkscape'):name,
'transform':'translate('+str(cx)+','+str(cy)+')',
'd':d}
etree.SubElement(parent, inkex.addNS('path','svg'),
regmark_attribs)
def draw_coluor_bars(self, cx, cy, rotate, name, parent):
g = etree.SubElement(parent, 'g', {
'id':name,
'transform':'translate('+str(cx)+','+str(cy)+\
') rotate('+str(rotate)+')' })
l = min( self.mark_size / 3, max(self.area_w,self.area_h) / 45 )
for bar in [{'c':'*', 'stroke':'#000', 'x':0, 'y':-(l+1)},
{'c':'r', 'stroke':'#0FF', 'x':0, 'y':0},
{'c':'g', 'stroke':'#F0F', 'x':(l*11)+1, 'y':-(l+1)},
{'c':'b', 'stroke':'#FF0', 'x':(l*11)+1, 'y':0}
]:
i = 0
while i <= 1:
cr = '255'
cg = '255'
cb = '255'
if bar['c'] == 'r' or bar['c'] == '*' : cr = str(255*i)
if bar['c'] == 'g' or bar['c'] == '*' : cg = str(255*i)
if bar['c'] == 'b' or bar['c'] == '*' : cb = str(255*i)
r_att = {'fill':'rgb('+cr+','+cg+','+cb+')',
'stroke':bar['stroke'],
'stroke-width':'0.5',
'x':str((l*i*10)+bar['x']), 'y':str(bar['y']),
'width':str(l), 'height':str(l)}
r = etree.SubElement(g, 'rect', r_att)
i += 0.1
def get_selection_area(self):
scale = self.svg.unittouu('1px') # convert to document units
sel_area = {}
min_x, min_y, max_x, max_y = False, False, False, False
for id in self.options.ids:
sel_area[id] = {}
for att in [ "x", "y", "width", "height" ]:
args = [ "inkscape", "-I", id, "--query-"+att, self.options.input_file ]
sel_area[id][att] = scale* \
float(Popen(args, stdout=PIPE, stderr=PIPE).communicate()[0])
current_min_x = sel_area[id]["x"]
current_min_y = sel_area[id]["y"]
current_max_x = sel_area[id]["x"] + \
sel_area[id]["width"]
current_max_y = sel_area[id]["y"] + \
sel_area[id]["height"]
if not min_x: min_x = current_min_x
if not min_y: min_y = current_min_y
if not max_x: max_x = current_max_x
if not max_y: max_y = current_max_y
if current_min_x < min_x: min_x = current_min_x
if current_min_y < min_y: min_y = current_min_y
if current_max_x > max_x: max_x = current_max_x
if current_max_y > max_y: max_y = current_max_y
#inkex.errormsg( '>> '+ id +
# ' min_x:'+ str(min_x) +
# ' min_y:'+ str(min_y) +
# ' max_x:'+ str(max_x) +
# ' max_y:'+ str(max_y) )
self.area_x1 = min_x
self.area_y1 = min_y
self.area_x2 = max_x
self.area_y2 = max_y
self.area_w = max_x - min_x
self.area_h = max_y - min_y
def effect(self):
self.mark_size = self.svg.unittouu('1cm')
self.min_mark_margin = self.svg.unittouu('3mm')
if self.options.where_to_crop == 'selection' :
self.get_selection_area()
#inkex.errormsg('Sory, the crop to selection is a TODO feature')
#exit(1)
else :
svg = self.document.getroot()
self.area_w = self.svg.unittouu(svg.get('width'))
self.area_h = self.svg.unittouu(svg.attrib['height'])
self.area_x1 = 0
self.area_y1 = 0
self.area_x2 = self.area_w
self.area_y2 = self.area_h
# Get SVG document dimensions
# self.width must be replaced by self.area_x2. same to others.
svg = self.document.getroot()
#self.width = width = self.svg.unittouu(svg.get('width'))
#self.height = height = self.svg.unittouu(svg.attrib['height'])
# Convert parameters to user unit
offset = self.svg.unittouu(str(self.options.crop_offset) + \
self.options.unit)
bt = self.svg.unittouu(str(self.options.bleed_top) + self.options.unit)
bb = self.svg.unittouu(str(self.options.bleed_bottom) + self.options.unit)
bl = self.svg.unittouu(str(self.options.bleed_left) + self.options.unit)
br = self.svg.unittouu(str(self.options.bleed_right) + self.options.unit)
# Bleed margin
if bt < offset : bmt = 0
else : bmt = bt - offset
if bb < offset : bmb = 0
else : bmb = bb - offset
if bl < offset : bml = 0
else : bml = bl - offset
if br < offset : bmr = 0
else : bmr = br - offset
# Define the new document limits
offset_left = self.area_x1 - offset
offset_right = self.area_x2 + offset
offset_top = self.area_y1 - offset
offset_bottom = self.area_y2 + offset
# Get middle positions
middle_vertical = self.area_y1 + ( self.area_h / 2 )
middle_horizontal = self.area_x1 + ( self.area_w / 2 )
# Test if printing-marks layer existis
layer = self.document.xpath(
'//*[@id="printing-marks" and @inkscape:groupmode="layer"]',
namespaces=inkex.NSS)
if layer: svg.remove(layer[0]) # remove if it existis
# Create a new layer
layer = etree.SubElement(svg, 'g')
layer.set('id', 'printing-marks')
layer.set(inkex.addNS('label', 'inkscape'), 'Printing Marks')
layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
layer.set(inkex.addNS('insensitive', 'sodipodi'), 'true')
# Crop Mark
if self.options.crop_marks == True:
# Create a group for Crop Mark
g_attribs = {inkex.addNS('label','inkscape'):'CropMarks',
'id':'CropMarks'}
g_crops = etree.SubElement(layer, 'g', g_attribs)
# Top left Mark
self.draw_crop_line(self.area_x1, offset_top,
self.area_x1, offset_top - self.mark_size,
'cropTL1', g_crops)
self.draw_crop_line(offset_left, self.area_y1,
offset_left - self.mark_size, self.area_y1,
'cropTL2', g_crops)
# Top right Mark
self.draw_crop_line(self.area_x2, offset_top,
self.area_x2, offset_top - self.mark_size,
'cropTR1', g_crops)
self.draw_crop_line(offset_right, self.area_y1,
offset_right + self.mark_size, self.area_y1,
'cropTR2', g_crops)
# Bottom left Mark
self.draw_crop_line(self.area_x1, offset_bottom,
self.area_x1, offset_bottom + self.mark_size,
'cropBL1', g_crops)
self.draw_crop_line(offset_left, self.area_y2,
offset_left - self.mark_size, self.area_y2,
'cropBL2', g_crops)
# Bottom right Mark
self.draw_crop_line(self.area_x2, offset_bottom,
self.area_x2, offset_bottom + self.mark_size,
'cropBR1', g_crops)
self.draw_crop_line(offset_right, self.area_y2,
offset_right + self.mark_size, self.area_y2,
'cropBR2', g_crops)
# Bleed Mark
if self.options.bleed_marks == True:
# Create a group for Bleed Mark
g_attribs = {inkex.addNS('label','inkscape'):'BleedMarks',
'id':'BleedMarks'}
g_bleed = etree.SubElement(layer, 'g', g_attribs)
# Top left Mark
self.draw_bleed_line(self.area_x1 - bl, offset_top - bmt,
self.area_x1 - bl, offset_top - bmt - self.mark_size,
'bleedTL1', g_bleed)
self.draw_bleed_line(offset_left - bml, self.area_y1 - bt,
offset_left - bml - self.mark_size, self.area_y1 - bt,
'bleedTL2', g_bleed)
# Top right Mark
self.draw_bleed_line(self.area_x2 + br, offset_top - bmt,
self.area_x2 + br, offset_top - bmt - self.mark_size,
'bleedTR1', g_bleed)
self.draw_bleed_line(offset_right + bmr, self.area_y1 - bt,
offset_right + bmr + self.mark_size, self.area_y1 - bt,
'bleedTR2', g_bleed)
# Bottom left Mark
self.draw_bleed_line(self.area_x1 - bl, offset_bottom + bmb,
self.area_x1 - bl, offset_bottom + bmb + self.mark_size,
'bleedBL1', g_bleed)
self.draw_bleed_line(offset_left - bml, self.area_y2 + bb,
offset_left - bml - self.mark_size, self.area_y2 + bb,
'bleedBL2', g_bleed)
# Bottom right Mark
self.draw_bleed_line(self.area_x2 + br, offset_bottom + bmb,
self.area_x2 + br, offset_bottom + bmb + self.mark_size,
'bleedBR1', g_bleed)
self.draw_bleed_line(offset_right + bmr, self.area_y2 + bb,
offset_right + bmr + self.mark_size, self.area_y2 + bb,
'bleedBR2', g_bleed)
# Registration Mark
if self.options.registration_marks == True:
# Create a group for Registration Mark
g_attribs = {inkex.addNS('label','inkscape'):'RegistrationMarks',
'id':'RegistrationMarks'}
g_center = etree.SubElement(layer, 'g', g_attribs)
# Left Mark
cx = max( bml + offset, self.min_mark_margin )
self.draw_registration_marks(self.area_x1 - cx - (self.mark_size/2),
middle_vertical - self.mark_size*1.5,
'0', 'regMarkL', g_center)
# Right Mark
cx = max( bmr + offset, self.min_mark_margin )
self.draw_registration_marks(self.area_x2 + cx + (self.mark_size/2),
middle_vertical - self.mark_size*1.5,
'180', 'regMarkR', g_center)
# Top Mark
cy = max( bmt + offset, self.min_mark_margin )
self.draw_registration_marks(middle_horizontal,
self.area_y1 - cy - (self.mark_size/2),
'90', 'regMarkT', g_center)
# Bottom Mark
cy = max( bmb + offset, self.min_mark_margin )
self.draw_registration_marks(middle_horizontal,
self.area_y2 + cy + (self.mark_size/2),
'-90', 'regMarkB', g_center)
# Star Target
if self.options.star_target == True:
# Create a group for Star Target
g_attribs = {inkex.addNS('label','inkscape'):'StarTarget',
'id':'StarTarget'}
g_center = etree.SubElement(layer, 'g', g_attribs)
if self.area_h < self.area_w :
# Left Star
cx = max( bml + offset, self.min_mark_margin )
self.draw_star_target(self.area_x1 - cx - (self.mark_size/2),
middle_vertical,
'starTargetL', g_center)
# Right Star
cx = max( bmr + offset, self.min_mark_margin )
self.draw_star_target(self.area_x2 + cx + (self.mark_size/2),
middle_vertical,
'starTargetR', g_center)
else :
# Top Star
cy = max( bmt + offset, self.min_mark_margin )
self.draw_star_target(middle_horizontal - self.mark_size*1.5,
self.area_y1 - cy - (self.mark_size/2),
'starTargetT', g_center)
# Bottom Star
cy = max( bmb + offset, self.min_mark_margin )
self.draw_star_target(middle_horizontal - self.mark_size*1.5,
self.area_y2 + cy + (self.mark_size/2),
'starTargetB', g_center)
# Colour Bars
if self.options.colour_bars == True:
# Create a group for Colour Bars
g_attribs = {inkex.addNS('label','inkscape'):'ColourBars',
'id':'PrintingColourBars'}
g_center = etree.SubElement(layer, 'g', g_attribs)
if self.area_h > self.area_w :
# Left Bars
cx = max( bml + offset, self.min_mark_margin )
self.draw_coluor_bars(self.area_x1 - cx - (self.mark_size/2),
middle_vertical + self.mark_size,
90,
'PrintingColourBarsL', g_center)
# Right Bars
cx = max( bmr + offset, self.min_mark_margin )
self.draw_coluor_bars(self.area_x2 + cx + (self.mark_size/2),
middle_vertical + self.mark_size,
90,
'PrintingColourBarsR', g_center)
else :
# Top Bars
cy = max( bmt + offset, self.min_mark_margin )
self.draw_coluor_bars(middle_horizontal + self.mark_size,
self.area_y1 - cy - (self.mark_size/2),
0,
'PrintingColourBarsT', g_center)
# Bottom Bars
cy = max( bmb + offset, self.min_mark_margin )
self.draw_coluor_bars(middle_horizontal + self.mark_size,
self.area_y2 + cy + (self.mark_size/2),
0,
'PrintingColourBarsB', g_center)
# Page Information
if self.options.page_info == True:
# Create a group for Page Information
g_attribs = {inkex.addNS('label','inkscape'):'PageInformation',
'id':'PageInformation'}
g_pag_info = etree.SubElement(layer, 'g', g_attribs)
y_margin = max( bmb + offset, self.min_mark_margin )
txt_attribs = {
'style': 'font-size:12px;font-style:normal;font-weight:normal;fill:#000000;font-family:Bitstream Vera Sans,sans-serif;text-anchor:middle;text-align:center',
'x': str(middle_horizontal),
'y': str(self.area_y2+y_margin+self.mark_size+20)
}
txt = etree.SubElement(g_pag_info, 'text', txt_attribs)
txt.text = 'Page size: ' +\
str(round(self.svg.uutounit(self.area_w,self.options.unit),2)) +\
'x' +\
str(round(self.svg.uutounit(self.area_h,self.options.unit),2)) +\
' ' + self.options.unit
if __name__ == '__main__':
PrintingMarksDotted().run()

View File

@ -0,0 +1,21 @@
[
{
"name": "Silhouette Cameo Registration Marks",
"id": "fablabchemnitz.de.render_silhouette_regmarks",
"path": "render_silhouette_regmarks",
"dependent_extensions": null,
"original_name": "Classic",
"original_id": "org.inkscape.render.silhouette-regmarks",
"license": "GNU GPL v3",
"license_url": "https://github.com/miLORD1337/silhouette-regmarks/blob/main/LICENSE",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/render_silhouette_regmarks",
"fork_url": "https://github.com/miLORD1337/silhouette-regmarks",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Silhouette+Cameo+Registration+Marks",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/miLORD1337",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Silhouette Cameo Registration Marks</name>
<id>fablabchemnitz.de.silhouette_cameo_registration_marks</id>
<param name="regwidth" type="float" min="0.0" max="10000" gui-text="X mark distance [mm]">180</param>
<param name="reglength" type="float" min="0.0" max="10000" gui-text="Y mark distance [mm]">230</param>
<param name="regoriginx" type="float" min="10.0" max="10000" gui-text="Position of regmark from document left [mm]">15</param>
<param name="regoriginy" type="float" min="10.0" max="10000" gui-text="Position of regmark from document top [mm]">20</param>
<label>Distance of the registration mark edges</label>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Cutting/Plotting/Printing"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">render_silhouette_regmarks.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,101 @@
#
# Copyright (C) 2021 miLORD1337
#
# 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, USA.
#
"""
Base module for rendering regmarks for Silhouette CAMEO products in Inkscape.
"""
import inkex
from lxml import etree
SVG_URI = u'http://www.w3.org/2000/svg'
class SilhouetteCameoRegistrationMarks(inkex.EffectExtension):
def add_arguments(self, pars):
# Define string option "--what" with "-w" shortcut and default value "World".
# Layer name static, since self.document.getroot() not available on initialization
self.layername = 'silhouette-regmark'
# Parse arguments
pars.add_argument("-X", "--reg-x", "--regwidth", type = float, dest = "regwidth", default = 180.0, help="X mark distance [mm]")
pars.add_argument("-Y", "--reg-y", "--reglength", type = float, dest = "reglength", default = 230.0, help="Y mark distance [mm]")
pars.add_argument("--rego-x", "--regoriginx", type = float, dest = "regoriginx", default = 15.0, help="X mark origin from left [mm]")
pars.add_argument("--rego-y", "--regoriginy", type = float, dest = "regoriginy", default = 20.0, help="X mark origin from top [mm]")
#SVG rect element generation routine
def drawRect(self, size, pos, name):
x, y = pos
w, h = size
rect = etree.Element('{%s}rect' % SVG_URI)
rect.set('x', str(x))
rect.set('y', str(y))
rect.set('id', name)
rect.set('width', str(w))
rect.set('height', str(h))
rect.set('style', 'fill: black;')
return rect
#SVG line element generation routine
def drawLine(self, posStart, posEnd, name):
x1, y1 = posStart
x2, y2, = posEnd
line = etree.Element('{%s}line' % SVG_URI)
line.set('x1', str(x1))
line.set('y1', str(y1))
line.set('x2', str(x2))
line.set('y2', str(y2))
line.set('id', name)
line.set('style', 'stroke: black; stroke-width: 0.5;')
return line
def effect(self):
svg = self.document.getroot()
# Create a new layer.
layer = etree.SubElement(svg, 'g')
layer.set(inkex.addNS('label', 'inkscape'), self.layername)
layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
# Create square in top left corner
layer.append(self.drawRect((5,5), (self.options.regoriginx,self.options.regoriginy), 'TopLeft'))
# Create group for top right corner
topRight = etree.Element('{%s}g' % SVG_URI)
topRight.set('id', 'TopRight')
topRight.set('style', 'fill: black;')
# Create horizontal and vertical lines in group
topRight.append(self.drawLine((self.options.regwidth-20,self.options.regoriginy), (self.options.regwidth,self.options.regoriginy), 'Horizontal'))
topRight.append(self.drawLine((self.options.regwidth,self.options.regoriginy), (self.options.regwidth,self.options.regoriginy + 20), 'Vertical'))
layer.append(topRight)
# Create group for top right corner
bottomLeft = etree.Element('{%s}g' % SVG_URI)
bottomLeft.set('id', 'BottomLeft')
bottomLeft.set('style', 'fill: black;')
# Create horizontal and vertical lines in group
bottomLeft.append(self.drawLine((self.options.regoriginx,self.options.reglength), (self.options.regoriginx+20,self.options.reglength), 'Horizontal'))
bottomLeft.append(self.drawLine((self.options.regoriginx,self.options.reglength), (self.options.regoriginx,self.options.reglength - 20), 'Vertical'))
layer.append(bottomLeft)
#Lock layer
layer.set(inkex.addNS('insensitive', 'sodipodi'), 'true')
if __name__ == '__main__':
SilhouetteCameoRegistrationMarks().run()

View File

@ -7,14 +7,14 @@
"original_name": "Scale To Size",
"original_id": "fablabchemnitz.de.scale_to_size",
"license": "GNU GPL v3",
"license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE",
"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.X/src/branch/master/extensions/fablabchemnitz/scale_to_size",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/scale_to_size",
"fork_url": null,
"documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=76054572",
"inkscape_gallery_url": null,
"main_authors": [
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -9,13 +9,13 @@
"license": "GNU GPL v3",
"license_url": "https://inkscape.org/de/~pakin/%E2%98%85snap-object-points",
"comment": "",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/snap_object_points",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/snap_object_points",
"fork_url": "https://inkscape.org/de/~pakin/%E2%98%85snap-object-points",
"documentation_url": "",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/pakin",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -9,13 +9,13 @@
"license": "GNU GPL v3",
"license_url": "https://inkscape.org/de/~jabiertxof/%E2%98%85stroke-color-as-fill",
"comment": "ported to Inkscape v1 by Mario Voigt",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/stroke_color_as_fill",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/stroke_color_as_fill",
"fork_url": "https://inkscape.org/de/~jabiertxof/%E2%98%85stroke-color-as-fill",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Stroke+Color+As+Fill",
"inkscape_gallery_url": null,
"main_authors": [
"inkscape.org/jabiertxof",
"github.com/vmario89"
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,266 @@
#!/usr/bin/env python3
"""
base_transform.py
Base matemathical operations for SVG 3x3 matrices
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import re
import inkex
import os
from math import *
class BaseTransform(inkex.Effect):
unitMatrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
def isset(self, v, i = None):
try:
if (i is None):
v
else:
v[i]
return True
except:
return False
def __init__(self):
inkex.Effect.__init__(self)
def sizeToPx(self, s, dim = "y"):
root = self.document.getroot()
try:
factor = float(root.attrib[inkex.addNS('export-' + dim + 'dpi', 'inkscape')])
except:
factor = 90
unit = ''
pattern = '[\\-\\d\\.]+([a-zA-Z][a-zA-Z])'
if (re.search(pattern, s)):
res = re.search(pattern, s)
unit = res.group(1)
pattern = '^([\\-\\d\\.]*)'
res = re.search(pattern, s)
n = float(res.group(1))
if unit == 'cm':
return (n / 2.54) * factor
elif unit == 'ft':
return n * 12 * factor
elif unit == 'in':
return n * factor
elif unit == 'm':
return ((n * 10) / 2.54) * factor
elif unit == 'mm':
return ((n / 10) / 2.54) * factor
elif unit == 'pc':
return ((n * 2.36228956229) / 2.54) * factor
elif unit == 'pt':
return (((n / 2.83464646465) / 10) / 2.54) * factor
elif unit == 'px' or unit == '':
return n
return 0
def transform(self, el):
result = self.unitMatrix
if (el.tag == inkex.addNS('svg', 'svg')):
return result
if (not self.isset(el.attrib, 'transform')):
return self.multiply(self.transform(el.getparent()), result)
pattern = '(matrix|translate|scale|rotate|skewX|skewY)[\\s|,]*\\(([^\\)]*)\\)'
transforms = re.findall(pattern, el.attrib['transform'])
for transform in transforms:
values = re.split('[\\s|,]+', transform[1])
for i in range(len(values)):
values[i] = float(values[i])
function = transform[0]
if (function == 'matrix'):
a = [[values[0], values[2], values[4]],
[values[1], values[3], values[5]],
[0, 0, 1]]
result = self.multiply(result, a)
elif (function == 'translate'):
a = [[1, 0, values[0]],
[0, 1, values[1]],
[0, 0, 1]]
result = self.multiply(result, a)
elif (function == 'scale'):
a = [[values[0], 0, 0],
[0, values[1], 0],
[0, 0, 1]]
result = self.multiply(result, a)
elif (function == 'rotate'):
if (len(values) == 1):
a = [[math.cos(values[0]), -math.sin(values[0]), 0],
[math.sin(values[0]), math.cos(values[0]), 0],
[0, 0, 1]]
result = self.multiply(result, a)
else:
a = [[1, 0, values[2]],
[0, 1, values[2]],
[0, 0, 1]]
result = self.multiply(result, a)
a = [[math.cos(values[0]), -math.sin(values[0]), 0],
[math.sin(values[0]), math.cos(values[0]), 0],
[0, 0, 1]]
result = self.multiply(result, a)
a = [[1, 0, -values[2]],
[0, 1, -values[2]],
[0, 0, 1]]
result = self.multiply(result, a)
elif (function == 'skewX'):
a = [[1, math.tan(values[0]), 0],
[0, 1, 0],
[0, 0, 1]]
result = self.multiply(result, a)
elif (function == 'skewY'):
a = [[1, 0, 0],
[math.tan(values[0]), 1, 0],
[0, 0, 1]]
result = self.multiply(result, a)
return self.multiply(self.transform(el.getparent()), result)
def getPosition(self, el):
if not self.isset(el.attrib, 'x'):
return False
x = self.sizeToPx(el.attrib['x'], 'x')
y = self.sizeToPx(el.attrib['y'], 'y')
v = [x, y, 1]
t = self.transform(el)
v = self.multiply(t, v)
return {'coordinates': v, 'matrix': t}
def setPosition(self, el, position):
c = position['coordinates']
a = position['matrix']
if (not self.isUnitMatrix(a)):
c = self.multiply(self.inverse(a), c)
el.set('x', str(c[0]))
el.set('y', str(c[1]))
def determinant(self, a):
if len(a) != 3:
return False
if (len(a[0]) != 3):
return False
det = a[0][0] * (a[1][1] * a[2][2] - a[2][1] * a[1][2]) - a[0][1] * (a[1][0] * a[2][2] - a[2][0] * a[1][2]) + a[0][2] * (a[1][0] * a[2][1] - a[2][0] * a[1][1])
if (det == 0):
det = 0.00001
return det
def minors(self, a):
if len(a) != 3:
return False
if (len(a[0]) != 3):
return False
return [[a[1][1] * a[2][2] - a[2][1] * a[1][2], a[1][0] * a[2][2] - a[2][0] * a[1][2], a[1][0] * a[2][1] - a[2][0] * a[1][1]],
[a[0][1] * a[2][2] - a[2][1] * a[0][2], a[0][0] * a[2][2] - a[0][2] * a[2][0], a[0][0] * a[2][1] - a[2][0] * a[0][1]],
[a[0][1] * a[1][2] - a[1][1] * a[0][2], a[0][0] * a[1][2] - a[0][1] * a[0][2], a[0][0] * a[1][1] - a[1][0] * a[0][1]]
]
def cofactors(self, a):
if len(a) != 3:
return False
if (len(a[0]) != 3):
return False
return [[a[0][0], -a[0][1], a[0][2]],
[-a[1][0], a[1][1], -a[1][2]],
[a[2][0], -a[2][1], a[2][2]]
]
def adjoint(self, a):
if len(a) != 3:
return False
if (len(a[0]) != 3):
return False
return [[a[0][0], a[1][0], a[2][0]],
[a[0][1], a[1][1], a[2][1]],
[a[0][2], a[1][2], a[2][2]]
]
def inverse(self, a):
if len(a) != 3:
return False
if (len(a[0]) != 3):
return False
det = self.determinant(a)
m = self.minors(a)
c = self.cofactors(m)
adj = self.adjoint(c)
return [[adj[0][0] / det, adj[0][1] / det, adj[0][2] / det],
[adj[1][0] / det, adj[1][1] / det, adj[1][2] / det],
[adj[2][0] / det, adj[2][1] / det, adj[2][2] / det]
]
def multiply(self, a, v):
if len(a) != 3:
return False
if (len(a[0]) != 3):
return False
if (len(v) != 3):
return False
if (not self.isset(v[0], 0)):
return [a[0][0] * v[0] + a[0][1] * v[1] + a[0][2] * v[2],
a[1][0] * v[0] + a[1][1] * v[1] + a[1][2] * v[2],
a[2][0] * v[0] + a[2][1] * v[1] + a[2][2] * v[2]
]
else:
return [[a[0][0] * v[0][0] + a[0][1] * v[1][0] + a[0][2] * v[2][0], a[0][0] * v[0][1] + a[0][1] * v[1][1] + a[0][2] * v[2][1], a[0][0] * v[0][2] + a[0][1] * v[1][2] + a[0][2] * v[2][2]],
[a[1][0] * v[0][0] + a[1][1] * v[1][0] + a[1][2] * v[2][0], a[1][0] * v[0][1] + a[1][1] * v[1][1] + a[1][2] * v[2][1], a[1][0] * v[0][2] + a[1][1] * v[1][2] + a[1][2] * v[2][2]],
[a[2][0] * v[0][0] + a[2][1] * v[1][0] + a[2][2] * v[2][0], a[2][0] * v[0][1] + a[2][1] * v[1][1] + a[2][2] * v[2][1], a[2][0] * v[0][2] + a[2][1] * v[1][2] + a[2][2] * v[2][2]]
]
def isUnitMatrix(self, a):
if (len(a) != 3):
return False
if (len(a[0]) != 3):
return False
for i in range(3):
for j in range(3):
if (a[i][j] != self.unitMatrix[i][j]):
return False
return True
def reParse(self):
if os.name == 'nt':
path = os.environ['USERPROFILE']
else:
path = os.path.expanduser("~")
text = inkex.etree.tostring(self.document.getroot())
f = open(path + '/tmp.svg', 'w')
f.write(text)
f.close()
self.parse(path + '/tmp.svg')
os.remove(path + '/tmp.svg')
def matrix2string(self, a):
return 'matrix(' + str(a[0][0]) + ',' + str(a[1][0]) + ',' + str(a[0][1]) + ',' + str(a[1][1]) + ',' + str(a[0][2]) + ',' + str(a[1][2]) + ')'

View File

@ -0,0 +1,21 @@
[
{
"name": "<various>",
"id": "fablabchemnitz.de.table_<various>",
"path": "table_support",
"dependent_extensions": null,
"original_name": "<various>",
"original_id": "org.greygreen.inkscape.effects.table_<various>",
"license": "GNU GPL v2",
"license_url": "https://sourceforge.net/projects/inkscape-tables/files/inkscape-table-1.0.tar.gz/download",
"comment": "ported to Inkscape v1 by Mario Voigt",
"source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2/src/branch/master/extensions/fablabchemnitz/table_support",
"fork_url": "https://sourceforge.net/projects/inkscape-tables",
"documentation_url": "https://stadtfabrikanten.org/display/IFM/Table+Support",
"inkscape_gallery_url": null,
"main_authors": [
"sourceforge.net/lixapopescu",
"github.com/eridur-de"
]
}
]

View File

@ -0,0 +1,850 @@
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import math
import inkex
from inkex import Guide
from lxml import etree
import base_transform
import re
class TableEngine(base_transform.BaseTransform):
defaultId = 'inkscape-table'
cell_type_row = 'row'
cell_type_column = 'column'
normalizeFactor = 5
tablesCount = 0
tables = None
selectedTables = {}
mergedCells = {}
tablesTexts = {}
get_tables = True
auto_split = True
delimiter = ','
def __init__(self, get_tables = True, auto_split = True):
inkex.NSS['inkex'] = 'http://sodipodi.sourceforge.net/DTD/inkex-0.dtd'
self.get_tables = get_tables
self.auto_split = auto_split
base_transform.BaseTransform.__init__(self)
def getTablesCount(self):
node = self.document.xpath('//inkex:tables', namespaces = inkex.NSS)
if len(node) == 0:
xml = '<inkex:tables xmlns:inkex="http://sodipodi.sourceforge.net/DTD/inkex-0.dtd" count="0"/>'
self.document.getroot().append(etree.fromstring(xml))
node = self.document.xpath('//inkex:tables', namespaces = inkex.NSS)
else:
self.tablesCount = int(node[0].attrib['count'])
self.tables = node[0]
def isTableCell(self, id):
el = self.svg.getElementById(id)
if (el == None):
return False
if (self.isset(el.attrib, inkex.addNS('table-id', 'inkex'))):
tableId = el.attrib[inkex.addNS('table-id', 'inkex')]
if (re.search('\\-text$', tableId)):
return False
else:
return True
return False
def effect(self):
self.getTablesCount()
if (self.get_tables):
self.getAllTables()
if (self.auto_split):
for id, table in self.selectedTables.items():
for i in range(len(table)):
for j in range(len(table[i])):
if (table[i][j] != None):
points = self.splitCell(table[i][j])
if (points != False):
if (self.isset(self.mergedCells, id)):
self.mergedCells[id].append(points)
else:
self.mergedCells[id] = [points]
for tableId in self.mergedCells:
self.getTable(tableId)
self.doinkex()
if (self.get_tables):
if (self.auto_split):
for tableId in self.mergedCells:
self.getTableText(tableId)
for points in self.mergedCells[tableId]:
if (not self.isset(points, 'removed')):
self.mergeTable(tableId, points)
def newCell(self, x, y, width, height, id, i, j, transform = None):
#path = '//*[@inkex:table-id="%s"]' % id
_id = self.svg.get_unique_id(id)
etree.SubElement(self.svg.get_current_layer(), 'rect', {
'id': _id,
'style': 'fill:none;stroke:#000000;stroke-width:1px;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none',
'width': str(width) + 'px',
'height': str(height) + 'px',
'x': str(x) + 'px',
'y': str(y) + 'px',
inkex.addNS('table-id', 'inkex'): id,
inkex.addNS('row', 'inkex'): str(i),
inkex.addNS('column', 'inkex'): str(j)
})
if (transform != None):
el = self.svg.getElementById(_id)
el.set('transform', transform)
return _id
'''
_id = self.svg.get_unique_id(id)
content = '<rect style="fill:none;stroke:#000000;stroke-width:1px;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"\n\
id="' + _id + '"\n\
width="' + str(width) + '"\n\
height="' + str(height) + '"\n\
x="' + str(x) + '"\n\
y="' + str(y) + '"\n\
/>'
self.svg.get_current_layer().append(etree.XML(content))
el = self.svg.getElementById(_id)
el.set(inkex.addNS('table-id', 'inkex'), id)
el.set(inkex.addNS('row', 'inkex'), str(i))
el.set(inkex.addNS('column', 'inkex'), str(j))
'''
def create(self, width, height, cols, rows):
tableId = self.defaultId + str(self.tablesCount)
self.tablesCount += 1
self.tables.set('count', str(self.tablesCount))
content = '<inkex:table xmlns:inkex="http://sodipodi.sourceforge.net/DTD/inkex-0.dtd" table-id="' + tableId + '" rows="' + str(rows) + '" columns="' + str(cols) + '"/>'
self.tables.append(etree.fromstring(content))
width = self.sizeToPx(width, 'x')
height = self.sizeToPx(height, 'y')
x = 0
y = 0
content = ''
for i in range(rows):
x = 0
for j in range(cols):
self.newCell(x, y, width, height, tableId, i, j)
x += width
y += height
def getTree(self, id):
ids = [id]
el = self.svg.getElementById(id)
for _el in list(el):
for _id in self.getTree(_el.attrib['id']):
ids.append(_id)
return ids
def getSubSelectedIds(self):
ids = []
for id in self.svg.selected.ids:
for _id in self.getTree(id):
ids.append(_id)
return ids
def getAllTables(self):
ids = self.getSubSelectedIds()
for id in ids:
el = self.svg.getElementById(id)
if (self.isTableCell(id)):
tableId = el.attrib[inkex.addNS('table-id', 'inkex')]
if (not self.isset(self.selectedTables, tableId)):
self.getTable(tableId)
self.tablesTexts[tableId] = self.getTableText(tableId)
def getTableDimensions(self, tableId):
nodes = self.tables.xpath('//inkex:table[@table-id="' + tableId + '"]', namespaces = inkex.NSS)
if (len(nodes) > 0):
return {'rows': int(nodes[0].attrib['rows']), 'cols': int(nodes[0].attrib['columns'])}
return False
def setTableDimensions(self, tableId, dimensions):
table_dim = self.tables.xpath('//inkex:table[@table-id="' + tableId + '"]', namespaces = inkex.NSS)
if (len(table_dim) > 0):
table_dim[0].set('rows', str(dimensions['rows']))
table_dim[0].set('columns', str(dimensions['cols']))
def getTable(self, tableId):
nodes = self.tables.xpath('//inkex:table[@table-id="' + tableId + '"]', namespaces = inkex.NSS)
if (len(nodes) > 0):
cols = int(nodes[0].attrib['columns'])
rows = int(nodes[0].attrib['rows'])
table = [[None for i in range(cols)] for j in range(rows)]
path = '//*[@inkex:table-id="' + tableId + '"]'
cells = self.document.xpath(path, namespaces = inkex.NSS)
for cell in cells:
i = int(cell.attrib[inkex.addNS('row', 'inkex')])
j = int(cell.attrib[inkex.addNS('column', 'inkex')])
table[i][j] = cell.attrib['id']
self.selectedTables[tableId] = table
def getTableText(self, tableId):
nodes = self.tables.xpath('//inkex:table[@table-id="' + tableId + '"]', namespaces = inkex.NSS)
if (len(nodes) > 0):
cols = int(nodes[0].attrib['columns'])
rows = int(nodes[0].attrib['rows'])
texts = [[None for i in range(cols)] for j in range(rows)]
path = '//*[@inkex:table-id="' + tableId + '-text"]'
cells = self.document.xpath(path, namespaces = inkex.NSS)
for cell in cells:
i = int(cell.attrib[inkex.addNS('row', 'inkex')])
j = int(cell.attrib[inkex.addNS('column', 'inkex')])
texts[i][j] = cell.attrib['id']
return texts
return None
def doAddGuide(self, el, type):
px = self.sizeToPx(str(self.svg.unittouu(self.document.getroot().attrib['height'])), 'y')
position = self.getPosition(el)
if (position != False):
c = position['coordinates']
a = position['matrix']
x = c[0]
y = c[1]
angle = math.acos(a[0][0]) * 180 / math.pi
if angle < 90:
angle = 90 - angle
elif angle < 180:
angle = 180 - angle
elif angle < 270:
angle = 270 - angle
else:
angle = 360 - angle
if (type == self.cell_type_row):
angle += 90
self.svg.namedview.add(Guide().move_to(str(x), str(px - y), angle))
def _addGuides(self, tableId, type):
table = self.selectedTables[tableId]
count = len(table)
if (type == self.cell_type_column):
count = len(table[0])
for i in range(count):
_i = i
_j = 0
if (type == self.cell_type_column):
_i = 0
_j = i
el = self.svg.getElementById(table[_i][_j])
self.doAddGuide(el, type)
if (i == count - 1):
if (type == self.cell_type_column):
el.attrib['x'] = str(self.sizeToPx(el.attrib['x'], 'x') + self.sizeToPx(el.attrib['width'], 'x'))
else:
el.attrib['y'] = str(self.sizeToPx(el.attrib['y'], 'y') + self.sizeToPx(el.attrib['height'], 'y'))
self.doAddGuide(el, type)
if (type == self.cell_type_column):
el.attrib['x'] = str(self.sizeToPx(el.attrib['x'], 'x') - self.sizeToPx(el.attrib['width'], 'x'))
else:
el.attrib['y'] = str(self.sizeToPx(el.attrib['y'], 'y') - self.sizeToPx(el.attrib['height'], 'y'))
def addGuides(self, type):
for tableId in self.selectedTables:
self._addGuides(tableId, type)
def doEditText(self, id, fontSize):
el = self.svg.getElementById(id)
if (not self.isTableCell(id)):
return
position = self.getPosition(el)
if (position != False):
a = position['matrix']
if (not self.isUnitMatrix(a)):
transform = 'transform="' + self.matrix2string(a) + '"'
else:
transform = ''
content = '<flowRoot id="' + self.svg.get_unique_id(el.attrib[inkex.addNS('table-id', 'inkex')]) + '" xmlns:inkex="http://sodipodi.sourceforge.net/DTD/inkex-0.dtd" ' + transform + ' \
inkex:table-id="' + el.attrib[inkex.addNS('table-id', 'inkex')] + '-text" inkex:row="' + el.attrib[inkex.addNS('row', 'inkex')] + '" inkex:column="' + el.attrib[inkex.addNS('column', 'inkex')] + '" \
style="font-size:' + fontSize + ';font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"\
xml:space="preserve"><flowRegion id="' + self.svg.get_unique_id(el.attrib[inkex.addNS('table-id', 'inkex')]) + '"><rect id="' + self.svg.get_unique_id(el.attrib[inkex.addNS('table-id', 'inkex')]) + '" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans"\
x="' + el.attrib['x'] + '"\
y="' + el.attrib['y'] + '"\
width="' + el.attrib['width'] + '"\
height="' + el.attrib['height'] + '"/></flowRegion><flowPara id="' + self.svg.get_unique_id(el.attrib[inkex.addNS('table-id', 'inkex')]) + '">text here</flowPara></flowRoot>'
self.svg.get_current_layer().append(etree.fromstring(content))
def editText(self, fontSize):
ids = self.getSubSelectedIds()
for id in ids:
self.doEditText(id, fontSize)
def getColumnIndex(self, id):
el = self.svg.getElementById(id)
if (self.isset(el.attrib, inkex.addNS('column', 'inkex'))):
return int(el.attrib[inkex.addNS('column', 'inkex')])
return -1
def getRowIndex(self, id):
el = self.svg.getElementById(id)
if (self.isset(el.attrib, inkex.addNS('row', 'inkex'))):
return int(el.attrib[inkex.addNS('row', 'inkex')])
return -1
def setTextRect(self, text, c):
for child in list(text):
if (child.tag == inkex.addNS('flowRegion', 'svg')):
for subchild in list(child):
if (subchild.tag == inkex.addNS('rect', 'svg')):
for key, value in c.items():
if value != None:
subchild.set(key, str(value))
break
def getTextRect(self, text):
for child in list(text):
if (child.tag == inkex.addNS('flowRegion', 'svg')):
for subchild in list(child):
if (subchild.tag == inkex.addNS('rect', 'svg')):
return subchild
return None
def moveCells(self, tableId, idx, delta, type):
table = self.selectedTables[tableId]
texts = self.tablesTexts[tableId]
if (type == self.cell_type_column):
starti = 0
startj = idx
else:
starti = idx
startj = 0
for i in range(starti, len(table)):
for j in range(startj, len(table[i])):
el = self.svg.getElementById(table[i][j])
position = self.getPosition(el)
if (position != False):
c = [self.sizeToPx(el.attrib['x'], 'x'), self.sizeToPx(el.attrib['y'], 'y')]
c[0] += delta[0]
c[1] += delta[1]
el.set('x', str(c[0]))
el.set('y', str(c[1]))
if (texts != None):
if (texts[i][j] != None):
el = self.svg.getElementById(texts[i][j])
rect = self.getTextRect(el)
if (rect != None):
c[0] = self.sizeToPx(rect.attrib['x'], 'x') + delta[0]
c[1] = self.sizeToPx(rect.attrib['y'], 'y') + delta[1]
self.setTextRect(el, {'x': c[0], 'y': c[1]})
def setCellSize(self, tableId, idx, size, type):
table = self.selectedTables[tableId]
texts = self.tablesTexts[tableId]
if (type == self.cell_type_column):
size = self.sizeToPx(size, 'x')
old_size = self.sizeToPx(self.svg.getElementById(table[0][idx]).attrib['width'], 'x')
else:
size = self.sizeToPx(size, 'y')
old_size = self.sizeToPx(self.svg.getElementById(table[idx][0]).attrib['height'], 'y')
if (type == self.cell_type_column):
delta = [size - old_size, 0, 1]
else:
delta = [0, size - old_size, 1]
if ((idx + 1 < len(table) and type == self.cell_type_row) or (idx + 1 < len(table[0]) and type == self.cell_type_column)):
self.moveCells(tableId, idx + 1, delta, type)
count = len(table[idx])
if (type == self.cell_type_column):
count = len(table)
for i in range(count):
_i = idx
_j = i
if type == self.cell_type_column:
_i = i
_j = idx
el = self.svg.getElementById(table[_i][_j])
param = 'height'
if (type == self.cell_type_column):
param = 'width'
el.set(param, str(size))
if texts != None:
if texts[_i][_j] != None:
el = self.svg.getElementById(texts[_i][_j])
self.setTextRect(el, {param: size})
def editSize(self, size, type):
processed = {}
for node in self.svg.selected.values():
id = node.get('id')
if (self.isTableCell(id)):
tableId = node.attrib[inkex.addNS('table-id', 'inkex')]
if (type == self.cell_type_column):
idx = self.getColumnIndex(id)
else:
idx = self.getRowIndex(id)
if (not self.isset(processed, tableId)):
processed[tableId] = []
if (not self.isset(processed[tableId], idx)):
self.setCellSize(tableId, idx, size, type)
processed[tableId].append(idx)
def getTableWidth(self, tableId):
table = self.selectedTables[tableId]
width = 0
for i in range(len(table[0])):
el = self.svg.getElementById(table[0][i])
width += self.sizeToPx(el.attrib['width'], 'x')
return width
def getTableHeight(self, tableId):
table = self.selectedTables[tableId]
height = 0
for i in range(len(table)):
el = self.svg.getElementById(table[i][0])
height += self.sizeToPx(el.attrib['height'], 'y')
return height
def setTableSize(self, tableId, size, type):
if (type == self.cell_type_column):
size = self.sizeToPx(size, 'x')
old_size = self.getTableWidth(tableId)
else:
size = self.sizeToPx(size, 'y')
old_size = self.getTableHeight(tableId)
factor = size / old_size
table = self.selectedTables[tableId]
count = len(table)
if (type == self.cell_type_column):
count = len(table[0])
for i in range(count):
if (type == self.cell_type_column):
el = self.svg.getElementById(table[0][i])
new_size = self.sizeToPx(el.attrib['width'], 'x') * factor
else:
el = self.svg.getElementById(table[i][0])
new_size = self.sizeToPx(el.attrib['height'], 'y') * factor
self.setCellSize(tableId, i, str(new_size), type)
def editTable(self, width, height):
for id in self.selectedTables:
self.setTableSize(id, width, self.cell_type_column)
self.setTableSize(id, height, self.cell_type_row)
def getTablePosition(self, tableId):
table = self.selectedTables[tableId]
el = self.svg.getElementById(table[0][0])
return self.getPosition(el)
def fitPage(self):
width = str(self.svg.unittouu(self.document.getroot().attrib['width']))
height = str(self.svg.unittouu(self.document.getroot().attrib['height']))
for id in self.selectedTables:
position = self.getTablePosition(id)
if (position != False):
c = position['coordinates']
self.moveCells(id, 0, [-c[0], -c[1], 1], type)
self.setTableSize(id, width, self.cell_type_column)
self.setTableSize(id, height, self.cell_type_row)
def fitPageWidth(self):
width = str(self.svg.unittouu(self.document.getroot().attrib['width']))
for id in self.selectedTables:
position = self.getTablePosition(id)
if (position != False):
c = position['coordinates']
self.moveCells(id, 0, [-c[0], 0, 1], type)
self.setTableSize(id, width, self.cell_type_column)
def fitPageHeight(self):
height = str(self.svg.unittouu(self.document.getroot().attrib['height']))
for id in self.selectedTables:
position = self.getTablePosition(id)
if (position != False):
c = position['coordinates']
self.moveCells(id, 0, [0, -c[1], 1], type)
self.setTableSize(id, height, self.cell_type_row)
def getSelectedListIds(self):
idList = []
for id in self.getSubSelectedIds():
idList.append(id)
return idList
def getCellText(self, tableId, i, j):
texts = self.tablesTexts[tableId]
if (texts != None):
if (texts[i][j] != None):
return self.svg.getElementById(texts[i][j])
return None
def getMergePoints(self, tableId):
dim = self.getTableDimensions(tableId)
table = self.selectedTables[tableId]
idList = self.getSelectedListIds()
start = []
for i in range(dim['rows']):
for j in range(dim['cols']):
if (idList.count(table[i][j]) > 0):
start = [i, j]
break
if len(start) > 0:
break
if (len(start) != 2):
return False
end = [1, 1]
for i in range(start[0] + 1, len(table)):
if (idList.count(table[i][start[1]]) > 0):
end[0] += 1
else:
break
for i in range(start[1] + 1, len(table[0])):
if (idList.count(table[start[0]][i]) > 0):
end[1] += 1
else:
break
for i in range(start[0], start[0] + end[0]):
for j in range(start[1], start[1] + end[1]):
if (idList.count(table[i][j]) == 0):
return False
return {'i': start[0], 'j': start[1], 'rows': end[0], 'cols': end[1]}
def mergeTable(self, tableId, points = None):
if (points == None):
points = self.getMergePoints(tableId)
if (points == False):
inkex.errormsg('You have to select the cells to form a rectangle from a single table.')
return
table = self.selectedTables[tableId]
cell = self.svg.getElementById(table[points['i']][points['j']])
width = 0
height = 0
widths = ''
heights = ''
for i in range(points['i'], points['i'] + points['rows']):
el = self.svg.getElementById(table[i][points['j']])
height += self.sizeToPx(el.attrib['height'], 'y')
if (heights != ''):
heights += self.delimiter
heights += el.attrib['height']
for j in range(points['j'], points['j'] + points['cols']):
el = self.svg.getElementById(table[points['i']][j])
width += self.sizeToPx(el.attrib['width'], 'x')
if (widths != ''):
widths += self.delimiter
widths += el.attrib['width']
for i in range(points['i'], points['i'] + points['rows']):
for j in range(points['j'], points['j'] + points['cols']):
if (i != points['i'] or j != points['j']):
el = self.svg.getElementById(table[i][j])
el.getparent().remove(el)
text = self.getCellText(tableId, i, j)
if (text != None):
text.getparent().remove(text)
cell.set('width', str(width) + 'px')
cell.set('height', str(height) + 'px')
cell.set(inkex.addNS('merged', 'inkex'), str(points['rows']) + self.delimiter + str(points['cols']))
cell.set(inkex.addNS('merged-columns-widths', 'inkex'), widths)
cell.set(inkex.addNS('merged-rows-heights', 'inkex'), heights)
text = self.getCellText(tableId, points['i'], points['j'])
if (text != None):
rect = self.getTextRect(text)
rect.set('width', str(width) + 'px')
rect.set('height', str(height) + 'px')
def mergeMerge(self):
for id in self.selectedTables:
self.mergeTable(id)
def splitCell(self, cellId):
cell = self.svg.getElementById(cellId)
if (self.isset(cell.attrib, inkex.addNS('merged', 'inkex'))):
tableId = cell.attrib[inkex.addNS('table-id', 'inkex')]
row = int(cell.attrib[inkex.addNS('row', 'inkex')])
column = int(cell.attrib[inkex.addNS('column', 'inkex')])
position = self.getPosition(cell)
merge_size = cell.attrib[inkex.addNS('merged', 'inkex')].split(self.delimiter)
widths = cell.attrib[inkex.addNS('merged-columns-widths', 'inkex')].split(self.delimiter)
heights = cell.attrib[inkex.addNS('merged-rows-heights', 'inkex')].split(self.delimiter)
y = self.sizeToPx(cell.attrib['y'], 'y')
for i in range(row, row + int(merge_size[0])):
x = self.sizeToPx(cell.attrib['x'], 'x')
for j in range(column, column + int(merge_size[1])):
if (i != row or j != column):
transform = None
if position != False:
a = position['matrix']
if (not self.isUnitMatrix(a)):
transform = self.matrix2string(a)
self.newCell(x, y, self.sizeToPx(widths[j - column], 'x'), self.sizeToPx(heights[i - row], 'y'), tableId, i, j, transform)
x += self.sizeToPx(widths[j - column], 'x')
y += self.sizeToPx(heights[i - row], 'y')
result = {'i': row, 'j': column, 'rows': int(merge_size[0]), 'cols': int(merge_size[1])}
cell.set('width', widths[0])
cell.set('height', heights[0])
text = self.getCellText(tableId, row, column)
if (text != None):
rect = self.getTextRect(text)
rect.set('width', widths[0])
rect.set('height', heights[0])
del cell.attrib[inkex.addNS('merged', 'inkex')]
del cell.attrib[inkex.addNS('merged-columns-widths', 'inkex')]
del cell.attrib[inkex.addNS('merged-rows-heights', 'inkex')]
return result
return False
def mergeSplit(self):
for id in self.svg.selected.ids:
self.splitCell(id)
def updateMergedPoints(self, tableId, idx, delta, type):
if (self.get_tables):
if (self.auto_split):
if (self.isset(self.mergedCells, tableId)):
for points in self.mergedCells[tableId]:
cond1 = idx > points['i'] and idx < points['i'] + points['rows']
cond2 = idx <= points['i']
if (type == self.cell_type_column):
cond1 = idx > points['j'] and idx < points['j'] + points['cols']
cond2 = idx <= points['j']
if (cond1):
if (type == self.cell_type_column):
points['cols'] += delta
if (points['cols'] <= 1):
points['removed'] = 1
else:
points['rows'] += delta
if (points['rows'] <= 1):
points['removed'] = 1
elif (cond2):
if (type == self.cell_type_column):
if (delta == -1 and idx == points['j']):
points['cols'] += delta
if (points['cols'] <= 1):
points['removed'] = 1
else:
points['j'] += delta
else:
if (delta == -1 and idx == points['i']):
points['rows'] += delta
if (points['rows'] <= 1):
points['removed'] = 1
else:
points['i'] += delta
def incrementCoordonate(self, tableId, idx, inc, type):
table = self.selectedTables[tableId]
texts = self.getTableText(tableId)
starti = idx
startj = 0
dim = self.getTableDimensions(tableId)
if type == self.cell_type_column:
dim['cols'] += inc
else:
dim['rows'] += inc
self.setTableDimensions(tableId, dim)
if (type == self.cell_type_column):
starti = 0
startj = idx
for i in range(starti, len(table)):
for j in range(startj, len(table[i])):
cell = self.svg.getElementById(table[i][j])
text = self.svg.getElementById(texts[i][j])
if (type == self.cell_type_column):
cell.set(inkex.addNS('column', 'inkex'), str(int(cell.attrib[inkex.addNS('column', 'inkex')]) + inc))
if (text != None):
text.set(inkex.addNS('column', 'inkex'), str(int(text.attrib[inkex.addNS('column', 'inkex')]) + inc))
else:
cell.set(inkex.addNS('row', 'inkex'), str(int(cell.attrib[inkex.addNS('row', 'inkex')]) + inc))
if (text != None):
text.set(inkex.addNS('row', 'inkex'), str(int(text.attrib[inkex.addNS('row', 'inkex')]) + inc))
def addCell(self, tableId, idx, type):
table = self.selectedTables[tableId]
if (type == self.cell_type_column):
if (idx != -1):
delta = [self.sizeToPx(self.svg.getElementById(table[0][idx]).attrib['width'], 'x'), 0, 1]
else:
delta = [self.sizeToPx(self.svg.getElementById(table[0][0]).attrib['width'], 'x'), 0, 1]
else:
if (idx != -1):
delta = [0, self.sizeToPx(self.svg.getElementById(table[idx][0]).attrib['height'], 'y'), 1]
else:
delta = [0, self.sizeToPx(self.svg.getElementById(table[0][0]).attrib['height'], 'y'), 1]
count = len(table)
if type == self.cell_type_row:
if (idx != -1):
count = len(table[idx])
else:
count = len(table[0])
for i in range(count):
if (type == self.cell_type_column):
if (idx != -1):
cell = self.svg.getElementById(table[i][idx])
else:
cell = self.svg.getElementById(table[i][0])
else:
if (idx != -1):
cell = self.svg.getElementById(table[idx][i])
else:
cell = self.svg.getElementById(table[0][i])
position = self.getPosition(cell)
transform = ''
if (position != False):
a = position['matrix']
if (not self.isUnitMatrix(a)):
transform = self.matrix2string(a)
x = self.sizeToPx(cell.attrib['x'], 'x')
y = self.sizeToPx(cell.attrib['y'], 'y')
width = self.sizeToPx(cell.attrib['width'], 'x')
height = self.sizeToPx(cell.attrib['height'], 'y')
if (type == self.cell_type_column):
if (idx != -1):
x += width
self.newCell(x, y, width, height, tableId, i, idx + 1, transform)
else:
if (idx != -1):
y += height
self.newCell(x, y, width, height, tableId, idx + 1, i, transform)
self.moveCells(tableId, idx + 1, delta, type)
self.updateMergedPoints(tableId, idx + 1, 1, type)
self.incrementCoordonate(tableId, idx + 1, 1, type)
self.getTable(tableId)
self.tablesTexts[tableId] = self.getTableText(tableId)
def addColumns(self, count, where):
for id in self.svg.selected.ids:
el = self.svg.getElementById(id)
if (self.isTableCell(id)):
tableId = el.attrib[inkex.addNS('table-id', 'inkex')]
idx = self.getColumnIndex(id)
if (where == 'before'):
idx -= 1
for i in range(count):
self.addCell(tableId, idx, self.cell_type_column)
def addRows(self, count, where):
for id in self.svg.selected.ids:
el = self.svg.getElementById(id)
if (self.isTableCell(id)):
tableId = el.attrib[inkex.addNS('table-id', 'inkex')]
idx = self.getRowIndex(id)
if (where == 'before'):
idx -= 1
for i in range(count):
self.addCell(tableId, idx, self.cell_type_row)
break
def removeCell(self, tableId, idx, type):
table = self.selectedTables[tableId]
texts = self.tablesTexts[tableId]
if (type == self.cell_type_column):
delta = [-self.sizeToPx(self.svg.getElementById(table[0][idx]).attrib['width'], 'x'), 0, 1]
else:
delta = [0, -self.sizeToPx(self.svg.getElementById(table[idx][0]).attrib['height'], 'y'), 1]
count = len(table)
if type == self.cell_type_row:
count = len(table[idx])
for i in range(count):
if (type == self.cell_type_column):
cell = self.svg.getElementById(table[i][idx])
text = self.svg.getElementById(texts[i][idx])
else:
cell = self.svg.getElementById(table[idx][i])
text = self.svg.getElementById(texts[idx][i])
if (cell != None):
cell.getparent().remove(cell)
if (text != None):
text.getparent().remove(text)
self.moveCells(tableId, idx + 1, delta, type)
self.updateMergedPoints(tableId, idx, -1, type)
self.incrementCoordonate(tableId, idx + 1, -1, type)
self.getTable(tableId)
self.tablesTexts[tableId] = self.getTableText(tableId)
def removeRowsColumns(self, type):
for id in self.svg.selected.ids:
el = self.svg.getElementById(id)
if (el != None):
if (self.isTableCell(id)):
tableId = el.attrib[inkex.addNS('table-id', 'inkex')]
if (type == self.cell_type_column):
idx = self.getColumnIndex(id)
else:
idx = self.getRowIndex(id)
self.removeCell(tableId, idx, type)

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Columns</name>
<id>fablabchemnitz.de.table_add_columns</id>
<param name="number" type="int" gui-text="The number of columns to add:">1</param>
<param name="where" type="optiongroup" appearance="radio" gui-text="Before or after the selected column:">
<option value="before">Before</option>
<option value="after">After</option>
</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Add" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_add_columns.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self, True, True)
self.arg_parser.add_argument('--number', type = int, default = 1, help = 'The number of columns')
self.arg_parser.add_argument('--where', default = "after", help = 'Where to add')
def doinkex(self):
self.addColumns(self.options.number, self.options.where)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Guide Lines</name>
<id>fablabchemnitz.de.table_add_guides</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Add" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_add_guides.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self)
def doinkex(self):
self.addGuides(self.cell_type_row)
self.addGuides(self.cell_type_column)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Rows</name>
<id>fablabchemnitz.de.table_add_rows</id>
<param name="number" type="int" gui-text="The number of rows to add:">1</param>
<param name="where" type="optiongroup" appearance="radio" gui-text="Before or after the selected rows:">
<option value="before">Before</option>
<option value="after">After</option>
</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Add" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_add_rows.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self, True, True)
self.arg_parser.add_argument('--number', type = int, default = 1, help = 'The number of rows')
self.arg_parser.add_argument('--where', default = "after", help = 'Where to add')
def doinkex(self):
self.addRows(self.options.number, self.options.where)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Create</name>
<id>fablabchemnitz.de.table_create</id>
<param name="tab" type="notebook">
<page name="options" gui-text="Options">
<param name="cols" type="int" gui-text="The number of columns:">2</param>
<param name="rows" type="int" gui-text="The number of rows:">2</param>
<param name="width" type="string" gui-text="The width of the cell:">100mm</param>
<param name="height" type="string" gui-text="The height of the cell:">20mm</param>
<label>VERY IMPORTANT: You will notice that the newly created table does not contain text. In order to edit any cell's text, just select the cell and then from the Extensions menu select Table -&gt; Edit -&gt; Selected cells text</label>
</page>
<page name="help" gui-text="Help">
<label>This is the first step in using the table support. First create a table. You have to input the number of rows, the number of columns and the width and the height of each cell. The width of the table will equal the number of columns times the width of each cell and the table height will equal the number of rows times the height of each cell. If you want to set a specific width and height for the table, after creating it, you just select it and then select from the Extensions menu -&gt; Table -&gt; Edit -&gt; Table width and height. For the width and height you can also input the measurement unit (mm, cm, in, px etc.). If you don't input any measurement unit, the size will be calculated in pixels. Do not use any space between the value and the unit.</label>
</page>
</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table" />
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_create.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def add_arguments(self, pars):
pars.add_argument("--rows", type=int, default=2, help='The number of table rows')
pars.add_argument("--cols", type=int, default=2, help='The number of table columns')
pars.add_argument("--width", default='100mm', help='The width of the table')
pars.add_argument("--height", default='20mm', help='The height of the table')
pars.add_argument("--tab")
def doinkex(self):
self.create(self.options.width, self.options.height, self.options.cols, self.options.rows)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected columns width</name>
<id>fablabchemnitz.de.table_edit_columns</id>
<param name="width" type="string" gui-text="Input the new width:">10mm</param>
<!--param name="keep" type="bool" gui-text="Keep the table original height">false</param-->
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Edit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_edit_columns.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def add_arguments(self, pars):
pars.add_argument("--width", default='10mm', help='The new width')
def doinkex(self):
self.editSize(self.options.width, self.cell_type_column)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected rows height</name>
<id>fablabchemnitz.de.table_edit_rows</id>
<param name="height" type="string" gui-text="Input the new height:">10mm</param>
<!--param name="keep" type="bool" gui-text="Keep the table original height">false</param-->
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Edit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_edit_rows.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def add_arguments(self, pars):
pars.add_argument("--height", default='10mm', help='The new height')
def doinkex(self):
self.editSize(self.options.height, self.cell_type_row)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected table width and height</name>
<id>fablabchemnitz.de.table_edit_table</id>
<param name="width" type="string" gui-text="Input the new width of the table:">150mm</param>
<param name="height" type="string" gui-text="Input the new height of the table:">60mm</param>
<!--param name="keep" type="bool" gui-text="Keep the table original height">false</param-->
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Edit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_edit_table.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def add_arguments(self, pars):
pars.add_argument("--width", default='150mm', help='The new width')
pars.add_argument("--height", default='60mm', help='The new height')
def doinkex(self):
self.editTable(self.options.width, self.options.height)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected cells text</name>
<id>fablabchemnitz.de.table_edit_text</id>
<param name="size" type="string" gui-text="The font size:">12px</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Edit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_edit_text.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def add_arguments(self, pars):
pars.add_argument("--size", default='12px', help='The font size')
def doinkex(self):
self.editText(self.options.size)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected table to page height</name>
<id>fablabchemnitz.de.table_fit_height</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Fit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_fit_height.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self)
def doinkex(self):
self.fitPageHeight()
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected table to page</name>
<id>fablabchemnitz.de.table_fit_page</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Fit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_fit_page.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def doinkex(self):
self.fitPage()
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected table to page width</name>
<id>fablabchemnitz.de.table_fit_width</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Fit" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_fit_width.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self)
def doinkex(self):
self.fitPageWidth()
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Merge selected cells</name>
<id>fablabchemnitz.de.table_merge_merge</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Merge cells" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_merge_merge.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self)
def doinkex(self):
self.mergeMerge()
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Split selected cells</name>
<id>fablabchemnitz.de.table_merge_split</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Merge cells" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_merge_split.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self, True, False)
def doinkex(self):
self.mergeSplit()
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected columns</name>
<id>fablabchemnitz.de.table_remove_columns</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Remove" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_remove_columns.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self, True, True)
def doinkex(self):
self.removeRowsColumns(self.cell_type_column)
if __name__ == '__main__': #pragma: no cover
Table().run()

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Selected rows</name>
<id>fablabchemnitz.de.table_remove_rows</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Table">
<submenu name="Remove" />
</submenu>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">table_remove_rows.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""
table.py
Table support for Inkscape
Copyright (C) 2011 Cosmin Popescu, cosminadrianpopescu@gmail.com
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.
"""
import sys
import os
import table
sys.path.append(os.path.dirname(sys.argv[0]))
class Table(table.TableEngine):
def __init__(self):
table.TableEngine.__init__(self, True, True)
def doinkex(self):
self.removeRowsColumns(self.cell_type_row)
if __name__ == '__main__': #pragma: no cover
Table().run()