├── resources ├── darwin │ ├── bin │ │ └── autotrace │ │ │ ├── AUTHORS │ │ │ ├── bin │ │ │ ├── autotrace │ │ │ └── autotrace-config │ │ │ ├── lib │ │ │ ├── libautotrace.3.0.0.dylib │ │ │ └── pkgconfig │ │ │ │ └── autotrace.pc │ │ │ ├── include │ │ │ └── autotrace │ │ │ │ ├── exception.h │ │ │ │ ├── types.h │ │ │ │ ├── input.h │ │ │ │ └── output.h │ │ │ ├── TODO │ │ │ ├── NEWS │ │ │ ├── README │ │ │ └── share │ │ │ ├── aclocal │ │ │ └── autotrace.m4 │ │ │ └── man │ │ │ └── man1 │ │ │ └── autotrace.1 │ ├── app.icns │ ├── dmg_back.png │ └── dmg_back@2x.png ├── win32 │ ├── bin │ │ └── autotrace │ │ │ ├── AUTHORS │ │ │ ├── autotrace.exe │ │ │ ├── THANKS │ │ │ └── README │ ├── app.ico │ └── install_anim.gif ├── app.png └── linux │ └── bin │ └── autotrace │ ├── autotrace │ └── lib │ ├── libpng12.so.0 │ ├── libautotrace.so.3 │ ├── libpstoedit.so.0 │ └── libMagickCore-6.Q16.so.2 ├── .travis.yml ├── src ├── images │ ├── icon-pen.png │ ├── icon-fill.png │ ├── icon-import.png │ ├── icon-select.png │ ├── cursor-fill-0.png │ ├── cursor-fill-1.png │ ├── cursor-fill-2.png │ ├── cursor-fill-3.png │ ├── cursor-pen-0.png │ ├── cursor-pen-1.png │ ├── cursor-pen-2.png │ ├── cursor-pen-3.png │ ├── cursor-select.png │ ├── cursor-eyedropper.png │ ├── icon-autotrace-color-2.svg │ ├── icon-select.svg │ ├── icon-import.svg │ ├── icon-autotrace-color-3.svg │ ├── icon-autotrace-color-4.svg │ ├── icon-pen.svg │ ├── griddle.svg │ ├── icon-autotrace-simple.svg │ ├── icon-manual.svg │ ├── icon-autotrace-complex.svg │ ├── logo.svg │ ├── icon-autotrace-color-5.svg │ └── icon-fill.svg ├── windows │ ├── window.autotrace.webview.html │ ├── window.export.webview.html │ ├── window.settings.js │ ├── window.settings.html │ ├── window.autotrace.html │ ├── window.export.html │ └── window.export.js ├── styles │ ├── _loaders.scss │ ├── _math.scss │ ├── _trace-menu.scss │ └── _fancy-elements.scss ├── index.html ├── squirrel-update.js ├── helpers │ ├── helper.clipboard.js │ ├── helper.undo.js │ └── helper.autotrace.js ├── tools │ ├── tool.pen.js │ └── tool.fill.js ├── main.js └── editor.ps.js ├── Gruntfile.js ├── .gitignore ├── locales └── en-US │ ├── menus-en-US.json │ └── app-en-US.json ├── menus ├── menu-init.js ├── menu-win32.js └── menu-darwin.js ├── .jshintrc ├── package.json └── README.md /resources/darwin/bin/autotrace/AUTHORS: -------------------------------------------------------------------------------- 1 | Martin Weber 2 | martweb@gmx.net -------------------------------------------------------------------------------- /resources/win32/bin/autotrace/AUTHORS: -------------------------------------------------------------------------------- 1 | Martin Weber 2 | martweb@gmx.net -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: node_js 3 | node_js: 4 | - "5.3" 5 | -------------------------------------------------------------------------------- /resources/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/app.png -------------------------------------------------------------------------------- /resources/win32/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/win32/app.ico -------------------------------------------------------------------------------- /src/images/icon-pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/icon-pen.png -------------------------------------------------------------------------------- /resources/darwin/app.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/darwin/app.icns -------------------------------------------------------------------------------- /src/images/icon-fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/icon-fill.png -------------------------------------------------------------------------------- /src/images/icon-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/icon-import.png -------------------------------------------------------------------------------- /src/images/icon-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/icon-select.png -------------------------------------------------------------------------------- /src/images/cursor-fill-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-fill-0.png -------------------------------------------------------------------------------- /src/images/cursor-fill-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-fill-1.png -------------------------------------------------------------------------------- /src/images/cursor-fill-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-fill-2.png -------------------------------------------------------------------------------- /src/images/cursor-fill-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-fill-3.png -------------------------------------------------------------------------------- /src/images/cursor-pen-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-pen-0.png -------------------------------------------------------------------------------- /src/images/cursor-pen-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-pen-1.png -------------------------------------------------------------------------------- /src/images/cursor-pen-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-pen-2.png -------------------------------------------------------------------------------- /src/images/cursor-pen-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-pen-3.png -------------------------------------------------------------------------------- /src/images/cursor-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-select.png -------------------------------------------------------------------------------- /resources/darwin/dmg_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/darwin/dmg_back.png -------------------------------------------------------------------------------- /resources/darwin/dmg_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/darwin/dmg_back@2x.png -------------------------------------------------------------------------------- /resources/win32/install_anim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/win32/install_anim.gif -------------------------------------------------------------------------------- /src/images/cursor-eyedropper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/src/images/cursor-eyedropper.png -------------------------------------------------------------------------------- /resources/linux/bin/autotrace/autotrace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/linux/bin/autotrace/autotrace -------------------------------------------------------------------------------- /resources/win32/bin/autotrace/autotrace.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/win32/bin/autotrace/autotrace.exe -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/bin/autotrace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/darwin/bin/autotrace/bin/autotrace -------------------------------------------------------------------------------- /resources/linux/bin/autotrace/lib/libpng12.so.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/linux/bin/autotrace/lib/libpng12.so.0 -------------------------------------------------------------------------------- /resources/linux/bin/autotrace/lib/libautotrace.so.3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/linux/bin/autotrace/lib/libautotrace.so.3 -------------------------------------------------------------------------------- /resources/linux/bin/autotrace/lib/libpstoedit.so.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/linux/bin/autotrace/lib/libpstoedit.so.0 -------------------------------------------------------------------------------- /resources/linux/bin/autotrace/lib/libMagickCore-6.Q16.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/linux/bin/autotrace/lib/libMagickCore-6.Q16.so.2 -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/lib/libautotrace.3.0.0.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PancakeBot/PancakePainter/HEAD/resources/darwin/bin/autotrace/lib/libautotrace.3.0.0.dylib -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/lib/pkgconfig/autotrace.pc: -------------------------------------------------------------------------------- 1 | prefix=/usr/local/Cellar/autotrace/0.31.1_2 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: Autotrace 7 | Description: a utility that converts bitmap to vector graphics 8 | Version: 0.31.1 9 | Requires: 10 | Libs: -L${exec_prefix}/lib -lautotrace 11 | Cflags: -I${prefix}/include 12 | -------------------------------------------------------------------------------- /src/images/icon-autotrace-color-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | sass: { // Task 5 | dist: { // Target 6 | options: { // Target options 7 | style: 'expanded' 8 | }, 9 | files: { // Dictionary of files 10 | 'src/styles/index.css': 'src/styles/index.scss' 11 | } 12 | } 13 | } 14 | }); 15 | 16 | grunt.loadNpmTasks('grunt-contrib-sass'); 17 | 18 | 19 | // Default task(s). 20 | grunt.registerTask('default', ['sass']); 21 | }; 22 | -------------------------------------------------------------------------------- /src/windows/window.autotrace.webview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PancakePainter 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/windows/window.export.webview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PancakePainter 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /resources/win32/bin/autotrace/THANKS: -------------------------------------------------------------------------------- 1 | If soneone missing please let me 2 | (Martin Weber ) know. 3 | 4 | --- 5 | Bernhard Herzog (Postscript, svg and sk export filter) 6 | Ian MacPhedran (xfig export filter) 7 | Martin Kroeker (bugfixes) 8 | Tobias Polzin (bugfixes) 9 | Kevin O'Gorman (Shockwave support) 10 | MenTaLguY (png import filter) 11 | Peter Cucka (bugfixes) 12 | Enrico Persiani (emf export) 13 | Johannes Schindelin (Magick import filter) 14 | Masatake YAMATO (library, help with cvs) 15 | Steffen Politzky (dxf export) 16 | David A. Bartold (part of despeckle) 17 | Han-Wen Nienhuys (rpm-spec file) 18 | R. P. C. Rodgers (man page) 19 | Allen Barnett (improved emf export) 20 | Andrew Elia (dr2d export filter) 21 | Ralf Stubner (bugfixes about pstoedit usage) 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # Builds directory 30 | /build/dist 31 | 32 | # App User Settings 33 | settings.json 34 | 35 | # Compiled resource cache (though this is sent out with production versions) 36 | .sass-cache 37 | -------------------------------------------------------------------------------- /src/images/icon-select.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /locales/en-US/menus-en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "creator": "techninja", 4 | "target": "en-US", 5 | "langname": "English", 6 | "release": "1.2.0" 7 | }, 8 | "file": { 9 | "title": "&File", 10 | "new": "&New Project", 11 | "open": "&Open Project", 12 | "close": "&Close Project", 13 | "export": "&Export for printing...", 14 | "exportmirrored": "&Export mirrored for printing...", 15 | "save": "&Save Project", 16 | "saveas": "Save Project &as…" 17 | }, 18 | "edit": { 19 | "title": "Edit", 20 | "undo": "&Undo", 21 | "redo": "&Redo", 22 | "cut": "C&ut", 23 | "copy": "&Copy", 24 | "paste": "&Paste", 25 | "duplicate": "&Duplicate", 26 | "selectall": "Select &All" 27 | }, 28 | "view" : { 29 | "settings": "Advanced Settings" 30 | }, 31 | "mac": { 32 | "about": "About __name__", 33 | "hide": "Hide __name__", 34 | "services": "Services", 35 | "hideothers": "Hide Others", 36 | "show": "Show All", 37 | "quit": "Quit" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/images/icon-import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/include/autotrace/exception.h: -------------------------------------------------------------------------------- 1 | /* exception.h: facility to handle error in autotrace */ 2 | 3 | #ifndef AT_EXCEPTION_H 4 | #define AT_EXCEPTION_H 5 | 6 | #include "autotrace.h" 7 | #include "types.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif /* __cplusplus */ 12 | 13 | /* Protocol: 14 | If a function raises a FATAL(including propagation), 15 | the function must release resources allocated by the 16 | function itself. */ 17 | typedef struct _at_exception_type at_exception_type; 18 | struct _at_exception_type 19 | { 20 | at_msg_type msg_type; 21 | at_msg_func client_func; 22 | at_address * client_data; 23 | }; 24 | 25 | at_exception_type at_exception_new(at_msg_func client_func, 26 | at_address client_data); 27 | at_bool at_exception_got_fatal(at_exception_type * exception); 28 | void at_exception_fatal(at_exception_type * exception, 29 | const at_string message); 30 | void at_exception_warning(at_exception_type * exception, 31 | const at_string message); 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif /* __cplusplus */ 36 | 37 | #endif /* Not def: AT_EXCEPTION_H */ 38 | -------------------------------------------------------------------------------- /src/styles/_loaders.scss: -------------------------------------------------------------------------------- 1 | 2 | .spin-loader { 3 | &, &:after { 4 | border-radius: 50%; 5 | width: 10em; 6 | height: 10em; 7 | } 8 | 9 | margin: 60px auto; 10 | font-size: 10px; 11 | position: relative; 12 | text-indent: -9999em; 13 | border-top: 1.1em solid rgba(255, 255, 255, 0.2); 14 | border-right: 1.1em solid rgba(255, 255, 255, 0.2); 15 | border-bottom: 1.1em solid rgba(255, 255, 255, 0.2); 16 | border-left: 1.1em solid #ffffff; 17 | transform: translateZ(0); 18 | animation: load8 1.1s infinite linear; 19 | } 20 | @keyframes load8 { 21 | 0% { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | 100% { 26 | -webkit-transform: rotate(360deg); 27 | transform: rotate(360deg); 28 | } 29 | } 30 | 31 | .bar-loader { 32 | width: 100%; 33 | height: 25px; 34 | border: 1px solid #2980b9; 35 | border-radius: 3px; 36 | background-image: 37 | repeating-linear-gradient( 38 | -45deg, 39 | #2980b9, 40 | #2980b9 11px, 41 | #eee 10px, 42 | #eee 20px /* determines size */ 43 | ); 44 | background-size: 28px 28px; 45 | animation: move .9s linear infinite; 46 | } 47 | 48 | @keyframes move { 49 | 0% { 50 | background-position: 0 0; 51 | } 52 | 100% { 53 | background-position: 28px 0; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/windows/window.settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file This is the window node module for the advanced settings window 3 | * that supplies init and binding code for the PancakePainter window API. 4 | * Exports function returns a window control object that allows triggering on 5 | * init, show, and hide events. 6 | * We have full access to globals loaded in the mainWindow as needed, just 7 | * reference them below. 8 | **/ 9 | /* globals $, mainWindow */ 10 | 11 | module.exports = function(context) { 12 | var settings = {}; 13 | 14 | function bindButtons() { 15 | $('button', context).click(function() { 16 | switch(this.name) { 17 | case 'done': 18 | mainWindow.overlay.toggleWindow('settings', false); 19 | break; 20 | 21 | case 'reset': 22 | mainWindow.resetSettings(); 23 | break; 24 | } 25 | }); 26 | } 27 | 28 | /** 29 | * Window initialization callback, triggered on window import. 30 | */ 31 | settings.init = function() { 32 | bindButtons(); 33 | }; 34 | 35 | /** 36 | * Window show event callback, triggered on window show. 37 | */ 38 | settings.show = function() { 39 | 40 | }; 41 | 42 | /** 43 | * Window hide event callback, triggered on window close. 44 | */ 45 | settings.hide = function() { 46 | 47 | }; 48 | 49 | return settings; 50 | }; 51 | -------------------------------------------------------------------------------- /menus/menu-init.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Menu "module" handler root. Figures out which menu to display for the 3 | * given operating system and translates keys into labels. 4 | **/ 5 | "use strict"; 6 | module.exports = function menuInit(app) { 7 | var remote = require('electron').remote; 8 | var Menu = remote.Menu; 9 | var i18n = remote.require('i18next'); 10 | var _ = require('underscore'); 11 | 12 | var platform = process.platform; 13 | 14 | // Only 2 supported platforms at the moment 15 | if (platform !== 'win32' && platform !== 'darwin') { 16 | platform = 'win32'; // Default to windows menu 17 | } 18 | 19 | var mainMenu = require('../menus/menu-' + platform)(); 20 | 21 | // Pre-process then apply menu to the window 22 | _.each(mainMenu, function(menu){ 23 | // Translate key to label for top level menus 24 | if (menu.key) menu.label = i18n.t('menus:' + menu.key, menu.var); 25 | 26 | _.each(menu.submenu, function(sub){ 27 | if (sub.key) { 28 | // Translate key to label for submenus 29 | sub.label = i18n.t('menus:' + sub.key, sub.var); 30 | if (!sub.click) { 31 | // Add generic click event only if not already bound 32 | sub.click = function(e) { 33 | app.menuClick(e.key); 34 | }; 35 | } 36 | } 37 | }); 38 | }); 39 | 40 | Menu.setApplicationMenu(Menu.buildFromTemplate(mainMenu)); 41 | }; 42 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PancakePainter 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
v0.0.0
19 |
20 | 21 | 22 |
23 | common.drawnote 24 |
25 | 26 |
27 | 28 |

export.wait

29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/TODO: -------------------------------------------------------------------------------- 1 | Core: 2 | - Speed up 3 | - Improve tracing quality 4 | - Bugs?! 5 | - Recognition of Circle and Ellipse pieces. 6 | - Addition of code to recognize lines, splines and circles even if there is 7 | a lot of noise 8 | - Currently pictures have to fit completely into memory 9 | - New algorithm to work best with anti-aliased pictures 10 | - 3D recognition 11 | - Better list management, that means the current generation of lists is time 12 | consuming and fragmentates the heap. 13 | - Outlines are traced two times that means that it could be faster and if we 14 | trace and fit every outline only once we will not have the problems with 15 | unwanted gaps anymore. 16 | - Better thinning algorithm like CAT (Chordal Axis Transformation) 17 | 18 | Input: 19 | - Migrate to new plug-in interface using glib(0.32.0) 20 | - Support of image libraries as freeimage, gdk-pixbuf or paintlib(0.32.0) 21 | 22 | Output: 23 | - Migrate to new plug-in interface using glib(0.32.0) 24 | - Output API abstraction(0.32.0) 25 | - New export formats like wmf, cdr, cmx, compressed pdf, compressed svg and 26 | dxf with splines... 27 | 28 | Library and its clients: 29 | - Graphical user interface 30 | -- For gnome/gtk+, frontline is under developing. 31 | See http://autotrace.sourceforge.net/frontline 32 | -- For KDE/Qt? 33 | 34 | Misc: 35 | - Gettextize(0.32.0) 36 | - Better documentations 37 | - Predefined parameter system(discussed as aop file, 0.32.0) 38 | -------------------------------------------------------------------------------- /src/styles/_math.scss: -------------------------------------------------------------------------------- 1 | // Math partial SASS 2 | 3 | @function pow($number, $exp) { 4 | $value: 1; 5 | @if $exp > 0 { 6 | @for $i from 1 through $exp { 7 | $value: $value * $number; 8 | } 9 | } 10 | @else if $exp < 0 { 11 | @for $i from 1 through -$exp { 12 | $value: $value / $number; 13 | } 14 | } 15 | @return $value; 16 | } 17 | 18 | @function fact($number) { 19 | $value: 1; 20 | @if $number > 0 { 21 | @for $i from 1 through $number { 22 | $value: $value * $i; 23 | } 24 | } 25 | @return $value; 26 | } 27 | 28 | @function pi() { 29 | @return 3.14159265359; 30 | } 31 | 32 | @function rad($angle) { 33 | $unit: unit($angle); 34 | $unitless: $angle / ($angle * 0 + 1); 35 | // If the angle has 'deg' as unit, convert to radians. 36 | @if $unit == deg { 37 | $unitless: $unitless / 180 * pi(); 38 | } 39 | @return $unitless; 40 | } 41 | 42 | @function sin($angle) { 43 | $sin: 0; 44 | $angle: rad($angle); 45 | // Iterate a bunch of times. 46 | @for $i from 0 through 10 { 47 | $sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1); 48 | } 49 | @return $sin; 50 | } 51 | 52 | @function cos($angle) { 53 | $cos: 0; 54 | $angle: rad($angle); 55 | // Iterate a bunch of times. 56 | @for $i from 0 through 10 { 57 | $cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i); 58 | } 59 | @return $cos; 60 | } 61 | 62 | @function tan($angle) { 63 | @return sin($angle) / cos($angle); 64 | } 65 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/include/autotrace/types.h: -------------------------------------------------------------------------------- 1 | /* types.h: general types 2 | Copyright (C) 2000, 2001 Martin Weber 3 | 4 | The author can be contacted at 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 19 | 20 | #ifndef TYPES_H 21 | #define TYPES_H 22 | 23 | #ifndef __cplusplus 24 | /* Booleans. */ 25 | #ifndef bool 26 | typedef enum { false = 0, true = 1 } at_bool; 27 | #else 28 | #define at_bool bool 29 | #endif 30 | #else 31 | #define at_bool bool 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif /* __cplusplus */ 37 | 38 | /* The usual null-terminated string. */ 39 | typedef char *at_string; 40 | 41 | /* A generic pointer in ANSI C. */ 42 | typedef void *at_address; 43 | 44 | /* We use `real' for our floating-point variables. */ 45 | typedef float at_real; 46 | 47 | /* Cartesian points. */ 48 | typedef struct _at_coord 49 | { 50 | unsigned short x, y; 51 | } at_coord; 52 | 53 | typedef struct _at_real_coord 54 | { 55 | at_real x, y, z; 56 | } at_real_coord; 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif /* __cplusplus */ 61 | 62 | #endif /* not TYPES_H */ 63 | -------------------------------------------------------------------------------- /src/squirrel-update.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs-plus'); 2 | var app = require('electron').app; 3 | 4 | exports.handleStartupEvent = function(app, squirrelCommand) { 5 | if (process.argv.length === 1) { 6 | return false; 7 | } 8 | 9 | const ChildProcess = require('child_process'); 10 | const path = require('path'); 11 | 12 | const appFolder = path.resolve(process.execPath, '..'); 13 | const rootAtomFolder = path.resolve(appFolder, '..'); 14 | const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe')); 15 | const exeName = path.basename(process.execPath); 16 | 17 | const spawn = function(command, args) { 18 | let spawnedProcess, error; 19 | 20 | try { 21 | spawnedProcess = ChildProcess.spawn(command, args, {detached: true}); 22 | } catch (error) {} 23 | 24 | return spawnedProcess; 25 | }; 26 | 27 | const spawnUpdate = function(args) { 28 | return spawn(updateDotExe, args); 29 | }; 30 | 31 | const squirrelEvent = process.argv[1]; 32 | switch (squirrelEvent) { 33 | case '--squirrel-install': 34 | case '--squirrel-updated': 35 | // Optionally do things such as: 36 | // - Add your .exe to the PATH 37 | // - Write to the registry for things like file associations and 38 | // explorer context menus 39 | 40 | // Install desktop and start menu shortcuts 41 | spawnUpdate(['--createShortcut', exeName]); 42 | 43 | setTimeout(app.quit, 1000); 44 | return true; 45 | 46 | case '--squirrel-uninstall': 47 | // Undo anything you did in the --squirrel-install and 48 | // --squirrel-updated handlers 49 | 50 | // Remove desktop and start menu shortcuts 51 | spawnUpdate(['--removeShortcut', exeName]); 52 | 53 | setTimeout(app.quit, 1000); 54 | return true; 55 | 56 | case '--squirrel-obsolete': 57 | // This is called on the outgoing version of your app before 58 | // we update to the new version - it's the opposite of 59 | // --squirrel-updated 60 | 61 | app.quit(); 62 | return true; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /src/windows/window.settings.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

settings.title

5 |
6 |
7 |
8 | settings.gcode.title 9 | 10 |
11 | 00 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 |
21 | 22 |
23 | 00 24 | 25 |
26 | 27 |
28 | 00 29 | 30 |
31 | 32 |
33 | 00 34 | 35 |
36 | 37 |
38 | 00 39 | 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "Promise": true 4 | }, 5 | "esversion" : 6, 6 | "maxerr" : 50, 7 | "bitwise" : true, 8 | "camelcase" : true, 9 | "curly" : false, 10 | "eqeqeq" : true, 11 | "forin" : false, 12 | "freeze" : true, 13 | "immed" : true, 14 | "latedef" : "nofunc", 15 | "newcap" : true, 16 | "noarg" : true, 17 | "noempty" : true, 18 | "nonbsp" : true, 19 | "nonew" : false, 20 | "plusplus" : false, 21 | "quotmark" : false, 22 | "undef" : true, 23 | "unused" : "strict", 24 | "maxparams" : 5, 25 | "maxdepth" : 4, 26 | "maxstatements" : false, 27 | "maxcomplexity" : false, 28 | "maxlen" : 80, 29 | "varstmt" : false, 30 | "asi" : false, 31 | "boss" : false, 32 | "debug" : true, 33 | "eqnull" : false, 34 | "moz" : false, 35 | "evil" : false, 36 | "expr" : false, 37 | "funcscope" : false, 38 | "iterator" : false, 39 | "lastsemic" : false, 40 | "laxbreak" : false, 41 | "laxcomma" : false, 42 | "loopfunc" : false, 43 | "multistr" : false, 44 | "noyield" : false, 45 | "notypeof" : false, 46 | "proto" : false, 47 | "scripturl" : false, 48 | "shadow" : false, 49 | "sub" : false, 50 | "supernew" : false, 51 | "validthis" : false, 52 | 53 | "browser" : false, 54 | "browserify" : false, 55 | "couch" : false, 56 | "devel" : true, 57 | "dojo" : false, 58 | "jasmine" : false, 59 | "jquery" : false, 60 | "mocha" : true, 61 | "mootools" : false, 62 | "node" : true, 63 | "nonstandard" : false, 64 | "phantom" : false, 65 | "prototypejs" : false, 66 | "qunit" : false, 67 | "rhino" : false, 68 | "shelljs" : false, 69 | "typed" : false, 70 | "worker" : false, 71 | "wsh" : false, 72 | "yui" : false 73 | } 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PancakePainter", 3 | "version": "1.4.0", 4 | "description": "A simple drawing application and GCODE generator for the PancakeBot", 5 | "main": "src/main.js", 6 | "author": "techninja", 7 | "stage": "development", 8 | "electronVersion": "1.0.1", 9 | "license": "Apache-2.0", 10 | "copyright": "Copyright (C) PancakeBot Inc., all rights reserved. Code under Apache v2.0 free and open source license.", 11 | "releaseInfo": { 12 | "description": "Interactive drawing software to create pancake images for your PancakeBot. See more about the PancakeBot @ http://pancakebot.com or Fork & improve the project @ https://github.com/PancakeBot/PancakePainter", 13 | "company": "StoreBound LLC.", 14 | "appName": "PancakePainter", 15 | "copyright": "PancakeBot & PancakePainter names copyright © PancakeBot LLC, all rights reserved. Code under Apache v2.0 free and open source license.", 16 | "categories": [ 17 | "Utility", 18 | "Graphics", 19 | "Education" 20 | ] 21 | }, 22 | "iconURL": "http://raw.githubusercontent.com/PancakeBot/PancakePainter/master/resources/win32/app.ico", 23 | "scripts": { 24 | "start": "electron .", 25 | "test": "jshint src/**/*.js menus/*.js --exclude=node_modules/*,/src/libs/*", 26 | "watch": "sass --watch src/styles/index.scss:src/styles/index.css" 27 | }, 28 | "dependencies": { 29 | "autotrace": "0.0.2", 30 | "datauri": "^0.7.1", 31 | "electron-canvas-to-buffer": "^2.0.0", 32 | "electron-squirrel-startup": "^1.0.0", 33 | "fs-plus": "^2.8.1", 34 | "grunt": "^0.4.5", 35 | "grunt-contrib-sass": "^0.9.2", 36 | "i18next": "^1.10.4", 37 | "jimp": "^0.2.27", 38 | "jquery": "^2.2.4", 39 | "n-dimensional-flood-fill": "^1.0.0", 40 | "ndarray": "^1.0.18", 41 | "paper": "0.10.2", 42 | "progress-promise": "0.0.5", 43 | "rangeslider.js": "^2.1.1", 44 | "toastr": "^2.1.2", 45 | "underscore": "^1.8.3" 46 | }, 47 | "repository": { 48 | "type": "git", 49 | "url": "https://github.com/PancakeBot/PancakePainter.git" 50 | }, 51 | "devDependencies": { 52 | "electron-prebuilt": "1.0.1", 53 | "jshint": "^2.9.2" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/helpers/helper.clipboard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file This is a helper include for adding clipboard (copy/cut/paste/dupe) 3 | * support. 4 | **/ 5 | "use strict"; 6 | /*globals _ */ 7 | 8 | module.exports = function(paper) { 9 | var clipboard = {}; 10 | 11 | var view = paper.view; 12 | var project = paper.project; 13 | var Point = paper.Point; 14 | 15 | // Array of paths to paste during a cut/copy. 16 | clipboard.data = []; 17 | 18 | /** 19 | * "Clipboard" copy: Duplicate a path selection into the data space. 20 | * 21 | * @param {boolean} deleteSelection 22 | * Pass true to delete the selection after copying. 23 | * 24 | * @return {undefined} 25 | */ 26 | clipboard.copy = function(deleteSelection) { 27 | if (paper.selectRect) { 28 | clipboard.data = []; 29 | _.each(paper.selectRect.ppaths, function(path){ 30 | clipboard.data.push(path.clone(false)); 31 | if (deleteSelection) path.remove(); 32 | }); 33 | 34 | if (deleteSelection) { 35 | paper.fileChanged(); 36 | paper.deselect(); 37 | view.update(); 38 | } 39 | } 40 | }; 41 | 42 | /** 43 | * "Clipboard" paste: Duplicate and offset the paths saved in the data space. 44 | * 45 | * @return {undefined} 46 | */ 47 | clipboard.paste = function() { 48 | if (clipboard.data.length) { 49 | // Deselect when pasting. 50 | paper.deselect(); 51 | 52 | // Clone each path, put in the layer, offset it, and add to selection. 53 | _.each(clipboard.data, function(path){ 54 | var pathCopy = path.clone(false); 55 | project.activeLayer.addChild(pathCopy); 56 | pathCopy.translate(new Point(25, 25)); 57 | paper.selectAdd(pathCopy); 58 | }); 59 | 60 | paper.fileChanged(); 61 | view.update(); 62 | } 63 | }; 64 | 65 | /** 66 | * "Clipboard" duplication: Duplicate selected paths w/out saving data. 67 | * 68 | * @return {undefined} 69 | */ 70 | clipboard.dupe = function() { 71 | if (paper.selectRect) { 72 | var newPaths = []; 73 | _.each(paper.selectRect.ppaths, function(path){ 74 | newPaths.push(path.clone(true)); 75 | }); 76 | 77 | // Deselect to clear for selecting the new paths. 78 | paper.deselect(); 79 | 80 | _.each(newPaths, function(path){ 81 | path.translate(new Point(25, 25)); 82 | paper.selectAdd(path); 83 | }); 84 | 85 | paper.fileChanged(); 86 | view.update(); 87 | } 88 | }; 89 | 90 | return clipboard; 91 | }; 92 | -------------------------------------------------------------------------------- /src/images/icon-autotrace-color-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /menus/menu-win32.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Menu "module", provides menu for Windows/win32 only. 3 | */ 4 | "use strict"; 5 | module.exports = function applyTemplate() { 6 | var remote = require('electron').remote; 7 | var BrowserWindow = remote.BrowserWindow; 8 | 9 | var template = [ 10 | { 11 | key: 'file.title', 12 | submenu: [ 13 | { 14 | key: 'file.new', 15 | accelerator: 'Control+N' 16 | }, 17 | { 18 | key: 'file.open', 19 | accelerator: 'o' 20 | }, 21 | { 22 | type: 'separator' 23 | }, 24 | { 25 | key: 'file.close', 26 | accelerator: 'Control+W' 27 | }, 28 | { 29 | type: 'separator' 30 | }, 31 | { 32 | key: 'file.export', 33 | accelerator: 'Control+E' 34 | }, 35 | { 36 | key: 'file.save', 37 | accelerator: 'Control+S' 38 | }, 39 | { 40 | key: 'file.saveas', 41 | accelerator: 'Control+Shift+S' 42 | } 43 | ] 44 | }, 45 | { 46 | key: 'edit.title', 47 | submenu: [ 48 | { 49 | key: 'edit.undo', 50 | accelerator: 'Control+z' 51 | }, 52 | { 53 | key: 'edit.redo', 54 | accelerator: 'Control+Shift+z' 55 | }, 56 | { 57 | type: 'separator' 58 | }, 59 | { 60 | key: 'edit.cut', 61 | accelerator: 'Control+x' 62 | }, 63 | { 64 | key: 'edit.copy', 65 | accelerator: 'Control+c' 66 | }, 67 | { 68 | key: 'edit.paste', 69 | accelerator: 'Control+v' 70 | }, 71 | { 72 | key: 'edit.duplicate', 73 | accelerator: 'Control+d' 74 | }, 75 | { 76 | type: 'separator' 77 | }, 78 | { 79 | key: 'edit.selectall', 80 | accelerator: 'Control+a' 81 | } 82 | ] 83 | }, 84 | { 85 | label: 'View', 86 | submenu: [ 87 | { 88 | key: 'view.settings', 89 | accelerator: 'Shift+Alt+S' 90 | }, 91 | { 92 | label: 'Reload', 93 | accelerator: 'Control+R', 94 | click: function () { 95 | BrowserWindow.getFocusedWindow().reloadIgnoringCache(); 96 | } 97 | }, 98 | { 99 | label: 'Toggle DevTools', 100 | accelerator: 'Alt+Control+I', 101 | click: function () { 102 | BrowserWindow.getFocusedWindow().toggleDevTools(); 103 | } 104 | } 105 | ] 106 | } 107 | ]; 108 | 109 | return template; 110 | }; 111 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/include/autotrace/input.h: -------------------------------------------------------------------------------- 1 | /* input.h: interface for input handlers 2 | 3 | Copyright (C) 1999, 2000, 2001 Bernhard Herzog. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public License 7 | as published by the Free Software Foundation; either version 2.1 of 8 | the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, but 11 | WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 | USA. */ 19 | 20 | #ifndef INPUT_H 21 | #define INPUT_H 22 | #include "types.h" 23 | #include "autotrace.h" 24 | #include "exception.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif /* __cplusplus */ 29 | 30 | /* Input handler should be implemented with using 31 | following functions and macros. */ 32 | 33 | /* at_input_add_handler 34 | Register an input handler to autotrace. */ 35 | extern int at_input_add_handler (at_string suffix, 36 | at_string description, 37 | at_input_read_func func); 38 | 39 | /* at_bitmap_init 40 | Return initialized at_bitmap_type value. 41 | 42 | args: 43 | AREA is used as a storage of returned value. 44 | If AREA is NULL, the storage is newly allocated 45 | by at_bitmap_init. In such case the size of storage 46 | is automatically calculated by WIDTH, HEIGHT and PLANES. 47 | 48 | PLANES must be 1(gray scale) or 3(RGB color). 49 | 50 | return value: 51 | The return value is not newly allocated. 52 | Only the storage is allocated if AREA is NULL. 53 | On the other hand, at_bitmap_new allocates 54 | mem for at_bitmap_type; and returns a pointer 55 | for the mem. 56 | at_bitmap_new is for autotrace library user. 57 | at_bitmap_init is for input-handler developer. 58 | Don't use at_bitmap_new in your input-handler. */ 59 | extern at_bitmap_type at_bitmap_init(unsigned char * area, 60 | unsigned short width, 61 | unsigned short height, 62 | unsigned int planes); 63 | 64 | /* TODO: free storage */ 65 | 66 | /* The number of color planes of each pixel */ 67 | #define AT_BITMAP_PLANES(b) ((b).np) 68 | 69 | /* The pixels, represented as an array of bytes (in contiguous storage). 70 | Each pixel is represented by np bytes. */ 71 | #define AT_BITMAP_BITS(b) ((b).bitmap) 72 | 73 | /* These are convenient abbreviations for geting inside the members. */ 74 | #define AT_BITMAP_WIDTH(b) ((b).width) 75 | #define AT_BITMAP_HEIGHT(b) ((b).height) 76 | 77 | /* This is the pixel at [ROW,COL]. */ 78 | #define AT_BITMAP_PIXEL(b, row, col) \ 79 | ((AT_BITMAP_BITS (b) + (row) * AT_BITMAP_PLANES (b) * AT_BITMAP_WIDTH (b) \ 80 | + (col) * AT_BITMAP_PLANES(b))) 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif /* __cplusplus */ 85 | 86 | #endif /* Not def: INPUT_H */ 87 | -------------------------------------------------------------------------------- /src/styles/_trace-menu.scss: -------------------------------------------------------------------------------- 1 | // Trace menu. 2 | 3 | @import 'math'; 4 | 5 | // vars 6 | $fg:#ff0000; 7 | $pi:3.14; 8 | 9 | // config 10 | $menu-items:3; 11 | $open-distance:120px; 12 | $opening-angle:$pi - 1.2; 13 | 14 | 15 | %ball { 16 | $size: 65px; 17 | border-radius:100%; 18 | width:$size; 19 | height:$size; 20 | position:absolute; 21 | color:white; 22 | text-align:center; 23 | line-height:$size; 24 | transform:translate3d(0,0,0); 25 | transition:all ease-out 200ms; 26 | } 27 | 28 | .menu-open { 29 | display:none; 30 | } 31 | 32 | .menu-item { 33 | @extend %ball; 34 | top: 8px; 35 | } 36 | 37 | .menu { 38 | box-sizing:border-box; 39 | font-size:20px; 40 | text-align:left; 41 | //background-color: purple; // Debug mouseoff area. 42 | } 43 | 44 | .menu.nav-open { 45 | $margin: 100px; 46 | width:280px; 47 | height:210px; 48 | margin-left: -$margin; 49 | padding-left: $margin; 50 | } 51 | 52 | .menu-item{ 53 | overflow: hidden; 54 | &:hover{ 55 | background:white; 56 | color:$fg; 57 | } 58 | @for $i from 1 through $menu-items{ 59 | &:nth-child(#{$i+2}){ 60 | transition-duration:10ms+(60ms*($i)); 61 | } 62 | } 63 | 64 | i { 65 | display: inline-block; 66 | width: 100%; 67 | height: 100%; 68 | background-size: 100%; 69 | background-position: center; 70 | background-repeat: no-repeat; 71 | transition:all ease-out 200ms; 72 | 73 | &.manual { 74 | background-image: url("../images/icon-manual.svg"); 75 | } 76 | &.simple { 77 | background-image: url("../images/icon-autotrace-simple.svg"); 78 | } 79 | &.complex { 80 | background-image: url("../images/icon-autotrace-complex.svg"); 81 | } 82 | } 83 | } 84 | 85 | .menu-open-button{ 86 | @extend %ball; 87 | width: 80px; 88 | height: 80px; 89 | background-color: transparent; 90 | background-position: -1px; 91 | background-image: url("../images/icon-import.png"); 92 | background-size: 160px; 93 | z-index:2; 94 | transition-timing-function:cubic-bezier(0.175, 0.885, 0.320, 1.275); 95 | transition-duration:400ms; 96 | transform:scale(1.1,1.1) translate3d(0,0,0); 97 | cursor:pointer; 98 | } 99 | .menu-open-button:hover{ 100 | transform:scale(1.2,1.2) translate3d(0,0,0); 101 | } 102 | .menu-open:checked+.menu-open-button{ 103 | transition-timing-function:linear; 104 | transition-duration:200ms; 105 | transform:scale(0.8,0.8) translate3d(0,0,0); 106 | } 107 | 108 | .menu-open:checked~.menu-item{ 109 | width: 80px; 110 | height: 80px; 111 | background:$fg; 112 | transition-timing-function:cubic-bezier(0.935, 0.000, 0.340, 1.330); 113 | @for $i from 1 through $menu-items{ 114 | $angle:(($pi - $opening-angle)/2)+(($opening-angle/($menu-items - 1))*($i - 1)); 115 | 116 | &:nth-child(#{$i+2}){ 117 | transition-duration:80ms+(80ms*$i); 118 | transform:translate3d(cos($angle)*$open-distance,sin($angle)*$open-distance,0); 119 | } 120 | } 121 | 122 | &:hover { 123 | margin-top: -20px; 124 | margin-left: -20px; 125 | width: 120px; 126 | height: 120px; 127 | background:white; 128 | 129 | i { 130 | background-size: 87%; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/NEWS: -------------------------------------------------------------------------------- 1 | What's new in AutoTrace 0.31.1? 2 | - fixed compile time error appeared when an user 3 | specifies --without-pstoedit option(Ralf Stubner). 4 | - fixed a bug related to centerline tracing(Martin). 5 | - fixed bugs in dr2d output and dxf output(Martin). 6 | - changed the name of tracing option structure 7 | field(width_weight_factor)(Masatake). This means 8 | source compatibility is broken. 9 | 10 | What's new in AutoTrace 0.31.0? 11 | (This NEWS items are the summary of changed from 0.30.1 to 0.30.8. 12 | For more detail, see ChangeLog.) 13 | - improved interface between pstoedit and autotrace 14 | - added library level pstoedit support 15 | - built autotrace library as a shared library 16 | - corrected output when background-color is used 17 | - changing the license of sources files input and output 18 | to GNU Lesser Public License(LGPL) 19 | - checking libautotrace version number in autotrace.m4 20 | - output in dr2d format(Andrew Elia) 21 | - introduced config.h 22 | - corrected thin-image 23 | - made more portable 24 | - corrected a bug in fitting 25 | - now recognizes line width 26 | 27 | What's new in AutoTrace 0.30.8? 28 | - added variable line width in centerline tracing(--width-factor, --preserve-width) 29 | autotrace library API is changed. 30 | - fixed memory leaks 31 | - many bugs fixes 32 | 33 | What's new in AutoTrace 0.30.6? 34 | - added workaround for a compile time error that appears when 35 | autotrace is linked to pstoedit-3.32.0. 36 | - made code that creates temporary file more portable. 37 | 38 | What's new in AutoTrace 0.30.5? 39 | - fixed a compile time error that appears when autotrace 40 | is not linked to pstoedit. 41 | 42 | What's new in AutoTrace 0.30.4? 43 | - fixed a bug reported by Gerhard Gaussling 44 | - improved the interface between pstoedit and autotrace 45 | 46 | What's new in AutoTrace 0.30.2? 47 | - added library level pstoedit support 48 | - built autotrace library as a shared library 49 | 50 | What's new in AutoTrace 0.30.1? 51 | - corrected output when background-color is used 52 | - changing the license of sources files input and output 53 | to GNU Lesser Public License(LGPL) 54 | - checking libautotrace version number in autotrace.m4 55 | - output in dr2d format(Andrew Elia) 56 | - introduced config.h 57 | 58 | What's new in AutoTrace 0.30? 59 | - fixed some bugs in the filtering routine 60 | - fixed pdf export 61 | - fixed despeckle 62 | - fixed emf export 63 | - better error handling mechanism 64 | - rpm spec file template(Han-Wen Nienhuys) 65 | - pkgconfig support 66 | - man page (R. P. C. Rodgers) 67 | 68 | What's new in AutoTrace 0.29? 69 | - Small bug fix for binary output 70 | - code rearrangements 71 | - CGM and MIF export 72 | - fixes the lowercase/uppercase problems 73 | - fix for swf export 74 | 75 | What's new in AutoTrace 0.28? 76 | - Several bug fixes 77 | - Progress bar 78 | - Cancel point 79 | - Efforts to make libautotrace.a thread-safe 80 | - Clean up library name space (all exported symbols have "at_" prefix) 81 | - DXF, EPD and PDF export 82 | - Despeckling filter 83 | 84 | What's new in AutoTrace 0.27? 85 | - Parts of the code were rearranged 86 | - Fixed a bug in color quantization 87 | - Centerline support 88 | - Elastic Reality output 89 | - Now works with new versions of ImageMagick 90 | - Swf output(via libming. You can get libming from 91 | http://www.opaque.net/ming/) 92 | - The dxf output was removed because it never worked. 93 | - Speed up and simplification of the fitting routine 94 | -------------------------------------------------------------------------------- /src/helpers/helper.undo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file This is a helper include for adding undo/redo functionality for the 3 | * Paper.JS canvas drawing area. 4 | **/ 5 | 6 | module.exports = function(paper) { 7 | var undo = {}; 8 | var project = paper.project; 9 | var view = paper.view; 10 | 11 | undo.options = { 12 | undoLevels: 20 13 | }; 14 | 15 | // Define the undo object's storage and methods. 16 | undo.data = []; 17 | undo.index = 0; // The index of undo, almost always 0 (the tip of changes). 18 | 19 | /** 20 | * Trigger a state change, and save it to the undo history list. 21 | * @return {undefined} 22 | */ 23 | undo.stateChanged = function(){ 24 | // If we're not at the tip of the undo, this now becomes the new tip, 25 | // erasing the data in front of it. 26 | if (this.index !== 0) { 27 | this.data.splice(0, this.index); 28 | this.index = 0; 29 | } 30 | 31 | // Add the new data to the beggining of the array. 32 | this.data.unshift(this.getState()); 33 | 34 | // When we have more data than we should, trim it off the end. 35 | if (this.data.length > this.options.undoLevels) { 36 | this.data.splice(-1, 1); 37 | } 38 | }; 39 | 40 | /** 41 | * Clear the state of the undo history completely, on new document or open. 42 | * @return {undefined} 43 | */ 44 | undo.clearState = function() { 45 | this.data = []; 46 | this.index = 0; 47 | this.stateChanged(); 48 | }; 49 | 50 | /** 51 | * Move backwards in the undo history from current index until end of history 52 | * @return {undefined} 53 | */ 54 | undo.goBack = function() { 55 | // Can't go past the length of the data we have. 56 | if (this.index < this.data.length - 1) { 57 | this.index++; 58 | this.setState(); 59 | } 60 | }; 61 | 62 | /** 63 | * Move forward in the undo history from current index until start of history 64 | * @return {undefined} 65 | */ 66 | undo.goForward = function() { 67 | // Can't go past the length of the data we have. 68 | if (this.index > 0) { 69 | this.index--; 70 | this.setState(); 71 | } 72 | }; 73 | 74 | /** 75 | * Get the current JSON "state" dump of the image, manages selections. 76 | * 77 | * @return {string} 78 | * JSON content of the entire canvas & layers to be read back by setState. 79 | */ 80 | undo.getState = function() { 81 | paper.deselect(true); 82 | var state = project.exportJSON(); 83 | 84 | paper.reselect(); 85 | return state; 86 | }; 87 | 88 | /** 89 | * Set the state of the canvas to the current index of the undo dataset. 90 | * @return {undefined} 91 | */ 92 | undo.setState = function() { 93 | paper.emptyProject(); 94 | project.importJSON(this.data[this.index]); 95 | 96 | paper.imageLayer = project.layers[0]; 97 | paper.mainLayer = project.layers[1]; 98 | paper.mainLayer.activate(); 99 | 100 | // Reinstate traceImage, if any. 101 | if (paper.imageLayer.children.length) { 102 | paper.traceImage = paper.imageLayer.children[0]; 103 | paper.traceImage.img = paper.traceImage.children[0]; 104 | } 105 | 106 | view.update(); 107 | }; 108 | 109 | // Set the initial state! 110 | undo.stateChanged(); 111 | 112 | // Give the main object back to the parent module. 113 | return undo; 114 | }; 115 | -------------------------------------------------------------------------------- /src/images/icon-autotrace-color-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 20 | 31 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/images/icon-pen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 13 | 14 | 15 | 17 | 20 | 21 | 22 | 24 | 27 | 28 | 29 | 31 | 34 | 35 | 36 | 37 | 38 | 40 | 43 | 44 | 45 | 47 | 50 | 51 | 52 | 54 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/styles/_fancy-elements.scss: -------------------------------------------------------------------------------- 1 | // Styles for fancy sliders, buttons & inputs. 2 | 3 | // Fancy button ================================================================ 4 | button.fancy{ 5 | cursor: pointer; 6 | display: inline-block; 7 | border:1px solid #439E2C; 8 | color: #fff; 9 | border-radius: 7px; 10 | font-family: Arial; 11 | width: auto; 12 | height: auto; 13 | font-size: 1.3em; 14 | padding: 0.15em 1em; 15 | box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.59); 16 | background-image: linear-gradient(to top, #1D612F, #36943F); 17 | 18 | &:hover, &:active{ 19 | border:1px solid #0dff00; 20 | color: #fff; 21 | background-image: linear-gradient(to top, #2d9448, #4cc757); 22 | } 23 | } 24 | 25 | button.fancy.orange{ 26 | border:1px solid #c87140; 27 | color: #ffffff; 28 | background-image: linear-gradient(to top, #d1831c, #b65800); 29 | 30 | &:hover, &:active{ 31 | border:1px solid #cb9c41; 32 | color: #fff; 33 | background-image: linear-gradient(to top, #ee9e33, #e08631); 34 | } 35 | } 36 | 37 | button.fancy.red{ 38 | border:1px solid #a8685c; 39 | color: #4e4d4d; 40 | background-image: linear-gradient(to top, #d4cbcb, #e7cfcf); 41 | 42 | &:hover, &:active { 43 | border:1px solid #cb4141; 44 | color: #fff; 45 | background-image: linear-gradient(to top, #611d1d, #943636); 46 | } 47 | } 48 | 49 | // X to close button. ========================================================== 50 | button.x-close { 51 | cursor: pointer; 52 | position: absolute; 53 | right: 0.5em; 54 | top: 0.5em; 55 | border: none; 56 | font-size: 1.3em; 57 | color: #E21A1A; 58 | background-color: #bdbdbd; 59 | font-weight: bold; 60 | 61 | &:hover, &:active { 62 | color: #bdbdbd; 63 | background-color: #E21A1A; 64 | } 65 | 66 | } 67 | 68 | // Fancy iOS8 Checkbox ========================================================= 69 | input.fancy[type="checkbox"] { 70 | position: absolute; 71 | opacity: 0; 72 | 73 | &:disabled{ 74 | &+ div { 75 | opacity: 0.8; 76 | background-image: linear-gradient(90deg, #add5ac 50%, transparent 50%); 77 | } 78 | 79 | &:checked + div { 80 | border: 2px solid #add5ac; 81 | } 82 | } 83 | 84 | &:checked + div { 85 | padding-left: 1em; width: 1em; 86 | background-position: 0 0; 87 | border: 2px solid #64bd63; 88 | } 89 | 90 | &+ div { 91 | cursor: pointer; 92 | display: inline-block; 93 | vertical-align: middle; 94 | width: 2em; height: 1em; 95 | border: 2px solid rgba(0,0,0,.3); 96 | border-radius: 999px; 97 | background: white; 98 | background-image: linear-gradient(90deg, #64bd63 50%, transparent 50%); 99 | background-size: 200% 100%; 100 | background-position: 100% 0; 101 | background-origin: border-box; 102 | background-clip: border-box; 103 | overflow: hidden; 104 | transition-duration: .2s; 105 | transition-property: padding, width, background-position, text-indent; 106 | font-size: 112%; /* change this and see how they adjust! */ 107 | 108 | &:before { 109 | content: ' '; 110 | float: left; 111 | width: 1.65em; height: 1.65em; 112 | margin: -.1em; 113 | border: 1px solid rgba(0,0,0,.35); 114 | border-radius: inherit; 115 | background: white; 116 | background-color: white; 117 | box-shadow: 0 .1em .1em .1em hsla(0,0%,100%,.8) inset, 118 | 0 0 .5em rgba(0,0,0,.3); 119 | color: white; 120 | text-shadow: 0 -1px 1px rgba(0,0,0,.3); 121 | text-indent: -2.5em; 122 | } 123 | } 124 | 125 | &:active + div:before { 126 | background-color: #eee; 127 | } 128 | 129 | &:focus + div { 130 | box-shadow: 0 .1em .1em rgba(0,0,0,.2) inset, 131 | 0 .45em 0 .1em rgba(0,0,0,.05) inset, 132 | 0 0 .4em 1px rgba(255,0,0,.5); 133 | } 134 | 135 | &+ div:before, &+ div:after { 136 | font: bold 60%/1.9 sans-serif; 137 | text-transform: uppercase; 138 | } 139 | 140 | &+ div:after { 141 | content: ' '; 142 | float: left; 143 | text-indent: .5em; 144 | color: rgba(0,0,0,.45); 145 | text-shadow: none; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/include/autotrace/output.h: -------------------------------------------------------------------------------- 1 | /* output.h: interface for output handlers 2 | 3 | Copyright (C) 1999, 2000, 2001, 2002 Bernhard Herzog. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public License 7 | as published by the Free Software Foundation; either version 2.1 of 8 | the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, but 11 | WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 | USA. */ 19 | 20 | #ifndef OUTPUT_H 21 | #define OUTPUT_H 22 | #include 23 | #include "autotrace.h" 24 | #include "types.h" 25 | #include "exception.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif /* __cplusplus */ 30 | 31 | /* Data struct hierarchy: 32 | spline_list_array (splines) 33 | -> spline_list... 34 | --> spline */ 35 | 36 | /* Accessors to the Data member */ 37 | #define AT_SPLINE_START_POINT_VALUE(spl) ((spl).v[0]) 38 | #define AT_SPLINE_CONTROL1_VALUE(spl) ((spl).v[1]) 39 | #define AT_SPLINE_CONTROL2_VALUE(spl) ((spl).v[2]) 40 | #define AT_SPLINE_END_POINT_VALUE(spl) ((spl).v[3]) 41 | #define AT_SPLINE_DEGREE_VALUE(spl) ((spl).degree) 42 | 43 | #define AT_SPLINE_START_POINT(spl) (&AT_SPLINE_START_POINT_VALUE(*(spl))) 44 | #define AT_SPLINE_CONTROL1(spl) (&AT_SPLINE_CONTROL1_VALUE(*(spl))) 45 | #define AT_SPLINE_CONTROL2(spl) (&AT_SPLINE_CONTROL2_VALUE(*(spl))) 46 | #define AT_SPLINE_END_POINT(spl) (&AT_SPLINE_END_POINT_VALUE(*(spl))) 47 | #define AT_SPLINE_DEGREE(spl) AT_SPLINE_DEGREE_VALUE(*(spl)) 48 | 49 | #define AT_SPLINE_LIST_LENGTH_VALUE(spll) ((spll).length) 50 | #define AT_SPLINE_LIST_LENGTH(spll) AT_SPLINE_LIST_LENGTH_VALUE(*(spll)) 51 | #define AT_SPLINE_LIST_DATA_VALUE(spll) ((spll).data) 52 | #define AT_SPLINE_LIST_DATA(spll) AT_SPLINE_LIST_DATA_VALUE((*spll)) 53 | #define AT_SPLINE_LIST_ELT_VALUE(spll,index) AT_SPLINE_LIST_DATA_VALUE(spll)[(index)] 54 | #define AT_SPLINE_LIST_ELT(spll,index) (&(AT_SPLINE_LIST_ELT_VALUE((*spll), (index)))) 55 | #define AT_SPLINE_LIST_COLOR_VALUE(spll) ((spll).color) 56 | #define AT_SPLINE_LIST_COLOR(spll) (&(AT_SPLINE_LIST_COLOR_VALUE(*spll))) 57 | #define AT_SPLINE_LIST_IS_OPENED_VALUE(spll) ((spll).open) 58 | #define AT_SPLINE_LIST_IS_OPENED(spll) AT_SPLINE_LIST_IS_OPENED_VALUE(*(spll)) 59 | 60 | #define AT_SPLINE_LIST_ARRAY_LENGTH_VALUE AT_SPLINE_LIST_LENGTH_VALUE 61 | #define AT_SPLINE_LIST_ARRAY_LENGTH AT_SPLINE_LIST_LENGTH 62 | #define AT_SPLINE_LIST_ARRAY_ELT_VALUE AT_SPLINE_LIST_ELT_VALUE 63 | #define AT_SPLINE_LIST_ARRAY_ELT AT_SPLINE_LIST_ELT 64 | 65 | #define AT_SPLINE_LIST_ARRAY_IS_CENTERLINE_VALUE(splla) ((splla).centerline) 66 | #define AT_SPLINE_LIST_ARRAY_IS_CENTERLINE(splla) AT_SPLINE_LIST_ARRAY_IS_CENTERLINE_VALUE(*(splla)) 67 | 68 | /* 69 | * Glib style traversing 70 | */ 71 | 72 | typedef void (* AtSplineListForeachFunc) (at_spline_list_type * spline_list, 73 | at_spline_type * spline, 74 | int index, 75 | at_address user_data); 76 | typedef void (* AtSplineListArrayForeachFunc) (at_spline_list_array_type * spline_list_array, 77 | at_spline_list_type * spline_list, 78 | int index, 79 | at_address user_data); 80 | 81 | void at_spline_list_foreach (at_spline_list_type *, 82 | AtSplineListForeachFunc func, 83 | at_address user_data); 84 | void at_spline_list_array_foreach (at_spline_list_array_type *, 85 | AtSplineListArrayForeachFunc func, 86 | at_address user_data); 87 | 88 | int at_output_add_handler (at_string suffix, 89 | at_string description, 90 | at_output_write_func func); 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif /* __cplusplus */ 95 | 96 | #endif /* not OUTPUT_H */ 97 | -------------------------------------------------------------------------------- /src/images/griddle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /menus/menu-darwin.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Menu "module", provides menu for Mac/darwin only. 3 | */ 4 | "use strict"; 5 | module.exports = function applyTemplate() { 6 | var remote = require('electron').remote; 7 | var app = remote.app; 8 | var BrowserWindow = remote.BrowserWindow; 9 | var path = require('path'); 10 | var packageData = require(path.join(app.getAppPath(), 'package.json')); 11 | var appName = packageData.name; 12 | 13 | var template = [ 14 | { 15 | label: appName, 16 | submenu: [ 17 | { 18 | key: 'mac.about', 19 | var: {name: appName}, 20 | selector: 'orderFrontStandardAboutPanel:' 21 | }, 22 | { 23 | type: 'separator' 24 | }, 25 | { 26 | key: 'mac.services', 27 | submenu: [] 28 | }, 29 | { 30 | type: 'separator' 31 | }, 32 | { 33 | key: 'mac.hide', 34 | var: {name: appName}, 35 | accelerator: 'Command+H', 36 | selector: 'hide:' 37 | }, 38 | { 39 | key: 'mac.hideothers', 40 | accelerator: 'Command+Shift+H', 41 | selector: 'hideOtherApplications:' 42 | }, 43 | { 44 | key: 'mac.show', 45 | selector: 'unhideAllApplications:' 46 | }, 47 | { 48 | type: 'separator' 49 | }, 50 | { 51 | key: 'mac.quit', 52 | accelerator: 'Command+Q', 53 | click: function () { 54 | app.quit(); 55 | } 56 | } 57 | 58 | ] 59 | }, 60 | { 61 | key: 'file.title', 62 | submenu: [ 63 | { 64 | key: 'file.new', 65 | accelerator: 'Command+N' 66 | }, 67 | { 68 | key: 'file.open', 69 | accelerator: 'o' 70 | }, 71 | { 72 | type: 'separator' 73 | }, 74 | { 75 | key: 'file.close', 76 | accelerator: 'Command+W' 77 | }, 78 | { 79 | type: 'separator' 80 | }, 81 | { 82 | key: 'file.export', 83 | accelerator: 'Command+E' 84 | }, 85 | { 86 | key: 'file.save', 87 | accelerator: 'Command+S' 88 | }, 89 | { 90 | key: 'file.saveas', 91 | accelerator: 'Command+Shift+S' 92 | } 93 | ] 94 | }, 95 | { 96 | key: 'edit.title', 97 | submenu: [ 98 | { 99 | key: 'edit.undo', 100 | accelerator: 'Command+z' 101 | }, 102 | { 103 | key: 'edit.redo', 104 | accelerator: 'Command+Shift+z' 105 | }, 106 | { 107 | type: 'separator' 108 | }, 109 | { 110 | key: 'edit.cut', 111 | accelerator: 'Command+x' 112 | }, 113 | { 114 | key: 'edit.copy', 115 | accelerator: 'Command+c' 116 | }, 117 | { 118 | key: 'edit.paste', 119 | accelerator: 'Command+v' 120 | }, 121 | { 122 | key: 'edit.duplicate', 123 | accelerator: 'Command+d' 124 | }, 125 | { 126 | type: 'separator' 127 | }, 128 | { 129 | key: 'edit.selectall', 130 | accelerator: 'Command+a' 131 | } 132 | ] 133 | }, 134 | { 135 | label: 'View', 136 | submenu: [ 137 | { 138 | key: 'view.settings', 139 | accelerator: 'Shift+Alt+S' 140 | }, 141 | { 142 | label: 'Reload', 143 | accelerator: 'Command+R', 144 | click: function () { 145 | BrowserWindow.getFocusedWindow().reloadIgnoringCache(); 146 | } 147 | }, 148 | { 149 | label: 'Toggle DevTools', 150 | accelerator: 'Alt+Command+I', 151 | click: function () { 152 | BrowserWindow.getFocusedWindow().toggleDevTools(); 153 | } 154 | } 155 | ] 156 | }, 157 | { 158 | label: 'Window', 159 | submenu: [ 160 | { 161 | label: 'Minimize', 162 | accelerator: 'Command+M', 163 | selector: 'performMiniaturize:' 164 | }, 165 | { 166 | label: 'Close', 167 | accelerator: 'Command+W', 168 | selector: 'performClose:' 169 | } 170 | ] 171 | } 172 | ]; 173 | 174 | return template; 175 | }; 176 | -------------------------------------------------------------------------------- /src/images/icon-autotrace-simple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 18 | 19 | 20 | 22 | 27 | 28 | 29 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 55 | 56 | 57 | 59 | 64 | 65 | 66 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/images/icon-manual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 67 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/windows/window.autotrace.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

