svg2gcode 1.2.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/PKG-INFO +40 -11
- svg2gcode-2.1.0/README.md +98 -0
- svg2gcode-2.1.0/svg2gcode/README.md +98 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/__init__.py +1 -1
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/__main__.py +13 -4
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/__init__.py +9 -7
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/compiler/_compiler.py +66 -23
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/svg_parser/_parser_methods.py +47 -32
- svg2gcode-1.2.0/README.md +0 -69
- svg2gcode-1.2.0/svg2gcode/README.md +0 -69
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/LICENSE +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/pyproject.toml +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/.DS_Store +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/compiler/__init__.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/compiler/interfaces/__init__.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/compiler/interfaces/_abstract_interface.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/compiler/interfaces/_fan_controlled_gcode.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/compiler/interfaces/_gcode.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/formulas.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/__init__.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_abstract_chain.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_abstract_curve.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_circular_arc.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_cubic_bazier.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_elliptical_arc.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_line.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_line_segment_chain.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_matrix.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_quadratic_bazier.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_raster_image.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_smooth_arc_chain.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/geometry/_vector.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/svg_parser/__init__.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/svg_parser/_path.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/svg_parser/_transformation.py +0 -0
- {svg2gcode-1.2.0 → svg2gcode-2.1.0}/svg2gcode/svg_to_gcode/svg_parser/debug_methods.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: svg2gcode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: svg2gcode: convert an SVG (Scalable Vector Graphic) image to gcode.
|
|
5
5
|
Keywords: scalable vector graphics,svg,image,laser cutter,laser engraving
|
|
6
6
|
Author-email: Johannes Noordanus <mailjohannes.mailnoordanus@gmail.com>
|
|
@@ -16,27 +16,48 @@ Project-URL: Home, https://github.com/johannesnoordanus/svg2gcode
|
|
|
16
16
|
A commandline steering program that enables laser cutting of svg drawings```<svg:path ..>tags``` and combined engraving of svg images```<svg:image ..>tags```.
|
|
17
17
|
It is based on library SvgToGcode (*fork*: https://github.com/johannesnoordanus/SvgToGcode) which should be installed <sup>(*)</sup>.
|
|
18
18
|
|
|
19
|
-
Drawings and images can be composed using Inkscape (for example) and saved to a
|
|
19
|
+
Drawings and images can be composed using Inkscape (for example) and saved to a *.svg* file. This file can be converted to gcode by *svg2gcode*.
|
|
20
20
|
Gcode produced in this way has the advantage that drawings and images have the same - relative - position and orientation as can be seen on the composer window.
|
|
21
21
|
This makes combined cutting and engraving as easy as orientating the (wood) slab once.
|
|
22
22
|
|
|
23
23
|
Controlling laser power, pixel size and other settings can be done via commandline parameters (see below) or within Inkscape using the XMLeditor.
|
|
24
|
-
Image attributes ```gcode_pixelsize```, ```gcode_maxpower``` and ```
|
|
24
|
+
Image attributes ```gcode_pixelsize```, ```gcode_maxpower```, ```gcode_speed```, ```gcode_noise``` and ```gcode_speedmoves``` can be set per object (they must be created: use **+**). Note that this overrides explicit or default commandline settings.
|
|
25
|
+
|
|
26
|
+
Version 2.0.0 has important new speed optimizations. Engravings run significantly faster and skip from one image zone to the other at maximum speed. See options ```--speedmoves``` and ```--noise``` for example.
|
|
27
|
+
|
|
28
|
+
To summarize:
|
|
29
|
+
|
|
30
|
+
Optimized gcode
|
|
31
|
+
- draw pixels in one go until change of power
|
|
32
|
+
- emit X/Y coordinates only when they change
|
|
33
|
+
- emit linear move 'G1/G0' code minimally
|
|
34
|
+
- does not emit zero power (or below cutoff) pixels
|
|
35
|
+
|
|
36
|
+
General optimizations
|
|
37
|
+
- laser head has defered and sparse moves.
|
|
38
|
+
(XY locations are virtual, head does not always follow)
|
|
39
|
+
- moves at high speed (G0) over 10mm (default) or more zero pixels
|
|
40
|
+
- low burn levels (stray pixels) can be suppressed (default off)
|
|
41
|
+
- option *--constantburn* selects constant burn mode *M3* (for cutting and engraving) instead of default dynamic burn mode *M4*
|
|
42
|
+
|
|
43
|
+
**Tip**: use commandline program *grblhud* *(https://github.com/johannesnoordanus/grblhud)* to have full control over gcode execution,
|
|
44
|
+
also, program *image2gcode* has similar capabilities but handles raster images files (like *png* and *jpg*) directly.
|
|
25
45
|
|
|
26
|
-
**Tip**: use commandline program grblhud (https://github.com/johannesnoordanus/grblhud) to have full control over gcode execution.
|
|
27
46
|
### Install:
|
|
28
47
|
```
|
|
29
48
|
>
|
|
30
49
|
> pip install svg2gcode
|
|
31
50
|
```
|
|
32
|
-
<sup>(*)</sup> Note that library
|
|
51
|
+
<sup>(*)</sup> Note that this library is included.
|
|
33
52
|
### Usage:
|
|
34
53
|
See notes below.
|
|
35
54
|
```
|
|
36
55
|
$ svg2gcode --help
|
|
37
|
-
usage: svg2gcode
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
usage: svg2gcode [-h] [--showimage] [--pixelsize <default:0.1>] [--imagespeed <default:800>]
|
|
57
|
+
[--cuttingspeed <default:1000>] [--imagepower <default:300>] [--cuttingpower <default:850>]
|
|
58
|
+
[--rapidmove <default:10>] [--noise <default:0>] [--constantburn] [--xmaxtravel <default:300>]
|
|
59
|
+
[--ymaxtravel <default:400>] [--fan] [-V]
|
|
60
|
+
svg gcode
|
|
40
61
|
|
|
41
62
|
Convert svg to gcode for GRBL v1.1 compatible diode laser engravers.
|
|
42
63
|
|
|
@@ -54,16 +75,24 @@ options:
|
|
|
54
75
|
--cuttingspeed <default:1000>
|
|
55
76
|
cutting speed in mm/min
|
|
56
77
|
--imagepower <default:300>
|
|
57
|
-
maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the
|
|
78
|
+
maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the
|
|
79
|
+
machine maximum for a 5W laser)
|
|
58
80
|
--cuttingpower <default:850>
|
|
59
81
|
sets laser power of line drawings/cutting
|
|
60
|
-
--rapidmove
|
|
82
|
+
--rapidmove <default:10>
|
|
83
|
+
generate G0 moves between shapes, for images: G0 moves when skipping more than 10mm
|
|
84
|
+
(default), 0 is no G0 moves
|
|
85
|
+
--noise <default:0> reduces image noise by not emitting pixels with power lower or equal than this setting
|
|
86
|
+
--constantburn use constant burn mode M3 (a bit more dangerous!), instead of dynamic burn mode M4
|
|
87
|
+
--origin Xdelta Ydelta
|
|
88
|
+
translate origin by (Xdelta,Ydelta) (default not set)
|
|
61
89
|
--xmaxtravel <default:300>
|
|
62
90
|
machine x-axis lengh in mm
|
|
63
91
|
--ymaxtravel <default:400>
|
|
64
92
|
machine y-axis lengh in mm
|
|
65
93
|
--fan set machine fan on
|
|
66
94
|
-V, --version show version number and exit
|
|
95
|
+
|
|
67
96
|
```
|
|
68
97
|
### Notes:
|
|
69
98
|
- example command to create two types of gcode file, one containing the drawings of the .svg, the other containing the images:
|
|
@@ -77,7 +106,7 @@ options:
|
|
|
77
106
|
- drawing objects - within the composer - must be converted to a```path```to be translated to a gcode sequence
|
|
78
107
|
- also, image objects should **not** be converted to a ```path```
|
|
79
108
|
- images must be linked or embedded using base64.
|
|
80
|
-
- images can be in several formats (my tests included
|
|
109
|
+
- images can be in several formats (my tests included *.png* and *.jpg* image files)
|
|
81
110
|
|
|
82
111
|
|
|
83
112
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# svg2gcode
|
|
2
|
+
|
|
3
|
+
A commandline steering program that enables laser cutting of svg drawings```<svg:path ..>tags``` and combined engraving of svg images```<svg:image ..>tags```.
|
|
4
|
+
It is based on library SvgToGcode (*fork*: https://github.com/johannesnoordanus/SvgToGcode) which should be installed <sup>(*)</sup>.
|
|
5
|
+
|
|
6
|
+
Drawings and images can be composed using Inkscape (for example) and saved to a *.svg* file. This file can be converted to gcode by *svg2gcode*.
|
|
7
|
+
Gcode produced in this way has the advantage that drawings and images have the same - relative - position and orientation as can be seen on the composer window.
|
|
8
|
+
This makes combined cutting and engraving as easy as orientating the (wood) slab once.
|
|
9
|
+
|
|
10
|
+
Controlling laser power, pixel size and other settings can be done via commandline parameters (see below) or within Inkscape using the XMLeditor.
|
|
11
|
+
Image attributes ```gcode_pixelsize```, ```gcode_maxpower```, ```gcode_speed```, ```gcode_noise``` and ```gcode_speedmoves``` can be set per object (they must be created: use **+**). Note that this overrides explicit or default commandline settings.
|
|
12
|
+
|
|
13
|
+
Version 2.0.0 has important new speed optimizations. Engravings run significantly faster and skip from one image zone to the other at maximum speed. See options ```--speedmoves``` and ```--noise``` for example.
|
|
14
|
+
|
|
15
|
+
To summarize:
|
|
16
|
+
|
|
17
|
+
Optimized gcode
|
|
18
|
+
- draw pixels in one go until change of power
|
|
19
|
+
- emit X/Y coordinates only when they change
|
|
20
|
+
- emit linear move 'G1/G0' code minimally
|
|
21
|
+
- does not emit zero power (or below cutoff) pixels
|
|
22
|
+
|
|
23
|
+
General optimizations
|
|
24
|
+
- laser head has defered and sparse moves.
|
|
25
|
+
(XY locations are virtual, head does not always follow)
|
|
26
|
+
- moves at high speed (G0) over 10mm (default) or more zero pixels
|
|
27
|
+
- low burn levels (stray pixels) can be suppressed (default off)
|
|
28
|
+
- option *--constantburn* selects constant burn mode *M3* (for cutting and engraving) instead of default dynamic burn mode *M4*
|
|
29
|
+
|
|
30
|
+
**Tip**: use commandline program *grblhud* *(https://github.com/johannesnoordanus/grblhud)* to have full control over gcode execution,
|
|
31
|
+
also, program *image2gcode* has similar capabilities but handles raster images files (like *png* and *jpg*) directly.
|
|
32
|
+
|
|
33
|
+
### Install:
|
|
34
|
+
```
|
|
35
|
+
>
|
|
36
|
+
> pip install svg2gcode
|
|
37
|
+
```
|
|
38
|
+
<sup>(*)</sup> Note that this library is included.
|
|
39
|
+
### Usage:
|
|
40
|
+
See notes below.
|
|
41
|
+
```
|
|
42
|
+
$ svg2gcode --help
|
|
43
|
+
usage: svg2gcode [-h] [--showimage] [--pixelsize <default:0.1>] [--imagespeed <default:800>]
|
|
44
|
+
[--cuttingspeed <default:1000>] [--imagepower <default:300>] [--cuttingpower <default:850>]
|
|
45
|
+
[--rapidmove <default:10>] [--noise <default:0>] [--constantburn] [--xmaxtravel <default:300>]
|
|
46
|
+
[--ymaxtravel <default:400>] [--fan] [-V]
|
|
47
|
+
svg gcode
|
|
48
|
+
|
|
49
|
+
Convert svg to gcode for GRBL v1.1 compatible diode laser engravers.
|
|
50
|
+
|
|
51
|
+
positional arguments:
|
|
52
|
+
svg svg file to be converted to gcode
|
|
53
|
+
gcode gcode output file
|
|
54
|
+
|
|
55
|
+
options:
|
|
56
|
+
-h, --help show this help message and exit
|
|
57
|
+
--showimage show b&w converted image
|
|
58
|
+
--pixelsize <default:0.1>
|
|
59
|
+
pixel size in mm (XY-axis): each image pixel is drawn this size
|
|
60
|
+
--imagespeed <default:800>
|
|
61
|
+
image draw speed in mm/min
|
|
62
|
+
--cuttingspeed <default:1000>
|
|
63
|
+
cutting speed in mm/min
|
|
64
|
+
--imagepower <default:300>
|
|
65
|
+
maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the
|
|
66
|
+
machine maximum for a 5W laser)
|
|
67
|
+
--cuttingpower <default:850>
|
|
68
|
+
sets laser power of line drawings/cutting
|
|
69
|
+
--rapidmove <default:10>
|
|
70
|
+
generate G0 moves between shapes, for images: G0 moves when skipping more than 10mm
|
|
71
|
+
(default), 0 is no G0 moves
|
|
72
|
+
--noise <default:0> reduces image noise by not emitting pixels with power lower or equal than this setting
|
|
73
|
+
--constantburn use constant burn mode M3 (a bit more dangerous!), instead of dynamic burn mode M4
|
|
74
|
+
--origin Xdelta Ydelta
|
|
75
|
+
translate origin by (Xdelta,Ydelta) (default not set)
|
|
76
|
+
--xmaxtravel <default:300>
|
|
77
|
+
machine x-axis lengh in mm
|
|
78
|
+
--ymaxtravel <default:400>
|
|
79
|
+
machine y-axis lengh in mm
|
|
80
|
+
--fan set machine fan on
|
|
81
|
+
-V, --version show version number and exit
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
### Notes:
|
|
85
|
+
- example command to create two types of gcode file, one containing the drawings of the .svg, the other containing the images:
|
|
86
|
+
```
|
|
87
|
+
> svg2gcode ambachtmanlogo.svg logo.gc
|
|
88
|
+
> ..
|
|
89
|
+
> ls *.gc
|
|
90
|
+
> logo.gc # all drawings
|
|
91
|
+
> logo_images.gc # all images
|
|
92
|
+
```
|
|
93
|
+
- drawing objects - within the composer - must be converted to a```path```to be translated to a gcode sequence
|
|
94
|
+
- also, image objects should **not** be converted to a ```path```
|
|
95
|
+
- images must be linked or embedded using base64.
|
|
96
|
+
- images can be in several formats (my tests included *.png* and *.jpg* image files)
|
|
97
|
+
|
|
98
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# svg2gcode
|
|
2
|
+
|
|
3
|
+
A commandline steering program that enables laser cutting of svg drawings```<svg:path ..>tags``` and combined engraving of svg images```<svg:image ..>tags```.
|
|
4
|
+
It is based on library SvgToGcode (*fork*: https://github.com/johannesnoordanus/SvgToGcode) which should be installed <sup>(*)</sup>.
|
|
5
|
+
|
|
6
|
+
Drawings and images can be composed using Inkscape (for example) and saved to a *.svg* file. This file can be converted to gcode by *svg2gcode*.
|
|
7
|
+
Gcode produced in this way has the advantage that drawings and images have the same - relative - position and orientation as can be seen on the composer window.
|
|
8
|
+
This makes combined cutting and engraving as easy as orientating the (wood) slab once.
|
|
9
|
+
|
|
10
|
+
Controlling laser power, pixel size and other settings can be done via commandline parameters (see below) or within Inkscape using the XMLeditor.
|
|
11
|
+
Image attributes ```gcode_pixelsize```, ```gcode_maxpower```, ```gcode_speed```, ```gcode_noise``` and ```gcode_speedmoves``` can be set per object (they must be created: use **+**). Note that this overrides explicit or default commandline settings.
|
|
12
|
+
|
|
13
|
+
Version 2.0.0 has important new speed optimizations. Engravings run significantly faster and skip from one image zone to the other at maximum speed. See options ```--speedmoves``` and ```--noise``` for example.
|
|
14
|
+
|
|
15
|
+
To summarize:
|
|
16
|
+
|
|
17
|
+
Optimized gcode
|
|
18
|
+
- draw pixels in one go until change of power
|
|
19
|
+
- emit X/Y coordinates only when they change
|
|
20
|
+
- emit linear move 'G1/G0' code minimally
|
|
21
|
+
- does not emit zero power (or below cutoff) pixels
|
|
22
|
+
|
|
23
|
+
General optimizations
|
|
24
|
+
- laser head has defered and sparse moves.
|
|
25
|
+
(XY locations are virtual, head does not always follow)
|
|
26
|
+
- moves at high speed (G0) over 10mm (default) or more zero pixels
|
|
27
|
+
- low burn levels (stray pixels) can be suppressed (default off)
|
|
28
|
+
- option *--constantburn* selects constant burn mode *M3* (for cutting and engraving) instead of default dynamic burn mode *M4*
|
|
29
|
+
|
|
30
|
+
**Tip**: use commandline program *grblhud* *(https://github.com/johannesnoordanus/grblhud)* to have full control over gcode execution,
|
|
31
|
+
also, program *image2gcode* has similar capabilities but handles raster images files (like *png* and *jpg*) directly.
|
|
32
|
+
|
|
33
|
+
### Install:
|
|
34
|
+
```
|
|
35
|
+
>
|
|
36
|
+
> pip install svg2gcode
|
|
37
|
+
```
|
|
38
|
+
<sup>(*)</sup> Note that this library is included.
|
|
39
|
+
### Usage:
|
|
40
|
+
See notes below.
|
|
41
|
+
```
|
|
42
|
+
$ svg2gcode --help
|
|
43
|
+
usage: svg2gcode [-h] [--showimage] [--pixelsize <default:0.1>] [--imagespeed <default:800>]
|
|
44
|
+
[--cuttingspeed <default:1000>] [--imagepower <default:300>] [--cuttingpower <default:850>]
|
|
45
|
+
[--rapidmove <default:10>] [--noise <default:0>] [--constantburn] [--xmaxtravel <default:300>]
|
|
46
|
+
[--ymaxtravel <default:400>] [--fan] [-V]
|
|
47
|
+
svg gcode
|
|
48
|
+
|
|
49
|
+
Convert svg to gcode for GRBL v1.1 compatible diode laser engravers.
|
|
50
|
+
|
|
51
|
+
positional arguments:
|
|
52
|
+
svg svg file to be converted to gcode
|
|
53
|
+
gcode gcode output file
|
|
54
|
+
|
|
55
|
+
options:
|
|
56
|
+
-h, --help show this help message and exit
|
|
57
|
+
--showimage show b&w converted image
|
|
58
|
+
--pixelsize <default:0.1>
|
|
59
|
+
pixel size in mm (XY-axis): each image pixel is drawn this size
|
|
60
|
+
--imagespeed <default:800>
|
|
61
|
+
image draw speed in mm/min
|
|
62
|
+
--cuttingspeed <default:1000>
|
|
63
|
+
cutting speed in mm/min
|
|
64
|
+
--imagepower <default:300>
|
|
65
|
+
maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the
|
|
66
|
+
machine maximum for a 5W laser)
|
|
67
|
+
--cuttingpower <default:850>
|
|
68
|
+
sets laser power of line drawings/cutting
|
|
69
|
+
--rapidmove <default:10>
|
|
70
|
+
generate G0 moves between shapes, for images: G0 moves when skipping more than 10mm
|
|
71
|
+
(default), 0 is no G0 moves
|
|
72
|
+
--noise <default:0> reduces image noise by not emitting pixels with power lower or equal than this setting
|
|
73
|
+
--constantburn use constant burn mode M3 (a bit more dangerous!), instead of dynamic burn mode M4
|
|
74
|
+
--origin Xdelta Ydelta
|
|
75
|
+
translate origin by (Xdelta,Ydelta) (default not set)
|
|
76
|
+
--xmaxtravel <default:300>
|
|
77
|
+
machine x-axis lengh in mm
|
|
78
|
+
--ymaxtravel <default:400>
|
|
79
|
+
machine y-axis lengh in mm
|
|
80
|
+
--fan set machine fan on
|
|
81
|
+
-V, --version show version number and exit
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
### Notes:
|
|
85
|
+
- example command to create two types of gcode file, one containing the drawings of the .svg, the other containing the images:
|
|
86
|
+
```
|
|
87
|
+
> svg2gcode ambachtmanlogo.svg logo.gc
|
|
88
|
+
> ..
|
|
89
|
+
> ls *.gc
|
|
90
|
+
> logo.gc # all drawings
|
|
91
|
+
> logo_images.gc # all images
|
|
92
|
+
```
|
|
93
|
+
- drawing objects - within the composer - must be converted to a```path```to be translated to a gcode sequence
|
|
94
|
+
- also, image objects should **not** be converted to a ```path```
|
|
95
|
+
- images must be linked or embedded using base64.
|
|
96
|
+
- images can be in several formats (my tests included *.png* and *.jpg* image files)
|
|
97
|
+
|
|
98
|
+
|
|
@@ -23,9 +23,10 @@ def svg2gcode(args) -> int:
|
|
|
23
23
|
# For line drawings 'pass_depth' controls how far down the tool moves after every pass. Set it to 0 if your machine does not support Z axis movement.
|
|
24
24
|
gcode_compiler = Compiler(interfaces.Gcode, params={'laser_power':args.cuttingpower,'movement_speed':args.cuttingspeed, 'pixel_size':args.pixelsize,
|
|
25
25
|
'maximum_image_laser_power':args.imagepower, 'image_movement_speed':args.imagespeed, 'fan':args.fan,'rapid_move':args.rapidmove,
|
|
26
|
-
'showimage':args.showimage, 'x_axis_maximum_travel':args.xmaxtravel,'y_axis_maximum_travel':args.ymaxtravel
|
|
26
|
+
'showimage':args.showimage, 'x_axis_maximum_travel':args.xmaxtravel,'y_axis_maximum_travel':args.ymaxtravel, 'image_noise':args.noise,
|
|
27
|
+
'laser_mode':"constant" if args.constantburn else "dynamic" })
|
|
27
28
|
# emit gcode for svg
|
|
28
|
-
gcode_compiler.compile_to_file(args.gcode, parse_file(args.svg), passes=1)
|
|
29
|
+
gcode_compiler.compile_to_file(args.gcode, parse_file(args.svg, delta_origin=args.origin), passes=1)
|
|
29
30
|
|
|
30
31
|
except Exception as error:
|
|
31
32
|
print(error)
|
|
@@ -45,6 +46,8 @@ def main() -> int:
|
|
|
45
46
|
cuttingpower_default = 850
|
|
46
47
|
xmaxtravel_default = 300
|
|
47
48
|
ymaxtravel_default = 400
|
|
49
|
+
rapidmove_default = 10
|
|
50
|
+
noise_default = 0
|
|
48
51
|
|
|
49
52
|
# Define command line argument interface
|
|
50
53
|
parser = argparse.ArgumentParser(description='Convert svg to gcode for GRBL v1.1 compatible diode laser engravers.')
|
|
@@ -58,10 +61,16 @@ def main() -> int:
|
|
|
58
61
|
parser.add_argument('--cuttingspeed', default=cuttingspeed_default, metavar="<default:" + str(cuttingspeed_default)+">",
|
|
59
62
|
type=int, help='cutting speed in mm/min')
|
|
60
63
|
parser.add_argument('--imagepower', default=imagepower_default, metavar="<default:" +str(imagepower_default)+ ">",
|
|
61
|
-
type=int, help="maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the machine maximum)")
|
|
64
|
+
type=int, help="maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the machine maximum for a 5W laser)")
|
|
62
65
|
parser.add_argument('--cuttingpower', default=cuttingpower_default, metavar="<default:" +str(cuttingpower_default)+ ">",
|
|
63
66
|
type=int, help="sets laser power of line drawings/cutting")
|
|
64
|
-
parser.add_argument('--rapidmove',
|
|
67
|
+
parser.add_argument('--rapidmove', default=rapidmove_default, metavar="<default:" +str(rapidmove_default)+ ">",
|
|
68
|
+
type=int, help='generate G0 moves between shapes, for images: G0 moves when skipping more than 10mm (default), 0 is no G0 moves' )
|
|
69
|
+
parser.add_argument('--noise', default=noise_default, metavar="<default:" +str(noise_default)+ ">",
|
|
70
|
+
type=int, help='reduces image noise by not emitting pixels with power lower or equal than this setting')
|
|
71
|
+
parser.add_argument('--constantburn', action='store_true', default=False, help='use constant burn mode M3 (a bit more dangerous!), instead of dynamic burn mode M4')
|
|
72
|
+
parser.add_argument('--origin', default=None, nargs=2, metavar=('Xdelta', 'Ydelta'),
|
|
73
|
+
type=float, help="translate origin by (Xdelta,Ydelta) (default not set)")
|
|
65
74
|
parser.add_argument('--xmaxtravel', default=xmaxtravel_default, metavar="<default:" +str(xmaxtravel_default)+ ">",
|
|
66
75
|
type=int, help="machine x-axis lengh in mm")
|
|
67
76
|
parser.add_argument('--ymaxtravel', default=ymaxtravel_default, metavar="<default:" +str(ymaxtravel_default)+ ">",
|
|
@@ -24,11 +24,14 @@ SETTING = {
|
|
|
24
24
|
"laser_mode", # LASERMODE set constant or dynamic laser power mode
|
|
25
25
|
"maximum_image_laser_power",# positive integer sets laser power (maximum) for image drawings (this is typically 1/3) of 'maximum_laser_power')
|
|
26
26
|
"image_movement_speed", # positive integer sets movement speed when drawing an image (typically a lot less than the 'maximum_rate')
|
|
27
|
+
"image_noise", # positive integer reduces image noise by not emitting pixels lower or equal this setting')
|
|
27
28
|
# Configuration
|
|
28
29
|
"unit", # UNITS sets machine unit (milimeters, inches), this also defines the Feed (movement) parameter (mm/min or in/min)
|
|
29
30
|
"distance_mode", # DISTANCEMODE sets machine distance mode ('absolute' from 0,0 or 'incremental' from current position)
|
|
30
|
-
"rapid_move", #
|
|
31
|
-
#
|
|
31
|
+
"rapid_move", # positive integer when 0, no rapid moves, > 0, G0 moves to the next line chain (otherwise a slow G1 S0 move is used).
|
|
32
|
+
# (note that the first move - to the start of the first line chain - is always a rapid move)
|
|
33
|
+
# This setting is overloaded for images: a number 'n' > 0 means, do a rapid (G0) move when skipping
|
|
34
|
+
# more than 'n'mm
|
|
32
35
|
"pixel_size", # float sets image pixel size (in mm)
|
|
33
36
|
"showimage" # boolean show image used for conversion to gcode
|
|
34
37
|
}
|
|
@@ -50,12 +53,13 @@ DEFAULT_SETTING = {
|
|
|
50
53
|
"movement_speed": None, # MANDATORY
|
|
51
54
|
"laser_power": 1000, # default set to 1
|
|
52
55
|
"laser_mode": "dynamic", # default set to dynamic (M4 safest mode, laser is off when not moving)
|
|
53
|
-
"maximum_image_laser_power":None, # MANDATORY should be ("maximum_laser_power" - "minimum_laser_power" / 3)
|
|
56
|
+
"maximum_image_laser_power":None, # MANDATORY should be ("maximum_laser_power" - "minimum_laser_power" / 3 for a 5W laser)
|
|
54
57
|
"image_movement_speed": None, # MANDATORY
|
|
58
|
+
"image_noise": 0, # default set to not reduces images noise')
|
|
55
59
|
# Configuration
|
|
56
60
|
"unit": "mm", # default set to milimeters
|
|
57
61
|
"distance_mode": "absolute", # default set to absolute
|
|
58
|
-
"rapid_move":
|
|
62
|
+
"rapid_move": 10, # default set to true, for images do a rapid move when skipping more than 10mm
|
|
59
63
|
"pixel_size": 0.1, # laser kerf is mostly < 0.1mm
|
|
60
64
|
"showimage": False # default image is not shown
|
|
61
65
|
}
|
|
@@ -84,7 +88,7 @@ def check_setting(setting: dict[str,Any] =None) -> bool:
|
|
|
84
88
|
raise ValueError(f"Unknown '{key}' value '{setting[key]}'. Please specify one of the following: {{True,False}}")
|
|
85
89
|
if key in {"minimum_laser_power","maximum_laser_power","x_axis_maximum_rate","y_axis_maximum_rate", "movement_speed",
|
|
86
90
|
"x_axis_maximum_travel","y_axis_maximum_travel", "maximum_image_laser_power",
|
|
87
|
-
"image_movement_speed","laser_power" } and (not isinstance(setting[key],int) or setting[key] < 0):
|
|
91
|
+
"image_movement_speed","laser_power","rapid_move" } and (not isinstance(setting[key],int) or setting[key] < 0):
|
|
88
92
|
raise ValueError(f"'{key}' has type {type(setting[key])} and value {setting[key]}, but should be of type {type(1)} and have a value >= 0")
|
|
89
93
|
# Toolparameters
|
|
90
94
|
if key in {"pass_depth","dwell_time"}:
|
|
@@ -98,8 +102,6 @@ def check_setting(setting: dict[str,Any] =None) -> bool:
|
|
|
98
102
|
raise ValueError(f"Unknown '{key}' value '{setting[key]}'. Please specify one of the following: {UNITS}")
|
|
99
103
|
if key == "distance_mode" and setting[key] not in DISTANCEMODE:
|
|
100
104
|
raise ValueError(f"Unknown '{key}' value '{setting[key]}'. Please specify one of the following: {DISTANCEMODE}")
|
|
101
|
-
if key == "rapid_move" and setting[key] not in {True,False}:
|
|
102
|
-
raise ValueError(f"Unknown '{key}' value '{setting[key]}'. Please specify one of the following: {{True,False}}")
|
|
103
105
|
if key in {"fan","showimage"} and setting[key] not in {True,False}:
|
|
104
106
|
raise ValueError(f"Unknown '{key}' value '{setting[key]}'. Please specify one of the following: {{True,False}}")
|
|
105
107
|
if key == "pixel_size" and setting[key] and (not isinstance(setting[key],(float)) or setting[key] <= 0):
|
|
@@ -126,7 +126,7 @@ class Compiler:
|
|
|
126
126
|
Assembles the code in the header, body and footer.
|
|
127
127
|
"""
|
|
128
128
|
|
|
129
|
-
header_gc = ["M5","M8", "
|
|
129
|
+
header_gc = ["M5","M8", 'M3' if self.settings["laser_mode"] == "constant" else 'M4']
|
|
130
130
|
# laser off, fan off, program stop
|
|
131
131
|
footer_gc = ["M5","M9","M2"]
|
|
132
132
|
|
|
@@ -250,11 +250,17 @@ class Compiler:
|
|
|
250
250
|
|
|
251
251
|
# convert image to new size
|
|
252
252
|
if img is not None:
|
|
253
|
-
|
|
253
|
+
# add alpha channel
|
|
254
|
+
img = img.convert("RGBA")
|
|
255
|
+
|
|
256
|
+
# create a white background and add it to the image
|
|
257
|
+
img_background = Image.new(mode = "RGBA", size = img.size, color = (255,255,255))
|
|
258
|
+
img = Image.alpha_composite(img_background, img)
|
|
259
|
+
|
|
260
|
+
# convert image to black&white (without alpha) and new size #reminder: 'img = img.convert("LA")'
|
|
261
|
+
img = img.resize((int(float(img_attrib['width']) * 1/float(pixelsize)),
|
|
262
|
+
int(float(img_attrib['height']) * 1/float(pixelsize))), Image.Resampling.LANCZOS).convert("L")
|
|
254
263
|
|
|
255
|
-
# convert to B&W without alpha
|
|
256
|
-
#img = img.convert("LA")
|
|
257
|
-
img = img.convert("L")
|
|
258
264
|
if self.settings['showimage']:
|
|
259
265
|
img.show()
|
|
260
266
|
|
|
@@ -263,6 +269,14 @@ class Compiler:
|
|
|
263
269
|
|
|
264
270
|
return None
|
|
265
271
|
|
|
272
|
+
def distance(self, A: (float,float),B: (float,float)):
|
|
273
|
+
"""
|
|
274
|
+
Does Pythagoras
|
|
275
|
+
"""
|
|
276
|
+
# |Ax - Bx|^2 + |Ay - By|^2 = C^2
|
|
277
|
+
# distance = √C^2
|
|
278
|
+
return math.sqrt(abs(A[0] - B[0])**2 + abs(A[1] - B[1])**2)
|
|
279
|
+
|
|
266
280
|
def image2gcode(self, img_attrib: dict[str, Any], img=None, transformation = None):
|
|
267
281
|
|
|
268
282
|
invert_intensity = True
|
|
@@ -272,9 +286,12 @@ class Compiler:
|
|
|
272
286
|
pixelsize = img_attrib['gcode_pixelsize'] if 'gcode_pixelsize' in img_attrib else self.settings["pixel_size"]
|
|
273
287
|
maxpower = img_attrib['gcode_maxpower'] if 'gcode_maxpower' in img_attrib else self.settings["maximum_image_laser_power"]
|
|
274
288
|
speed = img_attrib['gcode_speed'] if 'gcode_speed' in img_attrib else self.settings["image_movement_speed"]
|
|
289
|
+
noise = img_attrib['gcode_noise'] if 'gcode_noise' in img_attrib else self.settings["image_noise"]
|
|
290
|
+
speedmoves = img_attrib['gcode_speedmoves'] if 'gcode_speedmoves' in img_attrib else self.settings["rapid_move"]
|
|
275
291
|
|
|
276
292
|
# set header for this image
|
|
277
|
-
self.gcode += [f"; image name: {img_attrib['id']}, pixelsize: {pixelsize}, speed: {speed}
|
|
293
|
+
self.gcode += [f"; image name: {img_attrib['id']}, pixelsize: {pixelsize}, speed: {speed},\n"
|
|
294
|
+
f'; maxpower: {maxpower}, speedmoves {speedmoves}, noise level {noise}\n;\n']
|
|
278
295
|
|
|
279
296
|
# set X/Y-axis precision to number of digits after the decimal separator
|
|
280
297
|
XY_prec = len(str(pixelsize).split('.')[1])
|
|
@@ -304,6 +321,9 @@ class Compiler:
|
|
|
304
321
|
#
|
|
305
322
|
left2right = True
|
|
306
323
|
|
|
324
|
+
# current location of laser head
|
|
325
|
+
head = (X,Y)
|
|
326
|
+
|
|
307
327
|
# start print
|
|
308
328
|
for line in img:
|
|
309
329
|
|
|
@@ -322,40 +342,63 @@ class Compiler:
|
|
|
322
342
|
# Note also that drawing form left to right differs subtly from the reverse
|
|
323
343
|
|
|
324
344
|
# draw this pixel line
|
|
325
|
-
#for count, bw in np.ndenumerate(line):
|
|
326
345
|
for count, pixel in enumerate(line):
|
|
327
346
|
# power proportional to maximum laser power
|
|
328
347
|
laserpow = round((1.0 - float(pixel/255)) * maxpower) if invert_intensity else round(float(pixel/255) * maxpower)
|
|
329
|
-
|
|
348
|
+
|
|
330
349
|
if count == 0:
|
|
350
|
+
# delay emit first pixel (so all same power pixels can be emitted in one sweep)
|
|
331
351
|
prev_pow = laserpow
|
|
352
|
+
# set last head loaction on start of the line
|
|
353
|
+
lastloc = (X,Y)
|
|
332
354
|
|
|
333
355
|
# draw points until change of power
|
|
334
356
|
if laserpow != prev_pow or count == line.size-1:
|
|
335
|
-
if
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
357
|
+
if prev_pow > noise:
|
|
358
|
+
code = ""
|
|
359
|
+
if lastloc:
|
|
360
|
+
# head is not at correct location, go there
|
|
361
|
+
|
|
362
|
+
# Apply affine transformation (if needed)
|
|
363
|
+
# (Note that an affine transformation does not necessarily preserve angles between
|
|
364
|
+
# lines or distances between points!)
|
|
365
|
+
XYlastloc = (lastloc[0], lastloc[1]) if transformation is None else \
|
|
366
|
+
transformation.apply_affine_transformation(Vector(lastloc[0], lastloc[1]))
|
|
367
|
+
|
|
368
|
+
XYhead = (head[0], head[1]) if transformation is None else \
|
|
369
|
+
transformation.apply_affine_transformation(Vector(head[0], head[1]))
|
|
370
|
+
|
|
371
|
+
if speedmoves and (self.distance(XYhead,XYlastloc) > speedmoves):
|
|
372
|
+
# fast
|
|
373
|
+
code = f"G0 X{round(XYlastloc[0],XY_prec)}Y{round(XYlastloc[1],XY_prec)}\nG1\n"
|
|
374
|
+
else:
|
|
375
|
+
# normal speed
|
|
376
|
+
code = f"X{round(XYlastloc[0],XY_prec)}Y{round(XYlastloc[1],XY_prec)}S0\n"
|
|
377
|
+
|
|
378
|
+
# emit point
|
|
379
|
+
if transformation is not None:
|
|
380
|
+
XYt = transformation.apply_affine_transformation(Vector(X, Y))
|
|
381
|
+
code += f"X{round(XYt[0],XY_prec)}Y{round(XYt[1],XY_prec)}S{prev_pow}"
|
|
382
|
+
else:
|
|
383
|
+
code += f"X{X}S{prev_pow}"
|
|
384
|
+
self.gcode += [code]
|
|
385
|
+
|
|
386
|
+
# head at this location
|
|
387
|
+
head = (X,Y)
|
|
388
|
+
lastloc = None
|
|
339
389
|
else:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
self.gcode += [code]
|
|
390
|
+
# didn't move head to location, save it
|
|
391
|
+
lastloc = (X,Y)
|
|
343
392
|
|
|
344
393
|
if count == line.size-1:
|
|
345
394
|
continue
|
|
346
|
-
# if laserpow != prev_pow
|
|
347
|
-
prev_pow = laserpow
|
|
395
|
+
prev_pow = laserpow # if laserpow != prev_pow
|
|
348
396
|
|
|
349
397
|
# next point
|
|
350
398
|
X = round(X + (pixelsize if left2right else -pixelsize), XY_prec)
|
|
351
399
|
|
|
352
|
-
#
|
|
400
|
+
# next scan line (defer head movement: lazy head)
|
|
353
401
|
Y = round(Y + pixelsize, XY_prec)
|
|
354
|
-
if transformation is not None:
|
|
355
|
-
XYt = transformation.apply_affine_transformation(Vector(X, Y))
|
|
356
|
-
self.gcode += [f"X{round(XYt[0],XY_prec)}Y{round(XYt[1],XY_prec)}S0"]
|
|
357
|
-
else:
|
|
358
|
-
self.gcode += [f"Y{Y}S0"]
|
|
359
402
|
|
|
360
403
|
# change print direction
|
|
361
404
|
left2right = not left2right
|
|
@@ -19,7 +19,7 @@ def _has_style(element: ElementTree.Element, key: str, value: str) -> bool:
|
|
|
19
19
|
return element.get(key) == value or (element.get("style") and f"{key}:{value}" in element.get("style"))
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def add_viewbox_transformation(transformation: Transformation, transform_origin, vwbox):
|
|
22
|
+
def add_viewbox_transformation(transformation: Transformation, transform_origin, vwbox, origin):
|
|
23
23
|
"""
|
|
24
24
|
Transform SVG coordinate system to a math-cartesion coordinate system and correct its origin.
|
|
25
25
|
When viewBox is missing the 'height' value of the viewport is used.
|
|
@@ -50,16 +50,28 @@ def add_viewbox_transformation(transformation: Transformation, transform_origin,
|
|
|
50
50
|
# viewBox "width" and "height" represent the dimensions of the 'svg'
|
|
51
51
|
# (a rectangle - left upper at (vwbox['x'],vwbox['y']) - in user space)
|
|
52
52
|
|
|
53
|
+
# Set origin back at viewbox position after flip updown and add
|
|
54
|
+
# the user specified origin.
|
|
55
|
+
# When no user origin is specified, this translation is skipped,
|
|
56
|
+
# which effectively places the viewbox lower left (mind you after
|
|
57
|
+
# flipupdown) at (0,0) (so the canvas has positive coordinates only).
|
|
58
|
+
|
|
59
|
+
# (transformations are in reverse order see 'Note' below)
|
|
60
|
+
if origin is not None and ((vwbox["x"] + origin[0]) or (vwbox["y"] + origin[1])):
|
|
61
|
+
up_transformation.add_translation(vwbox["x"] + origin[0],vwbox["y"] + origin[1])
|
|
62
|
+
|
|
53
63
|
# Note: If A and B are the matrices of two linear transformations, then the effect of first applying A and then B
|
|
54
64
|
# to a column vector x is given by B(Ax) == (BA)x
|
|
55
65
|
# So, in the below case, transformation order is 'scale' first and 'translation' second.
|
|
66
|
+
|
|
67
|
+
# this effectively does a flip updown to set a carthesian coordinate system (origin at bottom left) gcode uses
|
|
56
68
|
up_transformation.add_translation(0, vwbox["height"]) # Translation
|
|
57
69
|
up_transformation.add_scale(1, -1) # T * Scale
|
|
58
70
|
# applying it to a vector: # T * S * Vector(x,y)
|
|
59
71
|
|
|
60
72
|
# viewBox "x" and "y" represent the upper left corner of the document.
|
|
61
|
-
# when non zero, the upper left corner should be corrected to (0,0)
|
|
62
|
-
#
|
|
73
|
+
# when non zero, the upper left corner should be corrected to (0,0) for
|
|
74
|
+
# the above flip updown to work correctly
|
|
63
75
|
if vwbox["x"] or vwbox["y"]:
|
|
64
76
|
up_transformation.add_translation(-vwbox["x"],-vwbox["y"])
|
|
65
77
|
|
|
@@ -97,7 +109,7 @@ def get_viewBox(root: ElementTree.Element) -> {}:
|
|
|
97
109
|
|
|
98
110
|
|
|
99
111
|
def parse_root(root: ElementTree.Element, transform_origin=True, viewbox=None, draw_hidden=False,
|
|
100
|
-
visible_root=True, root_transformation=None) -> List[Curve]:
|
|
112
|
+
visible_root=True, root_transformation=None, origin=None) -> List[Curve]:
|
|
101
113
|
|
|
102
114
|
"""
|
|
103
115
|
Recursively parse an etree root's children into geometric curves.
|
|
@@ -109,6 +121,7 @@ def parse_root(root: ElementTree.Element, transform_origin=True, viewbox=None, d
|
|
|
109
121
|
:param transform_origin: Whether or not to transform input coordinates from the svg coordinate system to standard
|
|
110
122
|
cartesian system. Depends on viewBox height for calculations.
|
|
111
123
|
:param draw_hidden: Whether or not to draw hidden elements based on their display, visibility and opacity attributes.
|
|
124
|
+
:param origin: translate origin to (origin[0],origin[1]); when None set viewbox upper left to (0,0)
|
|
112
125
|
:param visible_root: Specifies whether or the root is visible. (Inheritance can be overridden)
|
|
113
126
|
:param root_transformation: Specifies whether the root's transformation. (Transformations are inheritable)
|
|
114
127
|
:return: A list of geometric curves describing the svg. Use the Compiler sub-module to compile them to gcode.
|
|
@@ -153,7 +166,7 @@ def parse_root(root: ElementTree.Element, transform_origin=True, viewbox=None, d
|
|
|
153
166
|
if draw_hidden or visible:
|
|
154
167
|
if element.tag == "{%s}path" % NAMESPACES["svg"]:
|
|
155
168
|
path = Path(element.attrib['d'],
|
|
156
|
-
add_viewbox_transformation(transformation, transform_origin, viewbox))
|
|
169
|
+
add_viewbox_transformation(transformation, transform_origin, viewbox, origin))
|
|
157
170
|
curves.extend(path.curves)
|
|
158
171
|
else:
|
|
159
172
|
if element.tag == "{%s}image" % NAMESPACES["svg"]:
|
|
@@ -161,45 +174,47 @@ def parse_root(root: ElementTree.Element, transform_origin=True, viewbox=None, d
|
|
|
161
174
|
|
|
162
175
|
# instantiate curve (image)
|
|
163
176
|
ri = RasterImage(element.attrib, element.attrib["{%s}href" % NAMESPACES["xlink"]],
|
|
164
|
-
add_viewbox_transformation(transformation, transform_origin, viewbox))
|
|
177
|
+
add_viewbox_transformation(transformation, transform_origin, viewbox, origin))
|
|
165
178
|
curves.append(ri)
|
|
166
179
|
|
|
167
180
|
# Continue the recursion
|
|
168
|
-
curves.extend(parse_root(element, transform_origin, viewbox, draw_hidden, visible, transformation))
|
|
181
|
+
curves.extend(parse_root(element, transform_origin, viewbox, draw_hidden, visible, transformation, origin))
|
|
169
182
|
|
|
170
183
|
# ToDo implement shapes class
|
|
171
184
|
return curves
|
|
172
185
|
|
|
173
186
|
|
|
174
|
-
def parse_string(svg_string: str, transform_origin=True, viewbox=None, draw_hidden=False) -> List[Curve]:
|
|
187
|
+
def parse_string(svg_string: str, transform_origin=True, viewbox=None, draw_hidden=False, delta_origin=None) -> List[Curve]:
|
|
175
188
|
"""
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
189
|
+
Recursively parse an svg string into geometric curves. (Wrapper for parse_root)
|
|
190
|
+
|
|
191
|
+
:param svg_string: The etree element who's children should be recursively parsed. The root will not be drawn.
|
|
192
|
+
:param viewbox: ViewBox of the SVG, used to transform it to a math-cartesion coordinate system and
|
|
193
|
+
correct its origin. When the viewBox is missing the viewport (of the root) is used. If the root
|
|
194
|
+
does not contain a viewBox or viewport, it must be either manually specified or transform must be False.
|
|
195
|
+
:param transform_origin: Whether or not to transform input coordinates from the svg coordinate system to standard cartesian
|
|
196
|
+
system. Depends on canvas_height for calculations.
|
|
197
|
+
:param draw_hidden: Whether or not to draw hidden elements based on their display, visibility and opacity attributes.
|
|
198
|
+
:pram origin: translate origin to (origin[0],origin[1]), when None set viewbox upper left to (0,0)
|
|
199
|
+
:return: A list of geometric curves describing the svg. Use the Compiler sub-module to compile them to gcode.
|
|
186
200
|
"""
|
|
187
201
|
root = ElementTree.fromstring(svg_string)
|
|
188
|
-
return parse_root(root, transform_origin, viewbox, draw_hidden)
|
|
202
|
+
return parse_root(root, transform_origin, viewbox, draw_hidden, origin=delta_origin)
|
|
203
|
+
|
|
189
204
|
|
|
205
|
+
def parse_file(file_path: str, transform_origin=True, viewbox=None, draw_hidden=False, delta_origin=None) -> List[Curve]:
|
|
206
|
+
"""
|
|
207
|
+
Recursively parse an svg file into geometric curves. (Wrapper for parse_root)
|
|
190
208
|
|
|
191
|
-
|
|
209
|
+
:param file_path: The etree element who's children should be recursively parsed. The root will not be drawn.
|
|
210
|
+
:param viewbox: ViewBox of the SVG, used to transform it to a math-cartesion coordinate system and
|
|
211
|
+
correct its origin. When the viewBox is missing the viewport (of the root) is used. If the root
|
|
212
|
+
does not contain a viewBox or viewport, it must be either manually specified or transform must be False.
|
|
213
|
+
:param transform_origin: Whether or not to transform input coordinates from the svg coordinate system to standard cartesian
|
|
214
|
+
system. Depends on canvas_height for calculations.
|
|
215
|
+
:param draw_hidden: Whether or not to draw hidden elements based on their display, visibility and opacity attributes.
|
|
216
|
+
:param origin: translate origin to (origin[0],origin[1]), when None set viewbox upper left to (0,0)
|
|
217
|
+
:return: A list of geometric curves describing the svg. Use the Compiler sub-module to compile them to gcode.
|
|
192
218
|
"""
|
|
193
|
-
Recursively parse an svg file into geometric curves. (Wrapper for parse_root)
|
|
194
|
-
|
|
195
|
-
:param file_path: The etree element who's children should be recursively parsed. The root will not be drawn.
|
|
196
|
-
:param viewbox: ViewBox of the SVG, used to transform it to a math-cartesion coordinate system and
|
|
197
|
-
correct its origin. When the viewBox is missing the viewport (of the root) is used. If the root
|
|
198
|
-
does not contain a viewBox or viewport, it must be either manually specified or transform must be False.
|
|
199
|
-
:param transform_origin: Whether or not to transform input coordinates from the svg coordinate system to standard cartesian
|
|
200
|
-
system. Depends on canvas_height for calculations.
|
|
201
|
-
:param draw_hidden: Whether or not to draw hidden elements based on their display, visibility and opacity attributes.
|
|
202
|
-
:return: A list of geometric curves describing the svg. Use the Compiler sub-module to compile them to gcode.
|
|
203
|
-
"""
|
|
204
219
|
root = ElementTree.parse(file_path).getroot()
|
|
205
|
-
return parse_root(root, transform_origin, viewbox, draw_hidden)
|
|
220
|
+
return parse_root(root, transform_origin, viewbox, draw_hidden, origin=delta_origin)
|
svg2gcode-1.2.0/README.md
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# svg2gcode
|
|
2
|
-
|
|
3
|
-
A commandline steering program that enables laser cutting of svg drawings```<svg:path ..>tags``` and combined engraving of svg images```<svg:image ..>tags```.
|
|
4
|
-
It is based on library SvgToGcode (*fork*: https://github.com/johannesnoordanus/SvgToGcode) which should be installed <sup>(*)</sup>.
|
|
5
|
-
|
|
6
|
-
Drawings and images can be composed using Inkscape (for example) and saved to a .svg file. This file can be converted to gcode by svg2gcode.
|
|
7
|
-
Gcode produced in this way has the advantage that drawings and images have the same - relative - position and orientation as can be seen on the composer window.
|
|
8
|
-
This makes combined cutting and engraving as easy as orientating the (wood) slab once.
|
|
9
|
-
|
|
10
|
-
Controlling laser power, pixel size and other settings can be done via commandline parameters (see below) or within Inkscape using the XMLeditor.
|
|
11
|
-
Image attributes ```gcode_pixelsize```, ```gcode_maxpower``` and ```gcode_speed``` can be set per object (they must be created: use **+**). Note that this overrides explicit or default commandline settings.
|
|
12
|
-
|
|
13
|
-
**Tip**: use commandline program grblhud (https://github.com/johannesnoordanus/grblhud) to have full control over gcode execution.
|
|
14
|
-
### Install:
|
|
15
|
-
```
|
|
16
|
-
>
|
|
17
|
-
> pip install svg2gcode
|
|
18
|
-
```
|
|
19
|
-
<sup>(*)</sup> Note that library *svg_to_gcode* is included in this package.
|
|
20
|
-
### Usage:
|
|
21
|
-
See notes below.
|
|
22
|
-
```
|
|
23
|
-
$ svg2gcode --help
|
|
24
|
-
usage: svg2gcode.py [-h] [--showimage] [--pixelsize <default:0.1>] [--imagespeed <default:800>] [--cuttingspeed <default:1000>] [--imagepower <default:300>]
|
|
25
|
-
[--cuttingpower <default:0.85>] [--maxlaserpower <default:1000>] [--rapidmove] [--xmaxtravel <default:300>] [--ymaxtravel <default:400>] [--fan] [-V]
|
|
26
|
-
svg gcode
|
|
27
|
-
|
|
28
|
-
Convert svg to gcode for GRBL v1.1 compatible diode laser engravers.
|
|
29
|
-
|
|
30
|
-
positional arguments:
|
|
31
|
-
svg svg file to be converted to gcode
|
|
32
|
-
gcode gcode output file
|
|
33
|
-
|
|
34
|
-
options:
|
|
35
|
-
-h, --help show this help message and exit
|
|
36
|
-
--showimage show b&w converted image
|
|
37
|
-
--pixelsize <default:0.1>
|
|
38
|
-
pixel size in mm (XY-axis): each image pixel is drawn this size
|
|
39
|
-
--imagespeed <default:800>
|
|
40
|
-
image draw speed in mm/min
|
|
41
|
-
--cuttingspeed <default:1000>
|
|
42
|
-
cutting speed in mm/min
|
|
43
|
-
--imagepower <default:300>
|
|
44
|
-
maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the machine maximum)
|
|
45
|
-
--cuttingpower <default:850>
|
|
46
|
-
sets laser power of line drawings/cutting
|
|
47
|
-
--rapidmove generate inbetween G0 moves
|
|
48
|
-
--xmaxtravel <default:300>
|
|
49
|
-
machine x-axis lengh in mm
|
|
50
|
-
--ymaxtravel <default:400>
|
|
51
|
-
machine y-axis lengh in mm
|
|
52
|
-
--fan set machine fan on
|
|
53
|
-
-V, --version show version number and exit
|
|
54
|
-
```
|
|
55
|
-
### Notes:
|
|
56
|
-
- example command to create two types of gcode file, one containing the drawings of the .svg, the other containing the images:
|
|
57
|
-
```
|
|
58
|
-
> svg2gcode ambachtmanlogo.svg logo.gc
|
|
59
|
-
> ..
|
|
60
|
-
> ls *.gc
|
|
61
|
-
> logo.gc # all drawings
|
|
62
|
-
> logo_images.gc # all images
|
|
63
|
-
```
|
|
64
|
-
- drawing objects - within the composer - must be converted to a```path```to be translated to a gcode sequence
|
|
65
|
-
- also, image objects should **not** be converted to a ```path```
|
|
66
|
-
- images must be linked or embedded using base64.
|
|
67
|
-
- images can be in several formats (my tests included ```.png``` and ```.jpg``` image files)
|
|
68
|
-
|
|
69
|
-
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# svg2gcode
|
|
2
|
-
|
|
3
|
-
A commandline steering program that enables laser cutting of svg drawings```<svg:path ..>tags``` and combined engraving of svg images```<svg:image ..>tags```.
|
|
4
|
-
It is based on library SvgToGcode (*fork*: https://github.com/johannesnoordanus/SvgToGcode) which should be installed <sup>(*)</sup>.
|
|
5
|
-
|
|
6
|
-
Drawings and images can be composed using Inkscape (for example) and saved to a .svg file. This file can be converted to gcode by svg2gcode.
|
|
7
|
-
Gcode produced in this way has the advantage that drawings and images have the same - relative - position and orientation as can be seen on the composer window.
|
|
8
|
-
This makes combined cutting and engraving as easy as orientating the (wood) slab once.
|
|
9
|
-
|
|
10
|
-
Controlling laser power, pixel size and other settings can be done via commandline parameters (see below) or within Inkscape using the XMLeditor.
|
|
11
|
-
Image attributes ```gcode_pixelsize```, ```gcode_maxpower``` and ```gcode_speed``` can be set per object (they must be created: use **+**). Note that this overrides explicit or default commandline settings.
|
|
12
|
-
|
|
13
|
-
**Tip**: use commandline program grblhud (https://github.com/johannesnoordanus/grblhud) to have full control over gcode execution.
|
|
14
|
-
### Install:
|
|
15
|
-
```
|
|
16
|
-
>
|
|
17
|
-
> pip install svg2gcode
|
|
18
|
-
```
|
|
19
|
-
<sup>(*)</sup> Note that library *svg_to_gcode* is included in this package.
|
|
20
|
-
### Usage:
|
|
21
|
-
See notes below.
|
|
22
|
-
```
|
|
23
|
-
$ svg2gcode --help
|
|
24
|
-
usage: svg2gcode.py [-h] [--showimage] [--pixelsize <default:0.1>] [--imagespeed <default:800>] [--cuttingspeed <default:1000>] [--imagepower <default:300>]
|
|
25
|
-
[--cuttingpower <default:0.85>] [--maxlaserpower <default:1000>] [--rapidmove] [--xmaxtravel <default:300>] [--ymaxtravel <default:400>] [--fan] [-V]
|
|
26
|
-
svg gcode
|
|
27
|
-
|
|
28
|
-
Convert svg to gcode for GRBL v1.1 compatible diode laser engravers.
|
|
29
|
-
|
|
30
|
-
positional arguments:
|
|
31
|
-
svg svg file to be converted to gcode
|
|
32
|
-
gcode gcode output file
|
|
33
|
-
|
|
34
|
-
options:
|
|
35
|
-
-h, --help show this help message and exit
|
|
36
|
-
--showimage show b&w converted image
|
|
37
|
-
--pixelsize <default:0.1>
|
|
38
|
-
pixel size in mm (XY-axis): each image pixel is drawn this size
|
|
39
|
-
--imagespeed <default:800>
|
|
40
|
-
image draw speed in mm/min
|
|
41
|
-
--cuttingspeed <default:1000>
|
|
42
|
-
cutting speed in mm/min
|
|
43
|
-
--imagepower <default:300>
|
|
44
|
-
maximum laser power while drawing an image (as a rule of thumb set to 1/3 of the machine maximum)
|
|
45
|
-
--cuttingpower <default:850>
|
|
46
|
-
sets laser power of line drawings/cutting
|
|
47
|
-
--rapidmove generate inbetween G0 moves
|
|
48
|
-
--xmaxtravel <default:300>
|
|
49
|
-
machine x-axis lengh in mm
|
|
50
|
-
--ymaxtravel <default:400>
|
|
51
|
-
machine y-axis lengh in mm
|
|
52
|
-
--fan set machine fan on
|
|
53
|
-
-V, --version show version number and exit
|
|
54
|
-
```
|
|
55
|
-
### Notes:
|
|
56
|
-
- example command to create two types of gcode file, one containing the drawings of the .svg, the other containing the images:
|
|
57
|
-
```
|
|
58
|
-
> svg2gcode ambachtmanlogo.svg logo.gc
|
|
59
|
-
> ..
|
|
60
|
-
> ls *.gc
|
|
61
|
-
> logo.gc # all drawings
|
|
62
|
-
> logo_images.gc # all images
|
|
63
|
-
```
|
|
64
|
-
- drawing objects - within the composer - must be converted to a```path```to be translated to a gcode sequence
|
|
65
|
-
- also, image objects should **not** be converted to a ```path```
|
|
66
|
-
- images must be linked or embedded using base64.
|
|
67
|
-
- images can be in several formats (my tests included ```.png``` and ```.jpg``` image files)
|
|
68
|
-
|
|
69
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|