| Import Filters | Plugins | Plugin Objects |
Skencil uses export filters to write documents to files.
For export filter configuration, Skencil uses the following variables:
typeThe type must be Export. This identifier is defined in the
globals() dictionary.
tk_file_typeunload (optional)format_nameThese variables have the same meaning as in an import filter.
extensionsA string with the standard file extension of the export format. Alternatively this can be a tuple of file extension strings.
Skencil uses the file extension to find the export filter.
standard_messages (optional)A boolean indicating whether the messages in the plugin are standard messages that are defined in Skencil's message catalogs. For third-party plugins this should be omitted.
Given a document object and a filename for the output file, Skencil does the following to find an export filter and to export the drawing:
save function.save functionThe function save is the main entry point for an export plugin. It
is called with four positional parameters document, file,
filename and options.
document is the document that is to be saved. file is the output file object open for writing and filename is the corresponding filename. Finally, options is a dictionary with (user specified) options. Currently options is always an empty dictinary as there is no way yet to specify such options.
Apart from the save function entry point Skencil requires very
little from the plugin. The only other thing it expects is that the
plugin traverses the object tree by itself and uses the interface
provided by the Protocols class to distinguish the
different object types.
In the following, the svg export filter serves as the basis for a a brief outline of this technique.
Both the svg and the ai filter use the same basic approach. They implement the filter as a class and use an instance of that class to do the work:
def save(document, file, filename, options = {}):
saver = SVGSaver(file, filename, document, options)
saver.Save()
saver.close()
|
The interesting parts happen in the class. The constructor doesn't do much, it just saves the parameters in instance variables:
class SVGSaver:
def __init__(self, file, filename, document, options):
self.file = file
self.filename = filename
self.document = document
self.options = options
|
The Save method is where the real work begins. First it writes a kind of file header:
def Save(self):
self.file.write('<?xml version="1.0" standalone="yes"?>\n')
left, bottom, right, top = self.document.BoundingRect()
width = right - left
height = top - bottom
self.trafo = Trafo(1, 0, 0, -1, -left, top)
self.file.write('<svg width="%g" height="%g"' % (width, height))
self.file.write('>\n')
|
BoundingRect returns the bounding rectangle of the
entire document
After the header it loops over all the layers in the document...
for layer in self.document.Layers():
|
if not layer.is_SpecialLayer and layer.Printable():
|
self.BeginGroup()
self.save_objects(layer.GetObjects())
self.EndGroup()
|
GetObjects() returns a list of all objects in the layer. All
compound objects have this method. In the SVG filter, the BeginGroup
and EndGroup methods write the <g> and </g>
tags that mark groups in SVG.
Finally, the trailer to close the <svg> tag.
self.file.write('</svg>')
|
The next interesting method is save_objects. It loops over the list of objects...
def save_objects(self, objects):
for object in objects:
|
if object.is_Compound:
|
self.BeginGroup()
self.save_objects(object.GetObjects())
self.EndGroup()
|
otherwise, if the object is a bezier object, a rectangle or an ellipse...
elif object.is_Bezier or object.is_Rectangle or object.is_Ellipse:
|
self.PolyBezier(object.Paths(), object.Properties(),
object.bounding_rect)
|
The Paths method returns a tuple of path
objects. Properties returns an object that has members like
fill_pattern and line_width that define the properties of the
object.
| Import Filters | Plugins | Plugin Objects |