import.auto.title

4 | 5 |
6 | 7 | 8 | 9 |
10 |
11 | 12 |
13 | 17 | 18 | 19 | 102 |
103 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/bin/autotrace-config: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | af_libs= 4 | af_cflags= 5 | prefix=/usr/local/Cellar/autotrace/0.31.1_2 6 | exec_prefix=${prefix} 7 | 8 | 9 | ## 10 | ## Define usage() 11 | ## 12 | usage() 13 | { 14 | cat <&2 39 | fi 40 | 41 | # at least one option should be selected 42 | case "$1" in 43 | --*) 44 | ;; 45 | *) 46 | usage 1 1>&2 47 | ;; 48 | esac 49 | 50 | # grab all -- arguments 51 | while test $# -gt 0; do 52 | case "$1" in 53 | -*=*) af_optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; 54 | *) af_optarg= ;; 55 | esac 56 | 57 | case $1 in 58 | --help) 59 | usage 0 0>&2 60 | ;; 61 | --cflags) 62 | af_echo_cflags=yes 63 | ;; 64 | --libs) 65 | af_echo_libs_L=yes 66 | af_echo_libs_l=yes 67 | ;; 68 | --libs-dirs) 69 | af_echo_libs_L=yes 70 | ;; 71 | --libs-names) 72 | af_echo_libs_l=yes 73 | ;; 74 | --prefix=*) 75 | prefix=$af_optarg 76 | af_prefix_set=yes 77 | ;; 78 | --prefix) 79 | af_echo_prefix=yes 80 | ;; 81 | --exec_prefix=*) 82 | exec_prefix=$af_optarg 83 | af_exec_prefix_set=yes 84 | ;; 85 | --exec_prefix) 86 | af_echo_exec_prefix=yes 87 | ;; 88 | --version) 89 | af_echo_version=yes 90 | ;; 91 | --*) 92 | usage 1 1>&2 93 | ;; 94 | *) 95 | break 96 | ;; 97 | esac 98 | shift 99 | done 100 | 101 | # if we have a default library use it 102 | if test $# -eq 0; then 103 | if test "X$af_lib_default" != "X"; then 104 | af_lib__AF_LIB_DEFAULT=yes 105 | return 106 | fi 107 | fi 108 | 109 | while test $# -gt 0; do 110 | case $1 in 111 | autotrace) 112 | af_lib_autotrace=yes 113 | ;; 114 | *) 115 | usage 1 1>&2 116 | ;; 117 | esac 118 | shift 119 | done 120 | } 121 | 122 | print_result() 123 | { 124 | if test "X$af_echo_cflags" = "Xyes"; then 125 | af_all_flags="$af_cflags" 126 | fi 127 | 128 | if test "X$af_echo_libs_L" = "Xyes" || test "X$af_echo_libs_l" = "Xyes"; then 129 | af_all_flags="$af_all_flags $af_libs" 130 | fi 131 | 132 | if test -z "$af_all_flags" || test "X$af_all_flags" = "X "; then 133 | exit 1 134 | fi 135 | 136 | # Straight out any possible duplicates, but be careful to 137 | # get `-lfoo -lbar -lbaz' for `-lfoo -lbaz -lbar -lbaz' 138 | af_other_flags= 139 | af_lib_L_flags= 140 | af_rev_libs= 141 | for i in $af_all_flags; do 142 | case "$i" in 143 | # a library, save it for later, in reverse order 144 | -l*) af_rev_libs="$i $af_rev_libs" ;; 145 | -L*|-R*) 146 | if test "X$af_echo_libs_L" = "Xyes"; then 147 | case " $af_lib_L_flags " in 148 | *\ $i\ *) ;; # already there 149 | *) af_lib_L_flags="$af_lib_L_flags $i" ;; # add it to output 150 | esac 151 | fi;; 152 | *) 153 | case " $af_other_flags " in 154 | *\ $i\ *) ;; # already there 155 | *) af_other_flags="$af_other_flags $i" ;; # add it to output 156 | esac ;; 157 | esac 158 | done 159 | 160 | af_ord_libs= 161 | if test "X$af_echo_libs_l" = "Xyes"; then 162 | for i in $af_rev_libs; do 163 | case " $af_ord_libs " in 164 | *\ $i\ *) ;; # already there 165 | *) af_ord_libs="$i $af_ord_libs" ;; # add it to output in reverse order 166 | esac 167 | done 168 | fi 169 | 170 | echo $af_other_flags $af_lib_L_flags $af_ord_libs 171 | } 172 | 173 | ## 174 | ## Main Body 175 | ## 176 | 177 | parse $* 178 | 179 | 180 | ## 181 | ## Initialize names 182 | ## 183 | 184 | 185 | ## 186 | ## Available options 187 | ## 188 | if test "X$af_echo_prefix" = "Xyes"; then 189 | echo $prefix 190 | fi 191 | 192 | if test "X$af_echo_exec_prefix" = "Xyes"; then 193 | echo $exec_prefix 194 | fi 195 | 196 | if test "X$af_echo_version" = "Xyes"; then 197 | echo 0.31.1 198 | exit 0 199 | fi 200 | 201 | 202 | ## 203 | ## Libraries 204 | ## 205 | #dummy because this should always be selected 206 | 207 | af_cflags="$af_cflags -I${prefix}/include" 208 | af_libs="-L${exec_prefix}/lib -lautotrace $af_libs" 209 | 210 | 211 | 212 | print_result 213 | 214 | exit 0 215 | 216 | -------------------------------------------------------------------------------- /src/helpers/helper.autotrace.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file This is a helper include for adding base functionality surrounding auto 3 | * trace integration and handling import of autotrace data for printing. 4 | **/ 5 | 6 | module.exports = function(paper) { 7 | var app = require('electron').remote.app; 8 | var _ = require('underscore'); 9 | var fs = require('fs-plus'); 10 | var path = require('path'); 11 | var autotracer = require('autotrace'); 12 | var outFile = path.join(app.getPath('temp'), 'pancakepainter_temptrace.svg'); 13 | 14 | var autotrace = { 15 | settings: { 16 | backgroundColor: 'FFFFFF', // Color to ignore/make transparent. 17 | colorCount: 2, // Color simplification/Posterize amount. 18 | cornerAlwaysThreshold: 60, // Angle to make something alaways a corner. 19 | cornerSurround: 4, // Num of pixels to determine if a pixel is a corner. 20 | cornerThreshold: 100, // Angle for making corners depening on surrounding. 21 | despeckleLevel: 2, 22 | despeckleTightness: 2.0, 23 | dpi: 96, // Scaling size for output SVG 24 | errorThreshold: 2.0, // Subdivide fitted curves value 25 | filterIterations: 4, // Curve smoothing iterations. 26 | inputFormat: 'BMP', // Input image format, must be supported by bin. 27 | lineReversionThreshold: 0.1, // When to keep line straight when in curves. 28 | lineThreshold: 1, // Deviation in pixels to consider a line straight. 29 | outputFile: outFile, 30 | outputFormat: 'SVG', 31 | preserveWidth: true, // Preserve line width before thinning? 32 | removeAdjacentCorners: true, 33 | tangentSurround: 3, // Consider adjacent points when computing tangent. 34 | customBin: getBinaryPath(), // Binary path for the system. 35 | }, 36 | 37 | /** 38 | * Get the centerline traced SVG string from a given raster image. 39 | * 40 | * @param {String} img 41 | * Path to raster image matching input format given in options/defaults. 42 | * @param {Object} options 43 | * Optional overrides for settings object. 44 | * @return {Promise} 45 | * Resolved promise returns string data of completed SVG. 46 | */ 47 | getImageLines: function(img, options) { 48 | options = _.extend({}, options, {centerline: true}); 49 | return this.getImageFills(img, options); 50 | }, 51 | 52 | /** 53 | * Get the fill only traced SVG string from a given raster image. 54 | * 55 | * @param {String} img 56 | * Path to raster image matching input format given in options/defaults. 57 | * @param {Object} options 58 | * Optional overrides for settings object. 59 | * @return {Promise} 60 | * Resolved promise returns string data of completed SVG. 61 | */ 62 | getImageFills: function(img, options) { 63 | var settings = _.extend({}, 64 | this.settings, 65 | options // Pass along any customizations 66 | ); 67 | 68 | return new Promise(function(resolve, reject) { 69 | autotracer(img, settings, function(err) { 70 | if (err) { 71 | reject(Error(err)); 72 | } else { 73 | var data = paper.autotrace.getTraceData(); 74 | if (data) { 75 | resolve(data); 76 | } else { 77 | reject(Error("Null result from autotrace")); 78 | } 79 | } 80 | }); 81 | }); 82 | }, 83 | 84 | /** 85 | * Get the properly reformatted trace data from the output file. 86 | * 87 | * @return {String} 88 | * SVG string from the file at settings.outputFile. 89 | */ 90 | getTraceData: function() { 91 | // The SVG format from autotrace needs XML namespace before we can use it. 92 | var svgns = 'xmlns="http://www.w3.org/2000/svg" ' + 93 | 'xmlns:xlink="http://www.w3.org/1999/xlink" '; 94 | var svg = fs.readFileSync(this.settings.outputFile, 'utf8'); 95 | return svg.replace(' 2 | 3 | 4 | 6 | 8 | 9 | 10 | 20 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 50 | 52 | 53 | 54 | 55 | 56 | 58 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/windows/window.export.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

