Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save larscwallin/989080 to your computer and use it in GitHub Desktop.
Save larscwallin/989080 to your computer and use it in GitHub Desktop.
My fine Inkscape extensions
<inkscape-extension>
<_name>Create Sketch Layer</_name>
<id>com.larscwallin.create_sketch_layer</id>
<dependency type="executable" location="extensions">create_sketch_layer.py</dependency>
<dependency type="executable" location="extensions">inkex.py</dependency>
<!-- <param name="what" type="string" _gui-text="What?"></param> -->
<param name="where" type="string" _gui-text="Sketch save location"></param>
<param name="sketch_name" type="string" _gui-text="Sketch name"></param>
<param name="remove_border" type="boolean" _gui-text="Remove element border?"></param>
<param name="replace_source" type="boolean" _gui-text="Replace original element?"></param>
<param name="sketch_editor" type="string" _gui-text="Sketch editor"></param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu _name="Sketch"/>
</effects-menu>
</effect>
<script>
<command reldir="extensions" interpreter="python">larscwallin.inx.create-sketch-layer.py</command>
</script>
</inkscape-extension>
<!--
Contents
[hide]
1 boolean
2 int
3 float
4 string
5 description
6 enum
7 notebook
8 optiongroup
9 color
boolean
Gives a checkbox in the dialog; the default value may be "true" or "1", "false" or "0".
int
To get an integer; sort of textbox in the dialog.
float
To get an float number; sort of textbox in the dialog.
string
To get an character string; textbox in the dialog.
description
To show some text in the dialog.
enum
List of choices; the different choices are given by <item> elements.
notebook
To have different pages in the dialog; the other parameters are given inside <page> elements.
optiongroup
List of choices with rounded checkboxes; the different choices are given by <option> elements.
color
??
Retrieved from "http://wiki.inkscape.org/wiki/index.php/INX_Parameters"
-->
#!/usr/bin/env python
"""
Copyright (C) 2012 Lars C Wallin
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Version 0.2 121111
This script was written by Lars Wallin to make bitmap sketching easy.
It simply,
1. takes the currently selected element (a white/transparent surface seems a logical choice),
2. exports it to png
3. inserts it as a linked image element into a new layer in the current Inkscape drawing
4. opens the png in your editor of choice
5. lets you sketch away on the bitmap
6. waits for the sketching app to close
7. updates the linked bitmap in Inkscape
After this i use the bitmap to auto, or, manualy trace .
Have fun :)
PS.
Written on Ubuntu. If you run Windows make sure that you change the save path for the bitmap
as it defaults the Linux:y /home/
DS.
"""
import inkex
import sys, os, commands,subprocess
import os.path
import string
from time import time
from xml.dom.minidom import Document
from xml.dom.minidom import DocumentType
# This line is only needed if you don't put the script directly into
# the installation directory
# sys.path.append('/usr/share/inkscape/extensions')
# The simplestyle module provides functions for style parsing.
from simplestyle import *
# Effect main class
class CreateSketchLayer(inkex.Effect):
parserProcessHandle = None
saveLocation = ""
where = ""
what = ""
sketch_name = ""
remove_border = False
replace_source = False
sketch_editor = ""
svg_file = ""
renderHistory = []
rectangle_id = ""
def __init__(self):
"""
Constructor.
Defines the "--what" option of a script.
"""
# Call the base class constructor.
inkex.Effect.__init__(self)
# The OptionParser stuff below are Inkscape specific code which sets up the dialog for the extension GUI.
# The current options are just lab stuff and should be substituted with something more usefull.
self.OptionParser.add_option('--where', action = 'store',
type = 'string', dest = 'where', default = '',
help = 'Where to save?')
self.OptionParser.add_option('--sketch_name', action = 'store',
type = 'string', dest = 'sketch_name', default = 'New Sketch',
help = 'Sketch name')
self.OptionParser.add_option('--remove_border', action = 'store',
type = 'inkbool', dest = 'remove_border', default = False,
help = 'Remove canvas border?')
self.OptionParser.add_option('--replace_source', action = 'store',
type = 'inkbool', dest = 'replace_source', default = False,
help = 'Replace source element with sketch input?')
self.OptionParser.add_option('--sketch_editor', action = 'store',
type = 'string', dest = 'sketch_editor', default = '',
help = 'Application name for sketching. This value will be used at the command line, so please use the key used for starting the app in this context.')
# exportImage takes as argument the current svg element id. This is then used to select which element the Inkscape exe should export.
def exportImage(self,id):
# The easiest way to name rendered elements is by using their id since we can trust that this is always unique.
filename = os.path.join(self.where, id+'.png')
#self.debugPrint(filename)
# Inkscape has many really useful cmd line arguments which can be used to query for data, and render bitmaps.
# Please not that Inkscape supports shell execution and should really be started as such at the beginning of parsing.
# The shell spawning stuff is commented out at the bottom of this script.
# The current command will start/close a new instance of the app for every element parsed.
command = 'inkscape --without-gui --export-id-only --export-id %s --export-png %s %s' % (id, filename, self.svg_file)
#self.debugPrint(command)
processHandle = subprocess.Popen(command,
shell=True,
stdout=subprocess.PIPE)
# Inkscape is gracious enough to return some metadata regarding the exported bitmap.
stdout_value = processHandle.communicate()[0]
#self.debugPrint(stdout_value)
return (filename)
def openImage(self,filename,sketch_editor):
#self.debugPrint("opening "+filename)
if(sketch_editor!=""):
command = '"%s" "%s"' % (sketch_editor,filename)
else:
command = '"%s"' % (filename)
processHandle = subprocess.Popen(command,
shell=True,
stdout=subprocess.PIPE)
#self.debugPrint(command)
stdout_value = processHandle.communicate()[0]
#self.debugPrint('editor returned '+command)
def effect(self):
"""
Effect behaviour.
Overrides base class method
"""
self.svg_file = self.args[-1]
# Get script's "--where" option value.
self.where = self.options.where
if(self.where==''):
self.where = os.path.dirname(self.svg_file)
#self.debugPrint(self.replace_source)
if(self.where==''): sys.exit()
self.sketch_name = self.options.sketch_name
self.sketch_editor = self.options.sketch_editor
self.sketch_editor = self.sketch_editor if self.sketch_editor != '' else ''
sketch_file_path = ''
sketch_canvas = ''
sketch_canvas_x = ''
sketch_canvas_y = ''
sketch_canvas_height = ''
sketch_canvas_width = ''
sketch_canvas_id = ''
svg = self.document.xpath('//svg:svg',namespaces=inkex.NSS)[0]
layer_width = inkex.unittouu(svg.get('width'))
layer_height = inkex.unittouu(svg.get('height'))
# Create layer element
layer = inkex.etree.SubElement(svg, 'g')
layer.set(inkex.addNS('label', 'inkscape'), '%s' % (self.sketch_name))
layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
self.getselected()
if(self.selected.__len__() > 0):
sketch_canvas = self.selected.values()
sketch_canvas = sketch_canvas[0]
if(sketch_canvas!=''):
# Get the position of the sketch element
sketch_canvas_id = sketch_canvas.get('id')
sketch_canvas_x = sketch_canvas.get('x')
sketch_canvas_y = sketch_canvas.get('y')
sketch_canvas_height = sketch_canvas.get('height')
sketch_canvas_width = sketch_canvas.get('width')
# Export the selected element as sketch bitmap
sketch_bitmap_path = self.exportImage(sketch_canvas_id)
if(sketch_bitmap_path != ''):
# Create and insert a new image element for the sketch bitmap
sketch_bitmap_element = inkex.etree.SubElement(layer,'image')
# Set rectangle position to top/left width/height.
sketch_bitmap_element.set('x', str(sketch_canvas_x))
sketch_bitmap_element.set('y', str(sketch_canvas_y))
sketch_bitmap_element.set('width', str(sketch_canvas_width))
sketch_bitmap_element.set('height', str(sketch_canvas_height))
# Set basic style attributes
sketch_bitmap_element.set(inkex.addNS('href', 'xlink'), str(sketch_bitmap_path))
# Connect elements together.
layer.append(sketch_bitmap_element)
try:
self.openImage(sketch_bitmap_path,self.sketch_editor)
except:
self.debugPrint('Gimp error')
if(self.replace_source):
sketch_canvas.getparent().remove(sketch_canvas)
else:
self.debugPrint('sketch_bitmap_path was empty')
def debugPrint(self,textStr):
debugLayer = self.document.xpath('//svg:svg/svg:g',namespaces=inkex.NSS)[0]
# Create text element
text = inkex.etree.Element(inkex.addNS('text','svg'))
text.text = str(textStr)
# Set text position to center of document.
text.set('x', str(300 / 2))
text.set('y', str(300 / 2))
# Center text horizontally with CSS style.
style = {'text-align' : 'center', 'text-anchor': 'middle'}
text.set('style', formatStyle(style))
# Connect elements together.
debugLayer.append(text)
# Create effect instance and apply it.
effect = CreateSketchLayer()
effect.affect()
<inkscape-extension>
<_name>Elements to Layers</_name>
<id>larscwallin.inx.elements-to-layers</id>
<dependency type="executable" location="extensions">elements_to_layers.py</dependency>
<dependency type="executable" location="extensions">inkex.py</dependency>
<!--
self.prefix = self.options.prefix
self.suffix = self.options.suffix
self.keep_source_element = self.options.keep_source_element
self.name_using_element_id = self.options.name_using_element_id
self.center_element_on_layer = self.options.center_element_on_layer
-->
<param name="prefix" type="string" _gui-text="Layer prefix"></param>
<param name="suffix" type="string" _gui-text="Layer suffix"></param>
<param name="delete_source_element" type="boolean" _gui-text="Delete original elements?"></param>
<param name="center_element_on_layer" type="boolean" _gui-text="Center elements on canvas?"></param>
<param name="name_using_element_id" type="boolean" _gui-text="Name layers after element id?"></param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu _name="Generate from Path"/>
</effects-menu>
</effect>
<script>
<command reldir="extensions" interpreter="python">larscwallin.inx.elements-to-layers.py</command>
</script>
</inkscape-extension>
<!--
Contents
[hide]
1 boolean
2 int
3 float
4 string
5 description
6 enum
7 notebook
8 optiongroup
9 color
boolean
Gives a checkbox in the dialog; the default value may be "true" or "1", "false" or "0".
int
To get an integer; sort of textbox in the dialog.
float
To get an float number; sort of textbox in the dialog.
string
To get an character string; textbox in the dialog.
description
To show some text in the dialog.
enum
List of choices; the different choices are given by <item> elements.
notebook
To have different pages in the dialog; the other parameters are given inside <page> elements.
optiongroup
List of choices with rounded checkboxes; the different choices are given by <option> elements.
color
??
Retrieved from "http://wiki.inkscape.org/wiki/index.php/INX_Parameters"
-->
#!/usr/bin/env python
"""
Copyright (C) 2012 Lars C Wallin
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
import inkex
import simpletransform
import simplepath
import sys, os, commands,subprocess
import os.path
import string
from copy import deepcopy
from time import time
from xml.dom.minidom import Document
from xml.dom.minidom import DocumentType
# This line is only needed if you don't put the script directly into
# the installation directory
# sys.path.append('/usr/share/inkscape/extensions')
# The simplestyle module provides functions for style parsing.
from simplestyle import *
# Effect main class
class ElementToLayers(inkex.Effect):
parserProcessHandle = None
renderHistory = []
svg_doc = None
svg_doc_width = ''
svg_doc_height = ''
svg_file = ''
prefix = ''
suffix = ''
delete_source_element = False
name_using_element_id = True
center_element_on_layer = True
def __init__(self):
"""
Constructor.
"""
# Call the base class constructor.
inkex.Effect.__init__(self)
# The OptionParser stuff below are Inkscape specific code which sets up the dialog for the extension GUI.
# The current options are just lab stuff and should be substituted with something more usefull.
# Define string option "--what" with "-w" shortcut.
# self.prefix = self.options.prefix
# self.suffix = self.options.suffix
# self.delete_source_element = self.options.delete_source_element
# self.name_using_element_id = self.options.name_using_element_id
# self.center_element_on_layer = self.options.center_element_on_layer
self.OptionParser.add_option('--prefix', action = 'store',
type = 'string', dest = 'prefix', default = '',
help = 'Prefix to add to generated layers')
self.OptionParser.add_option('--suffix', action = 'store',
type = 'string', dest = 'suffix', default = '',
help = 'Suffix to add to generated layers')
self.OptionParser.add_option('--delete_source_element', action = 'store',
type = 'inkbool', dest = 'delete_source_element', default = False,
help = 'Delete source elements?')
self.OptionParser.add_option('--name_using_element_id', action = 'store',
type = 'inkbool', dest = 'name_using_element_id', default = True,
help = 'Name generated layers using the id of the elements?')
self.OptionParser.add_option('--center_element_on_layer', action = 'store',
type = 'inkbool', dest = 'center_element_on_layer', default = True,
help = 'Center element on layer?')
def effect(self):
"""
Effect behaviour.
Overrides base class method
"""
self.svg_file = self.args[-1]
self.prefix = self.options.prefix
self.suffix = self.options.suffix
self.delete_source_element = self.options.delete_source_element
self.name_using_element_id = self.options.name_using_element_id
self.center_element_on_layer = self.options.center_element_on_layer
self.svg_doc = self.document.xpath('//svg:svg',namespaces=inkex.NSS)[0]
self.svg_doc_width = inkex.unittouu(self.svg_doc.get('width'))
self.svg_doc_height = inkex.unittouu(self.svg_doc.get('height'))
self.getselected()
if(self.selected.__len__() > 0):
# Iterate through all selected elements
for element in self.selected.values():
self.CreateElementLayer(element)
def CreateElementLayer(self,element):
layer = ''
layer_id = ''
element_x = ''
element_copy = ''
element_y = ''
element_height = ''
element_width = ''
element_id = ''
# Got a valid element?
if(element!=''):
# Get the meta data of the current element
element_id = element.get('id')
element_x = element.get('x')
element_y = element.get('y')
element_height = element.get('height')
element_width = element.get('width')
transformation = 'translate(0,0)'
transform = simpletransform.parseTransform(transformation)
# Create layer element
layer = inkex.etree.SubElement(self.svg_doc, 'g')
layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
layer_id = layer.get('id');
# Should we name the layer after the current element id?
if(self.name_using_element_id):
layer.set(inkex.addNS('label', 'inkscape'), '%s%s%s' % (self.prefix,element_id,self.suffix))
else:
layer.set(inkex.addNS('label', 'inkscape'), '%s%s%s' % (self.prefix,layer_id,self.suffix))
# Clone source element
element_copy = deepcopy(element)
# Center on svg canvas
#if(self.center_element_on_layer == True):
#simplepath.translatePath(element_copy, 0, 0)
#element.set('x', str( (self.svg_doc_width - element_width) / 2 ))
#element.set('y', str( (self.svg_doc_height - element_height) / 2 ))
# Append to new layer
layer.append(element_copy)
# Delete source element?
if(self.delete_source_element == True):
element.getparent().remove(element)
def groupElement(self,element):
if(element):
parent = element.getparent()
# Create layer element
group = inkex.etree.SubElement(parent, 'g')
group.append(element)
def ungroupElements(self,group):
if(group):
# Create layer element
parent = group.getparent()
elements = group.getChildren()
for element in elements:
parent.append(element)
def parseElement(self,node):
element_metadata = ""
id = node.get('id')
# Do actual export
element_metadata = self.exportImage(id,'svg')
element_metadata = element_metadata.split(';')
element_metadata[3] = element_metadata[3].split(':')
# Assign the element_metadata values to an elementData struct which we later can query for element data. This will be used for rendering of content documents.
elementData = {
'id':element_metadata[0],
'parent_id':element_metadata[1],
'background': element_metadata[2],
'area':{
'x':element_metadata[3][0],
'y':element_metadata[3][1],
'rel_x':element_metadata[3][2],
'rel_y':element_metadata[3][3]
},
'width':element_metadata[4],
'height':element_metadata[5],
'path':element_metadata[6]
}
# Here we simply add the new struct to the renderHistory array.
#self.renderHistory.append(elementData)
# And just for debug sake write some stuff back to the document.
#self.debugLogger(self.renderHistory[0]['id'])
# Create effect instance and apply it.
effect = ElementToLayers()
effect.affect()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment