diff options
114 files changed, 1897 insertions, 1564 deletions
@@ -7,7 +7,3 @@ dist/ build/ locales/ - -# For development, I symlink into my clone, so I have to have a copy of libembroidery. -libembroidery.py -_libembroidery.so diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 228fc91e..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "embroidermodder"] - path = embroidermodder - url = https://github.com/Embroidermodder/Embroidermodder diff --git a/.travis.yml b/.travis.yml index 0bc49e06..a5841ba5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,11 @@ matrix: sudo: required env: BUILD=windows if: tag =~ ^v[0-9.]+$ OR branch != master + - language: generic + os: osx + sudo: required + env: BUILD=osx + if: tag =~ ^v[0-9.]+$ OR branch != master branches: except: - /^dev-build-/ @@ -48,23 +53,20 @@ install: # for wxPython sudo apt-get install glib-networking - # for embroidermodder/libembroidery - sudo apt-get install swig python-dev - # This is the same as the pypi module PyGObject. We can't just do # "pip install PyGObject" because it depends on a version of # libgirepository1.0-dev that doesn't exist in Trusty. sudo apt-get install python-gi python-gi-cairo libgirepository1.0-dev - + # wxPython doen't publish linux wheels in pypi wget -q https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-14.04/wxPython-4.0.3-cp27-cp27mu-linux_x86_64.whl pip install wxPython-4.0.3-cp27-cp27mu-linux_x86_64.whl - + # We can't use the shapely wheel because it includes the geos # library but with a weird file name. Details: # https://github.com/pyinstaller/pyinstaller/blob/61b1c75c2b0469b32d114298a63bf60b8d597e37/PyInstaller/hooks/hook-shapely.py#L34 pip install --no-binary shapely -r requirements.txt - + pip install pyinstaller elif [ "$BUILD" = "windows" ]; then set -x @@ -78,10 +80,6 @@ install: export WINEDEBUG=-all - wget -q https://github.com/lexelby/inkstitch-build-objects/releases/download/v1.1.0/windows-libembroidery.tar.gz - tar zxf windows-libembroidery.tar.gz - rm windows-libembroidery.tar.gz - wget -q http://download.microsoft.com/download/1/1/1/1116b75a-9ec3-481a-a3c8-1777b5381140/vcredist_x86.exe wine vcredist_x86.exe /q @@ -97,6 +95,31 @@ install: wine c:\\Python\\python.exe c:\\Python\\scripts\\pip.exe install -r requirements.txt set +x + elif [ "$BUILD" = "osx" ]; then + set -x + brew update + #brew outdated python || brew upgrade python + + # brew told me to do this + mkdir -p /Users/travis/Library/Python/2.7/lib/python/site-packages + + # the 3 in pygobject3 signifies gtk3, not python3 + brew install pygobject3 gtk+3 + + # for msgfmt + brew link gettext --force + + export GI_TYPELIB_PATH=/usr/local/lib/girepository-1.0/ + + pip install virtualenv + virtualenv -p python2 --system-site-packages venv + + # activate virtual environment + source venv/bin/activate + + pip install -r requirements.txt + pip install pyinstaller + set +x elif [ -n "$LINT" ]; then pip install flake8 fi @@ -104,16 +127,19 @@ before_script: - "echo LINT: $LINT BUILD: $BUILD" script: - | - set -e + if [ -n "$BUILD" -a "$DEBUG_BUILD" = "$BUILD" ]; then + mkdir .ssh + echo -e "${SSH_KEY}" > .ssh/id_rsa + chmod -R go-rwx .ssh + mkfifo fifo + ( while :; do cat fifo | /bin/bash -i 2>&1 | nc -l 127.0.0.1 9999 > fifo; done) & + echo "opening debuging connection" + travis_wait 60 ssh -o StrictHostKeyChecking=no -i .ssh/id_rsa -N -R 9999:localhost:9999 debug@lex.gd + fi if [ -n "$LINT" ]; then flake8 . --count --exit-zero --select=E901,E999,F821,F822,F823 --show-source --statistics --exclude=embroidermodder flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude=embroidermodder - elif [ "$BUILD" = "linux" ]; then - ( - cd embroidermodder/experimental - qmake swigpython.pro - make - ) + elif [ "$BUILD" = "linux" -o "$BUILD" = "osx" ]; then make dist elif [ "$BUILD" = "windows" ]; then # work around some bug... pyinstaller? shapely? not sure. @@ -2,7 +2,7 @@ EXTENSIONS:=inkstitch # This gets the branch name or the name of the tag VERSION:=$(TRAVIS_BRANCH) -OS:=$(shell uname) +OS:=$(TRAVIS_OS_NAME) ARCH:=$(shell uname -m) dist: distclean locales @@ -17,7 +17,7 @@ dist: distclean locales if [ "$$BUILD" = "windows" ]; then \ cd dist; zip -r ../inkstitch-$(VERSION)-win32.zip *; \ else \ - cd dist; tar zcf ../inkstitch-$(VERSION)-$(OS)-$(ARCH).tar.gz *; \ + cd dist; tar zcf ../inkstitch-$(VERSION)-$(OS)-$(ARCH).tar.gz *; \ fi distclean: @@ -25,7 +25,7 @@ distclean: messages.po: rm -f messages.po - pybabel extract -o messages.po -F babel.conf --no-location --add-comments l10n --add-comments L10n --add-comments L10N -s . + pybabel extract -o messages.po -F babel.conf --add-location=full --add-comments=l10n,L10n,L10N --sort-by-file --strip-comments . .PHONY: messages.po .PHONY: locales @@ -10,7 +10,7 @@ Want to learn more? * Check out our list of [features](https://inkstitch.org/features/) * [Quick Install](https://inkstitch.org/docs/install/) on Linux and Windows (Mac support in the works!) -* See some [photos](https://inkstitch.org/tutorials/inspiration/lexelby/) showing what Ink/Stitch can do +* See some [photos](https://inkstitch.org/tutorials/inspiration/) showing what Ink/Stitch can do * Watch some [videos](https://inkstitch.org/tutorials/video/) of Ink/Stitch in action * ...and lots more on our [website](https://inkstitch.org) @@ -1,4 +1,3 @@ -[ignore: libembroidery.py] [ignore: embroidermodder/**] [python: **.py] diff --git a/bin/build-dist b/bin/build-dist index 78e42430..a96b7506 100755 --- a/bin/build-dist +++ b/bin/build-dist @@ -19,13 +19,13 @@ fi # above! pyinstaller_args+="--hidden-import gi.repository.Gtk " -# mac and windows build seem to miss wx and libembroidery import -pyinstaller_args+="--hidden-import wx --hidden-import libembroidery " +# mac and windows build seem to miss wx import +pyinstaller_args+="--hidden-import wx " -if [ -d windows-libembroidery ]; then - pyinstaller_args+="-p windows-libembroidery " -else - pyinstaller_args+="-p embroidermodder/experimental/python/binding " +# We need to use the precompiled bootloader linked with graphical Mac OS X +# libraries if we develop a GUI application for Mac: +if [ "$TRAVIS_OS_NAME" = "osx" ]; then + pyinstaller_args+="--windowed " fi # This lets pyinstaller see inkex.py, etc. @@ -51,6 +51,11 @@ mkdir dist/bin mv dist/inkstitch/* dist/bin mv dist/bin dist/inkstitch +# on Mac, pyinstaller creates a .app version as well, but we don't need that +if [ "$TRAVIS_OS_NAME" = "osx" ]; then + rm -rf dist/inkstitch.app/ +fi + # Inkscape doesn't let us run native binaries as extensions(?!). Instead we # add this stub script which executes the binary that pyinstaller creates. cp stub.py dist/inkstitch.py diff --git a/bin/gen-input-inx b/bin/gen-input-inx index 6351d062..ae32b43f 100755 --- a/bin/gen-input-inx +++ b/bin/gen-input-inx @@ -2,7 +2,7 @@ import sys, os from os.path import dirname -from libembroidery import * +import pyembroidery from jinja2 import Environment, FileSystemLoader, select_autoescape @@ -15,30 +15,21 @@ def build_environment(): ) -def libembroidery_input_formats(): - formatList = embFormatList_create() - curFormat = formatList - while(curFormat): - extension = embFormat_extension(curFormat) - description = embFormat_description(curFormat) - reader_state = embFormat_readerState(curFormat) - - if reader_state.strip() and embFormat_type(curFormat) != EMBFORMAT_OBJECTONLY: - # extension includes the dot, so we'll remove it - yield extension[1:], description - - curFormat = curFormat.next +def pyembroidery_input_formats(): + for format in pyembroidery.supported_formats(): + if 'reader' in format and format['category'] == 'embroidery': + yield format['extension'], format['description'] def main(): env = build_environment() template = env.get_template('embroider_input.inx') - for format, description in libembroidery_input_formats(): + for format, description in pyembroidery_input_formats(): inx = template.render(format=format, description=description) with open("inx/inkstitch_input_%s.inx" % format.upper(), 'w') as inx_file: - inx_file.write(inx) + print >> inx_file, inx if __name__ == "__main__": diff --git a/bin/gen-output-format-option-list b/bin/gen-output-format-option-list index 674813bb..28a83976 100755 --- a/bin/gen-output-format-option-list +++ b/bin/gen-output-format-option-list @@ -1,19 +1,14 @@ #!/usr/bin/env python import sys +import pyembroidery -sys.path.append('embroidermodder/experimental/python/binding') -from libembroidery import * +formats = [format for format in pyembroidery.supported_formats() if 'writer' in format] +formats.sort(key=lambda format: (format['category'] != 'embroidery', format['extension'])) -formatList = embFormatList_create() -curFormat = formatList -while(curFormat): - extension = embFormat_extension(curFormat) - description = embFormat_description(curFormat) - writerState = embFormat_writerState(curFormat) - - if writerState.strip() and embFormat_type(curFormat) != EMBFORMAT_OBJECTONLY: - print '<_option value="%s">%s(%s)</_option>' % (extension[1:], description, extension.upper()) - - curFormat = curFormat.next +for format in formats: + tag = "" + if format['category'] != 'embroidery': + tag = " [DEBUG]" + print '<_option value="%s">%s(%s)%s</_option>' % (format['extension'], format['description'], format['extension'].upper(), tag) diff --git a/bin/gen-output-inx b/bin/gen-output-inx index f167dbee..fbe2ad55 100755 --- a/bin/gen-output-inx +++ b/bin/gen-output-inx @@ -2,7 +2,7 @@ import sys, os from os.path import dirname -from libembroidery import * +import pyembroidery from jinja2 import Environment, FileSystemLoader, select_autoescape @@ -15,30 +15,21 @@ def build_environment(): ) -def libembroidery_output_formats(): - formatList = embFormatList_create() - curFormat = formatList - while(curFormat): - extension = embFormat_extension(curFormat) - description = embFormat_description(curFormat) - writer_state = embFormat_writerState(curFormat) - - if writer_state.strip() and embFormat_type(curFormat) != EMBFORMAT_OBJECTONLY: - # extension includes the dot, so we'll remove it - yield extension[1:], description - - curFormat = curFormat.next +def pyembroidery_output_formats(): + for format in pyembroidery.supported_formats(): + if 'writer' in format and format['category'] == 'embroidery': + yield format['extension'], format['description'] def main(): env = build_environment() template = env.get_template('embroider_output.inx') - for format, description in libembroidery_output_formats(): + for format, description in pyembroidery_output_formats(): inx = template.render(format=format, description=description) with open("inx/inkstitch_output_%s.inx" % format.upper(), 'w') as inx_file: - inx_file.write(inx) + print >> inx_file, inx if __name__ == "__main__": diff --git a/bin/gen-zip-inx b/bin/gen-zip-inx index 5fbc8f1e..40948786 100755 --- a/bin/gen-zip-inx +++ b/bin/gen-zip-inx @@ -2,7 +2,7 @@ import sys, os from os.path import dirname -from libembroidery import * +import pyembroidery from jinja2 import Environment, FileSystemLoader, select_autoescape @@ -15,26 +15,17 @@ def build_environment(): ) -def libembroidery_output_formats(): - formatList = embFormatList_create() - curFormat = formatList - while(curFormat): - extension = embFormat_extension(curFormat) - description = embFormat_description(curFormat) - writer_state = embFormat_writerState(curFormat) - - if writer_state.strip() and embFormat_type(curFormat) != EMBFORMAT_OBJECTONLY: - # extension includes the dot, so we'll remove it - yield extension[1:], description - - curFormat = curFormat.next +def pyembroidery_output_formats(): + for format in pyembroidery.supported_formats(): + if 'writer' in format and format['category'] == 'embroidery': + yield format['extension'], format['description'] def main(): env = build_environment() template = env.get_template('embroider_zip_output.inx') - inx = template.render(formats=libembroidery_output_formats()) + inx = template.render(formats=pyembroidery_output_formats()) with open("inx/inkstitch_output_ZIP.inx", 'w') as inx_file: inx_file.write(inx) diff --git a/bin/install_libembroidery-convert_Ubuntu.sh b/bin/install_libembroidery-convert_Ubuntu.sh deleted file mode 100644 index ef2626bd..00000000 --- a/bin/install_libembroidery-convert_Ubuntu.sh +++ /dev/null @@ -1,58 +0,0 @@ -# This file is part of the Inkscape extension 'ink/stitch', -# an extension for machine embroidery design using Inkscape. - -# Copyright (C) 2017 Maren Hachmann - -# ink/stitch is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ink/stitch 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 ink/stitch. If not, see <http://www.gnu.org/licenses/>. - -#!/bin/bash - -# make sure we're in tmp directory -cd /tmp - -# install qmake (which is needed to configure libembroidery) -sudo apt-get install qt4-qmake - -# get the source for embroidermodder -wget https://github.com/Embroidermodder/Embroidermodder/archive/master.zip -O /tmp/embroidermodder-master.zip - -# unzip files -unzip embroidermodder-master.zip -d /tmp - -# switch into directory of the library we're interested in -cd Embroidermodder-master/libembroidery-convert/ - -# prepare build -qmake - -# build -make - -# create destination folder (which will automatically be in the PATH environment variable) -mkdir -p $HOME/bin/ - -# copy created library there -cp ./libembroidery-convert $HOME/bin/ - -echo "========================== - -Use the embroidery file format conversion tool like this: - -libembroidery-convert file_to_read file_to_write - -To get a list of supported embroidery formats, enter: - -libembroidery-convert --help - -Run this script again to update your libembroidery-convert version." diff --git a/bin/pyembroidery-convert b/bin/pyembroidery-convert new file mode 100755 index 00000000..ac58e3e5 --- /dev/null +++ b/bin/pyembroidery-convert @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +import sys +import pyembroidery + +pyembroidery.convert(sys.argv[1], sys.argv[2]) diff --git a/embroidermodder b/embroidermodder deleted file mode 160000 -Subproject 1a3faa9747fcff1cce07c4c58b54b1e780017f5 diff --git a/inkstitch.py b/inkstitch.py index a9ce829e..2e21d964 100644 --- a/inkstitch.py +++ b/inkstitch.py @@ -10,7 +10,11 @@ parser.add_argument("--extension") my_args, remaining_args = parser.parse_known_args() extension_name = my_args.extension -extension_class = getattr(extensions, extension_name.capitalize()) + +# example: foo_bar_baz -> FooBarBaz +extension_class_name = extension_name.title().replace("_", "") + +extension_class = getattr(extensions, extension_class_name) extension = extension_class() exception = None diff --git a/inx/inkstitch_commands.inx b/inx/inkstitch_commands.inx new file mode 100644 index 00000000..7b42ca0e --- /dev/null +++ b/inx/inkstitch_commands.inx @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Attach Commands</_name> + <id>org.inkstitch.commands</id> + <dependency type="executable" location="extensions">inkstitch.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="fill_start" type="boolean" _gui-text="Fill starting position">false</param> + <param name="fill_end" type="boolean" _gui-text="Fill ending position">false</param> + <param name="stop" type="boolean" _gui-text="Stop after sewing this object">false</param> + <param name="trim" type="boolean" _gui-text="Trim thread after sewing this object">false</param> + <param name="extension" type="string" gui-hidden="true">commands</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Embroidery" /> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">inkstitch.py</command> + </script> +</inkscape-extension> diff --git a/inx/inkstitch_convert_to_satin.inx b/inx/inkstitch_convert_to_satin.inx new file mode 100644 index 00000000..d71b2081 --- /dev/null +++ b/inx/inkstitch_convert_to_satin.inx @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Convert Line to Satin</_name> + <id>org.inkstitch.convert_to_satin</id> + <dependency type="executable" location="extensions">inkstitch.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="extension" type="string" gui-hidden="true">convert_to_satin</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Embroidery" /> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">inkstitch.py</command> + </script> +</inkscape-extension> diff --git a/inx/inkstitch_embroider.inx b/inx/inkstitch_embroider.inx index 1f5619a3..70bc10b0 100644 --- a/inx/inkstitch_embroider.inx +++ b/inx/inkstitch_embroider.inx @@ -4,34 +4,19 @@ <id>jonh.embroider</id> <dependency type="executable" location="extensions">inkstitch.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="collapse_len_mm" type="float" min="0.0" max="10.0" _gui-text="Collapse length (mm)"> _gui-description="Jump stitches smaller than this will be treated as normal stitches.">3.0</param> - <param name="hide_layers" type="boolean" _gui-text="Hide other layers" description="Hide all other top-level layers when the embroidery layer is generated, in order to make stitching discernable.">true</param> + <param name="collapse_len_mm" type="float" min="0.0" max="10.0" _gui-text="Collapse length (mm)" _gui-description="Jump stitches smaller than this will be treated as normal stitches.">3.0</param> + <param name="hide_layers" type="boolean" _gui-text="Hide other layers" _gui-description="Hide all other top-level layers when the embroidery layer is generated, in order to make stitching discernable.">true</param> <param name="output_format" type="optiongroup" _gui-text="Output file format" appearance="minimal"> - <_option value="csv">Comma Separated Values Format(.CSV)</_option> - <_option value="col">Embroidery Thread Color Format(.COL)</_option> - <_option value="dst">Tajima Embroidery Format(.DST)</_option> - <_option value="edr">Embird Embroidery Format(.EDR)</_option> - <_option value="exp">Melco Embroidery Format(.EXP)</_option> - <_option value="hus">Husqvarna Viking Embroidery Format(.HUS)</_option> - <_option value="inf">Embroidery Color Format(.INF)</_option> - <_option value="jef">Janome Embroidery Format(.JEF)</_option> - <_option value="ksm">Pfaff Embroidery Format(.KSM)</_option> - <_option value="max">Pfaff Embroidery Format(.MAX)</_option> - <_option value="pcd">Pfaff Embroidery Format(.PCD)</_option> - <_option value="pcq">Pfaff Embroidery Format(.PCQ)</_option> - <_option value="pcs">Pfaff Embroidery Format(.PCS)</_option> - <_option value="pec">Brother Embroidery Format(.PEC)</_option> - <_option value="pes">Brother Embroidery Format(.PES)</_option> - <_option value="plt">AutoCAD Plot Drawing Format(.PLT)</_option> - <_option value="rgb">RGB Embroidery Format(.RGB)</_option> - <_option value="sew">Janome Embroidery Format(.SEW)</_option> - <_option value="tap">Happy Embroidery Format(.TAP)</_option> - <_option value="thr">ThredWorks Embroidery Format(.THR)</_option> - <_option value="txt">Text File(.TXT)</_option> - <_option value="vp3">Pfaff Embroidery Format(.VP3)</_option> - <_option value="xxx">Singer Embroidery Format(.XXX)</_option> + <_option value="dst">Tajima Embroidery Format (DST)</_option> + <_option value="exp">Melco Embroidery Format (EXP)</_option> + <_option value="jef">Janome Embroidery Format (JEF)</_option> + <_option value="pec">Brother Embroidery Format (PEC)</_option> + <_option value="pes">Brother Embroidery Format (PES)</_option> + <_option value="vp3">Pfaff Embroidery Format (VP3)</_option> + <_option value="csv">Comma-separated values (CSV) [DEBUG]</_option> + <_option value="svg">Scalable Vector Graphics (SVG) [DEBUG]</_option> </param> - <param name="path" type="string" _gui-text="Directory"></param> + <param name="path" type="string" _gui-text="Directory" _gui-description="Leave empty to save the output in Inkscape's extension directory."></param> <param name="extension" type="string" gui-hidden="true">embroider</param> <effect> <object-type>all</object-type> diff --git a/inx/inkstitch_input_COL.inx b/inx/inkstitch_input_COL.inx deleted file mode 100644 index 38ebe7bd..00000000 --- a/inx/inkstitch_input_COL.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>COL file input</_name> - <id>org.inkstitch.input.col</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.col</extension> - <mimetype>application/x-embroidery-col</mimetype> - <_filetypename>Ink/Stitch: Embroidery Thread Color Format (.col)</_filetypename> - <_filetypetooltip>convert COL file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_CSV.inx b/inx/inkstitch_input_CSV.inx deleted file mode 100644 index 0c3e2096..00000000 --- a/inx/inkstitch_input_CSV.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>CSV file input</_name> - <id>org.inkstitch.input.csv</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.csv</extension> - <mimetype>application/x-embroidery-csv</mimetype> - <_filetypename>Ink/Stitch: Comma Separated Values Format (.csv)</_filetypename> - <_filetypetooltip>convert CSV file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_DAT.inx b/inx/inkstitch_input_DAT.inx deleted file mode 100644 index e82694b8..00000000 --- a/inx/inkstitch_input_DAT.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>DAT file input</_name> - <id>org.inkstitch.input.dat</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.dat</extension> - <mimetype>application/x-embroidery-dat</mimetype> - <_filetypename>Ink/Stitch: Barudan Embroidery Format (.dat)</_filetypename> - <_filetypetooltip>convert DAT file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_DSB.inx b/inx/inkstitch_input_DSB.inx index 8b7c6b02..c78e1c2d 100644 --- a/inx/inkstitch_input_DSB.inx +++ b/inx/inkstitch_input_DSB.inx @@ -7,7 +7,7 @@ <input> <extension>.dsb</extension> <mimetype>application/x-embroidery-dsb</mimetype> - <_filetypename>Ink/Stitch: Barudan Embroidery Format (.dsb)</_filetypename> + <_filetypename>Ink/Stitch: Tajima(Barudan) Embroidery Format (.dsb)</_filetypename> <_filetypetooltip>convert DSB file to Ink/Stitch manual-stitch paths</_filetypetooltip> </input> <param name="extension" type="string" gui-hidden="true">input</param> diff --git a/inx/inkstitch_input_EDR.inx b/inx/inkstitch_input_EDR.inx deleted file mode 100644 index 92cf7d14..00000000 --- a/inx/inkstitch_input_EDR.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>EDR file input</_name> - <id>org.inkstitch.input.edr</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.edr</extension> - <mimetype>application/x-embroidery-edr</mimetype> - <_filetypename>Ink/Stitch: Embird Embroidery Format (.edr)</_filetypename> - <_filetypetooltip>convert EDR file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_EXY.inx b/inx/inkstitch_input_EXY.inx deleted file mode 100644 index 78de68d8..00000000 --- a/inx/inkstitch_input_EXY.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>EXY file input</_name> - <id>org.inkstitch.input.exy</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.exy</extension> - <mimetype>application/x-embroidery-exy</mimetype> - <_filetypename>Ink/Stitch: Eltac Embroidery Format (.exy)</_filetypename> - <_filetypetooltip>convert EXY file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_FXY.inx b/inx/inkstitch_input_FXY.inx deleted file mode 100644 index c2be8c60..00000000 --- a/inx/inkstitch_input_FXY.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>FXY file input</_name> - <id>org.inkstitch.input.fxy</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.fxy</extension> - <mimetype>application/x-embroidery-fxy</mimetype> - <_filetypename>Ink/Stitch: Fortron Embroidery Format (.fxy)</_filetypename> - <_filetypetooltip>convert FXY file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_GT.inx b/inx/inkstitch_input_GT.inx deleted file mode 100644 index 20a9fda0..00000000 --- a/inx/inkstitch_input_GT.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>GT file input</_name> - <id>org.inkstitch.input.gt</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.gt</extension> - <mimetype>application/x-embroidery-gt</mimetype> - <_filetypename>Ink/Stitch: Gold Thread Embroidery Format (.gt)</_filetypename> - <_filetypetooltip>convert GT file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_HUS.inx b/inx/inkstitch_input_HUS.inx deleted file mode 100644 index bbac96a2..00000000 --- a/inx/inkstitch_input_HUS.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>HUS file input</_name> - <id>org.inkstitch.input.hus</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.hus</extension> - <mimetype>application/x-embroidery-hus</mimetype> - <_filetypename>Ink/Stitch: Husqvarna Viking Embroidery Format (.hus)</_filetypename> - <_filetypetooltip>convert HUS file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_INF.inx b/inx/inkstitch_input_INF.inx deleted file mode 100644 index 9c07ed7f..00000000 --- a/inx/inkstitch_input_INF.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>INF file input</_name> - <id>org.inkstitch.input.inf</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.inf</extension> - <mimetype>application/x-embroidery-inf</mimetype> - <_filetypename>Ink/Stitch: Embroidery Color Format (.inf)</_filetypename> - <_filetypetooltip>convert INF file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_MAX.inx b/inx/inkstitch_input_MAX.inx deleted file mode 100644 index 0f5ed952..00000000 --- a/inx/inkstitch_input_MAX.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>MAX file input</_name> - <id>org.inkstitch.input.max</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.max</extension> - <mimetype>application/x-embroidery-max</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.max)</_filetypename> - <_filetypetooltip>convert MAX file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_MIT.inx b/inx/inkstitch_input_MIT.inx deleted file mode 100644 index a0181182..00000000 --- a/inx/inkstitch_input_MIT.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>MIT file input</_name> - <id>org.inkstitch.input.mit</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.mit</extension> - <mimetype>application/x-embroidery-mit</mimetype> - <_filetypename>Ink/Stitch: Mitsubishi Embroidery Format (.mit)</_filetypename> - <_filetypetooltip>convert MIT file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_NEW.inx b/inx/inkstitch_input_NEW.inx deleted file mode 100644 index 15d877d8..00000000 --- a/inx/inkstitch_input_NEW.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>NEW file input</_name> - <id>org.inkstitch.input.new</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.new</extension> - <mimetype>application/x-embroidery-new</mimetype> - <_filetypename>Ink/Stitch: Ameco Embroidery Format (.new)</_filetypename> - <_filetypetooltip>convert NEW file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_OFM.inx b/inx/inkstitch_input_OFM.inx deleted file mode 100644 index 3e162355..00000000 --- a/inx/inkstitch_input_OFM.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>OFM file input</_name> - <id>org.inkstitch.input.ofm</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.ofm</extension> - <mimetype>application/x-embroidery-ofm</mimetype> - <_filetypename>Ink/Stitch: Melco Embroidery Format (.ofm)</_filetypename> - <_filetypetooltip>convert OFM file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PCD.inx b/inx/inkstitch_input_PCD.inx deleted file mode 100644 index eff3c2f7..00000000 --- a/inx/inkstitch_input_PCD.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCD file input</_name> - <id>org.inkstitch.input.pcd</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.pcd</extension> - <mimetype>application/x-embroidery-pcd</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcd)</_filetypename> - <_filetypetooltip>convert PCD file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PCM.inx b/inx/inkstitch_input_PCM.inx deleted file mode 100644 index 684b7e20..00000000 --- a/inx/inkstitch_input_PCM.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCM file input</_name> - <id>org.inkstitch.input.pcm</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.pcm</extension> - <mimetype>application/x-embroidery-pcm</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcm)</_filetypename> - <_filetypetooltip>convert PCM file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PCQ.inx b/inx/inkstitch_input_PCQ.inx deleted file mode 100644 index 44d2d6df..00000000 --- a/inx/inkstitch_input_PCQ.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCQ file input</_name> - <id>org.inkstitch.input.pcq</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.pcq</extension> - <mimetype>application/x-embroidery-pcq</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcq)</_filetypename> - <_filetypetooltip>convert PCQ file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PCS.inx b/inx/inkstitch_input_PCS.inx deleted file mode 100644 index 1a030e53..00000000 --- a/inx/inkstitch_input_PCS.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCS file input</_name> - <id>org.inkstitch.input.pcs</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.pcs</extension> - <mimetype>application/x-embroidery-pcs</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcs)</_filetypename> - <_filetypetooltip>convert PCS file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PHB.inx b/inx/inkstitch_input_PHB.inx deleted file mode 100644 index 0e14f097..00000000 --- a/inx/inkstitch_input_PHB.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PHB file input</_name> - <id>org.inkstitch.input.phb</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.phb</extension> - <mimetype>application/x-embroidery-phb</mimetype> - <_filetypename>Ink/Stitch: Brother Embroidery Format (.phb)</_filetypename> - <_filetypetooltip>convert PHB file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PHC.inx b/inx/inkstitch_input_PHC.inx deleted file mode 100644 index 3c2d10f5..00000000 --- a/inx/inkstitch_input_PHC.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PHC file input</_name> - <id>org.inkstitch.input.phc</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.phc</extension> - <mimetype>application/x-embroidery-phc</mimetype> - <_filetypename>Ink/Stitch: Brother Embroidery Format (.phc)</_filetypename> - <_filetypetooltip>convert PHC file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_PLT.inx b/inx/inkstitch_input_PLT.inx deleted file mode 100644 index d811ff02..00000000 --- a/inx/inkstitch_input_PLT.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PLT file input</_name> - <id>org.inkstitch.input.plt</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.plt</extension> - <mimetype>application/x-embroidery-plt</mimetype> - <_filetypename>Ink/Stitch: AutoCAD Plot Drawing Format (.plt)</_filetypename> - <_filetypetooltip>convert PLT file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_RGB.inx b/inx/inkstitch_input_RGB.inx deleted file mode 100644 index b64e285b..00000000 --- a/inx/inkstitch_input_RGB.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>RGB file input</_name> - <id>org.inkstitch.input.rgb</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.rgb</extension> - <mimetype>application/x-embroidery-rgb</mimetype> - <_filetypename>Ink/Stitch: RGB Embroidery Format (.rgb)</_filetypename> - <_filetypetooltip>convert RGB file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_SST.inx b/inx/inkstitch_input_SST.inx deleted file mode 100644 index 85533659..00000000 --- a/inx/inkstitch_input_SST.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>SST file input</_name> - <id>org.inkstitch.input.sst</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.sst</extension> - <mimetype>application/x-embroidery-sst</mimetype> - <_filetypename>Ink/Stitch: Sunstar Embroidery Format (.sst)</_filetypename> - <_filetypetooltip>convert SST file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_T09.inx b/inx/inkstitch_input_T09.inx deleted file mode 100644 index eb6ab6d9..00000000 --- a/inx/inkstitch_input_T09.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>T09 file input</_name> - <id>org.inkstitch.input.t09</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.t09</extension> - <mimetype>application/x-embroidery-t09</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.t09)</_filetypename> - <_filetypetooltip>convert T09 file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_CSD.inx b/inx/inkstitch_input_TBF.inx index 444270f0..e2b72ec9 100644 --- a/inx/inkstitch_input_CSD.inx +++ b/inx/inkstitch_input_TBF.inx @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>CSD file input</_name> - <id>org.inkstitch.input.csd</id> + <_name>TBF file input</_name> + <id>org.inkstitch.input.tbf</id> <dependency type="executable" location="extensions">inkstitch.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> <input> - <extension>.csd</extension> - <mimetype>application/x-embroidery-csd</mimetype> - <_filetypename>Ink/Stitch: Singer Embroidery Format (.csd)</_filetypename> - <_filetypetooltip>convert CSD file to Ink/Stitch manual-stitch paths</_filetypetooltip> + <extension>.tbf</extension> + <mimetype>application/x-embroidery-tbf</mimetype> + <_filetypename>Ink/Stitch: Tajima Embroidery Format (.tbf)</_filetypename> + <_filetypetooltip>convert TBF file to Ink/Stitch manual-stitch paths</_filetypetooltip> </input> <param name="extension" type="string" gui-hidden="true">input</param> <script> diff --git a/inx/inkstitch_input_THR.inx b/inx/inkstitch_input_THR.inx deleted file mode 100644 index e6a6e09e..00000000 --- a/inx/inkstitch_input_THR.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>THR file input</_name> - <id>org.inkstitch.input.thr</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.thr</extension> - <mimetype>application/x-embroidery-thr</mimetype> - <_filetypename>Ink/Stitch: ThredWorks Embroidery Format (.thr)</_filetypename> - <_filetypetooltip>convert THR file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_U00.inx b/inx/inkstitch_input_U01.inx index b28da66d..befadd5b 100644 --- a/inx/inkstitch_input_U00.inx +++ b/inx/inkstitch_input_U01.inx @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>U00 file input</_name> - <id>org.inkstitch.input.u00</id> + <_name>U01 file input</_name> + <id>org.inkstitch.input.u01</id> <dependency type="executable" location="extensions">inkstitch.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> <input> - <extension>.u00</extension> - <mimetype>application/x-embroidery-u00</mimetype> - <_filetypename>Ink/Stitch: Barudan Embroidery Format (.u00)</_filetypename> - <_filetypetooltip>convert U00 file to Ink/Stitch manual-stitch paths</_filetypetooltip> + <extension>.u01</extension> + <mimetype>application/x-embroidery-u01</mimetype> + <_filetypename>Ink/Stitch: Barudan Embroidery Format (.u01)</_filetypename> + <_filetypetooltip>convert U01 file to Ink/Stitch manual-stitch paths</_filetypetooltip> </input> <param name="extension" type="string" gui-hidden="true">input</param> <script> diff --git a/inx/inkstitch_input_VIP.inx b/inx/inkstitch_input_VIP.inx deleted file mode 100644 index 3723285c..00000000 --- a/inx/inkstitch_input_VIP.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>VIP file input</_name> - <id>org.inkstitch.input.vip</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.vip</extension> - <mimetype>application/x-embroidery-vip</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.vip)</_filetypename> - <_filetypetooltip>convert VIP file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_input_ZSK.inx b/inx/inkstitch_input_ZSK.inx deleted file mode 100644 index 4178126f..00000000 --- a/inx/inkstitch_input_ZSK.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>ZSK file input</_name> - <id>org.inkstitch.input.zsk</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <input> - <extension>.zsk</extension> - <mimetype>application/x-embroidery-zsk</mimetype> - <_filetypename>Ink/Stitch: ZSK USA Embroidery Format (.zsk)</_filetypename> - <_filetypetooltip>convert ZSK file to Ink/Stitch manual-stitch paths</_filetypetooltip> - </input> - <param name="extension" type="string" gui-hidden="true">input</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension> diff --git a/inx/inkstitch_output_COL.inx b/inx/inkstitch_output_COL.inx deleted file mode 100644 index 8a240a38..00000000 --- a/inx/inkstitch_output_COL.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>COL file output</_name> - <id>org.inkstitch.output.col</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.col</extension> - <mimetype>application/x-embroidery-col</mimetype> - <_filetypename>Ink/Stitch: Embroidery Thread Color Format (.col)</_filetypename> - <_filetypetooltip>Save design in COL format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">col</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_CSV.inx b/inx/inkstitch_output_CSV.inx deleted file mode 100644 index d2f340cd..00000000 --- a/inx/inkstitch_output_CSV.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>CSV file output</_name> - <id>org.inkstitch.output.csv</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.csv</extension> - <mimetype>application/x-embroidery-csv</mimetype> - <_filetypename>Ink/Stitch: Comma Separated Values Format (.csv)</_filetypename> - <_filetypetooltip>Save design in CSV format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">csv</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_DST.inx b/inx/inkstitch_output_DST.inx index 2230600a..fa034f40 100644 --- a/inx/inkstitch_output_DST.inx +++ b/inx/inkstitch_output_DST.inx @@ -16,4 +16,4 @@ <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/inx/inkstitch_output_EDR.inx b/inx/inkstitch_output_EDR.inx deleted file mode 100644 index 0756b37a..00000000 --- a/inx/inkstitch_output_EDR.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>EDR file output</_name> - <id>org.inkstitch.output.edr</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.edr</extension> - <mimetype>application/x-embroidery-edr</mimetype> - <_filetypename>Ink/Stitch: Embird Embroidery Format (.edr)</_filetypename> - <_filetypetooltip>Save design in EDR format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">edr</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_EXP.inx b/inx/inkstitch_output_EXP.inx index ce98dbc0..853bab9f 100644 --- a/inx/inkstitch_output_EXP.inx +++ b/inx/inkstitch_output_EXP.inx @@ -16,4 +16,4 @@ <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/inx/inkstitch_output_HUS.inx b/inx/inkstitch_output_HUS.inx deleted file mode 100644 index 44536f2a..00000000 --- a/inx/inkstitch_output_HUS.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>HUS file output</_name> - <id>org.inkstitch.output.hus</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.hus</extension> - <mimetype>application/x-embroidery-hus</mimetype> - <_filetypename>Ink/Stitch: Husqvarna Viking Embroidery Format (.hus)</_filetypename> - <_filetypetooltip>Save design in HUS format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">hus</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_INF.inx b/inx/inkstitch_output_INF.inx deleted file mode 100644 index 47c2b63e..00000000 --- a/inx/inkstitch_output_INF.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>INF file output</_name> - <id>org.inkstitch.output.inf</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.inf</extension> - <mimetype>application/x-embroidery-inf</mimetype> - <_filetypename>Ink/Stitch: Embroidery Color Format (.inf)</_filetypename> - <_filetypetooltip>Save design in INF format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">inf</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_JEF.inx b/inx/inkstitch_output_JEF.inx index af92a836..74b752fc 100644 --- a/inx/inkstitch_output_JEF.inx +++ b/inx/inkstitch_output_JEF.inx @@ -16,4 +16,4 @@ <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/inx/inkstitch_output_KSM.inx b/inx/inkstitch_output_KSM.inx deleted file mode 100644 index ad5ae4dd..00000000 --- a/inx/inkstitch_output_KSM.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>KSM file output</_name> - <id>org.inkstitch.output.ksm</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.ksm</extension> - <mimetype>application/x-embroidery-ksm</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.ksm)</_filetypename> - <_filetypetooltip>Save design in KSM format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">ksm</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_MAX.inx b/inx/inkstitch_output_MAX.inx deleted file mode 100644 index 45a5ba01..00000000 --- a/inx/inkstitch_output_MAX.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>MAX file output</_name> - <id>org.inkstitch.output.max</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.max</extension> - <mimetype>application/x-embroidery-max</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.max)</_filetypename> - <_filetypetooltip>Save design in MAX format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">max</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_PCD.inx b/inx/inkstitch_output_PCD.inx deleted file mode 100644 index b42f79de..00000000 --- a/inx/inkstitch_output_PCD.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCD file output</_name> - <id>org.inkstitch.output.pcd</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.pcd</extension> - <mimetype>application/x-embroidery-pcd</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcd)</_filetypename> - <_filetypetooltip>Save design in PCD format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">pcd</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_PCQ.inx b/inx/inkstitch_output_PCQ.inx deleted file mode 100644 index 1764f670..00000000 --- a/inx/inkstitch_output_PCQ.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCQ file output</_name> - <id>org.inkstitch.output.pcq</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.pcq</extension> - <mimetype>application/x-embroidery-pcq</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcq)</_filetypename> - <_filetypetooltip>Save design in PCQ format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">pcq</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_PCS.inx b/inx/inkstitch_output_PCS.inx deleted file mode 100644 index ef07c4bd..00000000 --- a/inx/inkstitch_output_PCS.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PCS file output</_name> - <id>org.inkstitch.output.pcs</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.pcs</extension> - <mimetype>application/x-embroidery-pcs</mimetype> - <_filetypename>Ink/Stitch: Pfaff Embroidery Format (.pcs)</_filetypename> - <_filetypetooltip>Save design in PCS format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">pcs</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_PEC.inx b/inx/inkstitch_output_PEC.inx index 15880ce6..6d76b165 100644 --- a/inx/inkstitch_output_PEC.inx +++ b/inx/inkstitch_output_PEC.inx @@ -16,4 +16,4 @@ <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/inx/inkstitch_output_PES.inx b/inx/inkstitch_output_PES.inx index cd7e7369..b821225a 100644 --- a/inx/inkstitch_output_PES.inx +++ b/inx/inkstitch_output_PES.inx @@ -16,4 +16,4 @@ <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/inx/inkstitch_output_PLT.inx b/inx/inkstitch_output_PLT.inx deleted file mode 100644 index 649ef76b..00000000 --- a/inx/inkstitch_output_PLT.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PLT file output</_name> - <id>org.inkstitch.output.plt</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.plt</extension> - <mimetype>application/x-embroidery-plt</mimetype> - <_filetypename>Ink/Stitch: AutoCAD Plot Drawing Format (.plt)</_filetypename> - <_filetypetooltip>Save design in PLT format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">plt</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_RGB.inx b/inx/inkstitch_output_RGB.inx deleted file mode 100644 index e60d729e..00000000 --- a/inx/inkstitch_output_RGB.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>RGB file output</_name> - <id>org.inkstitch.output.rgb</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.rgb</extension> - <mimetype>application/x-embroidery-rgb</mimetype> - <_filetypename>Ink/Stitch: RGB Embroidery Format (.rgb)</_filetypename> - <_filetypetooltip>Save design in RGB format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">rgb</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_THR.inx b/inx/inkstitch_output_THR.inx deleted file mode 100644 index c460bdfc..00000000 --- a/inx/inkstitch_output_THR.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>THR file output</_name> - <id>org.inkstitch.output.thr</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.thr</extension> - <mimetype>application/x-embroidery-thr</mimetype> - <_filetypename>Ink/Stitch: ThredWorks Embroidery Format (.thr)</_filetypename> - <_filetypetooltip>Save design in THR format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">thr</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_TXT.inx b/inx/inkstitch_output_TXT.inx deleted file mode 100644 index 805deffe..00000000 --- a/inx/inkstitch_output_TXT.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>TXT file output</_name> - <id>org.inkstitch.output.txt</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.txt</extension> - <mimetype>application/x-embroidery-txt</mimetype> - <_filetypename>Ink/Stitch: Text File (.txt)</_filetypename> - <_filetypetooltip>Save design in TXT format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">txt</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_VP3.inx b/inx/inkstitch_output_VP3.inx index dff29de4..11843420 100644 --- a/inx/inkstitch_output_VP3.inx +++ b/inx/inkstitch_output_VP3.inx @@ -16,4 +16,4 @@ <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/inx/inkstitch_output_XXX.inx b/inx/inkstitch_output_XXX.inx deleted file mode 100644 index ad4135b0..00000000 --- a/inx/inkstitch_output_XXX.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>XXX file output</_name> - <id>org.inkstitch.output.xxx</id> - <dependency type="executable" location="extensions">inkstitch.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.xxx</extension> - <mimetype>application/x-embroidery-xxx</mimetype> - <_filetypename>Ink/Stitch: Singer Embroidery Format (.xxx)</_filetypename> - <_filetypetooltip>Save design in XXX format using Ink/Stitch</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <param name="extension" type="string" gui-hidden="true">output</param> - <param name="format" type="string" gui-hidden="true">xxx</param> - <script> - <command reldir="extensions" interpreter="python">inkstitch.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/inx/inkstitch_output_ZIP.inx b/inx/inkstitch_output_ZIP.inx index b5b2cf1c..81f17b23 100644 --- a/inx/inkstitch_output_ZIP.inx +++ b/inx/inkstitch_output_ZIP.inx @@ -12,50 +12,20 @@ <dataloss>true</dataloss> </output> - <param name="format-col" type="boolean" _gui-text=".COL: Embroidery Thread Color Format">false</param> - - <param name="format-csv" type="boolean" _gui-text=".CSV: Comma Separated Values Format">false</param> - - <param name="format-dst" type="boolean" _gui-text=".DST: Tajima Embroidery Format">false</param> - - <param name="format-edr" type="boolean" _gui-text=".EDR: Embird Embroidery Format">false</param> - - <param name="format-exp" type="boolean" _gui-text=".EXP: Melco Embroidery Format">false</param> - - <param name="format-hus" type="boolean" _gui-text=".HUS: Husqvarna Viking Embroidery Format">false</param> - - <param name="format-inf" type="boolean" _gui-text=".INF: Embroidery Color Format">false</param> - - <param name="format-jef" type="boolean" _gui-text=".JEF: Janome Embroidery Format">false</param> - - <param name="format-ksm" type="boolean" _gui-text=".KSM: Pfaff Embroidery Format">false</param> - - <param name="format-max" type="boolean" _gui-text=".MAX: Pfaff Embroidery Format">false</param> - - <param name="format-pcd" type="boolean" _gui-text=".PCD: Pfaff Embroidery Format">false</param> - - <param name="format-pcq" type="boolean" _gui-text=".PCQ: Pfaff Embroidery Format">false</param> - - <param name="format-pcs" type="boolean" _gui-text=".PCS: Pfaff Embroidery Format">false</param> - <param name="format-pec" type="boolean" _gui-text=".PEC: Brother Embroidery Format">false</param> <param name="format-pes" type="boolean" _gui-text=".PES: Brother Embroidery Format">false</param> - <param name="format-plt" type="boolean" _gui-text=".PLT: AutoCAD Plot Drawing Format">false</param> - - <param name="format-rgb" type="boolean" _gui-text=".RGB: RGB Embroidery Format">false</param> + <param name="format-exp" type="boolean" _gui-text=".EXP: Melco Embroidery Format">false</param> - <param name="format-thr" type="boolean" _gui-text=".THR: ThredWorks Embroidery Format">false</param> + <param name="format-dst" type="boolean" _gui-text=".DST: Tajima Embroidery Format">false</param> - <param name="format-txt" type="boolean" _gui-text=".TXT: Text File">false</param> + <param name="format-jef" type="boolean" _gui-text=".JEF: Janome Embroidery Format">false</param> <param name="format-vp3" type="boolean" _gui-text=".VP3: Pfaff Embroidery Format">false</param> - <param name="format-xxx" type="boolean" _gui-text=".XXX: Singer Embroidery Format">false</param> - <param name="extension" type="string" gui-hidden="true">zip</param> <script> <command reldir="extensions" interpreter="python">inkstitch.py</command> </script> -</inkscape-extension> +</inkscape-extension>
\ No newline at end of file diff --git a/lib/commands.py b/lib/commands.py index ec62d716..02c13b25 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -77,9 +77,6 @@ def find_commands(node): try: commands.append(Command(connector)) except ValueError: - import sys - import traceback - print >> sys.stderr, "not a Command:", connector.get('id'), traceback.format_exc() # Parsing the connector failed, meaning it's not actually an Ink/Stitch command. pass diff --git a/lib/elements/element.py b/lib/elements/element.py index 3c31f1b0..ebca90a4 100644 --- a/lib/elements/element.py +++ b/lib/elements/element.py @@ -206,6 +206,10 @@ class EmbroideryElement(object): return apply_transforms(self.path, self.node) @property + def shape(self): + raise NotImplementedError("INTERNAL ERROR: %s must implement shape()", self.__class__) + + @property @cache def commands(self): return find_commands(self.node) @@ -215,6 +219,10 @@ class EmbroideryElement(object): return [c for c in self.commands if c.command == command] @cache + def has_command(self, command): + return len(self.get_commands(command)) > 0 + + @cache def get_command(self, command): commands = self.get_commands(command) @@ -238,22 +246,10 @@ class EmbroideryElement(object): return [self.strip_control_points(subpath) for subpath in path] @property - @param('trim_after', - _('TRIM after'), - tooltip=_('Trim thread after this object (for supported machines and file formats)'), - type='boolean', - default=False, - sort_index=1000) def trim_after(self): return self.get_boolean_param('trim_after', False) @property - @param('stop_after', - _('STOP after'), - tooltip=_('Add STOP instruction after this object (for supported machines and file formats)'), - type='boolean', - default=False, - sort_index=1000) def stop_after(self): return self.get_boolean_param('stop_after', False) @@ -264,8 +260,8 @@ class EmbroideryElement(object): patches = self.to_patches(last_patch) if patches: - patches[-1].trim_after = self.trim_after - patches[-1].stop_after = self.stop_after + patches[-1].trim_after = self.has_command("trim") or self.trim_after + patches[-1].stop_after = self.has_command("stop") or self.stop_after return patches diff --git a/lib/elements/polyline.py b/lib/elements/polyline.py index 5c474237..b9ffdc0b 100644 --- a/lib/elements/polyline.py +++ b/lib/elements/polyline.py @@ -1,3 +1,5 @@ +from shapely import geometry as shgeo + from .element import param, EmbroideryElement, Patch from ..i18n import _ from ..utils.geometry import Point @@ -28,6 +30,11 @@ class Polyline(EmbroideryElement): return points @property + @cache + def shape(self): + return shgeo.LineString(self.points) + + @property def path(self): # A polyline is a series of connected line segments described by their # points. In order to make use of the existing logic for incorporating diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 1d13c5e0..78275745 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -17,6 +17,12 @@ class SatinColumn(EmbroideryElement): def satin_column(self): return self.get_boolean_param("satin_column") + # I18N: "E" stitch is so named because it looks like the letter E. + @property + @param('e_stitch', _('"E" stitch'), type='boolean', default='false') + def e_stitch(self): + return self.get_boolean_param("e_stitch") + @property def color(self): return self.get_style("stroke") @@ -28,7 +34,7 @@ class SatinColumn(EmbroideryElement): return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01) @property - @param('pull_compensation_mm', _('Pull compensation'), unit='mm', type='float') + @param('pull_compensation_mm', _('Pull compensation'), unit='mm', type='float', default=0) def pull_compensation(self): # In satin stitch, the stitches have a tendency to pull together and # narrow the entire column. We can compensate for this by stitching @@ -76,7 +82,7 @@ class SatinColumn(EmbroideryElement): return max(self.get_float_param("zigzag_underlay_spacing_mm", 3), 0.01) @property - @param('zigzag_underlay_inset_mm', _('Inset amount (default: half of contour underlay inset)'), unit='mm', group=_('Zig-zag Underlay'), type='float') + @param('zigzag_underlay_inset_mm', _('Inset amount (default: half of contour underlay inset)'), unit='mm', group=_('Zig-zag Underlay'), type='float', default="") def zigzag_underlay_inset(self): # how far in from the edge of the satin the points in the zigzags # should be @@ -89,6 +95,17 @@ class SatinColumn(EmbroideryElement): @property @cache + def shape(self): + # This isn't used for satins at all, but other parts of the code + # may need to know the general shape of a satin column. + + flattened = self.flatten(self.parse_path()) + line_strings = [shgeo.LineString(path) for path in flattened] + + return shgeo.MultiLineString(line_strings) + + @property + @cache def csp(self): return self.parse_path() @@ -377,6 +394,28 @@ class SatinColumn(EmbroideryElement): return patch + def do_e_stitch(self): + # e stitch: do a pattern that looks like the letter "E". It looks like + # this: + # + # _|_|_|_|_|_|_|_|_|_|_|_| + + # print >> dbg, "satin", self.zigzag_spacing, self.pull_compensation + + patch = Patch(color=self.color) + + sides = self.walk_paths(self.zigzag_spacing, self.pull_compensation) + + # "left" and "right" here are kind of arbitrary designations meaning + # a point from the first and second rail repectively + for left, right in izip(*sides): + patch.add_stitch(left) + patch.add_stitch(right) + patch.add_stitch(left) + + return patch + + def to_patches(self, last_patch): # Stitch a variable-width satin column, zig-zagging between two paths. @@ -400,6 +439,9 @@ class SatinColumn(EmbroideryElement): # zigzags sit on the contour walk underlay like rail ties on rails. patches.append(self.do_zigzag_underlay()) - patches.append(self.do_satin()) + if self.e_stitch: + patches.append(self.do_e_stitch()) + else: + patches.append(self.do_satin()) return patches diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py index eca9e0ba..bc2ee54c 100644 --- a/lib/elements/stroke.py +++ b/lib/elements/stroke.py @@ -1,9 +1,10 @@ import sys +import shapely.geometry from .element import param, EmbroideryElement, Patch from ..i18n import _ from ..utils import cache, Point -from ..stitches import running_stitch +from ..stitches import running_stitch, bean_stitch from ..svg import parse_length_with_units warned_about_legacy_running_stitch = False @@ -26,18 +27,28 @@ class Stroke(EmbroideryElement): return self.get_style("stroke-dasharray") is not None @property - @param('running_stitch_length_mm', _('Running stitch length'), unit='mm', type='float', default=1.5) + @param('running_stitch_length_mm', _('Running stitch length'), unit='mm', type='float', default=1.5, sort_index=3) def running_stitch_length(self): return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01) @property - @param('zigzag_spacing_mm', _('Zig-zag spacing (peak-to-peak)'), unit='mm', type='float', default=0.4) + @param('bean_stitch_repeats', + _('Bean stitch number of repeats'), + tooltip=_('Backtrack each stitch this many times. A value of 1 would triple each stitch (forward, back, forward). A value of 2 would quintuple each stitch, etc. Only applies to running stitch.'), + type='int', + default=0, + sort_index=2) + def bean_stitch_repeats(self): + return self.get_int_param("bean_stitch_repeats", 0) + + @property + @param('zigzag_spacing_mm', _('Zig-zag spacing (peak-to-peak)'), unit='mm', type='float', default=0.4, sort_index=3) @cache def zigzag_spacing(self): return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01) @property - @param('repeats', _('Repeats'), type='int', default="1") + @param('repeats', _('Repeats'), type='int', default="1", sort_index=1) def repeats(self): return self.get_int_param("repeats", 1) @@ -51,7 +62,13 @@ class Stroke(EmbroideryElement): return self.flatten(path) @property - @param('manual_stitch', _('Manual stitch placement'), tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), type='boolean', default=False) + @cache + def shape(self): + line_strings = [shapely.geometry.LineString(path) for path in self.paths] + return shapely.geometry.MultiLineString(line_strings) + + @property + @param('manual_stitch', _('Manual stitch placement'), tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), type='boolean', default=False, sort_index=0) def manual_stitch_mode(self): return self.get_boolean_param('manual_stitch') @@ -145,6 +162,10 @@ class Stroke(EmbroideryElement): patch = Patch(color=self.color, stitches=path, stitch_as_is=True) elif self.is_running_stitch(): patch = self.running_stitch(path, self.running_stitch_length) + + if self.bean_stitch_repeats > 0: + patch.stitches = bean_stitch(patch.stitches, self.bean_stitch_repeats) + else: patch = self.simple_satin(path, self.zigzag_spacing, self.stroke_width) diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index b11ba1a4..30a08c9f 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -7,3 +7,5 @@ from input import Input from output import Output from zip import Zip from flip import Flip +from commands import Commands +from convert_to_satin import ConvertToSatin diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 78f75cf1..d230f1b0 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -58,11 +58,7 @@ class InkStitchMetadata(MutableMapping): def __setitem__(self, name, value): item = self._find_item(name) - - if value: - item.text = json.dumps(value) - else: - item.getparent().remove(item) + item.text = json.dumps(value) def _find_item(self, name, create=True): tag = inkex.addNS(name, "inkstitch") diff --git a/lib/extensions/commands.py b/lib/extensions/commands.py new file mode 100644 index 00000000..353c9874 --- /dev/null +++ b/lib/extensions/commands.py @@ -0,0 +1,146 @@ +import os +import sys +import inkex +import simpletransform +import cubicsuperpath +from copy import deepcopy +from random import random +from shapely import geometry as shgeo + +from .base import InkstitchExtension +from ..i18n import _ +from ..elements import SatinColumn +from ..utils import get_bundled_dir, cache +from ..svg.tags import SVG_DEFS_TAG, SVG_GROUP_TAG, SVG_USE_TAG, SVG_PATH_TAG, INKSCAPE_GROUPMODE, XLINK_HREF, CONNECTION_START, CONNECTION_END, CONNECTOR_TYPE +from ..svg import get_correction_transform + + +class Commands(InkstitchExtension): + COMMANDS = ["fill_start", "fill_end", "stop", "trim"] + + def __init__(self, *args, **kwargs): + InkstitchExtension.__init__(self, *args, **kwargs) + for command in self.COMMANDS: + self.OptionParser.add_option("--%s" % command, type="inkbool") + + @property + def symbols_path(self): + return os.path.join(get_bundled_dir("symbols"), "inkstitch.svg") + + @property + @cache + def symbols_svg(self): + with open(self.symbols_path) as symbols_file: + return inkex.etree.parse(symbols_file) + + @property + @cache + def symbol_defs(self): + return self.symbols_svg.find(SVG_DEFS_TAG) + + @property + @cache + def defs(self): + return self.document.find(SVG_DEFS_TAG) + + def ensure_symbol(self, command): + path = "./*[@id='inkstitch_%s']" % command + if self.defs.find(path) is None: + self.defs.append(deepcopy(self.symbol_defs.find(path))) + + def add_connector(self, symbol, element): + # I'd like it if I could position the connector endpoint nicely but inkscape just + # moves it to the element's center immediately after the extension runs. + start_pos = (symbol.get('x'), symbol.get('y')) + end_pos = element.shape.centroid + + path = inkex.etree.Element(SVG_PATH_TAG, + { + "id": self.uniqueId("connector"), + "d": "M %s,%s %s,%s" % (start_pos[0], start_pos[1], end_pos.x, end_pos.y), + "style": "stroke:#000000;stroke-width:1px;stroke-opacity:0.5;fill:none;", + "transform": get_correction_transform(symbol), + CONNECTION_START: "#%s" % symbol.get('id'), + CONNECTION_END: "#%s" % element.node.get('id'), + CONNECTOR_TYPE: "polyline", + } + ) + + symbol.getparent().insert(symbol.getparent().index(symbol), path) + + def get_command_pos(self, element, index, total): + # Put command symbols 30 pixels out from the shape, spaced evenly around it. + + # get a line running 30 pixels out from the shape + outline = element.shape.buffer(30).exterior + + # pick this item's spot arond the outline and perturb it a bit to avoid + # stacking up commands if they run the extension multiple times + position = index / float(total) + position += random() * 0.1 + + return outline.interpolate(position, normalized=True) + + def remove_legacy_param(self, element, command): + if command == "trim" or command == "stop": + # If they had the old "TRIM after" or "STOP after" attributes set, + # automatically delete them. THe new commands will do the same + # thing. + # + # If we didn't delete these here, then things would get confusing. + # If the user were to delete a "trim" symbol added by this extension + # but the "embroider_trim_after" attribute is still set, then the + # trim would keep happening. + + attribute = "embroider_%s_after" % command + + if attribute in element.node.attrib: + del element.node.attrib[attribute] + + def add_command(self, element, commands): + for i, command in enumerate(commands): + self.remove_legacy_param(element, command) + + pos = self.get_command_pos(element, i, len(commands)) + + symbol = inkex.etree.SubElement(element.node.getparent(), SVG_USE_TAG, + { + "id": self.uniqueId("use"), + XLINK_HREF: "#inkstitch_%s" % command, + "height": "100%", + "width": "100%", + "x": str(pos.x), + "y": str(pos.y), + "transform": get_correction_transform(element.node) + } + ) + + self.add_connector(symbol, element) + + def effect(self): + if not self.get_elements(): + return + + if not self.selected: + inkex.errormsg(_("Please select one or more objects to which to attach commands.")) + return + + self.svg = self.document.getroot() + + commands = [command for command in self.COMMANDS if getattr(self.options, command)] + + if not commands: + inkex.errormsg(_("Please choose one or more commands to attach.")) + return + + for command in commands: + self.ensure_symbol(command) + + # Each object (node) in the SVG may correspond to multiple Elements of different + # types (e.g. stroke + fill). We only want to process each one once. + seen_nodes = set() + + for element in self.elements: + if element.node not in seen_nodes: + self.add_command(element, commands) + seen_nodes.add(element.node) diff --git a/lib/extensions/convert_to_satin.py b/lib/extensions/convert_to_satin.py new file mode 100644 index 00000000..1eae69b1 --- /dev/null +++ b/lib/extensions/convert_to_satin.py @@ -0,0 +1,290 @@ +import inkex +from shapely import geometry as shgeo +from itertools import chain, groupby +import numpy +from numpy import diff, sign, setdiff1d +from scipy.signal import argrelmin +import math +from copy import deepcopy + +from .base import InkstitchExtension +from ..svg.tags import SVG_PATH_TAG +from ..svg import get_correction_transform, PIXELS_PER_MM +from ..elements import Stroke +from ..utils import Point + + +class SelfIntersectionError(Exception): + pass + + +class ConvertToSatin(InkstitchExtension): + """Convert a line to a satin column of the same width.""" + + def effect(self): + if not self.get_elements(): + return + + if not self.selected: + inkex.errormsg(_("Please select at least one line to convert to a satin column.")) + return + + if not all(isinstance(item, Stroke) for item in self.elements): + # L10N: Convert To Satin extension, user selected one or more objects that were not lines. + inkex.errormsg(_("Only simple lines may be converted to satin columns.")) + return + + for element in self.elements: + parent = element.node.getparent() + index = parent.index(element.node) + correction_transform = get_correction_transform(element.node) + style_args = self.join_style_args(element) + + for path in element.paths: + path = self.remove_duplicate_points(path) + + if len(path) < 2: + # ignore paths with just one point -- they're not visible to the user anyway + continue + + self.fix_loop(path) + + try: + rails, rungs = self.path_to_satin(path, element.stroke_width, style_args) + except SelfIntersectionError: + inkex.errormsg(_("Cannot convert %s to a satin column because it intersects itself. Try breaking it up into multiple paths.") % element.node.get('id')) + + # revert any changes we've made + self.document = deepcopy(self.original_document) + + return + + parent.insert(index, self.satin_to_svg_node(rails, rungs, correction_transform)) + + parent.remove(element.node) + + def fix_loop(self, path): + if path[0] == path[-1]: + # Looping paths seem to confuse shapely's parallel_offset(). It loses track + # of where the start and endpoint is, even if the user explicitly breaks the + # path. I suspect this is because parallel_offset() uses buffer() under the + # hood. + # + # To work around this we'll introduce a tiny gap by nudging the starting point + # toward the next point slightly. + start = Point(*path[0]) + next = Point(*path[1]) + direction = (next - start).unit() + start += 0.01 * direction + path[0] = start.as_tuple() + + def remove_duplicate_points(self, path): + return [point for point, repeats in groupby(path)] + + def join_style_args(self, element): + """Convert svg line join style to shapely parallel offset arguments.""" + + args = { + 'join_style': shgeo.JOIN_STYLE.round + } + + element_join_style = element.get_style('stroke-linejoin') + + if element_join_style is not None: + if element_join_style == "miter": + args['join_style'] = shgeo.JOIN_STYLE.mitre + + # 4 is the default per SVG spec + miter_limit = float(element.get_style('stroke-miterlimit', 4)) + args['mitre_limit'] = miter_limit + elif element_join_style == "bevel": + args['join_style'] = shgeo.JOIN_STYLE.bevel + + return args + + def path_to_satin(self, path, stroke_width, style_args): + path = shgeo.LineString(path) + + left_rail = path.parallel_offset(stroke_width / 2.0, 'left', **style_args) + right_rail = path.parallel_offset(stroke_width / 2.0, 'right', **style_args) + + if not isinstance(left_rail, shgeo.LineString) or \ + not isinstance(right_rail, shgeo.LineString): + # If the parallel offsets come out as anything but a LineString, that means the + # path intersects itself, when taking its stroke width into consideration. See + # the last example for parallel_offset() in the Shapely documentation: + # https://shapely.readthedocs.io/en/latest/manual.html#object.parallel_offset + raise SelfIntersectionError() + + # for whatever reason, shapely returns a right-side offset's coordinates in reverse + left_rail = list(left_rail.coords) + right_rail = list(reversed(right_rail.coords)) + + rungs = self.generate_rungs(path, stroke_width) + + return (left_rail, right_rail), rungs + + def get_scores(self, path): + """Generate an array of "scores" of the sharpness of corners in a path + + A higher score means that there are sharper corners in that section of + the path. We'll divide the path into boxes, with the score in each + box indicating the sharpness of corners at around that percentage of + the way through the path. For example, if scores[40] is 100 and + scores[45] is 200, then the path has sharper corners at a spot 45% + along its length than at a spot 40% along its length. + """ + + # need 101 boxes in order to encompass percentages from 0% to 100% + scores = numpy.zeros(101, numpy.int32) + path_length = path.length + + prev_point = None + prev_direction = None + length_so_far = 0 + for point in path.coords: + point = Point(*point) + + if prev_point is None: + prev_point = point + continue + + direction = (point - prev_point).unit() + + if prev_direction is not None: + # The dot product of two vectors is |v1| * |v2| * cos(angle). + # These are unit vectors, so their magnitudes are 1. + cos_angle_between = prev_direction * direction + angle = abs(math.degrees(math.acos(cos_angle_between))) + + # Use the square of the angle, measured in degrees. + # + # Why the square? This penalizes bigger angles more than + # smaller ones. + # + # Why degrees? This is kind of arbitrary but allows us to + # use integer math effectively and avoid taking the square + # of a fraction between 0 and 1. + scores[int(round(length_so_far / path_length * 100.0))] += angle ** 2 + + length_so_far += (point - prev_point).length() + prev_direction = direction + prev_point = point + + return scores + + def local_minima(self, array): + # from: https://stackoverflow.com/a/9667121/4249120 + # This finds spots where the curvature (second derivative) is > 0. + # + # This method has the convenient benefit of choosing points around + # 5% before and after a sharp corner such as in a square. + return (diff(sign(diff(array))) > 0).nonzero()[0] + 1 + + def generate_rungs(self, path, stroke_width): + """Create rungs for a satin column. + + Where should we put the rungs along a path? We want to ensure that the + resulting satin matches the original path as closely as possible. We + want to avoid having a ton of rungs that will annoy the user. We want + to ensure that the rungs we choose actually intersect both rails. + + We'll place a few rungs perpendicular to the tangent of the path. + Things get pretty tricky at sharp corners. If we naively place a rung + perpendicular to the path just on either side of a sharp corner, the + rung may not intersect both paths: + | | + _______________| | + ______|_ + ____________________| + + It'd be best to place rungs in the straight sections before and after + the sharp corner and allow the satin column to bend the stitches around + the corner automatically. + + How can we find those spots? + + The general algorithm below is: + + * assign a "score" to each section of the path based on how sharp its + corners are (higher means a sharper corner) + * pick spots with lower scores + """ + + scores = self.get_scores(path) + + # This is kind of like a 1-dimensional gaussian blur filter. We want to + # avoid the area near a sharp corner, so we spread out its effect for + # 5 buckets in either direction. + scores = numpy.convolve(scores, [1, 2, 4, 8, 16, 8, 4, 2, 1], mode='same') + + # Now we'll find the spots that aren't near corners, whose scores are + # low -- the local minima. + rung_locations = self.local_minima(scores) + + # Remove the start and end, because we can't stick a rung there. + rung_locations = setdiff1d(rung_locations, [0, 100]) + + if len(rung_locations) == 0: + # Straight lines won't have local minima, so add a rung in the center. + rung_locations = [50] + + rungs = [] + last_rung_center = None + + for location in rung_locations: + # Convert percentage to a fraction so that we can use interpolate's + # normalized parameter. + location = location / 100.0 + + rung_center = path.interpolate(location, normalized=True) + rung_center = Point(rung_center.x, rung_center.y) + + # Avoid placing rungs too close together. This somewhat + # arbitrarily rejects the rung if there was one less than 2 + # millimeters before this one. + if last_rung_center is not None and \ + (rung_center - last_rung_center).length() < 2 * PIXELS_PER_MM: + continue + else: + last_rung_center = rung_center + + # We need to know the tangent of the path's curve at this point. + # Pick another point just after this one and subtract them to + # approximate a tangent vector. + tangent_end = path.interpolate(location + 0.001, normalized=True) + tangent_end = Point(tangent_end.x, tangent_end.y) + tangent = (tangent_end - rung_center).unit() + + # Rotate 90 degrees left to make a normal vector. + normal = tangent.rotate_left() + + # Travel 75% of the stroke width left and right to make the rung's + # endpoints. This means the rung's length is 150% of the stroke + # width. + offset = normal * stroke_width * 0.75 + rung_start = rung_center + offset + rung_end = rung_center - offset + + rungs.append((rung_start.as_tuple(), rung_end.as_tuple())) + + return rungs + + + def satin_to_svg_node(self, rails, rungs, correction_transform): + d = "" + for path in chain(rails, rungs): + d += "M" + for x, y in path: + d += "%s,%s " % (x, y) + d += " " + + return inkex.etree.Element(SVG_PATH_TAG, + { + "id": self.uniqueId("path"), + "style": "stroke:#000000;stroke-width:1px;fill:none", + "transform": correction_transform, + "d": d, + "embroider_satin_column": "true", + } + ) diff --git a/lib/extensions/input.py b/lib/extensions/input.py index 21248dd9..cb5ac452 100644 --- a/lib/extensions/input.py +++ b/lib/extensions/input.py @@ -3,53 +3,29 @@ from os.path import realpath, dirname, join as path_join import sys from inkex import etree import inkex - -# help python find libembroidery when running in a local repo clone -if getattr(sys, 'frozen', None) is None: - sys.path.append(realpath(path_join(dirname(__file__), '..', '..'))) - -from libembroidery import * +import pyembroidery from ..svg import PIXELS_PER_MM, render_stitch_plan from ..svg.tags import INKSCAPE_LABEL from ..i18n import _ -from ..stitch_plan import StitchPlan +from ..stitch_plan import StitchPlan, ColorBlock from ..utils.io import save_stdout class Input(object): - def pattern_stitches(self, pattern): - stitch_pointer = pattern.stitchList - while stitch_pointer: - yield stitch_pointer.stitch - stitch_pointer = stitch_pointer.next - - def affect(self, args): - # libembroidery likes to dump a bunch of debugging stuff to stdout - save_stdout() - embroidery_file = args[0] - pattern = embPattern_create() - embPattern_read(pattern, embroidery_file) - embPattern_flipVertical(pattern) + pattern = pyembroidery.read(embroidery_file) stitch_plan = StitchPlan() color_block = None - current_color = None - - for stitch in self.pattern_stitches(pattern): - if stitch.color != current_color: - thread = embThreadList_getAt(pattern.threadList, stitch.color) - color = thread.color - color_block = stitch_plan.new_color_block((color.r, color.g, color.b)) - current_color = stitch.color - if not stitch.flags & END: - color_block.add_stitch(stitch.xx * PIXELS_PER_MM, stitch.yy * PIXELS_PER_MM, - jump=stitch.flags & JUMP, - color_change=stitch.flags & STOP, - trim=stitch.flags & TRIM) + for raw_stitches, thread in pattern.get_as_colorblocks(): + color_block = stitch_plan.new_color_block(thread) + for x, y, command in raw_stitches: + color_block.add_stitch(x * PIXELS_PER_MM / 10.0, y * PIXELS_PER_MM / 10.0, + jump=(command == pyembroidery.JUMP), + trim=(command == pyembroidery.TRIM)) extents = stitch_plan.extents svg = etree.Element("svg", nsmap=inkex.NSS, attrib= @@ -69,4 +45,4 @@ class Input(object): # Note: this is NOT the same as centering the design in the canvas! layer.set('transform', 'translate(%s,%s)' % (extents[0], extents[1])) - print >> sys.real_stdout, etree.tostring(svg) + print etree.tostring(svg) diff --git a/lib/extensions/install.py b/lib/extensions/install.py index d55b96d0..42a92113 100644 --- a/lib/extensions/install.py +++ b/lib/extensions/install.py @@ -13,7 +13,7 @@ import logging import wx import inkex -from ..utils import guess_inkscape_config_path +from ..utils import guess_inkscape_config_path, get_bundled_dir class InstallerFrame(wx.Frame): @@ -78,15 +78,9 @@ class InstallerFrame(wx.Frame): def install_addons(self, type): path = os.path.join(self.path, type) - src_dir = self.get_bundled_dir(type) + src_dir = get_bundled_dir(type) self.copy_files(glob(os.path.join(src_dir, "*")), path) - def get_bundled_dir(self, name): - if getattr(sys, 'frozen', None) is not None: - return realpath(os.path.join(sys._MEIPASS, '..', name)) - else: - return realpath(os.path.join(dirname(realpath(__file__)), '..', '..', name)) - if (sys.platform == "win32"): # If we try to just use shutil.copy it says the operation requires elevation. def copy_files(self, files, dest): diff --git a/lib/extensions/output.py b/lib/extensions/output.py index f4b153e6..1dc8d19d 100644 --- a/lib/extensions/output.py +++ b/lib/extensions/output.py @@ -29,20 +29,17 @@ class Output(InkstitchExtension): patches = self.elements_to_patches(self.elements) stitch_plan = patches_to_stitch_plan(patches, self.options.collapse_length_mm * PIXELS_PER_MM) - # libembroidery wants to write to an actual file rather than stdout temp_file = tempfile.NamedTemporaryFile(suffix=".%s" % self.options.file_extension, delete=False) # in windows, failure to close here will keep the file locked temp_file.close() - # libembroidery likes to debug log things to stdout. No way to disable it. - save_stdout() write_embroidery_file(temp_file.name, stitch_plan, self.document.getroot()) # inkscape will read the file contents from stdout and copy # to the destination file that the user chose with open(temp_file.name) as output_file: - sys.real_stdout.write(output_file.read()) + sys.stdout.write(output_file.read()) # clean up the temp file os.remove(temp_file.name) diff --git a/lib/extensions/params.py b/lib/extensions/params.py index 58fedd6b..1b8f2589 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -424,7 +424,7 @@ class SettingsFrame(wx.Frame): self.simulate_window.stop() self.simulate_window.load(stitch_plan=stitch_plan) else: - my_rect = self.GetRect() + my_rect = self.GetScreenRect() simulator_pos = my_rect.GetTopRight() simulator_pos.x += 5 diff --git a/lib/extensions/zip.py b/lib/extensions/zip.py index ca12efdd..02f29e8a 100644 --- a/lib/extensions/zip.py +++ b/lib/extensions/zip.py @@ -4,7 +4,7 @@ import os import inkex import tempfile from zipfile import ZipFile -from libembroidery import * +import pyembroidery from .base import InkstitchExtension from ..i18n import _ @@ -24,18 +24,11 @@ class Zip(InkstitchExtension): # it's kind of obnoxious that I have to do this... self.formats = [] - formatList = embFormatList_create() - curFormat = formatList - while(curFormat): - # extension includes the dot, so we'll remove it - extension = embFormat_extension(curFormat)[1:] - description = embFormat_description(curFormat) - writer_state = embFormat_writerState(curFormat) - - if writer_state.strip() and embFormat_type(curFormat) != EMBFORMAT_OBJECTONLY: + for format in pyembroidery.supported_formats(): + if 'writer' in format and format['category'] == 'embroidery': + extension = format['extension'] self.OptionParser.add_option('--format-%s' % extension, type="inkbool", dest=extension) self.formats.append(extension) - curFormat = curFormat.next def effect(self): if not self.get_elements(): @@ -49,19 +42,12 @@ class Zip(InkstitchExtension): files = [] - # libembroidery likes to debug log things to stdout. No way to disable it. - save_stdout() for format in self.formats: if getattr(self.options, format): output_file = os.path.join(path, "%s.%s" % (base_file_name, format)) write_embroidery_file(output_file, stitch_plan, self.document.getroot()) files.append(output_file) - # I'd love to do restore_stderr() here, but if I do, libembroidery's - # stuff still prints out and corrupts the zip! That's because it uses - # C's buffered stdout, so it hasn't actually written anything to the - # real standard output yet. - if not files: self.errormsg(_("No embroidery file formats selected.")) @@ -77,7 +63,7 @@ class Zip(InkstitchExtension): # inkscape will read the file contents from stdout and copy # to the destination file that the user chose with open(temp_file.name) as output_file: - sys.real_stdout.write(output_file.read()) + sys.stdout.write(output_file.read()) os.remove(temp_file.name) for file in files: diff --git a/lib/output.py b/lib/output.py index 84128a25..0d7f9918 100644 --- a/lib/output.py +++ b/lib/output.py @@ -1,4 +1,4 @@ -import libembroidery +import pyembroidery import inkex import simpletransform import shapely.geometry as shgeo @@ -7,36 +7,17 @@ from .utils import Point from .svg import PIXELS_PER_MM, get_doc_size, get_viewbox_transform -def make_thread(color): - thread = libembroidery.EmbThread() - thread.color = libembroidery.embColor_make(*color.rgb) - - thread.description = color.name - thread.catalogNumber = "" - - return thread - -def add_thread(pattern, thread): - """Add a thread to a pattern and return the thread's index""" - - libembroidery.embPattern_addThread(pattern, thread) - - return libembroidery.embThreadList_count(pattern.threadList) - 1 - -def get_flags(stitch): - flags = 0 - +def get_command(stitch): if stitch.jump: - flags |= libembroidery.JUMP - - if stitch.trim: - flags |= libembroidery.TRIM - - if stitch.color_change: - flags |= libembroidery.STOP - - return flags - + return pyembroidery.JUMP + elif stitch.trim: + return pyembroidery.TRIM + elif stitch.color_change: + return pyembroidery.COLOR_CHANGE + elif stitch.stop: + return pyembroidery.STOP + else: + return pyembroidery.NEEDLE_AT def _string_to_floats(string): floats = string.split(',') @@ -102,27 +83,32 @@ def get_origin(svg): def write_embroidery_file(file_path, stitch_plan, svg): origin = get_origin(svg) - pattern = libembroidery.embPattern_create() + pattern = pyembroidery.EmbPattern() for color_block in stitch_plan: - add_thread(pattern, make_thread(color_block.color)) + pattern.add_thread(color_block.color.pyembroidery_thread) for stitch in color_block: - if stitch.stop: - # This is the start of the extra color block added by the - # "STOP after" handler (see stitch_plan/stop.py). Assign it - # the same color. - add_thread(pattern, make_thread(color_block.color)) + command = get_command(stitch) + pattern.add_stitch_absolute(command, stitch.x, stitch.y) - flags = get_flags(stitch) - libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, flags, 1) - - libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, libembroidery.END, 1) + pattern.add_stitch_absolute(pyembroidery.END, stitch.x, stitch.y) # convert from pixels to millimeters - libembroidery.embPattern_scale(pattern, 1/PIXELS_PER_MM) + # also multiply by 10 to get tenths of a millimeter as required by pyembroidery + scale = 10 / PIXELS_PER_MM + + settings = { + # correct for the origin + "translate": -origin, + + # convert from pixels to millimeters + # also multiply by 10 to get tenths of a millimeter as required by pyembroidery + "scale": (scale, scale), - # SVG and embroidery disagree on the direction of the Y axis - libembroidery.embPattern_flipVertical(pattern) + # This forces a jump at the start of the design and after each trim, + # even if we're close enough not to need one. + "full_jump": True, + } - libembroidery.embPattern_write(pattern, file_path) + pyembroidery.write(pattern, file_path, settings) diff --git a/lib/simulator.py b/lib/simulator.py index c7e74353..2d2d3e08 100644 --- a/lib/simulator.py +++ b/lib/simulator.py @@ -27,6 +27,26 @@ class EmbroiderySimulator(wx.Frame): self.panel = wx.Panel(self, wx.ID_ANY) self.panel.SetFocus() + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.button_sizer = wx.BoxSizer(wx.HORIZONTAL) + + self.button_label = ( + [_("Speed up"),_('Press + or arrow up to speed up')], + [_("Slow down"),_('Press - or arrow down to slow down')], + [_("Pause"),_("Press P to pause the animation")], + [_("Restart"),_("Press R to restart the animation")], + [_("Quit"),_("Press Q to close the simulation window")]) + self.buttons = [] + for i in range(0, len(self.button_label)): + self.buttons.append(wx.Button(self, -1, self.button_label[i][0])) + self.button_sizer.Add(self.buttons[i], 1, wx.EXPAND) + self.buttons[i].Bind(wx.EVT_BUTTON, self.on_key_down) + self.buttons[i].SetToolTip(self.button_label[i][1]) + + self.sizer.Add(self.panel, 1, wx.EXPAND) + self.sizer.Add(self.button_sizer, 0, wx.EXPAND) + self.SetSizer(self.sizer) + self.load(stitch_plan) if self.target_duration: @@ -68,26 +88,30 @@ class EmbroiderySimulator(wx.Frame): self.stitches_per_frame *= 2 def on_key_down(self, event): - keycode = event.GetKeyCode() + if hasattr(event, 'GetKeyCode'): + keycode = event.GetKeyCode() + else: + keycode = event.GetEventObject().GetLabelText() + self.panel.SetFocus() - if keycode == ord("+") or keycode == ord("=") or keycode == wx.WXK_UP: + if keycode == ord("+") or keycode == ord("=") or keycode == wx.WXK_UP or keycode == "Speed up": if self.frame_period == 1: self.stitches_per_frame *= 2 else: self.frame_period = self.frame_period / 2 - elif keycode == ord("-") or keycode == ord("_") or keycode == wx.WXK_DOWN: + elif keycode == ord("-") or keycode == ord("_") or keycode == wx.WXK_DOWN or keycode == "Slow down": if self.stitches_per_frame == 1: self.frame_period *= 2 else: self.stitches_per_frame /= 2 - elif keycode == ord("Q"): + elif keycode == ord("Q") or keycode == "Quit": self.Close() - elif keycode == ord('P'): + elif keycode == ord("P") or keycode == "Pause": if self.timer.IsRunning(): self.timer.Stop() else: self.timer.Start(self.frame_period) - elif keycode == ord("R"): + elif keycode == ord("R") or keycode == "Restart": self.stop() self.clear() self.go() @@ -170,7 +194,7 @@ class EmbroiderySimulator(wx.Frame): self.width = width self.height = height - self.scale = min(float(self.max_width) / width, float(self.max_height) / height) + self.scale = min(float(self.max_width) / width, float(self.max_height - 60) / height) # make room for decorations and the margin self.scale *= 0.95 @@ -212,10 +236,15 @@ class EmbroiderySimulator(wx.Frame): client_width, client_height = self.GetClientSize() decorations_width = window_width - client_width - decorations_height = window_height - client_height + decorations_height = window_height - client_height + 40 + + setsize_window_width = self.width * self.scale + decorations_width + self.margin * 2 + setsize_window_height = (self.height) * self.scale + decorations_height + self.margin * 2 + + if setsize_window_width < 600: + setsize_window_width = 600 - self.SetSize((self.width * self.scale + decorations_width + self.margin * 2, - self.height * self.scale + decorations_height + self.margin * 2)) + self.SetSize(( setsize_window_width, setsize_window_height)) e.Skip() diff --git a/lib/stitch_plan/stitch.py b/lib/stitch_plan/stitch.py index 12642a60..5230efec 100644 --- a/lib/stitch_plan/stitch.py +++ b/lib/stitch_plan/stitch.py @@ -2,7 +2,7 @@ from ..utils.geometry import Point class Stitch(Point): - def __init__(self, x, y, color=None, jump=False, stop=False, trim=False, color_change=False, no_ties=False): + def __init__(self, x, y, color=None, jump=False, stop=False, trim=False, color_change=False, fake_color_change=False, no_ties=False): self.x = x self.y = y self.color = color @@ -10,10 +10,20 @@ class Stitch(Point): self.trim = trim self.stop = stop self.color_change = color_change + self.fake_color_change = fake_color_change self.no_ties = no_ties def __repr__(self): - return "Stitch(%s, %s, %s, %s, %s, %s, %s)" % (self.x, self.y, self.color, "JUMP" if self.jump else " ", "TRIM" if self.trim else " ", "STOP" if self.stop else " ", "NO TIES" if self.no_ties else " ") + return "Stitch(%s, %s, %s, %s, %s, %s, %s, %s%s)" % (self.x, + self.y, + self.color, + "JUMP" if self.jump else " ", + "TRIM" if self.trim else " ", + "STOP" if self.stop else " ", + "NO TIES" if self.no_ties else " ", + "FAKE " if self.fake_color_change else "", + "COLOR CHANGE" if self.color_change else " " + ) def copy(self): return Stitch(self.x, self.y, self.color, self.jump, self.stop, self.trim, self.color_change, self.no_ties) diff --git a/lib/stitch_plan/stitch_plan.py b/lib/stitch_plan/stitch_plan.py index 93bcd195..682ea09f 100644 --- a/lib/stitch_plan/stitch_plan.py +++ b/lib/stitch_plan/stitch_plan.py @@ -1,6 +1,4 @@ from .stitch import Stitch -from .stop import process_stop -from .trim import process_trim from .ties import add_ties from ..svg import PIXELS_PER_MM from ..utils.geometry import Point @@ -16,62 +14,45 @@ def patches_to_stitch_plan(patches, collapse_len=3.0 * PIXELS_PER_MM): """ stitch_plan = StitchPlan() - color_block = stitch_plan.new_color_block() - need_trim = False + if not patches: + return stitch_plan + + color_block = stitch_plan.new_color_block(color=patches[0].color) + for patch in patches: if not patch.stitches: continue - if not color_block.has_color(): - # set the color for the first color block - color_block.color = patch.color - - if color_block.color == patch.color: - if need_trim: - process_trim(color_block, patch.stitches[0]) - need_trim = False - - # add a jump stitch between patches if the distance is more - # than the collapse length - if color_block.last_stitch: - if (patch.stitches[0] - color_block.last_stitch).length() > collapse_len: - color_block.add_stitch(patch.stitches[0].x, patch.stitches[0].y, jump=True) - - else: - # add a color change (only if we didn't just do a "STOP after") - if not color_block.last_stitch.color_change: - stitch = color_block.last_stitch.copy() - stitch.color_change = True - color_block.add_stitch(stitch) + if color_block.color != patch.color: + if len(color_block) == 0: + # We just processed a stop, which created a new color block. + # We'll just claim this new block as ours: + color_block.color = patch.color + else: + # end the previous block with a color change + color_block.add_stitch(color_change=True) - color_block = stitch_plan.new_color_block() - color_block.color = patch.color + # make a new block of our color + color_block = stitch_plan.new_color_block(color=patch.color) - color_block.filter_duplicate_stitches() color_block.add_stitches(patch.stitches, no_ties=patch.stitch_as_is) if patch.trim_after: - # a trim needs to be followed by a jump to the next stitch, so - # we'll process it when we start the next patch - need_trim = True + color_block.add_stitch(trim=True) if patch.stop_after: - process_stop(color_block) - - add_jumps(stitch_plan) - add_ties(stitch_plan) - - return stitch_plan + color_block.add_stitch(stop=True) + color_block = stitch_plan.new_color_block(color_block.color) + if len(color_block) == 0: + # last block ended in a stop, so now we have an empty block + del stitch_plan.color_blocks[-1] -def add_jumps(stitch_plan): - """Add a JUMP stitch at the start of each color block.""" + stitch_plan.filter_duplicate_stitches() + stitch_plan.add_ties() - for color_block in stitch_plan: - stitch = color_block.stitches[0].copy() - stitch.jump = True - color_block.stitches.insert(0, stitch) + return stitch_plan class StitchPlan(object): @@ -85,6 +66,17 @@ class StitchPlan(object): self.color_blocks.append(color_block) return color_block + def add_color_block(self, color_block): + self.color_blocks.append(color_block) + + def filter_duplicate_stitches(self): + for color_block in self: + color_block.filter_duplicate_stitches() + + def add_ties(self): + # see ties.py + add_ties(self) + def __iter__(self): return iter(self.color_blocks) @@ -100,8 +92,12 @@ class StitchPlan(object): return len({block.color for block in self}) @property + def num_color_blocks(self): + return len(self.color_blocks) + + @property def num_stops(self): - return sum(block.num_stops for block in self) + return sum(1 for block in self if block.stop_after) @property def num_trims(self): @@ -137,6 +133,13 @@ class StitchPlan(object): dimensions = self.dimensions return (dimensions[0] / PIXELS_PER_MM, dimensions[1] / PIXELS_PER_MM) + @property + def last_color_block(self): + if self.color_blocks: + return self.color_blocks[-1] + else: + return None + class ColorBlock(object): """Holds a set of stitches, all with the same thread color.""" @@ -148,6 +151,9 @@ class ColorBlock(object): def __iter__(self): return iter(self.stitches) + def __len__(self): + return len(self.stitches) + def __repr__(self): return "ColorBlock(%s, %s)" % (self.color, self.stitches) @@ -180,20 +186,18 @@ class ColorBlock(object): return len(self.stitches) @property - def num_stops(self): - """Number of pauses in this color block.""" - - # Stops are encoded using two STOP stitches each. See the comment in - # stop.py for an explanation. - - return sum(1 for stitch in self if stitch.stop) / 2 - - @property def num_trims(self): """Number of trims in this color block.""" return sum(1 for stitch in self if stitch.trim) + @property + def stop_after(self): + if self.last_stitch is not None: + return self.last_stitch.stop + else: + return False + def filter_duplicate_stitches(self): if not self.stitches: return @@ -201,12 +205,12 @@ class ColorBlock(object): stitches = [self.stitches[0]] for stitch in self.stitches[1:]: - if stitches[-1].jump or stitch.stop or stitch.trim: - # Don't consider jumps, stops, or trims as candidates for filtering + if stitches[-1].jump or stitch.stop or stitch.trim or stitch.color_change: + # Don't consider jumps, stops, color changes, or trims as candidates for filtering pass else: l = (stitch - stitches[-1]).length() - if l <= 0.1: + if l <= 0.1 * PIXELS_PER_MM: # duplicate stitch, skip this one continue @@ -215,11 +219,21 @@ class ColorBlock(object): self.stitches = stitches def add_stitch(self, *args, **kwargs): + if not args: + # They're adding a command, e.g. `color_block.add_stitch(stop=True)``. + # Use the position from the last stitch. + if self.last_stitch: + args = (self.last_stitch.x, self.last_stitch.y) + else: + raise ValueError("internal error: can't add a command to an empty stitch block") + if isinstance(args[0], Stitch): self.stitches.append(args[0]) elif isinstance(args[0], Point): self.stitches.append(Stitch(args[0].x, args[0].y, *args[1:], **kwargs)) else: + if not args and self.last_stitch: + args = (self.last_stitch.x, self.last_stitch.y) self.stitches.append(Stitch(*args, **kwargs)) def add_stitches(self, stitches, *args, **kwargs): diff --git a/lib/stitch_plan/stop.py b/lib/stitch_plan/stop.py deleted file mode 100644 index 81dec1da..00000000 --- a/lib/stitch_plan/stop.py +++ /dev/null @@ -1,43 +0,0 @@ -def process_stop(color_block): - """Handle the "stop after" checkbox. - - The user wants the machine to pause after this patch. This can - be useful for applique and similar on multi-needle machines that - normally would not stop between colors. - - In machine embroidery files, there's no such thing as an actual - "STOP" instruction. All that exists is a "color change" command - (which libembroidery calls STOP just to be confusing). - - On multi-needle machines, the user assigns needles to the colors in - the design before starting stitching. C01, C02, etc are normal - needles, but C00 is special. For a block of stitches assigned - to C00, the machine will continue sewing with the last color it - had and pause after it completes the C00 block. - - That means we need to add an artificial color change instruction - shortly before the current stitch so that the user can set that color - block to C00. We'll go back 3 stitches and mark the start of the C00 - block: - """ - - if len(color_block.stitches) >= 3: - # make a copy of the stitch and set it as a color change - stitch = color_block.stitches[-3].copy() - stitch.color_change = True - - # mark this stitch as a "stop" so that we can avoid - # adding tie stitches in ties.py - stitch.stop = True - - # insert it after the stitch - color_block.stitches.insert(-2, stitch) - - # and also add a color change on this stitch, completing the C00 - # block: - - stitch = color_block.stitches[-1].copy() - stitch.color_change = True - color_block.add_stitch(stitch) - - # reference for the above: https://github.com/lexelby/inkstitch/pull/29#issuecomment-359175447 diff --git a/lib/stitch_plan/ties.py b/lib/stitch_plan/ties.py index 6d07ac71..573469f5 100644 --- a/lib/stitch_plan/ties.py +++ b/lib/stitch_plan/ties.py @@ -30,15 +30,16 @@ def add_tie_in(stitches, upcoming_stitches): def add_ties(stitch_plan): """Add tie-off before and after trims, jumps, and color changes.""" + need_tie_in = True for color_block in stitch_plan: - need_tie_in = True new_stitches = [] for i, stitch in enumerate(color_block.stitches): - # Tie before and after TRIMs, JUMPs, and color changes, but ignore - # the fake color change introduced by a "STOP after" (see stop.py). - is_special = stitch.trim or stitch.jump or (stitch.color_change and not stitch.stop) + is_special = stitch.trim or stitch.jump or stitch.color_change or stitch.stop - if is_special and not need_tie_in: + # see stop.py for an explanation of the fake color change + is_fake = stitch.fake_color_change + + if is_special and not is_fake and not need_tie_in: add_tie_off(new_stitches) new_stitches.append(stitch) need_tie_in = True @@ -49,7 +50,8 @@ def add_ties(stitch_plan): else: new_stitches.append(stitch) - if not need_tie_in: - add_tie_off(new_stitches) - color_block.replace_stitches(new_stitches) + + if not need_tie_in: + # tie off at the end if we haven't already + add_tie_off(color_block.stitches) diff --git a/lib/stitch_plan/trim.py b/lib/stitch_plan/trim.py deleted file mode 100644 index f692a179..00000000 --- a/lib/stitch_plan/trim.py +++ /dev/null @@ -1,23 +0,0 @@ -def process_trim(color_block, next_stitch): - """Handle the "trim after" checkbox. - - DST (and maybe other formats?) has no actual TRIM instruction. - Instead, 3 sequential JUMPs cause the machine to trim the thread. - - To support both DST and other formats, we'll add a TRIM and two - JUMPs. The TRIM will be converted to a JUMP by libembroidery - if saving to DST, resulting in the 3-jump sequence. - """ - - delta = next_stitch - color_block.last_stitch - delta = delta * (1/4.0) - - pos = color_block.last_stitch - - for i in xrange(3): - pos += delta - color_block.add_stitch(pos.x, pos.y, jump=True) - - # first one should be TRIM instead of JUMP - color_block.stitches[-3].jump = False - color_block.stitches[-3].trim = True diff --git a/lib/stitches/running_stitch.py b/lib/stitches/running_stitch.py index 96075e7a..5f8ed21e 100644 --- a/lib/stitches/running_stitch.py +++ b/lib/stitches/running_stitch.py @@ -1,3 +1,6 @@ +from copy import copy + + """ Utility functions to produce running stitches. """ @@ -64,3 +67,29 @@ def running_stitch(points, stitch_length): output.append(segment_start) return output + + +def bean_stitch(stitches, repeats): + """Generate bean stitch from a set of stitches. + + "Bean" stitch is made by backtracking each stitch to make it heaver. A + simple bean stitch would be two stitches forward, one stitch back, two + stitches forward, etc. This would result in each stitch being tripled. + + We'll say that the above counts as 1 repeat. Backtracking each stitch + repeatedly will result in a heavier bean stitch. There will always be + an odd number of threads piled up for each stitch. + """ + + if len(stitches) < 2: + return stitches + + new_stitches = [stitches[0]] + + for stitch in stitches: + new_stitches.append(stitch) + + for i in xrange(repeats): + new_stitches.extend(copy(new_stitches[-2:])) + + return new_stitches diff --git a/lib/svg/__init__.py b/lib/svg/__init__.py index 50543b1b..429e6b5e 100644 --- a/lib/svg/__init__.py +++ b/lib/svg/__init__.py @@ -1,3 +1,3 @@ from .svg import color_block_to_point_lists, render_stitch_plan from .units import * -from .path import apply_transforms +from .path import apply_transforms, get_node_transform, get_correction_transform diff --git a/lib/svg/path.py b/lib/svg/path.py index a8012774..52144332 100644 --- a/lib/svg/path.py +++ b/lib/svg/path.py @@ -4,17 +4,41 @@ import cubicsuperpath from .units import get_viewbox_transform def apply_transforms(path, node): + transform = get_node_transform(node) + + # apply the combined transform to this node's path + simpletransform.applyTransformToPath(transform, path) + + return path + +def get_node_transform(node): # start with the identity transform transform = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - # combine this node's transform with all parent groups' transforms - transform = simpletransform.composeParents(node, transform) + # this if is because sometimes inkscape likes to create paths outside of a layer?! + if node.getparent() is not None: + # combine this node's transform with all parent groups' transforms + transform = simpletransform.composeParents(node, transform) # add in the transform implied by the viewBox viewbox_transform = get_viewbox_transform(node.getroottree().getroot()) transform = simpletransform.composeTransform(viewbox_transform, transform) - # apply the combined transform to this node's path - simpletransform.applyTransformToPath(transform, path) + return transform - return path +def get_correction_transform(node): + """Get a transform to apply to new siblings of this SVG node""" + + # if we want to place our new nodes in the same group/layer as this node, + # then we'll need to factor in the effects of any transforms set on + # the parents of this node. + + # we can ignore the transform on the node itself since it won't apply + # to the objects we add + transform = get_node_transform(node.getparent()) + + # now invert it, so that we can position our objects in absolute + # coordinates + transform = simpletransform.invertTransform(transform) + + return simpletransform.formatTransform(transform) diff --git a/lib/svg/svg.py b/lib/svg/svg.py index 5552abd8..48b1343a 100644 --- a/lib/svg/svg.py +++ b/lib/svg/svg.py @@ -37,6 +37,9 @@ def color_block_to_realistic_stitches(color_block, svg): paths = [] for point_list in color_block_to_point_lists(color_block): + if not point_list: + continue + color = color_block.color.visible_on_white.darker.to_hex_str() start = point_list[0] for point in point_list[1:]: diff --git a/lib/svg/tags.py b/lib/svg/tags.py index 5488608c..7eb87540 100644 --- a/lib/svg/tags.py +++ b/lib/svg/tags.py @@ -12,6 +12,7 @@ INKSCAPE_LABEL = inkex.addNS('label', 'inkscape') INKSCAPE_GROUPMODE = inkex.addNS('groupmode', 'inkscape') CONNECTION_START = inkex.addNS('connection-start', 'inkscape') CONNECTION_END = inkex.addNS('connection-end', 'inkscape') +CONNECTOR_TYPE = inkex.addNS('connector-type', 'inkscape') XLINK_HREF = inkex.addNS('href', 'xlink') EMBROIDERABLE_TAGS = (SVG_PATH_TAG, SVG_POLYLINE_TAG) diff --git a/lib/threads/color.py b/lib/threads/color.py index fede2ecc..cc6c0c48 100644 --- a/lib/threads/color.py +++ b/lib/threads/color.py @@ -1,7 +1,7 @@ import simplestyle import re import colorsys - +from pyembroidery.EmbThread import EmbThread class ThreadColor(object): hex_str_re = re.compile('#([0-9a-z]{3}|[0-9a-z]{6})', re.I) @@ -9,6 +9,12 @@ class ThreadColor(object): def __init__(self, color, name=None, number=None, manufacturer=None): if color is None: self.rgb = (0, 0, 0) + elif isinstance(color, EmbThread): + self.name = color.description + self.number = color.catalog_number + self.manufacturer = color.brand + self.rgb = (color.get_red(), color.get_green(), color.get_blue()) + return elif isinstance(color, (list, tuple)): self.rgb = tuple(color) elif self.hex_str_re.match(color): @@ -39,6 +45,15 @@ class ThreadColor(object): return "#%s" % self.hex_digits @property + def pyembroidery_thread(self): + return { + "name": self.name, + "id": self.number, + "manufacturer": self.manufacturer, + "rgb": int(self.hex_digits, 16), + } + + @property def hex_digits(self): return "%02X%02X%02X" % self.rgb diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py index ff06d4a9..78d037f1 100644 --- a/lib/utils/__init__.py +++ b/lib/utils/__init__.py @@ -2,3 +2,4 @@ from geometry import * from cache import cache from io import * from inkscape import * +from paths import * diff --git a/lib/utils/geometry.py b/lib/utils/geometry.py index 7ff9b1cd..d0cb96cf 100644 --- a/lib/utils/geometry.py +++ b/lib/utils/geometry.py @@ -65,6 +65,9 @@ class Point: else: raise ValueError("cannot multiply Point by %s" % type(other)) + def __neg__(self): + return self * -1 + def __rmul__(self, other): if isinstance(other, (int, float)): return self.__mul__(other) diff --git a/lib/utils/paths.py b/lib/utils/paths.py new file mode 100644 index 00000000..863e8e69 --- /dev/null +++ b/lib/utils/paths.py @@ -0,0 +1,10 @@ +import sys +import os +from os.path import dirname, realpath + + +def get_bundled_dir(name): + if getattr(sys, 'frozen', None) is not None: + return realpath(os.path.join(sys._MEIPASS, "..", name)) + else: + return realpath(os.path.join(dirname(realpath(__file__)), '..', '..', name)) diff --git a/messages.po b/messages.po index 72b60bb0..70900191 100644 --- a/messages.po +++ b/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2018-06-30 13:02-0400\n" +"POT-Creation-Date: 2018-08-05 20:33-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,164 +17,214 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.5.3\n" +#: lib/elements/auto_fill.py:11 msgid "Auto-Fill" msgstr "" +#: lib/elements/auto_fill.py:14 msgid "Automatically routed fill stitching" msgstr "" +#: lib/elements/auto_fill.py:33 msgid "Running stitch length (traversal between sections)" msgstr "" +#: lib/elements/auto_fill.py:38 msgid "Underlay" msgstr "" +#: lib/elements/auto_fill.py:38 lib/elements/auto_fill.py:43 +#: lib/elements/auto_fill.py:54 lib/elements/auto_fill.py:60 +#: lib/elements/auto_fill.py:70 msgid "AutoFill Underlay" msgstr "" +#: lib/elements/auto_fill.py:43 msgid "Fill angle (default: fill angle + 90 deg)" msgstr "" +#: lib/elements/auto_fill.py:54 msgid "Row spacing (default: 3x fill row spacing)" msgstr "" +#: lib/elements/auto_fill.py:60 msgid "Max stitch length" msgstr "" +#: lib/elements/auto_fill.py:67 msgid "Inset" msgstr "" +#: lib/elements/auto_fill.py:78 msgid "Expand" msgstr "" +#: lib/elements/element.py:232 #, python-format msgid "%(id)s has more than one command of type '%(command)s' linked to it" msgstr "" -msgid "TRIM after" -msgstr "" - -msgid "Trim thread after this object (for supported machines and file formats)" -msgstr "" - -msgid "STOP after" -msgstr "" - -msgid "" -"Add STOP instruction after this object (for supported machines and file " -"formats)" -msgstr "" - +#: lib/elements/fill.py:12 msgid "Fill" msgstr "" +#: lib/elements/fill.py:18 msgid "Manually routed fill stitching" msgstr "" +#: lib/elements/fill.py:23 msgid "Angle of lines of stitches" msgstr "" +#: lib/elements/fill.py:34 msgid "Flip fill (start right-to-left)" msgstr "" +#: lib/elements/fill.py:39 msgid "Spacing between rows" msgstr "" +#: lib/elements/fill.py:48 msgid "Maximum fill stitch length" msgstr "" +#: lib/elements/fill.py:53 msgid "Stagger rows this many times before repeating" msgstr "" +#: lib/elements/satin_column.py:10 msgid "Satin Column" msgstr "" +#: lib/elements/satin_column.py:16 msgid "Custom satin column" msgstr "" +#: lib/elements/satin_column.py:22 +msgid "\"E\" stitch" +msgstr "" + +#: lib/elements/satin_column.py:31 lib/elements/stroke.py:45 msgid "Zig-zag spacing (peak-to-peak)" msgstr "" +#: lib/elements/satin_column.py:37 msgid "Pull compensation" msgstr "" +#: lib/elements/satin_column.py:45 msgid "Contour underlay" msgstr "" +#: lib/elements/satin_column.py:45 lib/elements/satin_column.py:52 +#: lib/elements/satin_column.py:57 msgid "Contour Underlay" msgstr "" +#: lib/elements/satin_column.py:52 lib/elements/satin_column.py:70 msgid "Stitch length" msgstr "" +#: lib/elements/satin_column.py:57 msgid "Contour underlay inset amount" msgstr "" +#: lib/elements/satin_column.py:63 msgid "Center-walk underlay" msgstr "" +#: lib/elements/satin_column.py:63 lib/elements/satin_column.py:70 msgid "Center-Walk Underlay" msgstr "" +#: lib/elements/satin_column.py:75 msgid "Zig-zag underlay" msgstr "" +#: lib/elements/satin_column.py:75 lib/elements/satin_column.py:80 +#: lib/elements/satin_column.py:85 msgid "Zig-zag Underlay" msgstr "" +#: lib/elements/satin_column.py:80 msgid "Zig-Zag spacing (peak-to-peak)" msgstr "" +#: lib/elements/satin_column.py:85 msgid "Inset amount (default: half of contour underlay inset)" msgstr "" +#: lib/elements/satin_column.py:118 #, python-format msgid "satin column: %(id)s: at least two subpaths required (%(num)d found)" msgstr "" +#: lib/elements/satin_column.py:144 msgid "" "One or more rails crosses itself, and this is not allowed. Please split " "into multiple satin columns." msgstr "" +#: lib/elements/satin_column.py:151 msgid "satin column: One or more of the rungs doesn't intersect both rails." msgstr "" +#: lib/elements/satin_column.py:151 lib/elements/satin_column.py:153 msgid "Each rail should intersect both rungs once." msgstr "" +#: lib/elements/satin_column.py:153 msgid "" "satin column: One or more of the rungs intersects the rails more than " "once." msgstr "" +#: lib/elements/satin_column.py:194 #, python-format msgid "satin column: object %s has a fill (but should not)" msgstr "" +#: lib/elements/satin_column.py:198 #, python-format msgid "" "satin column: object %(id)s has two paths with an unequal number of " "points (%(length1)d and %(length2)d)" msgstr "" +#: lib/elements/stroke.py:17 msgid "Satin stitch along paths" msgstr "" +#: lib/elements/stroke.py:30 msgid "Running stitch length" msgstr "" +#: lib/elements/stroke.py:36 +msgid "Bean stitch number of repeats" +msgstr "" + +#: lib/elements/stroke.py:37 +msgid "" +"Backtrack each stitch this many times. A value of 1 would triple each " +"stitch (forward, back, forward). A value of 2 would quintuple each " +"stitch, etc. Only applies to running stitch." +msgstr "" + +#: lib/elements/stroke.py:51 msgid "Repeats" msgstr "" +#: lib/elements/stroke.py:71 msgid "Manual stitch placement" msgstr "" +#: lib/elements/stroke.py:71 msgid "" "Stitch every node in the path. Stitch length and zig-zag spacing are " "ignored." msgstr "" +#: lib/elements/stroke.py:102 msgid "" "Legacy running stitch setting detected!\n" "\n" @@ -183,140 +233,206 @@ msgid "" "be dashed to indicate running stitch. Any kind of dash will work." msgstr "" +#: lib/extensions/base.py:108 msgid "No embroiderable paths selected." msgstr "" +#: lib/extensions/base.py:110 msgid "No embroiderable paths found in document." msgstr "" +#: lib/extensions/base.py:111 msgid "Tip: use Path -> Object to Path to convert non-paths." msgstr "" +#: lib/extensions/commands.py:125 +msgid "Please select one or more objects to which to attach commands." +msgstr "" + +#: lib/extensions/commands.py:133 +msgid "Please choose one or more commands to attach." +msgstr "" + +#: lib/extensions/convert_to_satin.py:29 +msgid "Please select at least one line to convert to a satin column." +msgstr "" + +#. : Convert To Satin extension, user selected one or more objects that were +#. not lines. +#: lib/extensions/convert_to_satin.py:34 +msgid "Only simple lines may be converted to satin columns." +msgstr "" + +#: lib/extensions/convert_to_satin.py:55 +#, python-format +msgid "" +"Cannot convert %s to a satin column because it intersects itself. Try " +"breaking it up into multiple paths." +msgstr "" + +#: lib/extensions/embroider.py:41 msgid "" "\n" "\n" "Seeing a 'no such option' message? Please restart Inkscape to fix." msgstr "" +#: lib/extensions/flip.py:35 msgid "Please select one or more satin columns to flip." msgstr "" +#: lib/extensions/install.py:30 msgid "" "Ink/Stitch can install files (\"add-ons\") that make it easier to use " "Inkscape to create machine embroidery designs. These add-ons will be " "installed:" msgstr "" +#: lib/extensions/install.py:31 msgid "thread manufacturer color palettes" msgstr "" +#: lib/extensions/install.py:32 msgid "Ink/Stitch visual commands (Object -> Symbols...)" msgstr "" +#: lib/extensions/install.py:41 msgid "Install" msgstr "" +#: lib/extensions/install.py:44 lib/extensions/params.py:380 msgid "Cancel" msgstr "" +#: lib/extensions/install.py:58 msgid "Choose Inkscape directory" msgstr "" +#: lib/extensions/install.py:68 msgid "Inkscape add-on installation failed" msgstr "" +#: lib/extensions/install.py:69 msgid "Installation Failed" msgstr "" +#: lib/extensions/install.py:73 msgid "" "Inkscape add-on files have been installed. Please restart Inkscape to " "load the new add-ons." msgstr "" +#: lib/extensions/install.py:74 msgid "Installation Completed" msgstr "" +#: lib/extensions/install.py:103 msgid "Ink/Stitch Add-ons Installer" msgstr "" +#: lib/extensions/params.py:244 msgid "These settings will be applied to 1 object." msgstr "" +#: lib/extensions/params.py:246 #, python-format msgid "These settings will be applied to %d objects." msgstr "" +#: lib/extensions/params.py:249 msgid "" "Some settings had different values across objects. Select a value from " "the dropdown or enter a new one." msgstr "" +#: lib/extensions/params.py:253 #, python-format msgid "Disabling this tab will disable the following %d tabs." msgstr "" +#: lib/extensions/params.py:255 msgid "Disabling this tab will disable the following tab." msgstr "" +#: lib/extensions/params.py:258 #, python-format msgid "Enabling this tab will disable %s and vice-versa." msgstr "" +#: lib/extensions/params.py:288 msgid "Inkscape objects" msgstr "" +#: lib/extensions/params.py:346 msgid "Embroidery Params" msgstr "" +#: lib/extensions/params.py:363 msgid "Presets" msgstr "" +#: lib/extensions/params.py:368 msgid "Load" msgstr "" +#: lib/extensions/params.py:371 msgid "Add" msgstr "" +#: lib/extensions/params.py:374 msgid "Overwrite" msgstr "" +#: lib/extensions/params.py:377 msgid "Delete" msgstr "" +#: lib/extensions/params.py:384 msgid "Use Last Settings" msgstr "" +#: lib/extensions/params.py:387 msgid "Apply and Quit" msgstr "" +#: lib/extensions/params.py:436 msgid "Preview" msgstr "" +#: lib/extensions/params.py:454 msgid "Internal Error" msgstr "" +#: lib/extensions/params.py:507 msgid "Please enter or select a preset name first." msgstr "" +#: lib/extensions/params.py:507 lib/extensions/params.py:513 +#: lib/extensions/params.py:541 msgid "Preset" msgstr "" +#: lib/extensions/params.py:513 #, python-format msgid "Preset \"%s\" not found." msgstr "" +#: lib/extensions/params.py:541 #, python-format msgid "" "Preset \"%s\" already exists. Please use another name or press " "\"Overwrite\"" msgstr "" +#: lib/extensions/print_pdf.py:134 msgid "Closing..." msgstr "" +#: lib/extensions/print_pdf.py:134 msgid "It is safe to close this window now." msgstr "" +#: lib/extensions/print_pdf.py:265 msgid "" "A print preview has been opened in your web browser. This window will " "stay open in order to communicate with the JavaScript code running in " @@ -326,184 +442,342 @@ msgid "" " or you can close it manually if necessary." msgstr "" +#: lib/extensions/print_pdf.py:411 msgid "Ink/Stitch Print" msgstr "" +#: lib/extensions/simulate.py:24 msgid "Embroidery Simulation" msgstr "" +#: lib/extensions/zip.py:52 msgid "No embroidery file formats selected." msgstr "" +#: lib/simulator.py:34 +msgid "Speed up" +msgstr "" + +#: lib/simulator.py:34 +msgid "Press + or arrow up to speed up" +msgstr "" + +#: lib/simulator.py:35 +msgid "Slow down" +msgstr "" + +#: lib/simulator.py:35 +msgid "Press - or arrow down to slow down" +msgstr "" + +#: lib/simulator.py:36 +msgid "Pause" +msgstr "" + +#: lib/simulator.py:36 +msgid "Press P to pause the animation" +msgstr "" + +#: lib/simulator.py:37 +msgid "Restart" +msgstr "" + +#: lib/simulator.py:37 +msgid "Press R to restart the animation" +msgstr "" + +#: lib/simulator.py:38 +msgid "Quit" +msgstr "" + +#: lib/simulator.py:38 +msgid "Press Q to close the simulation window" +msgstr "" + +#: lib/stitches/auto_fill.py:167 msgid "" "Unable to autofill. This most often happens because your shape is made " "up of multiple sections that aren't connected." msgstr "" +#: lib/stitches/auto_fill.py:392 msgid "" "Unexpected error while generating fill stitches. Please send your SVG " "file to lexelby@github." msgstr "" +#: lib/svg/svg.py:90 msgid "Stitch Plan" msgstr "" +#: lib/svg/units.py:44 #, python-format msgid "parseLengthWithUnits: unknown unit %s" msgstr "" +#: lib/svg/units.py:76 #, python-format msgid "Unknown unit: %s" msgstr "" +#: print/templates/color_swatch.html:8 print/templates/color_swatch.html:40 +#: print/templates/operator_detailedview.html:9 msgid "Color" msgstr "" +#: print/templates/color_swatch.html:11 print/templates/color_swatch.html:41 msgid "rgb" msgstr "" +#: print/templates/color_swatch.html:15 print/templates/color_swatch.html:42 msgid "thread" msgstr "" +#: print/templates/color_swatch.html:19 print/templates/color_swatch.html:43 +#: print/templates/operator_detailedview.html:62 msgid "# stitches" msgstr "" -msgid "# stops" +#: print/templates/color_swatch.html:23 print/templates/color_swatch.html:44 +msgid "# trims" +msgstr "" + +#: print/templates/color_swatch.html:24 print/templates/color_swatch.html:45 +#: print/templates/operator_detailedview.html:66 +msgid "stop after?" msgstr "" -msgid "# trims" +#: print/templates/color_swatch.html:24 print/templates/color_swatch.html:45 +#: print/templates/operator_detailedview.html:66 +msgid "yes" msgstr "" +#: print/templates/color_swatch.html:24 print/templates/color_swatch.html:45 +#: print/templates/operator_detailedview.html:66 +msgid "no" +msgstr "" + +#: print/templates/footer.html:2 msgid "Page" msgstr "" +#: print/templates/headline.html:5 msgid "Click to choose another logo" msgstr "" +#: print/templates/headline.html:10 msgid "Enter job title..." msgstr "" +#: print/templates/headline.html:11 msgid "CLIENT" msgstr "" +#: print/templates/headline.html:11 msgid "Enter client name..." msgstr "" +#: print/templates/headline.html:12 msgid "PURCHASE ORDER #:" msgstr "" +#: print/templates/headline.html:12 msgid "Enter purchase order number..." msgstr "" +#: print/templates/headline.html:15 #, python-format msgid "%Y.%m.%d" msgstr "" +#: print/templates/operator_detailedview.html:10 msgid "Thread Consumption" msgstr "" +#: print/templates/operator_detailedview.html:11 msgid "Stops and Trims" msgstr "" +#: print/templates/operator_detailedview.html:12 msgid "Notes" msgstr "" +#: print/templates/operator_detailedview.html:24 +#: print/templates/operator_overview.html:6 +#: print/templates/print_overview.html:6 msgid "Unique Colors" msgstr "" +#: print/templates/operator_detailedview.html:25 +#: print/templates/operator_overview.html:7 +#: print/templates/print_overview.html:7 msgid "Color Blocks" msgstr "" +#: print/templates/operator_detailedview.html:28 +#: print/templates/operator_overview.html:14 +#: print/templates/print_overview.html:14 msgid "Design box size" msgstr "" +#: print/templates/operator_detailedview.html:29 +#: print/templates/operator_overview.html:16 +#: print/templates/print_overview.html:16 msgid "Total thread used" msgstr "" +#: print/templates/operator_detailedview.html:30 +#: print/templates/operator_overview.html:15 +#: print/templates/print_overview.html:15 msgid "Total stitch count" msgstr "" -msgid "Total nr stops" +#: print/templates/operator_detailedview.html:33 +#: print/templates/operator_overview.html:8 +#: print/templates/print_overview.html:8 +msgid "Total stops" msgstr "" -msgid "Total nr trims" +#: print/templates/operator_detailedview.html:34 +#: print/templates/operator_overview.html:9 +#: print/templates/print_overview.html:9 +msgid "Total trims" msgstr "" +#: print/templates/operator_detailedview.html:61 msgid "thread used" msgstr "" +#: print/templates/operator_detailedview.html:65 +msgid "trims" +msgstr "" + +#: print/templates/operator_detailedview.html:69 msgid "Enter operator notes..." msgstr "" +#: print/templates/operator_overview.html:21 +#: print/templates/print_overview.html:21 msgid "Job estimated time" msgstr "" +#: print/templates/operator_overview.html:28 +#: print/templates/print_detail.html:18 print/templates/print_overview.html:28 msgid "Ctrl + Scroll to Zoom" msgstr "" -msgid "Scale" -msgstr "" - -msgid "Fit" -msgstr "" - -msgid "Apply to all" -msgstr "" - +#: print/templates/print_detail.html:6 msgid "COLOR" msgstr "" +#: print/templates/print_detail.html:11 msgid "Estimated time" msgstr "" +#: print/templates/print_overview.html:39 msgid "Client Signature" msgstr "" +#: print/templates/ui.html:2 msgid "Ink/Stitch Print Preview" msgstr "" +#: print/templates/ui.html:4 msgid "Print" msgstr "" +#: print/templates/ui.html:5 print/templates/ui.html:15 msgid "Settings" msgstr "" +#: print/templates/ui.html:6 msgid "Close" msgstr "" +#: print/templates/ui.html:9 msgid "âš lost connection to Ink/Stitch" msgstr "" +#: print/templates/ui.html:18 print/templates/ui.html:23 msgid "Page Setup" msgstr "" +#: print/templates/ui.html:19 print/templates/ui.html:47 +msgid "Design" +msgstr "" + +#: print/templates/ui.html:26 msgid "Printing Size" msgstr "" +#: print/templates/ui.html:35 msgid "Print Layouts" msgstr "" +#: print/templates/ui.html:36 +msgid "Client Overview" +msgstr "" + +#: print/templates/ui.html:37 +msgid "Client Detailed View" +msgstr "" + +#: print/templates/ui.html:38 +msgid "Operator Overview" +msgstr "" + +#: print/templates/ui.html:39 +msgid "Operator Detailed View" +msgstr "" + +#: print/templates/ui.html:40 +msgid "Thumbnail size" +msgstr "" + +#: print/templates/ui.html:43 msgid "Includes these Page Setup settings and also the icon." msgstr "" +#: print/templates/ui.html:43 msgid "Save as defaults" msgstr "" -msgid "Design" +#: print/templates/ui.html:48 +msgid "Thread Palette" msgstr "" -msgid "Thread Palette" +#: print/templates/ui.html:51 +msgid "None" msgstr "" +#: print/templates/ui.html:65 msgid "" "Changing the thread palette will cause thread names and catalog numbers " "to be recalculated based on the new palette. Any changes you have made " "to color or thread names will be lost. Are you sure?" msgstr "" +#: print/templates/ui.html:68 msgid "Yes" msgstr "" +#: print/templates/ui.html:69 msgid "No" msgstr "" +#: print/templates/ui_svg_action_buttons.html:1 +msgid "Scale" +msgstr "" + +#: print/templates/ui_svg_action_buttons.html:3 +msgid "Fit" +msgstr "" + +#: print/templates/ui_svg_action_buttons.html:5 +msgid "Apply to all" +msgstr "" + +#: print/templates/ui_svg_action_buttons.html:8 +msgid "Realistic" +msgstr "" + diff --git a/print/resources/favicon.ico b/print/resources/favicon.ico Binary files differnew file mode 100644 index 00000000..1b5455bd --- /dev/null +++ b/print/resources/favicon.ico diff --git a/print/resources/inkstitch.js b/print/resources/inkstitch.js index 6bcb183d..9f67bc90 100644 --- a/print/resources/inkstitch.js +++ b/print/resources/inkstitch.js @@ -17,6 +17,85 @@ function ping() { .fail(function() { $('#errors').attr('class', 'show') }); } +//function to chunk opd view into pieces + // source: https://stackoverflow.com/questions/3366529/wrap-every-3-divs-in-a-div +$.fn.chunk = function(size) { + var arr = []; + for (var i = 0; i < this.length; i += size) { + arr.push(this.slice(i, i + size)); + } + return this.pushStack(arr, "chunk", size); +} + +// build operator detailed view (opd) +function buildOpd(thumbnail_size = $('#operator-detailedview-thumbnail-size').val() ) { + + var thumbnail_size = parseInt(thumbnail_size); + var thumbnail_size_mm = thumbnail_size + 'mm'; + + var thumbnail_layout = (thumbnail_size >= 60) ? 'medium' : 'small'; + + // remove old settings + $( "div.page.operator-detailedview header" ).remove(); + $( "div.page.operator-detailedview footer" ).remove(); + $( "div.page.operator-detailedview .job-headline" ).remove(); + $('div.page.operator-detailedview .opd-color-block').parentsUntil('div.page.operator-detailedview').addBack().unwrap(); + $('.opd-color-block').removeClass('medium large'); + $('.opd-color-block').removeAttr('style'); + + // set thumbnail size + $('.operator-svg.operator-preview').css({ + 'width': thumbnail_size_mm, + 'height': thumbnail_size_mm, + 'max-width': thumbnail_size_mm + }); + + // calculate number of blocks per page + var num_blocks_per_page = 1; + if(thumbnail_layout == 'medium') { + $('.opd-color-block').addClass('medium'); + // set width to be able to calculate the height + $('.opd-color-block').css({ 'width': thumbnail_size_mm }); + // calculate max height -> source: https://stackoverflow.com/questions/6060992/element-with-the-max-height-from-a-set-of-elements + var color_box_height = Math.max.apply(null, $('.opd-color-block').map(function () { return $(this).height(); }).get()); + var container_height = $('#opd-info').height(); + var num_rows = Math.floor(container_height / color_box_height); + var num_columns = Math.floor(175 / thumbnail_size); + // if only two blocks fit into one row, use 50% of the space for each of them + if(num_columns == 2) { $('.opd-color-block').css({ 'width': 'calc(50% - 2mm)' }); } + // set equal height for all color blocks + $('.opd-color-block').css({ 'height': color_box_height }); + // set number of color blocks per page for medium thumbnails + num_blocks_per_page = num_columns * num_rows; + // use layout for large thumbnails if only 2 or less color blocks fit on one page + if(num_blocks_per_page <= 2) { + $('.opd-color-block').removeClass('medium').removeAttr('style').addClass('large'); + thumbnail_layout = 'large'; + // set number of color blocks per page for large thumbnails + num_blocks_per_page = 2; + } + } else { + // set number of color blocks per page for small thumbnails + num_blocks_per_page = Math.floor(220 / thumbnail_size); + } + // set number of color blocks per page to 1 if it defaults to zero + // this should never happen, but we want to avoid the browser to crash + num_blocks_per_page = (num_blocks_per_page <= 0) ? '1' : num_blocks_per_page; + + // adjust to new settings + var header = $('#opd-info header').prop('outerHTML'); + var footer = $('#opd-info footer').prop('outerHTML'); + var job_headline = $('#opd-info .job-headline').prop('outerHTML'); + var opd_visibility = ($('#operator-detailedview').is(':checked')) ? 'block' :'none'; + var paper_size = $('#printing-size').val(); + $('.opd-color-block').chunk(num_blocks_per_page).wrap('<div class="page operator-detailedview ' + paper_size + ' ' + thumbnail_layout +'" style="display:'+ opd_visibility +'"><main class="operator-detailedview"><div class="operator-job-info"></div></main></div>'); + $('div.operator-detailedview').prepend(header); + $('.operator-job-info').prepend(job_headline); + $('div.operator-detailedview').append(footer); + // update page numbers + setPageNumbers(); +} + // set pagenumbers function setPageNumbers() { var totalPageNum = $('body').find('.page:visible').length; @@ -46,11 +125,13 @@ function scaleSVG(element, scale = 'fit') { element.find('.scale').text(label); } -// set preview svg scale to fit into its box if transform is not set +// set preview svg scale to fit into its box if display block and transform is not set function scaleAllSvg() { $('.page').each(function() { - if( $(this).find('.inksimulation svg').css('transform') == 'none') { - scaleSVG($(this).find('.inksimulation'), 'fit'); + if( $(this).css('display') == 'block' ) { + if( $(this).find('.inksimulation svg').css('transform') == 'none') { + scaleSVG($(this).find('.inksimulation'), 'fit'); + } } }); } @@ -74,8 +155,6 @@ function setSVGTransform(figure, transform) { $(function() { setTimeout(ping, 1000); - setPageNumbers(); - /* SCALING AND MOVING SVG */ /* Mousewheel scaling */ @@ -192,6 +271,9 @@ $(function() { item.attr('src', value); } else if (item.is('select')) { item.val(value).trigger('initialize'); + } else if (item.is('input[type=range]')) { + item.val(value).trigger('initialize'); + $('#display-thumbnail-size').html(value + 'mm'); } else if (item.is('figure.inksimulation')) { setSVGTransform(item, value); } else { @@ -200,8 +282,11 @@ $(function() { }); }); - // wait until page size is set (if they've specified one) and then scale SVGs to fit - setTimeout(function() { scaleAllSvg() }, 500); + // wait until page size is set (if they've specified one) and then scale SVGs to fit and build operator detailed view + setTimeout(function() { + scaleAllSvg(); + buildOpd(); + }, 500); }); $('[contenteditable="true"]').keypress(function(e) { @@ -258,12 +343,37 @@ $(function() { /* Settings */ + // Settings Tabs + $('#tabs button').click(function() { + var active_fieldset_position = $(this).index() +1; + $('#settings-ui #fieldsets-ui > fieldset').css({'display': 'none'}); + $('#settings-ui #fieldsets-ui > fieldset:nth-child('+active_fieldset_position+')').css({'display': 'block'}); + $('#tabs .tab.active').removeClass("active"); + $(this).addClass("active"); + }); + // Paper Size $('select#printing-size').on('change initialize', function(){ $('.page').toggleClass('a4', $(this).find(':selected').val() == 'a4'); }).on('change', function() { $.postJSON('/settings/paper-size', {value: $(this).find(':selected').val()}); }); + + // Operator detailed view: thumbnail size setting + $(document).on('input', '#operator-detailedview-thumbnail-size', function() { + var thumbnail_size_mm = $(this).val() + 'mm'; + $('#display-thumbnail-size').html( thumbnail_size_mm ); + }); + + // Operator detailed view: thumbnail size setting action + $('#operator-detailedview-thumbnail-size').change(function() { + // set thumbnail size + var thumbnail_size = $(this).val(); + // set page break positions + buildOpd(thumbnail_size); + + $.postJSON('/settings/operator-detailedview-thumbnail-size', {value: thumbnail_size}); + }); // Thread Palette $('select#thread-palette').change(function(){ @@ -303,6 +413,7 @@ $(function() { var field_name = $(this).attr('data-field-name'); $('.' + field_name).toggle($(this).prop('checked')); + scaleAllSvg(); setPageNumbers(); }).on('change', function() { var field_name = $(this).attr('data-field-name'); @@ -397,6 +508,7 @@ $(function() { settings["client-detailedview"] = $("[data-field-name='client-detailedview']").is(':checked'); settings["operator-overview"] = $("[data-field-name='operator-overview']").is(':checked'); settings["operator-detailedview"] = $("[data-field-name='operator-detailedview']").is(':checked'); + settings["operator-detailedview-thumbnail-size"] = $("[data-field-name='operator-detailedview-thumbnail-size']").val(); settings["paper-size"] = $('select#printing-size').find(':selected').val(); var logo = $("figure.brandlogo img").attr('src'); diff --git a/print/resources/style.css b/print/resources/style.css index 81b2ea7e..174b21dd 100644 --- a/print/resources/style.css +++ b/print/resources/style.css @@ -42,65 +42,6 @@ src: url(barlow-condensed-extra-bold.ttf) format('truetype'); } -@media screen { - .page { - margin-top: 20mm !important; - outline: 1px dotted grey; - } - - .header-field::before { - content: attr(data-label); - padding-right: 0.5em; - } - - [contenteditable=true]:empty::after{ - content: attr(data-placeholder); - color: rgb(200, 200, 200); - font-weight: normal; - } -} - -@media print { - body { - margin-bottom: 0 !important; - } - - .page { - page-break-after: always; - margin: 0 !important; - } - - figure.inksimulation div { - display: none; - } - - .ui { - display: none; - } - - #settings-ui { - display: none !important; - } - - #errors { - display: none !important; - } - - .header-field:not(:empty)::before { - content: attr(data-label); - padding-right: 0.5em; - } - - span.logo-instructions { - display: none; - } -} - -@page { - size: auto; /* auto is the initial value */ - margin: 0; -} - body { font-family: "Barlow", sans-serif; font-size: 8pt; @@ -131,7 +72,24 @@ body { height: 292mm; padding: 15mm; } + + .page.client-overview.a4 header, .page.operator-overview.a4 header { + height: 50mm; + flex-direction: row; + } + + .page.client-overview.a4 div.job-details, .page.operator-overview.a4 div.job-details { + width: 100%; + } + .page.client-overview.a4 .client-overview-main figure.inksimulation { + height: 150mm; + } + + .page.client-overview.a4 figure.brandlogo, .page.operator-overview.a4 figure.brandlogo { + margin: -6mm 2.5mm; + } + /* Settings */ .ui { @@ -230,9 +188,71 @@ body { border-radius: 5px; cursor: pointer; } + + #settings-ui #tabs { + margin-left: 20px; + z-index: 1; + } + + #settings-ui button { + background: transparent; + border: 1px solid #413232; + padding: 5px; + } + + #settings-ui button.active { + border-bottom: 1px solid white; + } + + #settings-ui #ui-design { + display: none; + } + + #settings-ui > #fieldsets-ui > fieldset > legend { + display: none; + } #settings-ui fieldset { + margin-top: -1px; margin-bottom: 1em; + border: 1px solid rgb(80,80,80); + z-index: 2; + } + + #settings-ui div { + position: relative; + } + + #settings-ui .select-container { + position: relative; + display: inline-block; + } + + #settings-ui select { + margin-left: 1em; + height: 35px; + padding: 0px 25px 0 5px; + font-size: 16px; + background-color: transparent; + border: 1px solid rgb(80,80,80); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + + #settings-ui select::-ms-expand { + display: none; + } + + #settings-ui .select-container::after { + content: 'â–¾'; + position: absolute; + right: 0; + top: 0; + padding: 0 5px; + border-left: 1px solid rgb(80,80,80); + line-height: 35px; + pointer-events: none; } #modal-background { @@ -287,8 +307,8 @@ body { display: block; width: 100%; height: 100%; - line-height: 30mm; text-align: center; + position: relative; } figure.brandlogo img { @@ -308,14 +328,15 @@ body { } .logo-instructions { - white-space: nowrap; - - /* chrome ignores this :( + display: block; text-align: center; - */ - + font-weight: bold; font-size: 10px; - color: rgb(192, 192, 192); + color: rgb(117, 117, 117); + background: rgba(255,255,255, 0.8); + position: absolute; + bottom: 3mm; + cursor: pointer; } .operator-detailedview figure.brandlogo { @@ -482,13 +503,9 @@ body { } input.realistic { - position: absolute; transform: scale(0.7); - margin-left: 2px; - } - - label.realistic { - margin-left: 20px; + margin: 0; + vertical-align: bottom; } /* prevents Chrome from sending a double event for the checkbox @@ -599,26 +616,26 @@ body { height: 230mm; } - .operator-job-info { + .operator-detailedview.small .operator-job-info { display: table; width: 100%; } - .operator-job-info div { + .operator-detailedview.small .operator-job-info div { display: table-row; } - div.job-headline { + .operator-detailedview.small div.job-headline { display: table-header-group; font-size: 9pt; font-weight: bold; } - div.job-headline p { + .operator-detailedview.small div.job-headline p { height: 1em; } - .operator-job-info p { + .operator-detailedview.small .operator-job-info p { height: 15mm; max-width: 15mm; display: table-cell; @@ -628,11 +645,11 @@ body { border: 1px solid rgb(239,239,239); } - .operator-job-info span { + .operator-detailedview.small .operator-job-info span { display: block; } - .operator-job-info span.color-index { + .operator-detailedview.small .operator-job-info span.color-index { position: absolute; top: 0; left: 0; @@ -640,25 +657,126 @@ body { width: 10mm; } - .operator-svg.operator-colorswatch { - width: 15mm; + .operator-detailedview.small .operator-svg.operator-colorswatch { + width: 10mm; } - .operator-svg.operator-preview { - min-width: 15mm; - max-width: 20mm; + .operator-detailedview.small .operator-svg.operator-preview { + width: 15mm; height: 15mm; } - .operator-svg svg { + .operator-detailedview.small .operator-svg svg { position: absolute; top: 0; left: 0; - width: auto; - max-width: 30mm; + right: 0; + width: 100%; height: 100%; } + + /* opd medium/large thumbnails */ + + .operator-detailedview.medium div.job-headline, + .operator-detailedview.large div.job-headline { + display: none; + } + + .opd-color-block.medium, + .opd-color-block.large { + overflow: hidden; + position: relative; + border: 0.5mm solid rgb(239,239,239); + } + + .opd-color-block.medium .operator-colorswatch, + .opd-color-block.large .operator-colorswatch { + position: absolute; + top: 0; + padding: 0; + margin: 0; + width: 10mm; + height: 10mm; + border-right: 0.5mm solid rgb(239,239,239); + border-bottom: 0.5mm solid rgb(239,239,239); + } + + .opd-color-block.medium .operator-colorswatch svg, + .opd-color-block.medium .opd-summary p:first-child span, + .opd-color-block.medium .operator-preview svg, + .opd-color-block.large .operator-colorswatch svg, + .opd-color-block.large .opd-summary p:first-child span, + .opd-color-block.large .operator-preview svg { + height: 100%; + width: 100%; + } + + /* opd medium thumbnails */ + + .opd-color-block.medium { + display: inline-block; + float: left; + margin: 1mm; + } + + .opd-color-block.medium p { + margin: 0 auto; + } + + .opd-color-block.medium p:last-child { + margin-bottom: 1mm; + } + + .opd-color-block.medium .operator-preview { + margin: 1mm auto 0 auto; + } + + .opd-color-block.medium.opd-summary .operator-colorswatch { + display: none; + } + + .opd-color-block.medium span::before { + content: ' \00B7 '; + line-height: 0; + display: inline-block; + margin: 0 1mm; + vertical-align: super; + } + + .opd-color-block.medium span:first-child::before { + content: ''; + } + + /* opd large thumbnails */ + + .opd-color-block.large { + display: block; + margin: 5mm 0; + } + + .opd-color-block.large:first-child { + margin-top: 0; + } + .opd-color-block.large .operator-preview { + margin: 0; + } + + .opd-color-block.large .operator-preview { + float: left; + } + + .opd-color-block.large p { + text-align: left; + } + + .opd-color-block.large p:nth-child(3) { + margin-top: 5mm; + } + + .opd-color-block.large span { + display: block; + } /* Footer */ @@ -830,3 +948,62 @@ body { height: calc(100% / 5); width: calc(100% / 12); } + +@media screen { + .page { + margin-top: 20mm !important; + outline: 1px dotted grey; + } + + .header-field::before { + content: attr(data-label); + padding-right: 0.5em; + } + + [contenteditable=true]:empty::after{ + content: attr(data-placeholder); + color: rgb(200, 200, 200); + font-weight: normal; + } +} + +@media print { + body { + margin-bottom: 0 !important; + } + + .page { + page-break-after: always; + margin: 0 !important; + } + + figure.inksimulation div { + display: none; + } + + .ui { + display: none; + } + + #settings-ui { + display: none !important; + } + + #errors { + display: none !important; + } + + .header-field:not(:empty)::before { + content: attr(data-label); + padding-right: 0.5em; + } + + span.logo-instructions { + display: none; + } +} + +@page { + size: auto; /* auto is the initial value */ + margin: 0; +} diff --git a/print/templates/color_swatch.html b/print/templates/color_swatch.html index 6785b080..71022f6f 100644 --- a/print/templates/color_swatch.html +++ b/print/templates/color_swatch.html @@ -20,8 +20,8 @@ {% endif %} {# We don't want to see stops and trims if we have more than 13 colorSwatches to show #} {% if color_blocks|length < 13 %} - <tspan dy="1.2em" x="2mm" class="swatch-stops">{{ _('# stops') }}: {{ color_block.num_stops }}</tspan> <tspan dy="1.2em" x="2mm" class="swatch-trims">{{ _('# trims') }}: {{ color_block.num_trims }}</tspan> + <tspan dy="1.2em" x="2mm" class="swatch-stops">{{ _('stop after?') }}: {{ _("yes") if color_block.stop_after else _("no") }}</tspan> {% endif %} </text> </svg> @@ -41,8 +41,8 @@ <p><span class="color-rgb">{{ _('rgb') }}:</span><span>{{ color_block.color.rgb }}</span></p> <p><span class="swatch-thread">{{ _('thread') }}:</span><span data-field-name="thread-{{ color_block.color.hex_digits }}" contenteditable="true">{{ color_block.color.manufacturer }} {{ "#" + color_block.color.number if color_block.color.number }}</span></p> <p><span class="swatch-stitches">{{ _('# stitches') }}:</span><span>{{ color_block.num_stitches }}</span></p> - <p><span class="swatch-stops">{{ _('# stops') }}:</span><span>{{ color_block.num_stops }}</span></p> <p><span class="swatch-trims">{{ _('# trims') }}:</span><span>{{ color_block.num_trims }}</span></p> + <p><span class="swatch-stops">{{ _('stop after?') }}:</span><span>{{ _("yes") if color_block.stop_after else _("no") }}</span></p> </div> </div> </div> diff --git a/print/templates/headline.html b/print/templates/headline.html index 7a7059b9..369c370e 100644 --- a/print/templates/headline.html +++ b/print/templates/headline.html @@ -2,8 +2,8 @@ <label for="logo-picker"> <img src="{{ logo.src or "resources/inkstitch-logo.svg" }}" alt="{{ logo.title }}" title="{{ logo.title }}" data-field-name="logo"> <input type=file id="logo-picker" /> + <span class="logo-instructions">{{ _("Click to choose another logo") }}</span> </label> - <span class="logo-instructions">{{ _("Click to choose another logo") }}</span> </figure> <div class="headline"> <div class="pageTitle"> diff --git a/print/templates/index.html b/print/templates/index.html index 0c9cedfd..c7fa5d74 100644 --- a/print/templates/index.html +++ b/print/templates/index.html @@ -5,6 +5,7 @@ <script src="resources/jquery-3.3.1.min.js"></script> <script src="resources/inkstitch.js"></script> <link rel="stylesheet" href="resources/style.css" /> + <link rel="shortcut icon" type="image/png" href="/favicon.png"/> </head> <body> {% include 'ui.html' %} @@ -23,10 +24,7 @@ <div class="page operator-overview" style="display: {{ 'block' if view.operator_overview else 'none' }}">{% include 'operator_overview.html' %}</div> {# operator detailed view #} - {% for color_block_part in color_blocks | batch(12) %} - {% set outer_loop = loop %} - <div class="page operator-detailedview" style="display: {{ 'block' if view.operator_detailedview else 'none' }}">{% include 'operator_detailedview.html' %}</div> - {% endfor %} + {% include 'operator_detailedview.html' %} </body> </html> diff --git a/print/templates/operator_detailedview.html b/print/templates/operator_detailedview.html index 0b948cb0..e3c0d441 100644 --- a/print/templates/operator_detailedview.html +++ b/print/templates/operator_detailedview.html @@ -1,76 +1,72 @@ + <div id="opd-info" style="display: none; height: 220mm; width: 175mm;"> <header> {% include 'headline.html' %} </header> + {% include 'footer.html' %} + <div class="job-headline"> + <p class="operator-svg operator-colorswatch">{# svg color #}</p> + <p>{# svg preview #}</p> + <p>{{ _('Color') }}</p> + <p>{{ _('Thread Consumption') }}</p> + <p>{{ _('Stops and Trims') }}</p> + <p>{{ _('Notes') }}</p> + </div> + </div> - <main> - <div class="operator-job-info"> - <div class="job-headline"> - <p class="operator-svg operator-colorswatch">{# svg color #}</p> - <p>{# svg preview #}</p> - <p>{{ _('Color') }}</p> - <p>{{ _('Thread Consumption') }}</p> - <p>{{ _('Stops and Trims') }}</p> - <p>{{ _('Notes') }}</p> - </div> - {% if outer_loop.index == 1 %} - <div> - <p> - <span>##</span> - </p> - <p class="operator-svg operator-preview"> - {{ svg_overview|safe }} - </p> - <p> - <span>{{ _('Unique Colors') }}: {{ job.num_colors }}</span> - <span>{{ _('Color Blocks') }}: {{ job.num_color_blocks }}</span> - </p> - <p> - <span>{{ _('Design box size') }}: {{ "%0.1fmm X %0.1fmm" | format(*job.dimensions) }}</span> - <span>{{ _('Total thread used') }}: {{job.estimated_thread }}</span> - <span>{{ _('Total stitch count') }}: {{job.num_stitches }}</span> - </p> - <p> - <span>{{ _('Total nr stops') }}: {{ job.num_stops }}</span> - <span>{{ _('Total nr trims') }}: {{ job.num_trims }}</span> - </p> - <p> - <span></span> - </p> - </div> - {% endif %} - {% for color_block in color_block_part %} + <div class="opd-summary opd-color-block"> + <p class="operator-svg operator-colorswatch"> + <span>##</span> + </p> + <p class="operator-svg operator-preview"> + {{ svg_overview|safe }} + </p> + <p> + <span>{{ _('Unique Colors') }}: {{ job.num_colors }}</span> + <span>{{ _('Color Blocks') }}: {{ job.num_color_blocks }}</span> + </p> + <p> + <span>{{ _('Design box size') }}: {{ "%0.1fmm X %0.1fmm" | format(*job.dimensions) }}</span> + <span>{{ _('Total thread used') }}: {{job.estimated_thread }}</span> + <span>{{ _('Total stitch count') }}: {{job.num_stitches }}</span> + </p> + <p> + <span>{{ _('Total stops') }}: {{ job.num_stops }}</span> + <span>{{ _('Total trims') }}: {{ job.num_trims }}</span> + </p> + <p> + <span></span> + </p> + </div> - <div style="display: table-row;"> - <p class="operator-svg operator-colorswatch"> - <svg xmlns="http://www.w3.org/2000/svg"> - <rect fill="rgb{{ color_block.color.rgb }}" width="15mm" height="100%" /> - <text fill="rgb{{ color_block.color.font_color }}"> - <tspan x="4mm" y="7.5mm" class="color-index">#{{ loop.index + outer_loop.index0 * 12 }}</tspan> - </text> - </svg> - </p> - <p class="operator-svg operator-preview"> - {{ color_block.svg_preview|safe }} - </p> - <p> - <span data-field-name="color-{{ color_block.color.hex_digits }}" contenteditable="true" data-placeholder="Enter thread name...">{{ color_block.color.name }}</span> - <span>{{ color_block.color.rgb }}</span> - <span data-field-name="thread-{{ color_block.color.hex_digits }}" contenteditable="true">{{ color_block.color.manufacturer }} {{ "#" + color_block.color.number if color_block.color.number }}</span> - </p> - <p> - <span>{{ _('thread used') }}:</span> - <span>{{ _('# stitches') }}: {{ color_block.num_stitches }}</span> - </p> - <p> - <span>{{ _('# stops') }}: {{ color_block.num_stops }}</span> - <span>{{ _('# trims') }}: {{ color_block.num_trims }}</span> - </p> - <p> - <span class="notes" contenteditable="true" data-field-name="operator-notes-block{{ loop.index0 + outer_loop.index0 * 12 }}" data-placeholder="{{ _("Enter operator notes...") }}"></span> - </p> - </div> - {% endfor %} - </div> - </main> + {% for color_block in color_blocks %} - {% include 'footer.html' %} + <div class="opd-color-block"> + <p class="operator-svg operator-colorswatch"> + <svg xmlns="http://www.w3.org/2000/svg"> + <rect fill="rgb{{ color_block.color.rgb }}" width="15mm" height="100%" /> + <text fill="rgb{{ color_block.color.font_color }}"> + <tspan x="2mm" y="5mm" class="color-index">#{{ loop.index }}</tspan> + </text> + </svg> + </p> + <p class="operator-svg operator-preview"> + {{ color_block.svg_preview|safe }} + </p> + <p> + <span data-field-name="color-{{ color_block.color.hex_digits }}" contenteditable="true" data-placeholder="Enter thread name...">{{ color_block.color.name }}</span> + <span>{{ color_block.color.rgb }}</span> + <span data-field-name="thread-{{ color_block.color.hex_digits }}" contenteditable="true">{{ color_block.color.manufacturer }} {{ "#" + color_block.color.number if color_block.color.number }}</span> + </p> + <p> + <span>{{ _('thread used') }}:</span> + <span>{{ _('# stitches') }}: {{ color_block.num_stitches }}</span> + </p> + <p> + <span>{{ _('trims') }}: {{ color_block.num_trims }}</span> + <span>{{ _('stop after?') }}: {{ _("yes") if color_block.stop_after else _("no") }}</span> + </p> + <p> + <span class="notes" contenteditable="true" data-field-name="operator-notes-block{{ loop.index }}" data-placeholder="{{ _("Enter operator notes...") }}"></span> + </p> + </div> + {% endfor %} diff --git a/print/templates/operator_overview.html b/print/templates/operator_overview.html index 6fa46911..048fd58e 100644 --- a/print/templates/operator_overview.html +++ b/print/templates/operator_overview.html @@ -5,8 +5,8 @@ <div class="table"> <p><span>{{ _('Unique Colors') }}:</span><span>{{ job.num_colors }}</span></p> <p><span>{{ _('Color Blocks') }}:</span><span>{{ job.num_color_blocks }}</span></p> - <p><span>{{ _('Total nr stops') }}:</span><span>{{ job.num_stops }}</span></p> - <p><span>{{ _('Total nr trims') }}:</span><span>{{ job.num_trims }}</span></p> + <p><span>{{ _('Total stops') }}:</span><span>{{ job.num_stops }}</span></p> + <p><span>{{ _('Total trims') }}:</span><span>{{ job.num_trims }}</span></p> </div> </div> <div> @@ -27,16 +27,7 @@ <main> <figure class="inksimulation operator" data-field-name="operator-overview-transform" style="height: 210mm;" title="{{ _('Ctrl + Scroll to Zoom') }}"> {{ svg_overview|safe }} - <figcaption>{{ _('Scale') }} <span class="scale" data-field-name="svg-scale" contenteditable="true" data-placeholder=""></span>%</figcaption> - <div> - <button class="svg-fit">{{ _('Fit') }}</button> - <button class="svg-full">100%</button> - <button class="svg-apply">{{ _('Apply to all') }}</button> - <button class="svg-realistic"> - <input type="checkbox" id="realistic-operator-overview" data-field-name="overview" class="realistic" /> - <label for="realistic-operator-overview" class="realistic">Realistic</label> - </button> - </div> + {% include 'ui_svg_action_buttons.html' %} </figure> </main> {% include 'footer.html' %} diff --git a/print/templates/print_detail.html b/print/templates/print_detail.html index e73fe918..241ac88b 100644 --- a/print/templates/print_detail.html +++ b/print/templates/print_detail.html @@ -17,16 +17,7 @@ <main> <figure class="inksimulation" data-field-name="client-detail-transform-block{{ loop.index0 }}" title="{{ _('Ctrl + Scroll to Zoom') }}"> {{color_block.svg_preview|safe}} - <figcaption>{{ _('Scale') }} <span class="scale" data-field-name="svg-scale" contenteditable="true" data-placeholder=""></span>%</figcaption> - <div> - <button class="svg-fit">Fit</button> - <button class="svg-full">100%</button> - <button class="svg-apply">Apply to all</button> - <button class="svg-realistic"> - <input type="checkbox" id="realistic-color-block-{{ loop.index0 }}" data-field-name="block{{ loop.index0 }}" class="realistic" /> - <label for="realistic-color-block-{{ loop.index0 }}" class="realistic">Realistic</label> - </button> - </div> + {% include 'ui_svg_action_buttons.html' %} </figure> <div class="color-palette detailed"> {% include 'color_swatch.html' %} diff --git a/print/templates/print_overview.html b/print/templates/print_overview.html index b42ab7a9..cfbb81d1 100644 --- a/print/templates/print_overview.html +++ b/print/templates/print_overview.html @@ -5,8 +5,8 @@ <div class="table"> <p><span>{{ _('Unique Colors') }}:</span><span>{{ job.num_colors }}</span></p> <p><span>{{ _('Color Blocks') }}:</span><span>{{ job.num_color_blocks }}</span></p> - <p><span>{{ _('Total nr stops') }}:</span><span>{{ job.num_stops }}</span></p> - <p><span>{{ _('Total nr trims') }}:</span><span>{{ job.num_trims }}</span></p> + <p><span>{{ _('Total stops') }}:</span><span>{{ job.num_stops }}</span></p> + <p><span>{{ _('Total trims') }}:</span><span>{{ job.num_trims }}</span></p> </div> </div> <div> @@ -27,16 +27,7 @@ <main class="client-overview-main"> <figure class="inksimulation" data-field-name="client-overview-transform" title="{{ _('Ctrl + Scroll to Zoom') }}"> {{ svg_overview|safe }} - <figcaption>{{ _('Scale') }} <span class="scale" data-field-name="svg-scale" contenteditable="true" data-placeholder=""></span>%</figcaption> - <div> - <button class="svg-fit">Fit</button> - <button class="svg-full">100%</button> - <button class="svg-apply">Apply to all</button> - <button class="svg-realistic"> - <input type="checkbox" id="realistic-client-overview" data-field-name="overview" class="realistic" /> - <label for="realistic-client-overview" class="realistic">Realistic</label> - </button> - </div> + {% include 'ui_svg_action_buttons.html' %} </figure> <div class="color-palette"> diff --git a/print/templates/ui.html b/print/templates/ui.html index 3b11f345..bc6c57b9 100644 --- a/print/templates/ui.html +++ b/print/templates/ui.html @@ -13,41 +13,51 @@ <div id="settings-ui"> <p id="close-settings">X</p> <h1>{{ _('Settings') }}</h1> - <fieldset> - <legend>{{ _('Page Setup') }}</legend> - <div> - <p>{{ _('Printing Size') }}: - <select id="printing-size" data-field-name="paper-size"> - <option value="letter" selected="selected">Letter</option> - <option value="a4">A4</option> + + <div id="tabs"> + <button class="tab active">{{ _('Page Setup') }}</button> + <button class="tab">{{ _('Design') }}</button> + </div> + <div id="fieldsets-ui"> + <fieldset id="ui-page-setup"> + <legend>{{ _('Page Setup') }}</legend> + <div> + <p class="select-container"> + <label for="printing-size">{{ _('Printing Size') }}:</label> + <select id="printing-size" data-field-name="paper-size"> + <option value="letter" selected="selected">Letter</option> + <option value="a4">A4</option> + </select> + </p> + </div> + <div> + <fieldset> + <legend>{{ _('Print Layouts') }}</legend> + <p><input type="checkbox" class="view" id="client-overview" data-field-name="client-overview" /><label for="client-overview">{{ _('Client Overview') }}</label></p> + <p><input type="checkbox" class="view" id="client-detailedview" data-field-name="client-detailedview" /><label for="client-detailedview">{{ _('Client Detailed View') }}</label></p> + <p><input type="checkbox" class="view" id="operator-overview" data-field-name="operator-overview" CHECKED /><label for="operator-overview">{{ _('Operator Overview') }}</label></p> + <p><input type="checkbox" class="view" id="operator-detailedview" data-field-name="operator-detailedview" CHECKED /><label for="operator-detailedview">{{ _('Operator Detailed View') }}</label></p> + <p style="text-indent: 1.5em;">{{ _('Thumbnail size') }}: <input type="range" min="15" max="110" value="15" step="5" id="operator-detailedview-thumbnail-size" data-field-name="operator-detailedview-thumbnail-size" style="vertical-align: middle;"> <span id="display-thumbnail-size">15mm</span> + </p> + </fieldset> + <button id="save-settings" title="{{ _("Includes these Page Setup settings and also the icon.") }}">{{ _("Save as defaults") }}</button> + </div> + </fieldset> + <fieldset id="ui-design"> + <legend>{{ _('Design') }}</legend> + <p class="select-container"><label for="thread-palette">{{ _('Thread Palette') }}:</label> + <select id="thread-palette" data-field-name="thread-palette"> + {% if selected_palette is none %} + <option value="" selected>{{ _('None') }}</option> + {% endif %} + {% for palette in palettes %} + <option value="{{ palette }}" {{ "selected" if palette == selected_palette.name else "" }}>{{ palette }}</option> + {% endfor %} </select> </p> - </div> - <div> - <fieldset> - <legend>{{ _('Print Layouts') }}</legend> - <p><input type="checkbox" class="view" id="client-overview" data-field-name="client-overview" /><label for="client-overview">Client Overview</label></p> - <p><input type="checkbox" class="view" id="client-detailedview" data-field-name="client-detailedview" /><label for="client-detailedview">Client Detailed View</label></p> - <p><input type="checkbox" class="view" id="operator-overview" data-field-name="operator-overview" CHECKED /><label for="operator-overview">Operator Overview</label></p> - <p><input type="checkbox" class="view" id="operator-detailedview" data-field-name="operator-detailedview" CHECKED /><label for="operator-detailedview">Operator Detailed View</label></p> - </fieldset> - <button id="save-settings" title="{{ _("Includes these Page Setup settings and also the icon.") }}">{{ _("Save as defaults") }}</button> - </div> - </fieldset> - <fieldset> - <legend>{{ _('Design') }}</legend> - <p>{{ _('Thread Palette') }}: - <select id="thread-palette" data-field-name="thread-palette"> - {% if selected_palette is none %} - <option value="" selected>None</option> - {% endif %} - {% for palette in palettes %} - <option value="{{ palette }}" {{ "selected" if palette == selected_palette.name else "" }}>{{ palette }}</option> - {% endfor %} - </select> - </p> - </fieldset> - </div> + </fieldset> + </div><!-- END FIELDSETS-UI --> + </div><!-- END SETTINGS-UI--> <div id="modal-background" class="modal"></div> <div id="modal-content" class="modal"> diff --git a/print/templates/ui_svg_action_buttons.html b/print/templates/ui_svg_action_buttons.html new file mode 100644 index 00000000..c111d634 --- /dev/null +++ b/print/templates/ui_svg_action_buttons.html @@ -0,0 +1,10 @@ +<figcaption>{{ _('Scale') }} <span class="scale" data-field-name="svg-scale" contenteditable="true" data-placeholder=""></span>%</figcaption> +<div> + <button class="svg-fit">{{ _('Fit') }}</button> + <button class="svg-full">100%</button> + <button class="svg-apply">{{ _('Apply to all') }}</button> + <button class="svg-realistic"> + <input type="checkbox" id="realistic-operator-overview" data-field-name="overview" class="realistic" /> + <label for="realistic-operator-overview" class="realistic">{{ _('Realistic') }}</label> + </button> +</div> diff --git a/requirements.txt b/requirements.txt index 314a2b0e..8d487a2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +pyembroidery >=1.2.12, <1.3.0 backports.functools_lru_cache wxPython networkx diff --git a/symbols/inkstitch.svg b/symbols/inkstitch.svg index 2af52d92..4497e679 100644 --- a/symbols/inkstitch.svg +++ b/symbols/inkstitch.svg @@ -18,15 +18,16 @@ inkscape:version="0.92.3 (unknown)" sodipodi:docname="inkstitch.svg"> <sodipodi:namedview + inkscape:snap-object-midpoints="true" id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2" - inkscape:cx="64.500275" - inkscape:cy="322.07765" + inkscape:zoom="4" + inkscape:cx="30.48931" + inkscape:cy="293.08326" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" @@ -38,17 +39,20 @@ inkscape:window-maximized="1" inkscape:measure-start="128.23,226.536" inkscape:measure-end="114.217,226.536" - inkscape:snap-global="false" - showguides="false"> + inkscape:snap-global="true" + showguides="false" + inkscape:snap-others="true" + inkscape:object-nodes="false" + inkscape:snap-nodes="false"> <inkscape:grid - empspacing="2" - opacity="0.1254902" - color="#f03fff" - spacingy="18.897638" - spacingx="18.897638" - units="mm" + type="xygrid" id="grid5001" - type="xygrid" /> + units="mm" + spacingx="18.897638" + spacingy="18.897638" + color="#f03fff" + opacity="0.1254902" + empspacing="2" /> </sodipodi:namedview> <title id="title9425">Ink/Stitch Commands</title> @@ -57,38 +61,67 @@ <symbol id="inkstitch_fill_end"> <title - id="title9427">Fill stitch starting point</title> - <circle - inkscape:label="outline" - style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" - id="circle13166" - cx="47.235394" - cy="105.91732" - r="9.2465534" /> + id="inkstitch_title9427">Fill stitch ending point</title> + <path + id="inkstitch_circle13166" + d="m 9.220113,0.0792309 c -1.9e-6,5.106729 -4.1398241,9.24655 -9.246553,9.24655 -5.1067293,0 -9.2465521,-4.139821 -9.246554,-9.24655 1e-7,-2.452338 0.9741879,-4.804235 2.7082531,-6.538301 1.7340653,-1.734065 4.0859624,-2.708252 6.5383009,-2.708252 5.1067301,0 9.2465528,4.139823 9.246553,9.246553 0,0 0,0 0,0" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06500006;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19500017, 3.19500017;stroke-dashoffset:0;stroke-opacity:1" + inkscape:connector-curvature="0" /> <path - inkscape:connector-curvature="0" - id="rect5371-2" - d="m 42.691395,101.26765 h 9.140878 v 9.14087 h -9.140878 z" - style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60622311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.81866985, 4.81866985;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" /> + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.27154255;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.81866985, 4.81866985;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + d="m -4.570439,-4.5704391 c 0,0 9.140878,0 9.140878,0 0,0 0,9.14087 0,9.14087 0,0 -9.140878,0 -9.140878,0 0,0 0,-9.14087 0,-9.14087" + id="inkstitch_rect5371-2" + inkscape:connector-curvature="0" /> + </symbol> + <symbol + id="inkstitch_trim"> + <title + id="inkstitch_title9282">Trim the thread after sewing this object.</title> + <path + id="inkstitch_circle13405" + d="m 9.2465284,-8.6e-6 c 1.8e-6,2.452339 -0.9741847,4.804237 -2.7082493,6.538304 C 4.8042146,8.2723614 2.4523174,9.2465504 -2.1625959e-5,9.2465514 -2.4523623,9.2465534 -4.8042621,8.2723654 -6.5383288,6.5382984 -8.2723956,4.8042314 -9.2465834,2.4523324 -9.2465816,-8.6e-6 c 6e-7,-2.452339 0.9741895,-4.804237 2.708256,-6.538301 1.7340665,-1.734065 4.0859648,-2.708252 6.538303974041,-2.70825 C 5.1067066,-9.2465576 9.2465271,-5.1067366 9.2465284,-8.6e-6 c 0,0 0,0 0,0" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06500006;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19500017, 3.19500017;stroke-dashoffset:0;stroke-opacity:1" + inkscape:connector-curvature="0" /> + <path + 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:#050505;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.41421342;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + d="m -3.0000256,-5.9834096 c -1.30575,0 -2.375,1.06924 -2.375,2.375 0,1.30575 1.06925,2.375 2.375,2.375 0.58687,0 1.11944,-0.22369 1.53516,-0.58007 0,0 0.61717997,1.62109 0.61717997,1.62109 0,0 -2.29881997,6.01758 -2.29881997,6.01758 0.98655,-0.12511 1.23728,-0.26171 1.67382,-0.97461 0,0 1.33007997,-3.18945 1.33007997,-3.18945 0,0 1.23633003,3.25 1.23633003,3.25 0.23227,0.77906 0.84315,0.79218 1.57813,1.07226 0,0 -2.05469003,-6.14258 -2.05469003,-6.14258 0,0 0.73047003,-1.75 0.73047003,-1.75 0.42849,0.41682 1.01136,0.67578 1.65234,0.67578 1.30575,0 2.375,-1.06925 2.375,-2.375 0,-1.30576 -1.06925,-2.375 -2.375,-2.375 -1.06233,0 -1.95701,0.71265 -2.25781003,1.67969 0,0 -0.0117,-0.0156 -0.0117,-0.0156 0,0 -0.80274,2.10156 -0.80274,2.10156 0,0 -0.59179,-1.76562 -0.59179,-1.76562 -0.18242,-1.12808 -1.15864997,-2 -2.33593997,-2 0,0 -2e-5,-3e-5 -2e-5,-3e-5 m 0,1 c 0.76531,0 1.375,0.60968 1.375,1.375 0,0.76531 -0.60969,1.375 -1.375,1.375 -0.76531,0 -1.375,-0.60969 -1.375,-1.375 0,-0.76532 0.60969,-1.375 1.375,-1.375 0,0 0,0 0,0 m 6,0 c 0.76531,0 1.375,0.60968 1.375,1.375 0,0.76531 -0.60969,1.375 -1.375,1.375 -0.76531,0 -1.375,-0.60969 -1.375,-1.375 0,-0.76532 0.60969,-1.375 1.375,-1.375 0,0 0,0 0,0" + id="inkstitch_path13416" + inkscape:connector-curvature="0" /> </symbol> <symbol id="inkstitch_fill_start"> <title - id="title9432">Fill stitch ending point</title> - <circle - inkscape:label="outline" + id="inkstitch_title9432">Fill stitch starting point</title> + <path + id="inkstitch_circle13166-6" + d="m 9.2465269,-2.6e-6 c -1.9e-6,5.106729 -4.1398247,9.24655 -9.246554026709,9.24655 C -5.106756,9.2465474 -9.2465782,5.1067264 -9.2465801,-2.6e-6 c 2e-7,-5.10673 4.1398229,-9.246553 9.246552973291,-9.246553 2.452338526709,0 4.804235626709,0.974187 6.538300926709,2.708252 1.7340652,1.734066 2.708253,4.085963 2.7082531,6.538301 0,0 0,0 0,0" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" + inkscape:connector-curvature="0" /> + <path + style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.74180555;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + d="m 6.5728129,0.0035574 c 0,0 -10.4514,6.03412 -10.4514,6.03412 0,0 0,-12.06823 0,-12.06823 0,0 10.4514,6.03411 10.4514,6.03411" + id="inkstitch_path4183" + inkscape:connector-curvature="0" /> + </symbol> + <symbol + id="inkstitch_stop"> + <title + id="inkstitch_title13328">Stop the machine after sewing this object (for applique, etc)</title> + <path + id="inkstitch_circle13330" + d="m 9.2465269,-2.6e-6 c -1.9e-6,5.106729 -4.1398241,9.24655 -9.246553026709,9.24655 C -5.1067554,9.2465474 -9.2465782,5.1067264 -9.2465801,-2.6e-6 c 10e-8,-2.452338 0.9741879,-4.804235 2.7082531,-6.538301 1.7340653,-1.734065 4.0859624,-2.708252 6.538300873291,-2.708252 C 5.106704,-9.2465556 9.2465267,-5.1067326 9.2465269,-2.6e-6 c 0,0 0,0 0,0" style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" - id="circle13166-6" - cx="85.223907" - cy="106.13256" - r="9.2465534" /> + inkscape:connector-curvature="0" /> + <path + id="inkstitch_path13332" + d="m -3.1690251,-4.6497026 c 0,0 2.51587797,0 2.51587797,0 0,0 0,9.14087 0,9.14087 0,0 -2.51587797,0 -2.51587797,0 0,0 0,-9.14087 0,-9.14087" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60622311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.81866985, 4.81866985;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + inkscape:connector-curvature="0" /> <path - inkscape:connector-curvature="0" - id="path4183" - d="m 91.796747,106.13612 -10.4514,6.03412 v -12.06823 z" - inkscape:transform-center-y="3.0183984e-06" - inkscape:transform-center-x="-1.7419043" - style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.74180555;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="inkstitch_path13333" + d="m 0.83097287,-4.6497026 c 0,0 2.51588003,0 2.51588003,0 0,0 0,9.14087 0,9.14087 0,0 -2.51588003,0 -2.51588003,0 0,0 0,-9.14087 0,-9.14087" + style="display:inline;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60622311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.81866985, 4.81866985;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + inkscape:connector-curvature="0" /> </symbol> </defs> <metadata @@ -104,24 +137,53 @@ </rdf:RDF> </metadata> <g - style="display:inline" - transform="translate(0,-58.409503)" - id="layer1" + inkscape:label="Layer 1" inkscape:groupmode="layer" - inkscape:label="Layer 1"> - <use + id="layer1" + style="display:inline"> + <flowRoot + transform="translate(0,58.409503)" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333302px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#050505;stroke-width:1.06500006;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:3.19500017, 3.19500017;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + id="flowRoot37658" + xml:space="preserve"><flowRegion + id="flowRegion37660"><rect + y="71.702759" + x="20.75" + height="62.5" + width="217.5" + id="rect37662" /></flowRegion><flowPara + style="fill:#000000;fill-opacity:1;stroke:none" + id="flowPara37664">Create symbols carefully! They must be centered about the origin before being converted to a symbol.</flowPara></flowRoot> <use xlink:href="#inkstitch_fill_end" - id="use18860" + id="use9454" + x="0" + y="0" + width="100%" + height="100%" + transform="translate(37.82169,75.511319)" /> + <use + xlink:href="#inkstitch_trim" + id="use9461" x="0" y="0" width="100%" - height="100%" /> + height="100%" + transform="translate(75.590552,75.590552)" /> <use xlink:href="#inkstitch_fill_start" - id="use18871" + id="use9468" + x="0" + y="0" + width="100%" + height="100%" + transform="translate(113.38583,75.590552)" /> + <use + xlink:href="#inkstitch_stop" + id="use9476" x="0" y="0" width="100%" - height="100%" /> + height="100%" + transform="translate(151.1811,75.590552)" /> </g> </svg> |