export.title

4 |
5 |
6 | 10 | 11 |
12 | settings.gcode.title 13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 | 00 24 | 25 | 26 |
27 | 28 |
29 | 00 30 | 31 | 32 |
33 | 34 |
35 | 00 36 | 37 | 38 |
39 | 40 |
41 | 00 42 | 43 | 44 |
45 | 46 |
47 | 00 48 | 49 | 50 |
51 |
52 | 53 |
54 |
55 | 56 | 57 | 58 |
59 | 60 |
61 | 00 62 | 63 | 64 |
65 | 66 |
67 | 68 | 69 | 70 |
71 | 72 |
73 | 74 | 75 | 76 |
77 | 78 |
79 | settings.gcode.linefillgroup 80 |
81 | 00 82 | 83 | 84 |
85 | 86 |
87 | 00 88 | 89 | 90 |
91 | 92 |
93 | 00 94 | 95 | 96 |
97 |
98 |
99 |
100 | 101 |
102 |
103 | -------------------------------------------------------------------------------- /src/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 11 | 15 | 18 | 21 | 25 | 27 | 32 | 33 | 37 | 41 | 44 | 49 | 51 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/images/icon-autotrace-color-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 16 | 35 | 47 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/images/icon-fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 17 | 28 | 29 | 31 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 45 | 46 | 47 | 48 | 53 | 54 | 56 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/README: -------------------------------------------------------------------------------- 1 | AutoTrace is a utility for converting bitmap into vector graphics. 2 | 3 | Features 4 | ======== 5 | - tracing outline and midline 6 | - color reduction and despeckling 7 | - supports a lot of input and output format 8 | 9 | Licenses 10 | ======== 11 | The program can be used under the GNU General Public License. 12 | 13 | The input and output functions (input-*.[ch] and output-*.[ch]) 14 | can also be used under the GNU Lesser General Public License(LGPL). 15 | 16 | Some of code was partially derived from limn of GNU fontutils. 17 | However, almost all code is rewritten. 18 | 19 | Platforms 20 | ========= 21 | The program was tested using GNU/Linux, HP UX, Solaris, Windows98, 22 | Windows NT, Windows 2000, MAC and OS/2 4.0. It compiles with GCC, 23 | Borland C++ Builder, Visual C++ and many other compilers. 24 | 25 | If you use Visual C++ 6.0 for compilation be sure to have at 26 | least SP 5 otherwise you could get Memory access violations due to 27 | a bug in earlier versions. 28 | 29 | Requirements 30 | ============ 31 | AutoTrace can be compiled standalone, then it can import pnm, pbm, 32 | pgm, ppm, bmp and tga files. If you have installed libpng 33 | (http://www.libpng.org/pub/png/libpng.html) you can also read png 34 | files and with ImageMagick a very broad range of input formats is 35 | available. 36 | 37 | You will need at least libpng 1.0.6 and ImageMagick 5.2.1. Most 38 | output formats like dxf, emf, eps, ai, er, fig, svg, epd, dr2d and sk 39 | are directly integrated in AutoTrace, but if you need swf export you 40 | need to install Ming (http://www.opaque.net/ming/). Also you can 41 | export to the p2e format. This format can be converted by pstoedit 42 | (www.pstoedit.net) to a large number of other formats. If you have 43 | installed the latest pstoedit(3.32 or newer), autotrace uses pstoedit 44 | directly. However, direct pstoedit support is not stable enough. 45 | See INSTALL file for more detail. 46 | 47 | Installation 48 | ============ 49 | See the file INSTALL. 50 | 51 | Usage 52 | ===== 53 | Program comes from two parts: command and library. 54 | 55 | Here the options you can use in the command: 56 | Usage: autotrace.exe [options] . 57 | Options: should be a supported image. 58 | You can use `--' or `-' to start an option. 59 | You can use any unambiguous abbreviation for an option name. 60 | You can separate option names and values with `=' or ` '. 61 | background-color : the color of the background that 62 | should be ignored, for example FFFFFF; 63 | default is no background color. 64 | centerline: trace a character's centerline, rather than its outline. 65 | color-count : number of colors a color bitmap is reduced to, 66 | it does not work on gray scale, allowed are 1..256; 67 | default is 0, that means not color reduction is done. 68 | corner-always-threshold : if the angle at a pixel is 69 | less than this, it is considered a corner, even if it is within 70 | `corner-surround' pixels of another corner; default is 60. 71 | corner-surround : number of pixels on either side of a 72 | point to consider when determining if that point is a corner; 73 | default is 4. 74 | corner-threshold : if a pixel, its predecessor(s), 75 | and its successor(s) meet at an angle smaller than this, it's a 76 | corner; default is 100. 77 | despeckle-level : 0..20; default is no despeckling. 78 | despeckle-tightness : 0.0..8.0; default is 2.0. 79 | dpi : The dots per inch value in the input image, affects scaling 80 | of mif output image 81 | error-threshold : subdivide fitted curves that are off by 82 | more pixels than this; default is 2.0. 83 | filter-iterations : smooth the curve this many times 84 | before fitting; default is 4. 85 | input-format: TGA, PBM, PNM, PGM, PPM or BMP. 86 | help: print this message. 87 | line-reversion-threshold : if a spline is closer to a straight 88 | line than this, weighted by the square of the curve length, keep it a 89 | straight line even if it is a list with curves; default is .01. 90 | line-threshold : if the spline is not more than this far away 91 | from the straight line defined by its endpoints, 92 | then output a straight line; default is 1. 93 | list-output-formats: print a list of support output formats to stderr. 94 | list-input-formats: print a list of support input formats to stderr. 95 | log: write detailed progress reports to .log. 96 | output-file : write to 97 | output-format : use format for the output file 98 | output-format : use format for the output file 99 | eps, ai, p2e, sk, svg, fig, swf, emf, mif, er, dxf, epd, pdf, cgm or dr2d 100 | can be used. 101 | preserve-width: whether to preserve line width prior to thinning.\n\ 102 | remove-adjacent-corners: remove corners that are adjacent. 103 | tangent-surround : number of points on either side of a 104 | point to consider when computing the tangent at that point; default is 3. 105 | report-progress: report tracing status in real time. 106 | debug-arch: print the type of cpu. 107 | debug-bitmap: dump loaded bitmap to .bitmap. 108 | version: print the version number of this program. 109 | width-weight-factor: weight factor for fitting the line width. 110 | 111 | The library is named libautotrace. About the usage of the library 112 | see autotrace.h. 113 | Here is a sample program that uses libautotrace. 114 | To compile, invoke following commands (on posix): 115 | gcc sample.c `./autotrace-config --libs` `./autotrace-config --cflags` 116 | 117 | /* sample.c */ 118 | #include 119 | 120 | int main() 121 | { 122 | char * fname = "img/triangle.png"; 123 | at_fitting_opts_type * opts = at_fitting_opts_new(); 124 | at_input_read_func rfunc = at_input_get_handler(fname); 125 | at_bitmap_type * bitmap ; 126 | at_splines_type * splines; 127 | at_output_write_func wfunc = at_output_get_handler_by_suffix("eps"); 128 | 129 | bitmap = at_bitmap_read(rfunc, fname, NULL, NULL, NULL); 130 | splines = at_splines_new(bitmap, opts, NULL, NULL); 131 | at_splines_write(wfunc, stdout, "", NULL splines, NULL, NULL); 132 | return 0; 133 | } 134 | 135 | GUI Frontend 136 | ============ 137 | Frontline, a Gtk+/Gnome based GUI frontend, is under development. 138 | See http://autotrace.sourceforge.net/frontline 139 | 140 | autotrace mailing list is used to discuss frontline. See next. 141 | 142 | More Information 143 | ================ 144 | See http://autotrace.sourceforge.net 145 | 146 | There is a mailing list to discussion autotrace. 147 | See also http://groups.yahoo.com/group/autotrace/ 148 | 149 | Contribution 150 | ============ 151 | Programmers wanted!!! 152 | 153 | See TODO and HACKING file and contact the author. 154 | 155 | Author 156 | ====== 157 | Martin Weber (martweb@gmx.net) 158 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/share/aclocal/autotrace.m4: -------------------------------------------------------------------------------- 1 | # a macro to get the libs/cflags for libautotrace 2 | # Copyed from gdk-pixbuf.m4 3 | 4 | dnl AM_PATH_AUTOTRACE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) 5 | dnl Test to see if libautotrace is installed, and define AUTOTRACE_CFLAGS, LIBS 6 | dnl 7 | AC_DEFUN([AM_PATH_AUTOTRACE], 8 | [dnl 9 | dnl Get the cflags and libraries from the autotrace-config script 10 | dnl 11 | AC_ARG_WITH(autotrace-prefix,[ --with-autotrace-prefix=PFX Prefix where Autotrace is installed (optional)], 12 | autotrace_prefix="$withval", autotrace_prefix="") 13 | AC_ARG_WITH(autotrace-exec-prefix,[ --with-autotrace-exec-prefix=PFX Exec prefix where Autotrace is installed (optional)], 14 | autotrace_exec_prefix="$withval", autotrace_exec_prefix="") 15 | AC_ARG_ENABLE(autotracetest, [ --disable-autotracetest Do not try to compile and run a test Autotrace program], 16 | , enable_autotracetest=yes) 17 | 18 | if test x$autotrace_exec_prefix != x ; then 19 | autotrace_args="$autotrace_args --exec_prefix=$autotrace_exec_prefix" 20 | if test x${AUTOTRACE_CONFIG+set} != xset ; then 21 | AUTOTRACE_CONFIG=$autotrace_exec_prefix/bin/autotrace-config 22 | fi 23 | fi 24 | if test x$autotrace_prefix != x ; then 25 | autotrace_args="$autotrace_args --prefix=$autotrace_prefix" 26 | if test x${AUTOTRACE_CONFIG+set} != xset ; then 27 | AUTOTRACE_CONFIG=$autotrace_prefix/bin/autotrace-config 28 | fi 29 | fi 30 | 31 | AC_PATH_PROG(AUTOTRACE_CONFIG, autotrace-config, no) 32 | min_autotrace_version=ifelse([$1], ,0.30.1,$1) 33 | AC_MSG_CHECKING(for AUTOTRACE - version >= $min_autotrace_version) 34 | no_autotrace="" 35 | if test "$AUTOTRACE_CONFIG" = "no" ; then 36 | no_autotrace=yes 37 | else 38 | AUTOTRACE_CFLAGS=`$AUTOTRACE_CONFIG $autotrace_args --cflags` 39 | AUTOTRACE_LIBS=`$AUTOTRACE_CONFIG $autotrace_args --libs` 40 | 41 | autotrace_major_version=`$AUTOTRACE_CONFIG $autotrace_args --version | \ 42 | sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` 43 | autotrace_minor_version=`$AUTOTRACE_CONFIG $autotrace_args --version | \ 44 | sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` 45 | autotrace_micro_version=`$AUTOTRACE_CONFIG $autotrace_args --version | \ 46 | sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` 47 | if test "x$enable_autotracetest" = "xyes" ; then 48 | ac_save_CFLAGS="$CFLAGS" 49 | ac_save_LIBS="$LIBS" 50 | CFLAGS="$CFLAGS $AUTOTRACE_CFLAGS" 51 | LIBS="$AUTOTRACE_LIBS $LIBS" 52 | dnl 53 | dnl Now check if the installed AUTOTRACE is sufficiently new. (Also sanity 54 | dnl checks the results of autotrace-config to some extent 55 | dnl 56 | rm -f conf.autotracetest 57 | AC_TRY_RUN([ 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | char* 64 | my_strdup (char *str) 65 | { 66 | char *new_str; 67 | 68 | if (str) 69 | { 70 | new_str = malloc ((strlen (str) + 1) * sizeof(char)); 71 | strcpy (new_str, str); 72 | } 73 | else 74 | new_str = NULL; 75 | 76 | return new_str; 77 | } 78 | 79 | int main () 80 | { 81 | int major, minor, micro; 82 | char *tmp_version; 83 | 84 | system ("touch conf.autotracetest"); 85 | 86 | /* HP/UX 9 (%@#!) writes to sscanf strings */ 87 | tmp_version = my_strdup("$min_autotrace_version"); 88 | if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { 89 | printf("%s, bad version string\n", "$min_autotrace_version"); 90 | exit(1); 91 | } 92 | 93 | if (($autotrace_major_version > major) || 94 | (($autotrace_major_version == major) && ($autotrace_minor_version > minor)) || 95 | (($autotrace_major_version == major) && ($autotrace_minor_version == minor) && ($autotrace_micro_version >= micro))) 96 | { 97 | return 0; 98 | } 99 | else 100 | { 101 | printf("\n*** 'autotrace-config --version' returned %d.%d.%d, but the minimum version\n", $autotrace_major_version, $autotrace_minor_version, $autotrace_micro_version); 102 | printf("*** of AUTOTRACE required is %d.%d.%d. If autotrace-config is correct, then it is\n", major, minor, micro); 103 | printf("*** best to upgrade to the required version.\n"); 104 | printf("*** If autotrace-config was wrong, set the environment variable AUTOTRACE_CONFIG\n"); 105 | printf("*** to point to the correct copy of autotrace-config, and remove the file\n"); 106 | printf("*** config.cache before re-running configure\n"); 107 | return 1; 108 | } 109 | } 110 | ],, no_autotrace=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) 111 | CFLAGS="$ac_save_CFLAGS" 112 | LIBS="$ac_save_LIBS" 113 | fi 114 | fi 115 | if test "x$no_autotrace" = x ; then 116 | AC_MSG_RESULT(yes) 117 | ifelse([$2], , :, [$2]) 118 | else 119 | AC_MSG_RESULT(no) 120 | if test "$AUTOTRACE_CONFIG" = "no" ; then 121 | echo "*** The autotrace-config script installed by AUTOTRACE could not be found" 122 | echo "*** If AUTOTRACE was installed in PREFIX, make sure PREFIX/bin is in" 123 | echo "*** your path, or set the AUTOTRACE_CONFIG environment variable to the" 124 | echo "*** full path to autotrace-config." 125 | else 126 | if test -f conf.autotracetest ; then 127 | : 128 | else 129 | echo "*** Could not run AUTOTRACE test program, checking why..." 130 | CFLAGS="$CFLAGS $AUTOTRACE_CFLAGS" 131 | LIBS="$LIBS $AUTOTRACE_LIBS" 132 | AC_TRY_LINK([ 133 | #include 134 | #include 135 | ], [ return 0; ], 136 | [ echo "*** The test program compiled, but did not run. This usually means" 137 | echo "*** that the run-time linker is not finding AUTOTRACE or finding the wrong" 138 | echo "*** version of AUTOTRACE. If it is not finding AUTOTRACE, you'll need to set your" 139 | echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" 140 | echo "*** to the installed location Also, make sure you have run ldconfig if that" 141 | echo "*** is required on your system" 142 | echo "***" 143 | echo "*** If you have an old version installed, it is best to remove it, although" 144 | echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], 145 | [ echo "*** The test program failed to compile or link. See the file config.log for the" 146 | echo "*** exact error that occured. This usually means AUTOTRACE was incorrectly installed" 147 | echo "*** or that you have moved AUTOTRACE since it was installed. In the latter case, you" 148 | echo "*** may want to edit the autotrace-config script: $AUTOTRACE_CONFIG" ]) 149 | CFLAGS="$ac_save_CFLAGS" 150 | LIBS="$ac_save_LIBS" 151 | fi 152 | fi 153 | AUTOTRACE_CFLAGS="" 154 | AUTOTRACE_LIBS="" 155 | ifelse([$3], , :, [$3]) 156 | fi 157 | AC_SUBST(AUTOTRACE_CFLAGS) 158 | AC_SUBST(AUTOTRACE_LIBS) 159 | rm -f conf.autotracetest 160 | ]) -------------------------------------------------------------------------------- /resources/win32/bin/autotrace/README: -------------------------------------------------------------------------------- 1 | AutoTrace is a utility for converting bitmap into vector graphics. 2 | 3 | Features 4 | ======== 5 | - tracing outline and midline 6 | - color reduction and despeckling 7 | - supports a lot of input and output format 8 | 9 | Licenses 10 | ======== 11 | The program can be used under the GNU General Public License. 12 | 13 | The input and output functions (input-*.[ch] and output-*.[ch]) 14 | can also be used under the GNU Lesser General Public License(LGPL). 15 | 16 | Some of code was partially derived from limn of GNU fontutils. 17 | However, almost all code is rewritten. 18 | 19 | Platforms 20 | ========= 21 | The program was tested using GNU/Linux, HP UX, Solaris, Windows98, 22 | Windows NT, Windows 2000, MAC and OS/2 4.0. It compiles with GCC, 23 | Borland C++ Builder, Visual C++ and many other compilers. 24 | 25 | If you use Visual C++ 6.0 for compilation be sure to have at 26 | least SP 5 otherwise you could get Memory access violations due to 27 | a bug in earlier versions. 28 | 29 | Requirements 30 | ============ 31 | AutoTrace can be compiled standalone, then it can import pnm, pbm, 32 | pgm, ppm, bmp and tga files. If you have installed libpng 33 | (http://www.libpng.org/pub/png/libpng.html) you can also read png 34 | files and with ImageMagick a very broad range of input formats is 35 | available. 36 | 37 | You will need at least libpng 1.0.6 and ImageMagick 5.2.1. Most 38 | output formats like dxf, emf, eps, ai, er, fig, svg, epd, dr2d and sk 39 | are directly integrated in AutoTrace, but if you need swf export you 40 | need to install Ming (http://www.opaque.net/ming/). Also you can 41 | export to the p2e format. This format can be converted by pstoedit 42 | (www.pstoedit.net) to a large number of other formats. If you have 43 | installed the latest pstoedit(3.32 or newer), autotrace uses pstoedit 44 | directly. However, direct pstoedit support is not stable enough. 45 | See INSTALL file for more detail. 46 | 47 | Installation 48 | ============ 49 | See the file INSTALL. 50 | 51 | Usage 52 | ===== 53 | Program comes from two parts: command and library. 54 | 55 | Here the options you can use in the command: 56 | Usage: autotrace.exe [options] . 57 | Options: should be a supported image. 58 | You can use `--' or `-' to start an option. 59 | You can use any unambiguous abbreviation for an option name. 60 | You can separate option names and values with `=' or ` '. 61 | background-color : the color of the background that 62 | should be ignored, for example FFFFFF; 63 | default is no background color. 64 | centerline: trace a character's centerline, rather than its outline. 65 | color-count : number of colors a color bitmap is reduced to, 66 | it does not work on gray scale, allowed are 1..256; 67 | default is 0, that means not color reduction is done. 68 | corner-always-threshold : if the angle at a pixel is 69 | less than this, it is considered a corner, even if it is within 70 | `corner-surround' pixels of another corner; default is 60. 71 | corner-surround : number of pixels on either side of a 72 | point to consider when determining if that point is a corner; 73 | default is 4. 74 | corner-threshold : if a pixel, its predecessor(s), 75 | and its successor(s) meet at an angle smaller than this, it's a 76 | corner; default is 100. 77 | despeckle-level : 0..20; default is no despeckling. 78 | despeckle-tightness : 0.0..8.0; default is 2.0. 79 | dpi : The dots per inch value in the input image, affects scaling 80 | of mif output image 81 | error-threshold : subdivide fitted curves that are off by 82 | more pixels than this; default is 2.0. 83 | filter-iterations : smooth the curve this many times 84 | before fitting; default is 4. 85 | input-format: TGA, PBM, PNM, PGM, PPM or BMP. 86 | help: print this message. 87 | line-reversion-threshold : if a spline is closer to a straight 88 | line than this, weighted by the square of the curve length, keep it a 89 | straight line even if it is a list with curves; default is .01. 90 | line-threshold : if the spline is not more than this far away 91 | from the straight line defined by its endpoints, 92 | then output a straight line; default is 1. 93 | list-output-formats: print a list of support output formats to stderr. 94 | list-input-formats: print a list of support input formats to stderr. 95 | log: write detailed progress reports to .log. 96 | output-file : write to 97 | output-format : use format for the output file 98 | output-format : use format for the output file 99 | eps, ai, p2e, sk, svg, fig, swf, emf, mif, er, dxf, epd, pdf, cgm or dr2d 100 | can be used. 101 | preserve-width: whether to preserve line width prior to thinning.\n\ 102 | remove-adjacent-corners: remove corners that are adjacent. 103 | tangent-surround : number of points on either side of a 104 | point to consider when computing the tangent at that point; default is 3. 105 | report-progress: report tracing status in real time. 106 | debug-arch: print the type of cpu. 107 | debug-bitmap: dump loaded bitmap to .bitmap. 108 | version: print the version number of this program. 109 | width-weight-factor: weight factor for fitting the line width. 110 | 111 | The library is named libautotrace. About the usage of the library 112 | see autotrace.h. 113 | Here is a sample program that uses libautotrace. 114 | To compile, invoke following commands (on posix): 115 | gcc sample.c `./autotrace-config --libs` `./autotrace-config --cflags` 116 | 117 | /* sample.c */ 118 | #include 119 | 120 | int main() 121 | { 122 | char * fname = "img/triangle.png"; 123 | at_fitting_opts_type * opts = at_fitting_opts_new(); 124 | at_input_read_func rfunc = at_input_get_handler(fname); 125 | at_bitmap_type * bitmap ; 126 | at_splines_type * splines; 127 | at_output_write_func wfunc = at_output_get_handler_by_suffix("eps"); 128 | 129 | bitmap = at_bitmap_read(rfunc, fname, NULL, NULL, NULL); 130 | splines = at_splines_new(bitmap, opts, NULL, NULL); 131 | at_splines_write(wfunc, stdout, "", NULL splines, NULL, NULL); 132 | return 0; 133 | } 134 | 135 | GUI Frontend 136 | ============ 137 | Frontline, a Gtk+/Gnome based GUI frontend, is under development. 138 | See http://autotrace.sourceforge.net/frontline 139 | 140 | autotrace mailing list is used to discuss frontline. See next. 141 | 142 | More Information 143 | ================ 144 | See http://autotrace.sourceforge.net 145 | 146 | There is a mailing list to discussion autotrace. 147 | See also http://groups.yahoo.com/group/autotrace/ 148 | 149 | Contribution 150 | ============ 151 | Programmers wanted!!! 152 | 153 | See TODO and HACKING file and contact the author. 154 | 155 | Author 156 | ====== 157 | Martin Weber (martweb@gmx.net) 158 | -------------------------------------------------------------------------------- /src/tools/tool.pen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Tool definition for the PC dual purpose drawing tool. Provides event 3 | * handlers and special logic for the drawing tool ONLY. 4 | **/ 5 | /*globals $, document, _ */ 6 | "use strict"; 7 | 8 | module.exports = function(paper) { 9 | // Init Tool (to be handed back) 10 | var tool = new paper.Tool(); 11 | 12 | // Constant tool tweaks 13 | var endSnapDistance = 10; 14 | var minLineLength = 8; 15 | var simplifyAmount = 3; 16 | var simplifyThreshold = 150; // Smallest shape that will be simplified 17 | 18 | // Paper global extenders 19 | var Path = paper.Path; 20 | 21 | // Handy internal vars 22 | var drawPath = null; 23 | var polygonalDraw = false; 24 | var pencilDraw = false; 25 | var bandLine = null; 26 | var endSnap = null; 27 | 28 | // Tool identification (for building out tool palette) 29 | tool.name = 'tools.pen'; 30 | tool.key = 'pen'; 31 | tool.cursorOffset = '1 31'; // Position for cursor point 32 | tool.cursorColors = true; // Different icons/cursor for each color? 33 | 34 | // Catch when undo is being changed, and kill it/augment it depending. 35 | tool.undoSet = function(op) { 36 | if (pencilDraw && drawPath) return false; 37 | 38 | if (polygonalDraw) { 39 | if (op === 'undo' && drawPath.segments.length > 1) { 40 | drawPath.segments.pop(); 41 | bandLine.segments[0].point = drawPath.lastSegment.point; 42 | paper.view.update(); 43 | } 44 | return false; 45 | } 46 | 47 | return true; 48 | }; 49 | 50 | tool.onMouseDown = function(event) { 51 | // Continue drawing polygonal (ignores hitTest while on) 52 | if (drawPath && polygonalDraw) { 53 | if (event.event.button === 0) drawPath.add(event.point); 54 | 55 | // Shortcut single click end polygon draw shape via path closing, or 56 | // right click 57 | if (drawPath.segments.length > 2 && 58 | checkEndSnap(event.point) || event.event.button === 2) { 59 | polygonDrawComplete(); 60 | return; 61 | } 62 | 63 | // Make a new point, delete the first one 64 | bandLine.segments[0].point = event.point; 65 | return; 66 | } 67 | 68 | // Create a new drawPath and set its stroke color 69 | if (event.event.button === 0) { 70 | pencilDraw = true; 71 | drawPath = newBatterPath(event.point); 72 | 73 | // Set position of endSnap notifier 74 | initEndSnap(event.point); 75 | } 76 | 77 | }; 78 | 79 | tool.onMouseDrag = function(event) { 80 | // While the user drags the mouse, points are added to the drawPath at the 81 | // position of the mouse event 82 | if (drawPath && !polygonalDraw && pencilDraw) { 83 | drawPath.add(event.point); 84 | if (drawPath.length > endSnapDistance + 5) checkEndSnap(event.point); 85 | } 86 | }; 87 | 88 | tool.onMouseMove = function(event) { 89 | if (drawPath && polygonalDraw) { 90 | // Move the rubber band to the point if polygonal 91 | bandLine.segments[1].point = event.point; 92 | 93 | if (drawPath.segments.length > 2) checkEndSnap(event.point); 94 | } 95 | }; 96 | 97 | tool.onMouseUp = function(event) { 98 | if (drawPath) { 99 | if (drawPath.length <= minLineLength && event.event.button === 0) { 100 | // Restart the path 101 | drawPath.remove(); 102 | drawPath = newBatterPath(event.point); 103 | 104 | polygonalDraw = true; 105 | pencilDraw = false; 106 | bandLine = new Path({ 107 | segments: [event.point, event.point], 108 | strokeColor: 'red', 109 | strokeWidth: paper.strokeWidth, 110 | dashArray: [10, 4] 111 | }); 112 | 113 | drawPath.onDoubleClick = function(){ 114 | // Remove the last segment (from the first click of the double) 115 | drawPath.segments.pop(); 116 | polygonDrawComplete(); 117 | }; 118 | paper.setCursor('copy'); 119 | } 120 | 121 | 122 | // Freehand pencil draw complete 123 | if (!polygonalDraw && pencilDraw && event.event.button === 0) { 124 | // When the mouse is released, simplify it (if it's not too small): 125 | if (drawPath.length > simplifyThreshold) { 126 | drawPath.simplify(simplifyAmount); 127 | } else { 128 | drawPath.simplify(1); 129 | } 130 | 131 | // If the distance is right and we have end snap... make it closed! 132 | if (drawPath.length > endSnapDistance + 5 && 133 | checkEndSnap(drawPath.lastSegment.point)) { 134 | drawPath.lastSegment.remove(); 135 | drawPath.closed = true; 136 | } 137 | 138 | pencilDraw = false; 139 | 140 | // Select the drawPath, so we can see its segments: 141 | drawPath = null; 142 | clearEndSnap(); 143 | 144 | paper.fileChanged(); 145 | } 146 | 147 | } 148 | }; 149 | 150 | 151 | // Catch Escape key (not caught with the tool's onKeyDown). 152 | $(document).keyup(function(e) { 153 | if (e.keyCode === 27) { 154 | polygonDrawComplete(); 155 | } 156 | }); 157 | 158 | tool.onKeyDown = function (event) { 159 | if (_.contains(['enter'], event.key)) { 160 | polygonDrawComplete(); 161 | } 162 | }; 163 | 164 | tool.polygonDrawComplete = polygonDrawComplete; 165 | function polygonDrawComplete() { 166 | if (polygonalDraw) { 167 | polygonalDraw = false; 168 | 169 | // If the distance is right and we have end snap... make it closed! 170 | if (drawPath.segments.length > 2 && 171 | checkEndSnap(drawPath.lastSegment.point)) { 172 | drawPath.lastSegment.remove(); 173 | drawPath.closed = true; 174 | } 175 | 176 | 177 | bandLine.remove(); 178 | bandLine = null; 179 | paper.setCursor(); 180 | clearEndSnap(); 181 | 182 | // Remove orphan node paths 183 | if (drawPath.segments.length === 1) { 184 | drawPath.remove(); 185 | } else { 186 | drawPath.data.isPolygonal = true; 187 | paper.cleanPath(drawPath); 188 | paper.fileChanged(); 189 | } 190 | 191 | drawPath = null; 192 | } 193 | } 194 | 195 | function newBatterPath(point) { 196 | return new Path({ 197 | segments: [point], 198 | strokeColor: paper.pancakeShades[paper.pancakeCurrentShade], 199 | strokeWidth: paper.strokeWidth, 200 | strokeCap: 'round', 201 | miterLimit: 1, 202 | data: {color: paper.pancakeCurrentShade} 203 | }); 204 | } 205 | 206 | // Initialize the endSnap notifier and position 207 | function initEndSnap(point) { 208 | endSnap = new Path.Circle({ 209 | center: point, 210 | radius: endSnapDistance, 211 | strokeWidth: 0, 212 | strokeColor: '#00FF00' 213 | }); 214 | } 215 | 216 | // Check to see if we're within the end snapping threshold 217 | function checkEndSnap(point) { 218 | if (!endSnap) return false; 219 | 220 | // Above a certain number of segments, highlight an end fill snap 221 | var vector = point.subtract(endSnap.position); 222 | 223 | if (vector.length <= endSnapDistance) { 224 | endSnap.strokeWidth = 3; 225 | return true; 226 | } else { 227 | endSnap.strokeWidth = 0; 228 | return false; 229 | } 230 | } 231 | 232 | // Clean up the endSnap path 233 | function clearEndSnap() { 234 | endSnap.remove(); 235 | endSnap = null; 236 | } 237 | 238 | return tool; 239 | }; 240 | -------------------------------------------------------------------------------- /resources/darwin/bin/autotrace/share/man/man1/autotrace.1: -------------------------------------------------------------------------------- 1 | .TH AUTOTRACE 1 "10 October 2002" 2 | .SH NAME 3 | autotrace \- converts bitmap image data into vector graphics 4 | .SH SYNOPSIS 5 | .B autotrace 6 | .RB [ \-background-color 7 | .IR " hexvalue" ] 8 | .RB [ \-centerline ] 9 | .RB [ \-color-count 10 | .IR " int" ] 11 | .RB [ \-corner-always-threshold 12 | .IR " angle" ] 13 | .RB [ \-corner-surround 14 | .IR " int" ] 15 | .RB [ \-corner-threshold 16 | .IR " angle" ] 17 | .RB [ \-despeckle-level 18 | .IR " int" ] 19 | .RB [ \-despeckle-tightness 20 | .IR " real" ] 21 | .RB [ \-dpi 22 | .IR " int" ] 23 | .RB [ \-error-threshold 24 | .IR " real" ] 25 | .RB [ \-filter-iterations 26 | .IR " int" ] 27 | .RB [ \-help ] 28 | .RB [ \-input-format 29 | .IR " format" ] 30 | .RB [ \-line-reversion-threshold 31 | .IR " real" ] 32 | .RB [ \-line-threshold 33 | .IR " real" ] 34 | .RB [ \-list-input-formats ] 35 | .RB [ \-list-output-formats ] 36 | .RB [ \-log ] 37 | .RB [ \-output-file 38 | .IR " file" ] 39 | .RB [ \-output-format 40 | .IR " format" ] 41 | .RB [ \-preserve-width ] 42 | .RB [ \-remove-adjacent-corners ] 43 | .RB [ \-report-progress ] 44 | .RB [ \-debug-arch ] 45 | .RB [ \-debug-bitmap ] 46 | .RB [ \-tangent-surround 47 | .IR " int" ] 48 | .RB [ \-version ] 49 | .RB [ \-width-factor 50 | .IR " real" ] 51 | .I inputfile 52 | .SH DESCRIPTION 53 | The 54 | .I autotrace 55 | program accepts bitmap graphics from the file 56 | .I inputfile 57 | specified on the command line, 58 | and as output produces a collection of splines approximating the original image, 59 | the converting the image from bitmap to vector format. 60 | It behaves in a manner similar to the commercial software known as 61 | *tream*ine or *orel*race. 62 | The result is sent to standard output unless the 63 | .B \-output-file 64 | option is active. 65 | .SH OPTIONS 66 | Options can begin with either 67 | .B \-\- 68 | or 69 | .BR \- . 70 | Any unambiguous abbreviation can be used for the option name. 71 | Option names and values can be separated with either a space or equal sign (=). 72 | .TP 73 | .BI \-background-color " hexvalue" 74 | Employ the color specified by the hexadecimal code 75 | .I hexcode 76 | as the background that should be ignored, for example FFFFFF 77 | (default: no background color). 78 | .TP 79 | .B \-centerline 80 | Trace an object's centerline 81 | (default: employ its outline). 82 | .TP 83 | .BI \-color-count " int" 84 | Reduce the bitmap to using the number of colors specified by 85 | the unsigned integer 86 | .I int 87 | (range: 1-256). 88 | The default value of 0 indicates that no color reduction is to be done. 89 | Does not work with grayscale images. 90 | .TP 91 | .BI \-corner-always-threshold " angle" 92 | Consider any angle at a pixel which falls below the specified 93 | .I angle 94 | (in degrees) as a corner, 95 | even if it is bordered by other corner pixels (default: 60). 96 | .TP 97 | .BI \-corner-surround " int" 98 | Consider the specified number of pixels on either side of a 99 | point when determining if that point is a corner (default: 4). 100 | .TP 101 | .BI \-corner-threshold " angle" 102 | Consider any pixel which forms an angle with its predecessor(s) and successor(s) 103 | that is smaller than the specified 104 | .I angle 105 | (in degrees) as a corner (default: 100). 106 | .TP 107 | .BI \-despeckle-level " int" 108 | Employ the specified integer (range: 1-20) as the value for despeckling 109 | (default: no despeckling). 110 | .TP 111 | .BI \-despeckle-tightness " real" 112 | Employ the specified real number (range: 0.0-8.0) as the value for despeckle 113 | tightness (default: 2.0). 114 | .TP 115 | .BI \-dpi " int" 116 | The dots per inch value in the input image, affects scaling 117 | of mif output image. 118 | .TP 119 | .BI \-error-threshold " real" 120 | Subdivide fitted curves that are offset by a number of pixels exceeding the 121 | specified real number (default: 2.0). 122 | .TP 123 | .BI \-filter-iterations " int" 124 | Smooth the curve the specified number of times prior to fitting (default: 4). 125 | .TP 126 | .B \-help 127 | Print a help message and exit. 128 | .TP 129 | .BI \-input-format " format" 130 | Employ the specified input format, 131 | where 132 | .I format 133 | is one of: 134 | .RS 135 | .TP 136 | .BR BMP " (Windows bitmap format)" 137 | .TP 138 | .BR PBM " (Portable BitMap format)" 139 | .TP 140 | .BR PGM " (Portable Graymap format)" 141 | .TP 142 | .BR PNM " (Portable Anymap format)" 143 | .TP 144 | .BR PPM " (Portable Pixmap format)" 145 | .TP 146 | .BR TGA " (Targa format)" 147 | .RE 148 | .IP 149 | The supported input formats are determined when the application is built 150 | and depend upon the availability of other software (the 151 | .B \-list-input-formats 152 | command can be used to determine which are supported locally). 153 | .TP 154 | .BI \-line-reversion-threshold " real" 155 | When a spline is closer to a straight line than the specified real number 156 | weighted by the square of the curve length (default: .01), 157 | maintain it as a straight line, 158 | even if it is a list with curves. 159 | .TP 160 | .BI \-line-threshold " real" 161 | If a spline does not deviate from the straight line defined by its endpoints 162 | by more than the specified number of pixels, 163 | then treat it as a straight line (default: 1). 164 | .TP 165 | .B \-list-input-formats 166 | Send a list of the supported input formats to stderr. 167 | .TP 168 | .B \-list-output-formats 169 | Send a list of the supported output formats to stderr. 170 | .TP 171 | .B \-log 172 | Send a detailed progress report to the file 173 | .IR inputfile .log. 174 | .TP 175 | .BI \-output-file " file" 176 | Send the output to the specified file. 177 | .TP 178 | .BI \-output-format " format" 179 | Employ the specified output format, 180 | where 181 | .I format 182 | is one of: 183 | .RS 184 | .TP 185 | .BR ai "(Adobe Illustrator)" 186 | .TP 187 | .BR cgm "(Computer Graphics Metafile)" 188 | .TP 189 | .BR dr2d "(IFF DR2D format, used almost exclusively on Amiga platforms)" 190 | .TP 191 | .BR dxf "(AutoCAD Drawing Exchange format)" 192 | .TP 193 | .BR emf "(Windows Enhanced Metafile format)" 194 | .TP 195 | .BR epd "(Encapsulated Vectorial Graphics format)" 196 | .TP 197 | .BR eps "(Encapsulated \*(Ps)" 198 | .TP 199 | .BR er "(Elastic Reality Shape format)" 200 | .TP 201 | .BR fig "(\fIxfig\fP (1) 3.2)" 202 | .TP 203 | .BR mif "(FrameMaker MIF format)" 204 | .TP 205 | .BR pdf "(Portable Data Format)" 206 | .TP 207 | .BR p2e "(\fIpstoedit\fP (1) frontend)" 208 | .TP 209 | .BR sk "(Sketch)" 210 | .TP 211 | .BR svg "(Scalable Vector Graphics)" 212 | .TP 213 | .BR swf "(Shockwave Flash 3)" 214 | .RE 215 | .IP 216 | The supported output formats are determined when the application is built 217 | and depend upon the availability of other software (the 218 | .B \-list-output-formats 219 | command can be used to determine which are supported locally). 220 | .TP 221 | .B \-preserve-width 222 | Whether to preserve line width prior to thinning. 223 | .TP 224 | .B \-remove-adjacent-corners 225 | Remove adjacent corners. 226 | .TP 227 | .B \-report-progress 228 | Report tracing status in real time. 229 | .TP 230 | .B \-debug-arch 231 | Print the type of cpu. 232 | .TP 233 | .B \-debug-bitmap 234 | Dump loaded bitmap to .bitmap. 235 | .TP 236 | .BI \-tangent-surround " int" 237 | Consider the specified number of points to either side of a point 238 | when computing the tangent at that point (default: 3). 239 | .TP 240 | .B \-version 241 | Print the version number of the program and exit. 242 | .TP 243 | .BI \-width-factor " real" 244 | Weight factor for fitting the linewidth. 245 | .SH FILES 246 | .TP 2.2i 247 | /depot/bin/autotrace 248 | binary 249 | .SH "SEE ALSO" 250 | gimp(1), 251 | ImageMagick(1), 252 | pbm(1), 253 | pgm(1), 254 | pnm(1), 255 | ps2pdf(1), 256 | pstoedit(1), 257 | pstoepd(1), 258 | sketch(1), 259 | xfig(1), 260 | xv(1) 261 | .SH AUTHORS 262 | Martin Weber (martweb@gmx.net) 263 | .LP 264 | Manual page by R. P. C. Rodgers, 265 | Lister Hill National Center for Biomedical Communications, 266 | U.S. National Library of Medicine 267 | (rodgers@nlm.nih.gov). 268 | .\" end of man page 269 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file This is the central "main process" node-only window/update manager 3 | * script file for PacnackePainter. This is loaded first and is always running 4 | * as long as the application runs. 5 | **/ 6 | "use strict"; 7 | if (require('electron-squirrel-startup')) return; 8 | const path = require('path'); 9 | 10 | var app = require('electron').app; // Module to control application life. 11 | var appPath = app.getAppPath(); 12 | var fs = require('fs-plus'); 13 | var _ = require('underscore'); 14 | 15 | // Module to create native browser window. 16 | var BrowserWindow = require('electron').BrowserWindow; 17 | var dialog = require('electron').dialog; 18 | var i18n = require('i18next'); 19 | 20 | // Report crashes to our server. 21 | //require('crash-reporter').start(); 22 | 23 | // Handle app startup with command line arguments from squirrel (windows). 24 | function start() { 25 | // Process squirrel update/install command line. 26 | if (process.platform === 'win32') { 27 | var SquirrelUpdate = require('./squirrel-update'); 28 | var squirrelCommand = process.argv[1]; 29 | if (SquirrelUpdate.handleStartupEvent(app, squirrelCommand)) { 30 | // If we processed one, quit right after. 31 | return false; 32 | } 33 | } 34 | 35 | settingsInit(); 36 | windowInit(); 37 | } 38 | 39 | // Keep a global reference of the window object, if you don't, the window will 40 | // be closed automatically when the javascript object is GCed. 41 | var mainWindow = null; 42 | 43 | /** 44 | * Initialize the settings, constants & defaults 45 | */ 46 | function settingsInit() { 47 | // Global application constants (set and referenced from here only!) 48 | // TODO: Gather more of these from around the app. 49 | app.constants = { 50 | pancakeShades: [ 51 | '#ffea7e', 52 | '#e2bc15', 53 | '#a6720e', 54 | '#714a00' 55 | ], 56 | botSpeedMax: 6600, // Real world PancakeBot speed maximum. 57 | 58 | // Real world measurement of the griddle maximum dimensions in MM 59 | griddleSize: { 60 | width: 507.5, 61 | height: 267.7, 62 | }, 63 | 64 | // Printable/drawable area in MM from furthest griddle edge. 65 | printableArea: { 66 | offset: { 67 | left: 36.22, 68 | top: 34.77, 69 | right: 42, // Used exclusively for GCODE X offset 70 | }, 71 | width: 443, 72 | height: 210, 73 | }, 74 | }; 75 | 76 | // Global user configurable settings. 77 | var settingsFile = path.join(appPath, 'settings.json'); 78 | var userSettingsFile = path.join(app.getPath('userData'), 'config.json'); 79 | app.settings = { 80 | v: {}, // Values are saved to/from here 81 | defaults: { 82 | window: { 83 | width: 980, 84 | height: 600, 85 | y: 'center', 86 | x: 'center' 87 | }, 88 | lastFile: '', 89 | flatten: 2, // Flatten curve value (smaller value = more points) 90 | shutoff: 25, // Remaining line length threshold for pump shutoff 91 | startwait: 350, // Time to wait for batter flow begin 92 | endwait: 250, // Time to wait for batter flow at end of line 93 | changewait: 15, // Number of seconds to wait between shade changes. 94 | botspeed: 70, // Locked stepper speed percentage written to GCODE 95 | usecolorspeed: false, // Whether to use different speeds for colors. 96 | useshortest: true, // Whether to travel sort the final layer. 97 | botspeedcolor1: 100, // Light speed. 98 | botspeedcolor2: 80, // Medium speed. 99 | botspeedcolor3: 80, // Medium Dark speed. 100 | botspeedcolor4: 50, // Dark speed. 101 | uselinefill: false, // Whether to use line fill over shape fill. 102 | fillspacing: 10, // Space between each trace fill line 103 | fillangle: 23, // Angle of line for trace fill 104 | fillthresh: 27, // Threshold to group zig zags 105 | shapefillwidth: 3 // Effective fill space. 106 | }, 107 | clear: function() { 108 | fs.removeSync(settingsFile); 109 | }, 110 | save: function() { 111 | try { 112 | fs.writeFileSync(settingsFile, JSON.stringify(this.v)); 113 | } catch (e) { 114 | fs.writeFileSync(userSettingsFile, JSON.stringify(this.v)); 115 | } 116 | }, 117 | load: function() { 118 | this.v = {}; 119 | try { 120 | if (fs.existsSync(settingsFile)) { 121 | this.v = JSON.parse(fs.readFileSync(settingsFile)); 122 | } 123 | } catch(e) {} 124 | 125 | // Comb in defaults 126 | for(var i in this.defaults) { 127 | if (!_.has(this.v, i)) { 128 | this.v[i] = this.defaults[i]; 129 | } 130 | } 131 | 132 | // Load user config. 133 | var user_config = {}; 134 | try { 135 | if (fs.existsSync(userSettingsFile)) { 136 | user_config = require(userSettingsFile); 137 | } 138 | } catch(e) {} 139 | 140 | for(var i in user_config) { 141 | this.v[i] = user_config[i]; 142 | } 143 | 144 | this.save(); // Resave when we're done loading. 145 | }, 146 | reset: function() { 147 | this.clear(); 148 | this.load(); 149 | }, 150 | }; 151 | 152 | app.settings.load(); 153 | } 154 | 155 | 156 | /** 157 | * Initialize the windows/attach menus 158 | */ 159 | function windowInit() { 160 | // Quit when all windows are closed (including OSX). 161 | app.on('window-all-closed', function() { 162 | app.quit(); 163 | }); 164 | 165 | // This method will be called when Electron has done all the initialization 166 | // and should be ready for creating menus & browser windows. 167 | app.on('ready', function() { 168 | i18n.init({ 169 | ns: { 170 | namespaces: ['app', 'menus'], 171 | defaultNs: 'app' 172 | }, 173 | // Path to find file 174 | resGetPath: path.join(appPath, 'locales', '__lng__', '__ns__-__lng__.json'), 175 | // Path to store file 176 | resSetPath: path.join(appPath, 'locales', '__lng__', '__ns__-__lng__.json'), 177 | sendMissingTo: 'fallback|current|all', // Send missing values to 178 | lng: 'en-US' 179 | }, function(){ 180 | // Setup main window. 181 | var windowSettings = { 182 | minWidth: 680, 183 | minHeight: 420, 184 | width: app.settings.v.window.width, 185 | height: app.settings.v.window.height, 186 | resizable: true, 187 | icon: path.join(appPath, 'resources', 'app.png'), 188 | title: "PancakePainter", 189 | fullscreenable: false // Workaround for fullscreen OSX bug :'( 190 | }; 191 | 192 | // Centered or fixed window position? 193 | if (app.settings.v.window.y === 'center') { 194 | windowSettings.center = true; 195 | } else { 196 | windowSettings.x = app.settings.v.window.x; 197 | windowSettings.y = app.settings.v.window.y; 198 | } 199 | 200 | // Create the main application window. 201 | mainWindow = new BrowserWindow(windowSettings); 202 | 203 | // Window wrapper for dialog (can't include module outside of this) :P 204 | mainWindow.dialog = function(options, callback) { 205 | return dialog['show' + options.t](mainWindow, options, callback); 206 | }; 207 | 208 | // and load the index.html of the app. 209 | mainWindow.loadURL('file://' + __dirname + '/index.html'); 210 | 211 | 212 | // Save Move/Resize back to file 213 | mainWindow.on('move', function(){ 214 | var b = this.getBounds(); 215 | app.settings.v.window.x = b.x; 216 | app.settings.v.window.y = b.y; 217 | app.settings.v.window.width = b.width; 218 | app.settings.v.window.height = b.height; 219 | app.settings.save(); 220 | }); 221 | 222 | // Emitted when the window is closed. 223 | mainWindow.on('closed', function() { 224 | // Dereference the window object, usually you would store windows 225 | // in an array if your app supports multi windows, this is the time 226 | // when you should delete the corresponding element. 227 | mainWindow = null; 228 | }); 229 | }); 230 | }); 231 | } 232 | 233 | // Actually start initializing. We do this here to ensure we can completely exit 234 | // initialization without loading any windows during Squirrel updates. 235 | start(); 236 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PancakePainter! 2 | #### The super-simple drawing software for your PancakeBot. 3 | 4 | ### Download/Install [Latest release] - v1.4.0 5 | * *Windows 7-10* ➤ [x32](https://github.com/PancakeBot/PancakePainter/releases/download/v1.4.0/Install_PancakePainter_Win_32bit_v1.4.0.exe) / [x64](https://github.com/PancakeBot/PancakePainter/releases/download/v1.4.0/Install_PancakePainter_Win_64bit_v1.4.0.exe) 6 | * *Mac OSX 10.8+* ➤ [x64](https://github.com/PancakeBot/PancakePainter/releases/download/v1.4.0/PancakePainter_Mac_v1.4.0.dmg) 7 | * *Linux x64:*\* ➤ [Ubuntu/Debian](https://github.com/PancakeBot/PancakePainter/releases/download/v1.4.0/PancakePainter_1.4.0_amd64.deb) / [Redhat RPM](https://github.com/PancakeBot/PancakePainter/releases/download/v1.4.0/PancakePainter_1.4.0.x86_64.rpm) 8 | 9 | \*(requires [`autotrace`](http://packages.ubuntu.com/xenial/autotrace) system package) 10 | 11 | #### Check the [latest release page](https://github.com/PancakeBot/PancakePainter/releases/latest) for feature notes, known issues, and other details. 12 | 13 | ![PancakePainter](https://cloud.githubusercontent.com/assets/320747/10681916/96629bc8-78e3-11e5-99e6-4f6c3e13cc86.png) 14 | 15 | ---- 16 | 17 | ### User Documentation 18 | 0. **Using the drawing tool:** 19 | * Click and drag to draw pancake lines freehand 20 | * Click single points to draw polygonal shapes, press right click or 21 | ESC/Enter to complete drawing. 22 | 0. **Using the selection tool:** 23 | * Click the center or near a line to select it, shift click to add to 24 | selection. 25 | * Alternate selection: Click and drag to create a selection marquee to fully 26 | encompass any objects you'd like to select _(v1.3.0)_. 27 | * Once selected, click and drag the corner handles to scale the object, or 28 | the top rotation handle to rotate it. 29 | * Click and drag points on the line to move them, shift-click to remove, or 30 | click an area on the line without any points to add a new point. 31 | * Click and drag the selected object anywhere else to move it to a new 32 | position. 33 | 0. **Manual image trace import tool:** 34 | * To import an image to trace by hand, click the image import icon, then 35 | select the manual import icon on the left. Select your image (in any standard 36 | web format, GIF, JPG, PNG), and it will be placed on the canvas. 37 | * Once imported, you can move the image around and scale/rotate it as needed. 38 | * When done, click outside the image, press ESC, or select the drawing 39 | tool. 40 | * To adjust the image position, just click the image import button again. To 41 | choose a new image, press the Delete key when in edit mode then click import 42 | again. 43 | 0. **Automatic image trace import tool _(v1.3.0)_:** 44 | * Click the image import icon and select either of the two automatic trace 45 | presets. 46 | * Within the automatic trace window, adjust the settings to your liking. 47 | * When complete, select how many copies you want & click the "Place" button. 48 | * You now should have fills and strokes as if you had drawn them yourself. 49 | 0. **Using the fill tool:** 50 | * The fill tool is used to visually fill an area with a specific shade, which 51 | will then be used to create a zig-zag fill pattern used by the PancakeBot. 52 | * Click inside an empty area enclosed on all sides by drawn lines to fill 53 | that space. Large or complex fills may take some time. 54 | * Only drawn lines define what can be filled, not imported images or the 55 | drawable boundary. 56 | * If the algorithm cannot fill what you've drawn, you will be notified with a 57 | reason why. 58 | * If a complex fill ends up with triangles across it or doesn't look right, 59 | select and delete it, then adjust the surrounding shapes and try again. 60 | 0. **Export your drawing for printing:** 61 | * Your PancakeBot uses a readable text format for input called GCODE to 62 | create your pancake art. Unique to each drawing and configuration, they tell 63 | your bot how to move and when to extrude batter to make your drawing. 64 | * To generate the file you need, use the menu "File > Export for printing..." 65 | and select a location to save the file. You can then place this on your bot's 66 | SD card and print at your leisure. 67 | 68 | Official support will eventually be found @ 69 | [PancakeBot.com](http://www.pancakebot.com) 70 | 71 | ## Problems? 72 | ***Stuck on something?*** Submit an issue! Click the 73 | [issues tab](https://github.com/PancakeBot/PancakePainter/issues) and see if 74 | someone is covering your question or problem, if not, ask away! Someone will be 75 | around to help soon. 76 | 77 | ***Know how to fix a problem? Or want to add a new feature??*** Submit a pull 78 | request! Just fork the repo using the button on the 79 | [github homepage](https://github.com/PancakeBot/PancakePainter), and 80 | this will give you your own version of PancakePainter. Make your change in a few 81 | commits to a new branch, then click the pull request button at the top! Talk 82 | about what changes you made and submit. A maintainer of the project will check 83 | your work, possibly ask you to fix a few more things, and then if all is well, 84 | your work will be merged into the project. It's that easy, really. 85 | 86 | ## Contributing to the Project 87 | PancakePainter uses Github's [Electron application shell](http://electron.atom.io) 88 | as a cross platform wrapper, and to create the application logic everything is 89 | written in plain JavaScript. If you know how to mess with websites, HTML, CSS or 90 | jQuery, you can bend PancakePainter to your whim! Read on to get your own dev 91 | environment setup to start hacking. 92 | 93 | ### Local Run Prerequisites 94 | 95 | #### Node.js (4.x+) & npm 96 | Required for automated builds and node module install. Electron uses Node.js 97 | and npm to manage running and packages. See [nodejs.org](http://nodejs.org) for 98 | installation for your operating system. `npm` is installed along with it. If you 99 | already have node installed, you can probably go without upgrading as Electron 100 | provides its own node.js implementation built in. 101 | 102 | #### Install PancakePainter run resources 103 | Though the `src/index.html` may somewhat render in a regular browser, you're 104 | going to need to run it inside of Electron before it all works. To get the local 105 | code running, be sure to run `npm install --force` from the repository root, 106 | this will give you the third party resources needed to run. The `--force` is 107 | unfortunately required to pass install of Paper.js as a node module, even 108 | though we only use it as a clientside library, so we can ignore the 109 | errors. See the tracking [issue here](https://github.com/paperjs/paper.js/issues/739). 110 | 111 | #### Build Tools 112 | Various node modules require builds and may complain if you don't have the right 113 | build tools. These are great to have regardless on any OS you use. 114 | 115 | ##### Windows 116 | * You'll need the free download version of 117 | [Visual Studio Express 2013](http://www.microsoft.com/visualstudio/eng/2013-downloads#d-2013-express) 118 | which will have the command line tools required for builds. 119 | 120 | ##### Mac OSX 121 | * Install Xcode and the CLI Developer tools. 122 | * You _might_ be able to [skip installing Xcode to get the GCC tools alone](http://osxdaily.com/2012/07/06/install-gcc-without-xcode-in-mac-os-x/). 123 | 124 | ##### Linux 125 | * This is the easiest, as most [FOSS](http://en.wikipedia.org/wiki/FOSS) ships 126 | as source to be built on the target machines, so you shouldn't have to install 127 | anything new for this at all. 128 | * Note there is currently no officially supported Linux release, but the app 129 | should run fine there. If there is call for support, it can be added (or submit 130 | a Pull Request!) 131 | 132 | ### Running from source 133 | * Once `npm install` has run, just run `npm start` from the repository root. 134 | * Remember: Alt+Ctrl+I to open the debug console, Ctl+R will reload if the 135 | console is open, and a reload _only_ reloads the contents of the window, and 136 | will _**not**_ reload the application main process. 137 | 138 | ## ETC. 139 | This open source project has been built with love by 140 | [TechNinja](https://github.com/techninja), made possible though direct support 141 | from [Storebound](http://storebound.com), 142 | [PancakeBot](https://github.com/PancakeBot), and Kickstarter Backers like _you_! 143 | 144 | [Windows installation GIF](https://github.com/PancakeBot/PancakePainter/blob/master/resources/win32/install_anim.gif) 145 | made with permission from animation work done by 146 | the incredible [Orbo](https://www.reddit.com/r/orbo). 147 | 148 | All code licensed under Apache v2.0 149 | -------------------------------------------------------------------------------- /src/tools/tool.fill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Tool definition for the PC super-crazy visual flood fill tool. 3 | **/ 4 | /*globals $, _, toastr, i18n */ 5 | "use strict"; 6 | 7 | module.exports = function(paper) { 8 | var tool = new paper.Tool(); 9 | 10 | // Paper global extenders 11 | var Path = paper.Path; 12 | var Point = paper.Point; 13 | var Rectangle = paper.Rectangle; 14 | var project = paper.project; 15 | var CompoundPath = paper.CompoundPath; 16 | var view = paper.view; 17 | 18 | // Tool identification (for building out tool palette) 19 | tool.name = 'tools.fill'; 20 | tool.key = 'fill'; 21 | tool.cursorColors = true; // Different icons/cursor for each color? 22 | tool.cursorOffset = '1 9'; // Position for cursor point 23 | tool.pathSimplifyAmt = 0.7; // How much to simplify pixel boundary paths 24 | tool.smallShapeArea = 200; // Minimum size to be considered a "small" shape 25 | tool.smallShapeSimplify = 0.2; // Amount to simplify "small" fill shapes 26 | tool.islandThreshold = 10; // Max distance between fill boundary nodes 27 | tool.alphaBitmapThreshold = 150; // 0-255, value that's considered visible 28 | 29 | // Tool vars 30 | var ndarray = require('ndarray'); 31 | var flood = require('n-dimensional-flood-fill'); 32 | 33 | var filling = false; 34 | tool.onMouseDown = function(event) { 35 | if (filling) return; 36 | 37 | $('#editor').toggleClass('wait', true); 38 | filling = true; 39 | 40 | // Run the fill in a timeout to allow the previous code to run first. 41 | setTimeout(function() { 42 | cleanAllPaths(); // Clean paths of any duplicate points. 43 | var fillPath = floodFill(event.point); 44 | 45 | if (fillPath !== false) { 46 | fillPath.fillColor = paper.pancakeShades[paper.pancakeCurrentShade]; 47 | fillPath.data.color = paper.pancakeCurrentShade; 48 | paper.fileChanged(); 49 | } 50 | 51 | $('#editor').toggleClass('wait', false); 52 | view.update(true); 53 | filling = false; 54 | }, 200); 55 | 56 | }; 57 | 58 | // TEMPORARY path cleaning function to ensure we can always fill with the 59 | // paperjs/paper.js#801 issue still around. 60 | function cleanAllPaths() { 61 | var cLayer = project.getActiveLayer(); 62 | _.each(cLayer.children, function(path) { 63 | paper.cleanPath(path); 64 | }); 65 | } 66 | 67 | // Attempt to flood fill at the given point, on the current layer. 68 | // Will return false if clicked out of bounds or floods to boundary. 69 | // Otherwise will return either the fill path underneath the point, or the 70 | // new fill path created. 71 | function floodFill(point) { 72 | var cLayer = project.getActiveLayer(); 73 | 74 | // Check for Paths 75 | if (cLayer.children.length === 0) { 76 | // No paths? Can't do a darn thing. 77 | toastr.warning(i18n.t("tools.warnings.fill.nopaths")); 78 | return; 79 | } 80 | 81 | // Fist check to see if the user clicked ON a stroke or existing fill 82 | var ht = cLayer.hitTest(point, { 83 | tolerance: 3, 84 | fill: true, 85 | stroke: true 86 | }); 87 | 88 | if (ht) { 89 | if (ht.item.data.fill) { 90 | return ht.item; 91 | } else { 92 | toastr.warning(i18n.t("tools.warnings.fill.path")); 93 | return false; 94 | } 95 | } 96 | 97 | var rast, rastPt; 98 | var boundaryPoints = []; 99 | try { 100 | rast = cLayer.rasterize(50); 101 | var w = rast.width; var h = rast.height; 102 | var pix = rast.getImageData(new Rectangle(0, 0, w, h)).data; 103 | var grid = ndarray(new Int8Array(pix.length/4), [w-1, h-1]); 104 | 105 | // Move through all RGBA pixel data to generate a 1bit map of visible pix. 106 | for (var p = 0; p < pix.length; p+= 4) { 107 | // If the alpha is greater than threshold, it's visible! Map a 1. 108 | if (pix[p+3] > tool.alphaBitmapThreshold) { 109 | grid.set((p / 4) % w, Math.floor((p / 4) / w), 1); 110 | } 111 | } 112 | 113 | rastPt = rast.globalToLocal(point); 114 | // Offset for centered matrix position and trunc floats. 115 | rastPt.x = parseInt(rastPt.x + w/2); 116 | rastPt.y = parseInt(rastPt.y + h/2); 117 | 118 | // Outside the bounds of the layer data! 119 | if (rastPt.x > w || rastPt.x < 0 || rastPt.y > h || rastPt.y < 0) { 120 | toastr.warning(i18n.t("tools.warnings.fill.bounds")); 121 | rast.remove(); 122 | return false; 123 | } 124 | } catch(e) { 125 | toastr.error(i18n.t("tools.error.fill")); 126 | console.error(e); 127 | rast.remove(); 128 | return false; 129 | } 130 | 131 | // n-dimensional-flood-fill 132 | var hitLimit = false; 133 | flood({ 134 | seed: [rastPt.x, rastPt.y], 135 | getter: function(x, y){ 136 | // Apparently ndarray will take insane values and return real values :/ 137 | if (x < 0 || y < 0 || x > w || y > h || hitLimit) return undefined; 138 | return grid.get(x, y); 139 | }, 140 | onBoundary: function(x, y) { 141 | if (x === w || x === 0 || y === h || y === 0) { 142 | hitLimit = true; 143 | } 144 | 145 | if (!hitLimit) { 146 | boundaryPoints.push(rast.localToGlobal(new Point(x - w/2, y - h/2))); 147 | } 148 | } 149 | }); 150 | 151 | // If our flood fill touched the edge of the layer, fill wasn't closed. 152 | if (hitLimit) { 153 | toastr.warning(i18n.t("tools.warnings.fill.notclosed")); 154 | rast.remove(); 155 | return false; 156 | } 157 | 158 | // We're done with the raster. 159 | rast.remove(); 160 | 161 | // Create the compound fillpath from the boundary points. 162 | var fillPath = new CompoundPath({ 163 | children: getCompoundBoundaryPaths(boundaryPoints), 164 | data: {fill: true} 165 | }); 166 | fillPath.remove(); 167 | cLayer.insertChild(0, fillPath); // Put all fills at the bottom 168 | 169 | return fillPath; 170 | } 171 | 172 | // Convert the list of fill boundary points into an array of paths. 173 | // If you're filling a face, everything within it will be a new path, 174 | function getCompoundBoundaryPaths(bPoints) { 175 | var pathGroups = distanceSort(bPoints); 176 | var out = []; 177 | _.each(pathGroups, function(segments){ 178 | out.push(new Path({ 179 | closed: true, 180 | segments: segments 181 | })); 182 | var idx = out.length-1; 183 | var area = out[idx].bounds.width * out[idx].bounds.height; 184 | 185 | // Cleanup based on area size 186 | if (area === 0) { 187 | out.pop().remove(); 188 | } else if (area <= tool.smallShapeArea) { 189 | out[idx].simplify(tool.smallShapeSimplify); 190 | } else { 191 | out[idx].simplify(tool.pathSimplifyAmt); 192 | } 193 | }); 194 | return out; 195 | } 196 | 197 | // Sort an array of Points by distance, grouped by distance threshold. 198 | function distanceSort(points) { 199 | // Use an external function to find the most appropriate starting point. 200 | var out = [[points.splice(getFillStartID(points), 1)[0]]]; 201 | var cGroup = 0; 202 | 203 | // Loop through every point, adding the next closest point, 204 | // removing the previous points. 205 | while (points.length) { 206 | var lastPoint = out[cGroup][out[cGroup].length-1]; 207 | var nextPoint = closestPoint(lastPoint, points); 208 | 209 | // If the distance is further away than "normal", we must be jumping to a 210 | // sub path. Increment the group. 211 | if (nextPoint.dist > tool.islandThreshold) { 212 | cGroup++; 213 | out[cGroup] = []; 214 | } 215 | 216 | out[cGroup].push(points.splice(nextPoint.id, 1)[0]); 217 | } 218 | 219 | return out; 220 | } 221 | 222 | // Given a list of points, find the one closest to the given point. 223 | function closestPoint(point, list) { 224 | var closestID = 0; 225 | var closest = point.getDistance(list[0]); 226 | _.each(list, function(p, index){ 227 | var dist = point.getDistance(p); 228 | if (dist < closest) { 229 | closest = dist; 230 | closestID = index; 231 | } 232 | }); 233 | 234 | return {id: closestID, dist: closest}; 235 | } 236 | 237 | 238 | // Find the most appropriate fill starting point given an array of points. 239 | function getFillStartID(points) { 240 | var bestID = 0; 241 | var lowestY = points[0].y; 242 | _.each(points, function(p, index){ 243 | if (p.y < lowestY) { 244 | lowestY = p.y; 245 | bestID = index; 246 | } 247 | }); 248 | 249 | return bestID; 250 | } 251 | 252 | return tool; 253 | }; 254 | -------------------------------------------------------------------------------- /src/editor.ps.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @file This PaperScript file controls the main PancakePainter SVG Editor and 3 | * all importing/exporting of its data. 4 | */ 5 | /* globals 6 | window, mainWindow, _, toastr, i18n, paper, view, project, scale, app, 7 | Raster, Group, Point, Path, Layer, path, fs, editorLoadedInit 8 | */ 9 | 10 | var dataURI = require('datauri'); 11 | 12 | paper.strokeWidth = 5; // Custom 13 | paper.settings.handleSize = 10; 14 | 15 | // Layer Management (custom vars) 16 | paper.imageLayer = project.getActiveLayer(); // Behind the active layer 17 | paper.mainLayer = new Layer(); // Everything is drawn on here by default now 18 | 19 | // Hold onto the base colors for the palette (also custom) 20 | paper.pancakeShades = app.constants.pancakeShades; 21 | 22 | // Handy translated color names 23 | paper.pancakeShadeNames = []; 24 | _.each(paper.pancakeShades, function(color, index){ /* jshint unused:false */ 25 | paper.pancakeShadeNames.push(i18n.t('color.color' + index)); 26 | }); 27 | 28 | paper.pancakeCurrentShade = 0; 29 | 30 | // TODO: Load all tools in folder based on weight 31 | var toolPen = require('./tools/tool.pen')(paper); 32 | var toolFill = require('./tools/tool.fill')(paper); /* jshint ignore:line */ 33 | var toolSelect = require('./tools/tool.select')(paper); 34 | 35 | // Load Helpers 36 | // TODO: Load via files in dir, API style. 37 | _.each(['undo', 'clipboard', 'utils', 'autotrace'], function(helperName) { 38 | paper[helperName] = require('./helpers/helper.' + helperName)(paper); 39 | }); 40 | 41 | paper.setCursor = function(type) { 42 | // TODO: Implement cursor change on hover of handles, objects, etc 43 | if (!type) type = 'default'; 44 | }; 45 | 46 | function onResize(event) { /* jshint ignore:line */ 47 | // Ensure paper project view retains correct scaling and position. 48 | view.zoom = scale; 49 | var corner = view.viewToProject(new Point(0,0)); 50 | view.scrollBy(new Point(0,0).subtract(corner)); 51 | } 52 | 53 | // Initialize (or edit) an image import for tracing on top of 54 | paper.initImageImport = function() { 55 | if (!paper.traceImage) { 56 | mainWindow.dialog({ 57 | t: 'OpenDialog', 58 | title: i18n.t('import.title'), 59 | filters: [ 60 | { 61 | name: i18n.t('import.files'), 62 | extensions: ['jpg', 'jpeg', 'gif', 'png'] 63 | } 64 | ] 65 | }, function(filePath){ 66 | if (!filePath) { // Open cancelled 67 | paper.finishImageImport(); 68 | return; 69 | } 70 | 71 | paper.imageLayer.activate(); // Draw the raster to the image layer 72 | var img = new Raster({ 73 | source: dataURI(filePath[0]), 74 | position: view.center 75 | }); 76 | // The raster MUST be in a group to alleviate coord & scaling issues. 77 | paper.traceImage = new Group([img]); 78 | paper.traceImage.img = img; 79 | paper.mainLayer.activate(); // We're done with the image layer for now 80 | 81 | // TODO: Bad images never trigger onload 82 | img.onLoad = function() { 83 | // Size the image down 84 | var scale = { 85 | x: (view.bounds.width * 0.8) / this.width, 86 | y: (view.bounds.height * 0.8) / this.height 87 | }; 88 | 89 | paper.traceImage.pInitialBounds = this.bounds; 90 | 91 | // Use the smallest scale 92 | scale = (scale.x < scale.y ? scale.x : scale.y); 93 | paper.traceImage.scale(scale); 94 | 95 | paper.traceImage.opacity = 0.5; 96 | 97 | // Select the thing and disable other selections 98 | toolSelect.imageTraceMode(true); 99 | }; 100 | }); 101 | } else { 102 | // Select the thing and disable other selections 103 | toolSelect.imageTraceMode(true); 104 | } 105 | 106 | view.update(); 107 | }; 108 | 109 | // Called when completing image import management 110 | paper.finishImageImport = function() { 111 | window.activateToolItem('#tool-pen'); 112 | toolPen.activate(); 113 | toolSelect.imageTraceMode(false); 114 | view.update(); 115 | }; 116 | 117 | // Shortcut for deferring logic to paperscript from app.js. 118 | paper.selectAll = function(items) { 119 | if (paper.tool.name !== "tools.select") { 120 | window.activateToolItem('#tool-select'); 121 | toolSelect.activate(); 122 | } 123 | 124 | toolSelect.selectAll(items); 125 | }; 126 | 127 | // Clear the existing project workspace/file (no confirmation) 128 | paper.newPBP = function(noLayers) { 129 | paper.emptyProject(); 130 | 131 | if (!noLayers) { 132 | paper.imageLayer = project.getActiveLayer(); // Creates the default layer 133 | paper.mainLayer = new Layer(); // Everything is drawn on here by default now 134 | paper.undo.clearState(); 135 | } 136 | 137 | view.update(); 138 | 139 | // Reset current file status (keeping previous file name, for kicks) 140 | app.currentFile.name = ""; 141 | app.currentFile.changed = false; 142 | }; 143 | 144 | // Just Empty/Clear the workspace. 145 | paper.emptyProject = function() { 146 | paper.deselect(); 147 | paper.selectRectLast = null; 148 | 149 | paper.imageLayer.remove(); 150 | paper.mainLayer.remove(); 151 | project.clear(); 152 | 153 | if (paper.traceImage) { 154 | paper.traceImage.remove(); 155 | paper.traceImage = null; 156 | } 157 | }; 158 | 159 | // Handle undo requests (different depending on if the tool cares). 160 | paper.handleUndo = function(op) { 161 | // If the tool provides a function, and it returns false, don't run undo. 162 | if (typeof paper.tool.undoSet === 'function') { 163 | if (!paper.tool.undoSet(op)) { 164 | return; 165 | } 166 | } 167 | 168 | if (op === 'undo') { 169 | paper.undo.goBack(); 170 | } else if (op === 'redo') { 171 | paper.undo.goForward(); 172 | } 173 | }; 174 | 175 | // Handle clipboard requests 176 | paper.handleClipboard = function(op) { 177 | // Select all is being weird... 178 | // TODO: this probably shouldn't go here... 179 | if (op.ctrlKey && op.keyCode === 65) { 180 | paper.selectAll(); 181 | return; 182 | } 183 | 184 | // For clarity, don't do any clipboard operations if not on the select tool. 185 | if (paper.tool.name !== 'tools.select') { 186 | return; 187 | } 188 | 189 | // Support "event" passthrough from window keydown event. 190 | var event = op; 191 | if (typeof op === 'object') { 192 | if (event.ctrlKey && event.keyCode === 67) { 193 | op = 'copy'; 194 | } 195 | if (event.ctrlKey && event.keyCode === 88) { 196 | op = 'cut'; 197 | } 198 | if (event.ctrlKey && event.keyCode === 86) { 199 | op = 'paste'; 200 | } 201 | if (event.ctrlKey && event.keyCode === 68) { 202 | op = 'duplicate'; 203 | } 204 | 205 | // If our captured keystroke didn't result in valid op, quit. 206 | if (typeof op !== 'string') { 207 | return; 208 | } 209 | 210 | // Prevent whatever else was going to happen. 211 | event.preventDefault(); 212 | } 213 | 214 | switch (op) { 215 | case 'cut': 216 | case 'copy': 217 | paper.clipboard.copy(op === 'cut'); 218 | break; 219 | case 'paste': 220 | paper.clipboard.paste(); 221 | break; 222 | case 'duplicate': 223 | paper.clipboard.dupe(); 224 | break; 225 | } 226 | }; 227 | 228 | 229 | // Render the text/SVG for the pancakebot project files 230 | paper.getPBP = function(){ 231 | paper.deselect(); // Don't export with something selected! 232 | return project.exportJSON(); 233 | }; 234 | 235 | // Called whenever the file is changed from a tool 236 | paper.fileChanged = function() { 237 | app.currentFile.changed = true; 238 | paper.undo.stateChanged(); 239 | }; 240 | 241 | // Stopgap till https://github.com/paperjs/paper.js/issues/801 is resolved. 242 | // Clean a path of duplicated segment points, triggered on change/create 243 | paper.cleanPath = function(path){ 244 | _.each(path.segments, function(seg, index){ 245 | if (index > 0 && typeof path.segments[index-1] !== 'undefined') { 246 | var lastP = path.segments[index-1].point; 247 | if (lastP.x === seg.point.x && lastP.y === seg.point.y) { 248 | // Duplicate point found, remove it. 249 | seg.remove(); 250 | } 251 | } 252 | }); 253 | }; 254 | 255 | // Load a given PBP filepath into the project workspace 256 | paper.loadPBP = function(filePath){ 257 | paper.newPBP(true); 258 | 259 | app.currentFile.name = path.parse(filePath).base; 260 | app.currentFile.path = filePath; 261 | app.currentFile.changed = false; 262 | 263 | project.importJSON(fs.readFileSync(filePath, "utf8")); 264 | 265 | paper.imageLayer = project.layers[0]; 266 | paper.mainLayer = project.layers[1]; 267 | 268 | paper.mainLayer.activate(); 269 | 270 | // Reinstate traceImage, if any. 271 | if (paper.imageLayer.children.length) { 272 | paper.traceImage = paper.imageLayer.children[0]; 273 | paper.traceImage.img = paper.traceImage.children[0]; 274 | } 275 | 276 | toastr.info(i18n.t('file.opened', {file: app.currentFile.name})); 277 | paper.undo.clearState(); 278 | view.update(); 279 | }; 280 | 281 | 282 | // Editor should be done loading, trigger loadInit 283 | editorLoadedInit(); 284 | -------------------------------------------------------------------------------- /src/windows/window.export.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file This is the window node module for the export/settings window 3 | * that supplies init and binding code for the PancakePainter window API. 4 | * Exports function returns a window control object that allows triggering on 5 | * init, show, and hide events. 6 | * We have full access to globals loaded in the mainWindow as needed, just 7 | * reference them below. 8 | **/ 9 | /* globals window, mainWindow, app, $, paper, i18n, fs, toastr, path */ 10 | 11 | module.exports = function(context) { 12 | var exportData = { 13 | simulatorLoaded: false, // Sets to true when the simulator is ready. 14 | initLoaded: false, // Sets to true when the path data has been imported. 15 | renderUpdateRunning: false, // Whether we're currently rendering an update. 16 | renderConfig: {}, // Placeholder for render config passover from settings. 17 | gcode: "", // Placeholder for exported GCODE. 18 | filePath: "", // Export final data write path. 19 | }; 20 | 21 | var $loadingBar = $('.loader', context); 22 | 23 | /** 24 | * Initialize the renderConfig object for GCODE export with static constants. 25 | */ 26 | function initRenderConfig() { 27 | var ac = app.constants; 28 | exportData.renderConfig = { 29 | printArea: { // Print area limitations (in 1 MM increments) 30 | x: ac.printableArea.offset.right, 31 | t: 0, 32 | l: ac.printableArea.width + ac.printableArea.offset.right, 33 | y: ac.printableArea.height 34 | }, 35 | version: app.getVersion() // Application version written to GCODE header 36 | }; 37 | } 38 | 39 | /** 40 | * Bind change on the non-managed inputs to trigger setRenderSettings. 41 | */ 42 | function bindSettings() { 43 | $('input:not(.settings-managed)', context).change(function() { 44 | exportData.setRenderSettings(); 45 | }); 46 | } 47 | 48 | /** 49 | * Bind the various buttons on the window. 50 | */ 51 | function bindButtons() { 52 | $('button', context).click(function() { 53 | switch(this.name) { 54 | case 'cancel': 55 | mainWindow.overlay.toggleWindow('export', false); 56 | break; 57 | 58 | case 'reset': 59 | mainWindow.resetSettings(); 60 | break; 61 | 62 | case 'reselect': 63 | exportData.pickFile(function(filePath) { 64 | if (filePath) { 65 | exportData.filePath = filePath; 66 | mainWindow.overlay.toggleWindow('overlay', true); 67 | } 68 | }); 69 | break; 70 | 71 | case 'export': 72 | exportData.saveData(); 73 | break; 74 | } 75 | }); 76 | 77 | // Bind ESC key exit. 78 | // TODO: Build this off data attr global bind thing. 79 | $(context).keydown(function(e){ 80 | if (e.keyCode === 27) { // Global escape key exit window 81 | $('button[name=cancel]', context).click(); 82 | } 83 | }); 84 | } 85 | 86 | /** 87 | * Initialize the webview allowing multiprocess rendering. 88 | */ 89 | function setupWebview() { 90 | exportData.$webview = $('#simulator-webview'); 91 | var wv = exportData.$webview[0]; 92 | 93 | // FWD console messages & errors. 94 | wv.addEventListener('console-message', function(event) { 95 | console.log('SIMULATOR:', event.message); 96 | }); 97 | 98 | // Send message handlers TO app. 99 | exportData.$webview.send = { 100 | loadInit: function() { 101 | wv.send('loadInit', paper.mainLayer.exportJSON()); 102 | }, 103 | renderTrigger: function() { 104 | wv.send('renderTrigger', exportData.renderConfig); 105 | }, 106 | cleanup: function() { 107 | wv.send('cleanup'); 108 | } 109 | }; 110 | 111 | // Catch IPC messages FROM app. 112 | wv.addEventListener('ipc-message', function(event) { 113 | //console.log('RECV ', event.channel); // DEBUG 114 | var data = event.args[0]; 115 | switch (event.channel) { 116 | case 'paperReady': 117 | // Only run on first window init. 118 | exportData.simulatorLoaded = true; 119 | exportData.$webview.send.loadInit(); 120 | exportData.$webview.css('opacity', 1); 121 | break; 122 | case 'initLoaded': 123 | exportData.initLoaded = true; 124 | exportData.renderUpdate(); // Run Initial render. 125 | break; 126 | case 'renderComplete': 127 | renderUpdateComplete(); 128 | exportData.gcode = data; 129 | break; 130 | } 131 | }); 132 | 133 | wv.addEventListener('dom-ready', function(){ 134 | //wv.openDevTools(); // DEBUG 135 | }); 136 | } 137 | 138 | // Map the settings to the renderConfig object. 139 | // @see: main.js settings init default for explanations and default values. 140 | exportData.setRenderSettings = function() { 141 | var rc = exportData.renderConfig; 142 | rc.flattenResolution = app.settings.v.flatten; 143 | rc.lineEndPreShutoff = app.settings.v.shutoff; 144 | rc.startWait = app.settings.v.startwait; 145 | rc.endWait = app.settings.v.endwait; 146 | rc.shadeChangeWait = app.settings.v.changewait; 147 | rc.useLineFill = app.settings.v.uselinefill; 148 | rc.useShortest = app.settings.v.useshortest; 149 | rc.fillSpacing = app.settings.v.fillspacing; 150 | rc.fillAngle = app.settings.v.fillangle; 151 | rc.fillGroupThreshold = app.settings.v.fillthresh; 152 | rc.shapeFillWidth = app.settings.v.shapefillwidth; 153 | rc.botSpeed = parseInt( 154 | (app.settings.v.botspeed / 100) * app.constants.botSpeedMax, 155 | 10 156 | ); 157 | 158 | // Capture editor view bounds and pass along for conversion as source. 159 | rc.sourceBounds = paper.view.bounds; 160 | 161 | // Mirroring swap. 162 | rc.noMirror = !$('#mirrorexport', context).prop('checked'); 163 | 164 | rc.useColorSpeed = app.settings.v.usecolorspeed; 165 | rc.botColorSpeed = [ 166 | parseInt( 167 | (app.settings.v.botspeedcolor1 / 100) * app.constants.botSpeedMax, 10 168 | ), 169 | parseInt( 170 | (app.settings.v.botspeedcolor2 / 100) * app.constants.botSpeedMax, 10 171 | ), 172 | parseInt( 173 | (app.settings.v.botspeedcolor3 / 100) * app.constants.botSpeedMax, 10 174 | ), 175 | parseInt( 176 | (app.settings.v.botspeedcolor4 / 100) * app.constants.botSpeedMax, 10 177 | ), 178 | ]; 179 | 180 | exportData.renderUpdate(); 181 | }; 182 | 183 | /** 184 | * Save rendered GCODE data to the given initialized filePath. 185 | */ 186 | exportData.saveData = function() { 187 | try { 188 | fs.writeFileSync(exportData.filePath, exportData.gcode); // Write file! 189 | 190 | // Notify user 191 | toastr.success( 192 | i18n.t('export.note', {file: path.parse(exportData.filePath).base}) 193 | ); 194 | mainWindow.overlay.toggleWindow('export', false); // Hide window. 195 | } catch(e) { 196 | console.error(e); 197 | // Notify user 198 | toastr.error( 199 | i18n.t('export.err', {file: path.parse(exportData.filePath).base}) 200 | ); 201 | } 202 | 203 | }; 204 | 205 | /** 206 | * Spawn the file save dialog for GCODE export, returns filePath in callback. 207 | * @param {Function} callback 208 | * Function to call back when the user is done picking the file. 209 | */ 210 | exportData.pickFile = function(callback) { 211 | mainWindow.dialog({ 212 | t: 'SaveDialog', 213 | title: i18n.t('export.title'), 214 | defaultPath: path.join( 215 | app.getPath('userDesktop'), 216 | app.currentFile.name.split('.')[0] 217 | ), 218 | filters: [ 219 | { name: 'PancakeBot GCODE', extensions: ['gcode'] } 220 | ] 221 | }, function(filePath) { 222 | // Verify file extension 223 | if (filePath && filePath.split('.').pop().toLowerCase() !== 'gcode') { 224 | filePath += '.gcode'; 225 | } 226 | 227 | callback(filePath); 228 | }); 229 | }; 230 | 231 | /** 232 | * Run a render multiprocess render update. 233 | */ 234 | exportData.renderUpdate = function () { 235 | if (!exportData.renderUpdateRunning && exportData.initLoaded) { 236 | exportData.renderUpdateRunning = true; 237 | $loadingBar.css('opacity', 100); 238 | 239 | exportData.$webview.send.renderTrigger(); 240 | } 241 | }; 242 | 243 | /** 244 | * Everything that has to happen to wrap up the render update. 245 | */ 246 | function renderUpdateComplete() { 247 | exportData.renderUpdateRunning = false; 248 | $loadingBar.css('opacity', 0); 249 | } 250 | 251 | /** 252 | * Window initialization callback, triggered on window import. 253 | */ 254 | exportData.init = function() { 255 | $(window).on('settingsChanged', exportData.setRenderSettings); 256 | setupWebview(); 257 | initRenderConfig(); 258 | bindSettings(); 259 | bindButtons(); 260 | }; 261 | 262 | /** 263 | * Window show event callback, triggered on window show. 264 | */ 265 | exportData.show = function() { 266 | if (exportData.simulatorLoaded) { 267 | exportData.$webview.send.loadInit(); 268 | } 269 | exportData.setRenderSettings(); 270 | }; 271 | 272 | /** 273 | * Window hide event callback, triggered on window close. 274 | */ 275 | exportData.hide = function() { 276 | exportData.$webview.send.cleanup(); 277 | exportData.initLoaded = false; 278 | }; 279 | 280 | /** 281 | * Window resize event callback, triggered on window resize. 282 | */ 283 | exportData.resize = function() { 284 | var h = $('.overlay-content > fieldset', context).height(); 285 | $('div.flex-wrapper', context).height(h - 18); 286 | }; 287 | 288 | return exportData; 289 | }; 290 | -------------------------------------------------------------------------------- /locales/en-US/app-en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "creator": "techninja", 4 | "target": "en-US", 5 | "langname": "English", 6 | "release": "1.2.0" 7 | }, 8 | "common": { 9 | "done": "Done", 10 | "loading": "Loading…", 11 | "complete": "Complete", 12 | "drawnote": "The design above will resemble the actual pancake once it has been flipped.", 13 | "button": { 14 | "cancel": "Cancel", 15 | "import": "Place", 16 | "yes": "Yes", 17 | "no": "No" 18 | } 19 | }, 20 | "tools": { 21 | "pen": "Batter line", 22 | "select": "Select", 23 | "fill": "Batter fill", 24 | "error": { 25 | "fill": "Error creating fill! Something may be wrong with the draw layer, check the console for more info." 26 | }, 27 | "warnings": { 28 | "fill": { 29 | "notclosed": "Flood fill area not closed.", 30 | "bounds": "Flood fill out of bounds.", 31 | "path": "Can't flood fill on top of an existing line.", 32 | "nopaths": "Can't flood fill without at least one closed line." 33 | } 34 | } 35 | }, 36 | "file": { 37 | "save": "Save PancakePainter Project…", 38 | "saveas": "Save PancakePainter Project as…", 39 | "open": "Open PancakePainter project file…", 40 | "opened": "Opened project \"__file__\"", 41 | "default": "Pancake Project", 42 | "type": "PancakePainter Project File", 43 | "note": "Saved project file \"__file__\"", 44 | "new": "Empty project started", 45 | "close": "Project closed, empty project started", 46 | "error": "Problem saving file! Try saving to a different file name or location.", 47 | "discarded": "File not saved, changes discarded", 48 | "confirm": { 49 | "notsaved": "Project file has not been saved!", 50 | "changed": "Project has changed since last save!", 51 | "savenew": "Save new project before continuing?", 52 | "save": "Save changes to \"__file__\" before continuing?" 53 | }, 54 | "button": { 55 | "discard": "Discard changes", 56 | "savenew": "Save as a new file", 57 | "save": "Save current file" 58 | } 59 | }, 60 | "color" : { 61 | "title": "Color selection", 62 | "color0": "Light", 63 | "color1": "Medium", 64 | "color2": "Medium dark", 65 | "color3": "Dark" 66 | }, 67 | "import": { 68 | "title": "Import image for tracing…", 69 | "autotitle": { 70 | "simple": "Import simple logo/cartoon image for tracing…", 71 | "complex": "Import complex image/photo for tracing…" 72 | }, 73 | "files": "Web format tracing image", 74 | "err": { 75 | "title": "Error opening image file for tracing", 76 | "message": "There was a problem loading \"__file__\"", 77 | "desc": "The error given was:\n\"__err__\"", 78 | "button": "Choose Another File" 79 | }, 80 | "auto": { 81 | "title": "Automatic Trace", 82 | "options": { 83 | "manual": "Place image in background for manual tracing", 84 | "simple": "Automatic trace for logos or cartoons", 85 | "complex": "Automatic trace for complex art or photos" 86 | }, 87 | "place": { 88 | "title": "Placement options" 89 | }, 90 | "settings": { 91 | "title": "Settings", 92 | "transparent": "Transparent color", 93 | "transparent-pick": "Pick color from image", 94 | "colors": "Shade Limit (1-4)", 95 | "presets": { 96 | "title": "Presets:", 97 | "simple": "Logos/Cartoons", 98 | "complex": "Photos/Complex art" 99 | }, 100 | "types": { 101 | "title": "Trace type", 102 | "options": { 103 | "mixed": { 104 | "title": "Dynamic Lines/Fills", 105 | "desc": "Good for logos and cartoons. Bad for photos or complex art." 106 | }, 107 | "fills": { 108 | "title": "Fills/shapes only", 109 | "desc": "Better for photos and complex art. Bad for line art and cartoons." 110 | }, 111 | "lines": { 112 | "title": "Lines only", 113 | "desc": "Good for simple line/coloring book art. Bad for cartoons, photos or complex art." 114 | } 115 | } 116 | }, 117 | "preprocess": "Preprocessing", 118 | "outline": "Outline fills in darker shade", 119 | "invert": "Invert colors", 120 | "contrast": "Contrast", 121 | "brightness": "Brightness", 122 | "blur": "Blur" 123 | } 124 | } 125 | }, 126 | "export": { 127 | "title": "Export creation for printing…", 128 | "start": "Export", 129 | "wait": "Exporting, please wait…", 130 | "err" : "Error exporting \"__file__\", please report this issue with the problem project file.", 131 | "note" : "Successfully exported \"__file__\" for printing.", 132 | "buttons": { 133 | "cancel": "Cancel", 134 | "reset": "Reset Settings", 135 | "export": "Export to File", 136 | "reselect": "Select a Different File" 137 | } 138 | }, 139 | "settings": { 140 | "done": "Done", 141 | "reset": "Reset", 142 | "title": "Advanced Settings", 143 | "resetconfirm": "Reset to factory default settings?", 144 | "resetconfirmdetail": "This will revert all settings on this page to default. This cannot be undone.", 145 | "button": { 146 | "reset": "Revert All Settings" 147 | }, 148 | "units": { 149 | "milliseconds": { 150 | "label": "ms", 151 | "title": "milliseconds" 152 | }, 153 | "seconds": { 154 | "label": " sec", 155 | "title": "second(s)" 156 | }, 157 | "millimeters": { 158 | "label": "mm", 159 | "title": "millimeter(s)" 160 | }, 161 | "percent": { 162 | "label": "% (__value__)", 163 | "title": "percent" 164 | }, 165 | "pixels": { 166 | "label": " dv/px", 167 | "title": "device pixels" 168 | }, 169 | "px": { 170 | "label": "px", 171 | "title": "pixels" 172 | }, 173 | "degrees": { 174 | "label": "°", 175 | "title": "degrees" 176 | } 177 | }, 178 | "gcode": { 179 | "title": "Print Export Options", 180 | "botspeed": "Print Speed:", 181 | "botspeedinfo": "The percent of the maximum speed that the PancakeBot will move at, defaults to 70%. If this has no effect on your PancakeBot you may need to install the new firmware available on PancakeBot.com. Increasing the speed of the PancakeBot may reduce its life span.", 182 | "flatten": "Smallest flatten distance:", 183 | "flatteninfo": "The resolution limit when converting curves into polygons for GCODE coordinates. Lower value creates more points and higher resolution, higher value creates fewer points and lower resolution approximation.", 184 | "shutoff": "Line end pre-shutoff distance:", 185 | "shutoffinfo": "The distance of travel before the end of a line that the pump should turn off ahead of, prevents line end drip increase. Larger distance means pump will shut off sooner.", 186 | "startwait": "Line start pump ON wait time:", 187 | "startwaitinfo": "The number of milliseconds to wait before we start moving at the beggining of a line once the pump has turned on. Correct value depends on batter viscosity and pump pressure.", 188 | "mirrorexport": "Mirror export", 189 | "mirrorexportinfo": "Mirror image before rendering GCODE, so pancake will appear correctly when flipped.", 190 | "endwait": "Line end pump OFF wait time:", 191 | "endwaitinfo": "The number of milliseconds to wait at the end of a line. Pump should have already shutoff early, this should ensure a clean line end. Correct value depends on batter viscosity and pump pressure.", 192 | "changewait": "Seconds between bottle/shade changes:", 193 | "changewaitinfo": "Amount of time the bot will wait between shade/color changes. Bot will remain parked during this time to allow cooking or bottle change.", 194 | "linefillgroup": "Line Fill Options", 195 | "uselinefill": "Use diagonal line fill:", 196 | "uselinefillinfo": "If enabled, PancakePainter will use the diagonal line fill algorithm when creating GCODE to fill shapes, instead of the default shape fill algorithm.", 197 | "fillspacing": "Line fill spacing:", 198 | "fillspacinginfo": "The amount of space between fill lines. Smaller values are closer together and more of them, larger values create fewer lines spaced further apart.", 199 | "fillangle": "Line fill angle (in degrees):", 200 | "fillangleinfo": "Angle of the automatic fill lines, defaults at 23, and be -180 to 180.", 201 | "fillthresh": "Line fill grouping threshold:", 202 | "fillthreshinfo": "Minimum threshold for grouping dynamic line endings together into connected groups. Large value connects more groups, 0 will ensure no groups are made.", 203 | "useshortest": "Use shortest path:", 204 | "useshortestinfo": "If enabled, the shortest movement path between each point for each shade will be selected when printing. When disabled, line drawing will remain in original order drawn, favoring lines before fills.", 205 | "shapefillwidth": "Shape fill effective batter width:", 206 | "shapefillwidthinfo": "Effective width of the batter line being drawn, iterated from the edge inwards on paths to be filled. Smaller values will make more lines when filling, adding more batter. Larger values will add fewer lines and less batter, and may leave some shapes unfilled or with holes in them.", 207 | "botspeedcolor1": "Shade 1 speed (light):", 208 | "botspeedcolor2": "Shade 2 speed (medium):", 209 | "botspeedcolor3": "Shade 3 speed (medium dark):", 210 | "botspeedcolor4": "Shade 4 speed (dark):", 211 | "usecolorspeed": "Shade specific speed:", 212 | "usecolorspeedinfo": "If enabled, set the shade specific speeds below to allow automatic setting of a different print speed after each shade change. Disable to use only the speed at the top of settings." 213 | } 214 | } 215 | } 216 | --------------------------------------------------------------------------------