kopia lustrzana https://github.com/inkstitch/inkstitch
Add inkstitch svg version tag (#2199)
... to make it easier to update legacy default valuespull/2127/head
rodzic
067ef9095a
commit
6504c72fb7
|
@ -58,60 +58,6 @@ def param(*args, **kwargs):
|
|||
class EmbroideryElement(object):
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
self._update_legacy_params()
|
||||
|
||||
def _update_legacy_params(self): # noqa: C901
|
||||
# update legacy embroider_ attributes to namespaced attributes
|
||||
legacy_attribs = False
|
||||
for attrib in self.node.attrib:
|
||||
if attrib.startswith('embroider_'):
|
||||
self.replace_legacy_param(attrib)
|
||||
legacy_attribs = True
|
||||
|
||||
# convert legacy tie setting
|
||||
legacy_tie = self.get_param('ties', None)
|
||||
if legacy_tie == "True":
|
||||
self.set_param('ties', 0)
|
||||
elif legacy_tie == "False":
|
||||
self.set_param('ties', 3)
|
||||
|
||||
# convert legacy fill_method
|
||||
legacy_fill_method = self.get_int_param('fill_method', None)
|
||||
if legacy_fill_method == 0:
|
||||
self.set_param('fill_method', 'auto_fill')
|
||||
elif legacy_fill_method == 1:
|
||||
self.set_param('fill_method', 'contour_fill')
|
||||
elif legacy_fill_method == 2:
|
||||
self.set_param('fill_method', 'guided_fill')
|
||||
elif legacy_fill_method == 3:
|
||||
self.set_param('fill_method', 'legacy_fill')
|
||||
|
||||
# legacy satin method
|
||||
if self.get_boolean_param('e_stitch', False) is True:
|
||||
self.remove_param('e_stitch')
|
||||
self.set_param('satin_method', 'e_stitch')
|
||||
|
||||
# default setting for fill_underlay has changed
|
||||
if legacy_attribs and not self.get_param('fill_underlay', ""):
|
||||
self.set_param('fill_underlay', False)
|
||||
|
||||
# convert legacy stroke_method
|
||||
if self.get_style("stroke"):
|
||||
# manual stitch
|
||||
legacy_manual_stitch = self.get_boolean_param('manual_stitch', False)
|
||||
if legacy_manual_stitch is True:
|
||||
self.remove_param('manual_stitch')
|
||||
self.set_param('stroke_method', 'manual_stitch')
|
||||
# stroke_method
|
||||
legacy_stroke_method = self.get_int_param('stroke_method', None)
|
||||
if legacy_stroke_method == 0:
|
||||
self.set_param('stroke_method', 'running_stitch')
|
||||
elif legacy_stroke_method == 1:
|
||||
self.set_param('stroke_method', 'ripple_stitch')
|
||||
if (not self.get_param('stroke_method', None) and
|
||||
self.get_param('satin_column', False) is False and
|
||||
not self.node.style('stroke-dasharray')):
|
||||
self.set_param('stroke_method', 'zigzag_stitch')
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
|
@ -128,14 +74,6 @@ class EmbroideryElement(object):
|
|||
params.append(prop.fget.param)
|
||||
return params
|
||||
|
||||
def replace_legacy_param(self, param):
|
||||
# remove "embroider_" prefix
|
||||
new_param = param[10:]
|
||||
if new_param in INKSTITCH_ATTRIBS:
|
||||
value = self.node.get(param, "").strip()
|
||||
self.set_param(param[10:], value)
|
||||
del self.node.attrib[param]
|
||||
|
||||
@cache
|
||||
def get_param(self, param, default):
|
||||
value = self.node.get(INKSTITCH_ATTRIBS[param], "").strip()
|
||||
|
|
|
@ -3,112 +3,33 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from collections.abc import MutableMapping
|
||||
|
||||
from lxml import etree
|
||||
from lxml.etree import Comment
|
||||
from stringcase import snakecase
|
||||
|
||||
import inkex
|
||||
from lxml.etree import Comment
|
||||
from stringcase import snakecase
|
||||
|
||||
from ..commands import is_command, layer_commands
|
||||
from ..elements import EmbroideryElement, nodes_to_elements
|
||||
from ..elements.clone import is_clone
|
||||
from ..i18n import _
|
||||
from ..marker import has_marker
|
||||
from ..metadata import InkStitchMetadata
|
||||
from ..svg import generate_unique_id
|
||||
from ..svg.tags import (CONNECTOR_TYPE, EMBROIDERABLE_TAGS, INKSCAPE_GROUPMODE,
|
||||
NOT_EMBROIDERABLE_TAGS, SVG_CLIPPATH_TAG, SVG_DEFS_TAG,
|
||||
SVG_GROUP_TAG, SVG_MASK_TAG)
|
||||
from ..utils.settings import DEFAULT_METADATA, global_settings
|
||||
|
||||
SVG_METADATA_TAG = inkex.addNS("metadata", "svg")
|
||||
from ..update import update_inkstitch_document
|
||||
|
||||
|
||||
def strip_namespace(tag):
|
||||
"""Remove xml namespace from a tag name.
|
||||
|
||||
>>> {http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}namedview
|
||||
<<< namedview
|
||||
"""
|
||||
|
||||
match = re.match(r'^\{[^}]+\}(.+)$', tag)
|
||||
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
return tag
|
||||
|
||||
|
||||
class InkStitchMetadata(MutableMapping):
|
||||
"""Helper class to get and set inkstitch-specific metadata attributes.
|
||||
|
||||
Operates on a document and acts like a dict. Setting an item adds or
|
||||
updates a metadata element in the document. Getting an item retrieves
|
||||
a metadata element's text contents or None if an element by that name
|
||||
doesn't exist.
|
||||
"""
|
||||
|
||||
def __init__(self, document):
|
||||
super().__init__()
|
||||
self.document = document
|
||||
self.metadata = document.metadata
|
||||
|
||||
for setting in DEFAULT_METADATA:
|
||||
if self[setting] is None:
|
||||
self[setting] = global_settings[f'default_{setting}']
|
||||
|
||||
# Because this class inherints from MutableMapping, all we have to do is
|
||||
# implement these five methods and we get a full dict-like interface.
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
item = self._find_item(name)
|
||||
item.text = json.dumps(value)
|
||||
|
||||
def _find_item(self, name, create=True):
|
||||
tag = inkex.addNS(name, "inkstitch")
|
||||
item = self.metadata.find(tag)
|
||||
if item is None and create:
|
||||
item = etree.SubElement(self.metadata, tag)
|
||||
|
||||
return item
|
||||
|
||||
def __getitem__(self, name):
|
||||
item = self._find_item(name)
|
||||
|
||||
try:
|
||||
return json.loads(item.text)
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
def __delitem__(self, name):
|
||||
item = self._find_item(name, create=False)
|
||||
|
||||
if item is not None:
|
||||
self.metadata.remove(item)
|
||||
|
||||
def __iter__(self):
|
||||
for child in self.metadata:
|
||||
if child.prefix == "inkstitch":
|
||||
yield strip_namespace(child.tag)
|
||||
|
||||
def __len__(self):
|
||||
i = 0
|
||||
for i, item in enumerate(self):
|
||||
pass
|
||||
|
||||
return i + 1
|
||||
|
||||
def __json__(self):
|
||||
return dict(self)
|
||||
|
||||
|
||||
class InkstitchExtension(inkex.Effect):
|
||||
class InkstitchExtension(inkex.EffectExtension):
|
||||
"""Base class for Inkstitch extensions. Not intended for direct use."""
|
||||
|
||||
def load(self, *args, **kwargs):
|
||||
document = super().load(*args, **kwargs)
|
||||
update_inkstitch_document(document)
|
||||
return document
|
||||
|
||||
@classmethod
|
||||
def name(cls):
|
||||
return snakecase(cls.__name__)
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import json
|
||||
import re
|
||||
from collections.abc import MutableMapping
|
||||
|
||||
import inkex
|
||||
from lxml import etree
|
||||
|
||||
from .utils.settings import DEFAULT_METADATA, global_settings
|
||||
|
||||
|
||||
def strip_namespace(tag):
|
||||
"""Remove xml namespace from a tag name.
|
||||
|
||||
>>> {http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}namedview
|
||||
<<< namedview
|
||||
"""
|
||||
|
||||
match = re.match(r'^\{[^}]+\}(.+)$', tag)
|
||||
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
return tag
|
||||
|
||||
|
||||
class InkStitchMetadata(MutableMapping):
|
||||
"""Helper class to get and set inkstitch-specific metadata attributes.
|
||||
|
||||
Operates on a document and acts like a dict. Setting an item adds or
|
||||
updates a metadata element in the document. Getting an item retrieves
|
||||
a metadata element's text contents or None if an element by that name
|
||||
doesn't exist.
|
||||
"""
|
||||
|
||||
def __init__(self, document):
|
||||
super().__init__()
|
||||
self.document = document
|
||||
self.metadata = document.metadata
|
||||
|
||||
for setting in DEFAULT_METADATA:
|
||||
if self[setting] is None:
|
||||
self[setting] = global_settings[f'default_{setting}']
|
||||
|
||||
# Because this class inherints from MutableMapping, all we have to do is
|
||||
# implement these five methods and we get a full dict-like interface.
|
||||
def __setitem__(self, name, value):
|
||||
item = self._find_item(name)
|
||||
item.text = json.dumps(value)
|
||||
|
||||
def _find_item(self, name, create=True):
|
||||
tag = inkex.addNS(name, "inkstitch")
|
||||
item = self.metadata.find(tag)
|
||||
if item is None and create:
|
||||
item = etree.SubElement(self.metadata, tag)
|
||||
|
||||
return item
|
||||
|
||||
def __getitem__(self, name):
|
||||
item = self._find_item(name)
|
||||
|
||||
try:
|
||||
return json.loads(item.text)
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
def __delitem__(self, name):
|
||||
item = self._find_item(name, create=False)
|
||||
|
||||
if item is not None:
|
||||
self.metadata.remove(item)
|
||||
|
||||
def __iter__(self):
|
||||
for child in self.metadata:
|
||||
if child.prefix == "inkstitch":
|
||||
yield strip_namespace(child.tag)
|
||||
|
||||
def __len__(self):
|
||||
i = 0
|
||||
for i, item in enumerate(self):
|
||||
pass
|
||||
|
||||
return i + 1
|
||||
|
||||
def __json__(self):
|
||||
return dict(self)
|
|
@ -27,6 +27,7 @@ SVG_IMAGE_TAG = inkex.addNS('image', 'svg')
|
|||
SVG_CLIPPATH_TAG = inkex.addNS('clipPath', 'svg')
|
||||
SVG_MASK_TAG = inkex.addNS('mask', 'svg')
|
||||
|
||||
SVG_METADATA_TAG = inkex.addNS("metadata", "svg")
|
||||
INKSCAPE_LABEL = inkex.addNS('label', 'inkscape')
|
||||
INKSCAPE_GROUPMODE = inkex.addNS('groupmode', 'inkscape')
|
||||
CONNECTION_START = inkex.addNS('connection-start', 'inkscape')
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
from inkex import errormsg
|
||||
|
||||
from .i18n import _
|
||||
from .elements import EmbroideryElement
|
||||
from .metadata import InkStitchMetadata
|
||||
from .svg.tags import INKSTITCH_ATTRIBS
|
||||
|
||||
INKSTITCH_SVG_VERSION = 1
|
||||
|
||||
|
||||
def update_inkstitch_document(svg):
|
||||
document = svg.getroot()
|
||||
# get the inkstitch svg version from the document
|
||||
search_string = "//*[local-name()='inkstitch_svg_version']//text()"
|
||||
file_version = document.findone(search_string)
|
||||
try:
|
||||
file_version = int(file_version)
|
||||
except (TypeError, ValueError):
|
||||
file_version = 0
|
||||
|
||||
if file_version == INKSTITCH_SVG_VERSION:
|
||||
return
|
||||
|
||||
if file_version > INKSTITCH_SVG_VERSION:
|
||||
errormsg(_("This document was created with a newer Version of Ink/Stitch. "
|
||||
"It is possible that not everything works as expected.\n\n"
|
||||
"Please update your Ink/Stitch version: https://inkstitch.org/docs/install/"))
|
||||
# they may not want to be bothered with this info everytime they call an inkstitch extension
|
||||
# let's udowngrade the file version number
|
||||
_update_inkstitch_svg_version(svg)
|
||||
else:
|
||||
# this document is either a new document or it is outdated
|
||||
# if we cannot find any inkstitch attribute in the document, we assume that this is a new document which doesn't need to be updated
|
||||
search_string = "//*[namespace-uri()='http://inkstitch.org/namespace' or " \
|
||||
"@*[namespace-uri()='http://inkstitch.org/namespace'] or " \
|
||||
"@*[starts-with(name(), 'embroider_')]]"
|
||||
inkstitch_element = document.findone(search_string)
|
||||
if inkstitch_element is None:
|
||||
_update_inkstitch_svg_version(svg)
|
||||
return
|
||||
|
||||
# update elements
|
||||
for element in document.iterdescendants():
|
||||
# We are just checking for params and update them.
|
||||
# No need to check for specific stitch types at this point
|
||||
update_legacy_params(EmbroideryElement(element), file_version, INKSTITCH_SVG_VERSION)
|
||||
_update_inkstitch_svg_version(svg)
|
||||
|
||||
|
||||
def _update_inkstitch_svg_version(svg):
|
||||
# set inkstitch svg version
|
||||
metadata = InkStitchMetadata(svg.getroot())
|
||||
metadata['inkstitch_svg_version'] = INKSTITCH_SVG_VERSION
|
||||
|
||||
|
||||
def update_legacy_params(element, file_version, inkstitch_svg_version):
|
||||
for version in range(file_version + 1, inkstitch_svg_version + 1):
|
||||
_update_to(version, element)
|
||||
|
||||
|
||||
def _update_to(version, element):
|
||||
if version == 1:
|
||||
_update_to_one(element)
|
||||
|
||||
|
||||
def _update_to_one(element): # noqa: C901
|
||||
# update legacy embroider_ attributes to namespaced attributes
|
||||
legacy_attribs = False
|
||||
for attrib in element.node.attrib:
|
||||
if attrib.startswith('embroider_'):
|
||||
_replace_legacy_embroider_param(element, attrib)
|
||||
legacy_attribs = True
|
||||
|
||||
# convert legacy tie setting
|
||||
legacy_tie = element.get_param('ties', None)
|
||||
if legacy_tie == "True":
|
||||
element.set_param('ties', 0)
|
||||
elif legacy_tie == "False":
|
||||
element.set_param('ties', 3)
|
||||
|
||||
# convert legacy fill_method
|
||||
legacy_fill_method = element.get_int_param('fill_method', None)
|
||||
if legacy_fill_method == 0:
|
||||
element.set_param('fill_method', 'auto_fill')
|
||||
elif legacy_fill_method == 1:
|
||||
element.set_param('fill_method', 'contour_fill')
|
||||
elif legacy_fill_method == 2:
|
||||
element.set_param('fill_method', 'guided_fill')
|
||||
elif legacy_fill_method == 3:
|
||||
element.set_param('fill_method', 'legacy_fill')
|
||||
|
||||
# legacy satin method
|
||||
if element.get_boolean_param('e_stitch', False) is True:
|
||||
element.remove_param('e_stitch')
|
||||
element.set_param('satin_method', 'e_stitch')
|
||||
|
||||
# default setting for fill_underlay has changed
|
||||
if legacy_attribs and not element.get_param('fill_underlay', ""):
|
||||
element.set_param('fill_underlay', False)
|
||||
|
||||
# convert legacy stroke_method
|
||||
if element.get_style("stroke"):
|
||||
# manual stitch
|
||||
legacy_manual_stitch = element.get_boolean_param('manual_stitch', False)
|
||||
if legacy_manual_stitch is True:
|
||||
element.remove_param('manual_stitch')
|
||||
element.set_param('stroke_method', 'manual_stitch')
|
||||
# stroke_method
|
||||
legacy_stroke_method = element.get_int_param('stroke_method', None)
|
||||
if legacy_stroke_method == 0:
|
||||
element.set_param('stroke_method', 'running_stitch')
|
||||
elif legacy_stroke_method == 1:
|
||||
element.set_param('stroke_method', 'ripple_stitch')
|
||||
if (not element.get_param('stroke_method', None) and
|
||||
element.get_param('satin_column', False) is False and
|
||||
not element.node.style('stroke-dasharray')):
|
||||
element.set_param('stroke_method', 'zigzag_stitch')
|
||||
|
||||
|
||||
def _replace_legacy_embroider_param(element, param):
|
||||
# remove "embroider_" prefix
|
||||
new_param = param[10:]
|
||||
if new_param in INKSTITCH_ATTRIBS:
|
||||
value = element.node.get(param, "").strip()
|
||||
element.set_param(param[10:], value)
|
||||
del element.node.attrib[param]
|
Ładowanie…
Reference in New Issue