laser-cutter 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +45 -21
- data/bin/laser-cutter +26 -18
- data/lib/laser-cutter.rb +1 -0
- data/lib/laser-cutter/configuration.rb +1 -38
- data/lib/laser-cutter/page_manager.rb +43 -0
- data/lib/laser-cutter/renderer.rb +3 -8
- data/lib/laser-cutter/renderer/base.rb +27 -0
- data/lib/laser-cutter/renderer/box_renderer.rb +12 -78
- data/lib/laser-cutter/renderer/layout_renderer.rb +40 -0
- data/lib/laser-cutter/renderer/line_renderer.rb +4 -1
- data/lib/laser-cutter/renderer/meta_renderer.rb +77 -0
- data/lib/laser-cutter/renderer/rect_renderer.rb +2 -3
- data/lib/laser-cutter/version.rb +1 -1
- data/spec/configuration_spec.rb +2 -36
- data/spec/page_manager_spec.rb +45 -0
- data/spec/renderer_spec.rb +8 -5
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06711815bb7563755b270427de4acb6dc2208777
|
4
|
+
data.tar.gz: 8daa7da0e30ed501f04b5786cf0b31c8b62ec823
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 267e0cc220e9e83a0f8a8570429d3f11207d677b5d876831544ac33871fef9ce14daaab7f2594784d4d0a6da1e5161e8299d205d177543a3408ad3ccec42a2b5
|
7
|
+
data.tar.gz: f5c49c5f68fc71df0e84af028086f9a231cf9abfd42c07350bdfc175f3df31bf40469032c30c33ca49a000f5e82764d1e5788db5d42c90de65e6ed91936e71d9
|
data/README.md
CHANGED
@@ -18,7 +18,14 @@ command line options, and perhaps a light weight web application. If you are in
|
|
18
18
|
contributing to the project, please see [contributing](CONTRIBUTING.md) for more details.
|
19
19
|
|
20
20
|
```laser-cutter``` supports many flexible command line options that allow setting dimensions,
|
21
|
-
stroke width, page size, layout, margins, padding (spacing between the boxes), and many more.
|
21
|
+
stroke width, page size, layout, margins, padding (spacing between the boxes), and many more.
|
22
|
+
|
23
|
+
## Web Front-End
|
24
|
+
|
25
|
+
There is a web online application that uses this gem and allows you to generate PDFs with
|
26
|
+
a friendly UI.
|
27
|
+
|
28
|
+
Please visit [http://makeabox.io](http://makeabox.io).
|
22
29
|
|
23
30
|
## Dependencies
|
24
31
|
|
@@ -42,25 +49,24 @@ Or install it yourself as:
|
|
42
49
|
|
43
50
|
```bash
|
44
51
|
Usage: laser-cutter [options] -o filename.pdf
|
45
|
-
eg: laser-cutter -
|
52
|
+
eg: laser-cutter -s 1x1.5x2/0.125/0.125 -O -o box.pdf
|
46
53
|
|
47
54
|
Specific Options:
|
48
|
-
|
55
|
+
-w, --width WIDTH Internal width of the box
|
49
56
|
-h, --height HEIGHT Internal height of the box
|
50
57
|
-d, --depth DEPTH Internal depth of the box
|
51
|
-
|
58
|
+
-t, --thickness THICKNESS Thickness of the box material
|
52
59
|
-n, --notch NOTCH Preferred notch length (used only as a guide)
|
53
60
|
|
54
61
|
-m, --margin MARGIN Margins from the edge of the document
|
55
62
|
-p, --padding PADDING Space between the boxes on the page
|
56
|
-
-
|
63
|
+
-k, --stroke WIDTH Numeric stroke width of the line
|
57
64
|
-z, --page_size LETTER Page size, see --list-all-page-sizes for more info.
|
58
65
|
-y, --page_layout portrait Page layout, other option is 'landscape'
|
59
66
|
|
60
67
|
-O, --open Open generated file with system viewer before exiting
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-u, --units UNITS Either 'mm' (default) or 'in'
|
68
|
+
-W, --write FILE Save provided configuration to a file, use '-' for STDOUT
|
69
|
+
-R, --read FILE Read configuration from a file, or use '-' for STDIN
|
64
70
|
|
65
71
|
-l, --list-all-page-sizes Print all available page sizes with dimensions and exit
|
66
72
|
-M, --no-metadata Do not print box metadata on the PDF
|
@@ -75,24 +81,43 @@ Common Options:
|
|
75
81
|
-s, --size WxHxD/T/N Combined internal dimensions: W = width, H = height,
|
76
82
|
D = depth, T = thickness, N = notch length
|
77
83
|
|
78
|
-
-
|
84
|
+
-u, --units UNITS Either 'in' for inches (default) or 'mm'
|
85
|
+
```
|
86
|
+
|
87
|
+
### Examples
|
79
88
|
|
80
|
-
|
81
|
-
1. Create a box defined in inches, and open PDF in preview right after:
|
89
|
+
Create a box defined in inches, and open PDF in preview right after:
|
82
90
|
|
83
|
-
|
91
|
+
```bash
|
92
|
+
laser-cutter -s 3x2x2/0.125/0.5 -O -o box.pdf
|
93
|
+
```
|
84
94
|
|
85
|
-
|
86
|
-
|
95
|
+
Create a box defined in millimeters, print verbose info, and set
|
96
|
+
page size to A3, and layout to landscape, and stroke width to 1/2mm:
|
87
97
|
|
88
|
-
|
98
|
+
```bash
|
99
|
+
laser-cutter -u mm -w70 -h20 -d50 -t4.3 -n5 -zA3 -y landscape -k0.5 -v -O -o box.pdf
|
100
|
+
```
|
89
101
|
|
90
|
-
|
102
|
+
List all possible page sizes in metric system:
|
91
103
|
|
92
|
-
|
93
|
-
|
104
|
+
```bash
|
105
|
+
laser-cutter -l -u mm
|
94
106
|
```
|
95
107
|
|
108
|
+
Create a box with provided dimensions, and save the config to a file for later use:
|
109
|
+
|
110
|
+
```bash
|
111
|
+
laser-cutter -s 1.1x2.5x1.5/0.125/0.125 -p 0.1 -O -o box.pdf -W box-settings.json
|
112
|
+
```
|
113
|
+
|
114
|
+
Read settings from a previously saved file:
|
115
|
+
|
116
|
+
```bash
|
117
|
+
laser-cutter -O -o box.pdf -R box-settings.json
|
118
|
+
cat box-settings.json | laser-cutter -O -o box.pdf -R -
|
119
|
+
```
|
120
|
+
|
96
121
|
## Future Features
|
97
122
|
|
98
123
|
* Extensibility with various layout strategies, notch drawing strategies, basically plug and play
|
@@ -100,7 +125,6 @@ Examples:
|
|
100
125
|
* Support more shapes than just box
|
101
126
|
* Create T-style joins, using various standard sizes of nuts and bolts (such as common #4-40 and M2 sizes)
|
102
127
|
* Supporting lids and front panels, that are larger than the box itself and have holes for notches.
|
103
|
-
* A web-app that uses the gem and renders box live in CSS using CSS 2D to show preview.
|
104
128
|
* Your brilliant idea can be here too! Please see [contributing](CONTRIBUTING.md) for more info.
|
105
129
|
|
106
130
|
## Comparison with BoxMaker
|
@@ -137,14 +161,14 @@ niceties):
|
|
137
161
|
```bash
|
138
162
|
git clone https://github.com/aphelps/boxmaker && cd boxmaker && ant
|
139
163
|
java -cp BOX.jar com.rahulbotics.boxmaker.BoxMaker \
|
140
|
-
-
|
164
|
+
-W 1 -H 2 -D 1.5 -T 0.125 -n 0.125 -o box.pdf
|
141
165
|
```
|
142
166
|
|
143
167
|
And laser-cutter:
|
144
168
|
|
145
169
|
```bash
|
146
170
|
gem install laser-cutter
|
147
|
-
laser-cutter -
|
171
|
+
laser-cutter -s 1x1.5x2/0.125/0.125 -O -o box.pdf
|
148
172
|
```
|
149
173
|
|
150
174
|
![LaserCutter Comparison](doc/comparison.jpg).
|
data/bin/laser-cutter
CHANGED
@@ -18,7 +18,7 @@ module Laser
|
|
18
18
|
#{('Laser-Cutter v'+ Laser::Cutter::VERSION).bold}
|
19
19
|
|
20
20
|
Usage: laser-cutter [options] -o filename.pdf
|
21
|
-
eg: laser-cutter -
|
21
|
+
eg: laser-cutter -s 1x1.5x2/0.125/0.125 -O -o box.pdf
|
22
22
|
EOF
|
23
23
|
|
24
24
|
examples = <<-EOF
|
@@ -26,21 +26,31 @@ Usage: laser-cutter [options] -o filename.pdf
|
|
26
26
|
Examples:
|
27
27
|
1. Create a box defined in inches, and open PDF in preview right after:
|
28
28
|
|
29
|
-
laser-cutter -
|
29
|
+
laser-cutter -s 3x2x2/0.125/0.5 -O -o box.pdf
|
30
30
|
|
31
|
-
2. Create a box defined in millimeters, print verbose info and set
|
31
|
+
2. Create a box defined in millimeters, print verbose info, and set
|
32
32
|
page size to A3, and layout to landscape, and stroke width to 1/2mm:
|
33
33
|
|
34
|
-
laser-cutter -w70 -h20 -d50 -t4.3 -n5 -
|
34
|
+
laser-cutter -u mm -w70 -h20 -d50 -t4.3 -n5 -zA3 -y landscape -k0.5 -v -O -o box.pdf
|
35
35
|
|
36
|
-
3. List all possible page sizes in metric
|
36
|
+
3. List all possible page sizes in metric systems:
|
37
|
+
|
38
|
+
laser-cutter -l -u mm
|
39
|
+
|
40
|
+
4. Create a box with provided dimensions, and save the config to a file
|
41
|
+
for later use:
|
42
|
+
|
43
|
+
laser-cutter -s 1.1x2.5x1.5/0.125/0.125 -p 0.1 -O -o box.pdf -W box-settings.json
|
44
|
+
|
45
|
+
5. Read settings from a previously saved file:
|
46
|
+
|
47
|
+
laser-cutter -O -o box.pdf -R box-settings.json
|
48
|
+
cat box-settings.json | laser-cutter -O -o box.pdf -R -
|
37
49
|
|
38
|
-
laser-cutter --list-all-page-sizes
|
39
|
-
laser-cutter --list-all-page-sizes --inches
|
40
50
|
EOF
|
41
51
|
options = Hashie::Mash.new
|
42
52
|
options.verbose = false
|
43
|
-
options.units = '
|
53
|
+
options.units = 'in'
|
44
54
|
|
45
55
|
opt_parser = OptionParser.new do |opts|
|
46
56
|
opts.banner = banner_text.blue
|
@@ -53,14 +63,13 @@ Examples:
|
|
53
63
|
opts.separator ""
|
54
64
|
opts.on("-m", "--margin MARGIN", "Margins from the edge of the document") { |value| options.margin = value }
|
55
65
|
opts.on("-p", "--padding PADDING", "Space between the boxes on the page") { |value| options.padding = value }
|
56
|
-
opts.on("-
|
66
|
+
opts.on("-k", "--stroke WIDTH", "Numeric stroke width of the line") { |value| options.stroke = value }
|
57
67
|
opts.on("-z", "--page_size LETTER", "Page size, see --list-all-page-sizes for more info.") { |value| options.page_size = value }
|
58
68
|
opts.on("-y", "--page_layout portrait", "Page layout, other option is 'landscape' ") { |value| options.page_layout = value }
|
59
69
|
opts.separator ""
|
60
70
|
opts.on("-O", "--open", "Open generated file with system viewer before exiting") { |v| options.open = v }
|
61
|
-
opts.on("-
|
62
|
-
opts.on("-
|
63
|
-
opts.on("-u", "--units UNITS", "Either 'mm' (default) or 'in'") { |value| options.units = value }
|
71
|
+
opts.on("-W", "--write FILE", "Save provided configuration to a file, use '-' for STDOUT") { |v| options.write_file = v }
|
72
|
+
opts.on("-R", "--read FILE", "Read configuration from a file, or use '-' for STDIN") { |v| options.read_file = v }
|
64
73
|
opts.separator ""
|
65
74
|
opts.on("-l", "--list-all-page-sizes", "Print all available page sizes with dimensions and exit") { |v| options.list_all_page_sizes = true }
|
66
75
|
opts.on("-M", "--no-metadata", "Do not print box metadata on the PDF") { |value| options.metadata = value }
|
@@ -76,7 +85,7 @@ Examples:
|
|
76
85
|
"Combined internal dimensions: W = width, H = height,\n#{" " * 37}D = depth, T = thickness, N = notch length\n\n") do |size|
|
77
86
|
options.size = size
|
78
87
|
end
|
79
|
-
opts.on_tail("-
|
88
|
+
opts.on_tail("-u", "--units UNITS", "Either 'in' for inches (default) or 'mm'") { |value| options.units = value }
|
80
89
|
end
|
81
90
|
|
82
91
|
opt_parser.parse!(args)
|
@@ -87,7 +96,7 @@ Examples:
|
|
87
96
|
|
88
97
|
config = Laser::Cutter::Configuration.new(options.to_hash)
|
89
98
|
if config.list_all_page_sizes
|
90
|
-
puts config.all_page_sizes
|
99
|
+
puts PageManager.new(config.units).all_page_sizes
|
91
100
|
exit 0
|
92
101
|
end
|
93
102
|
|
@@ -150,14 +159,13 @@ end # class OptParse
|
|
150
159
|
config = Laser::Cutter::OptParse.parse(ARGV)
|
151
160
|
|
152
161
|
begin
|
153
|
-
Laser::Cutter::Renderer::
|
162
|
+
Laser::Cutter::Renderer::LayoutRenderer.new(config).render
|
154
163
|
if config.open
|
155
164
|
`open #{config.file}`
|
156
165
|
end
|
157
166
|
rescue Exception => e
|
158
|
-
|
159
|
-
if
|
160
|
-
STDERR.puts "Exception: #{e.inspect}".red
|
167
|
+
STDERR.puts "#{e.inspect}".red
|
168
|
+
if config.verbose
|
161
169
|
STDERR.puts e.backtrace.join("\n").red
|
162
170
|
end
|
163
171
|
end
|
data/lib/laser-cutter.rb
CHANGED
@@ -10,8 +10,7 @@ module Laser
|
|
10
10
|
end
|
11
11
|
class Configuration < Hashie::Mash
|
12
12
|
DEFAULTS = {
|
13
|
-
units: '
|
14
|
-
page_size: 'LETTER',
|
13
|
+
units: 'in',
|
15
14
|
page_layout: 'portrait',
|
16
15
|
metadata: true
|
17
16
|
}
|
@@ -64,42 +63,6 @@ module Laser
|
|
64
63
|
raise ZeroValueNotAllowed.new("#{zeros.join(', ')} #{zeros.size > 1 ? 'are' : 'is'} required, but is zero.") unless zeros.empty?
|
65
64
|
end
|
66
65
|
|
67
|
-
def page_size_values
|
68
|
-
h = PDF::Core::PageGeometry::SIZES
|
69
|
-
array = []
|
70
|
-
h.keys.sort.each do |k|
|
71
|
-
array << [k, value_from_units(h[k][0].to_f), value_from_units(h[k][1].to_f)]
|
72
|
-
end
|
73
|
-
array
|
74
|
-
end
|
75
|
-
|
76
|
-
# if from_units is nil, we expect it to be in dots per inch (default
|
77
|
-
# measurements for Prawn
|
78
|
-
def value_from_units value, from_units = nil
|
79
|
-
multiplier = if from_units.nil?
|
80
|
-
if units.eql?('in')
|
81
|
-
1.0 / 72.0 # PDF units per inch
|
82
|
-
else
|
83
|
-
25.4 * 1.0 / 72.0
|
84
|
-
end
|
85
|
-
elsif self.units.eql?(from_units)
|
86
|
-
1.0
|
87
|
-
elsif self.units.eql?('in') && from_units.eql?('mm')
|
88
|
-
(1.0 / 25.4)
|
89
|
-
else
|
90
|
-
25.4
|
91
|
-
end
|
92
|
-
value.to_f * multiplier
|
93
|
-
end
|
94
|
-
|
95
|
-
def all_page_sizes
|
96
|
-
output = ""
|
97
|
-
page_size_values.each do |k|
|
98
|
-
output << sprintf("\t%10s:\t%6.1f x %6.1f\n", *k)
|
99
|
-
end
|
100
|
-
output
|
101
|
-
end
|
102
|
-
|
103
66
|
def change_units(new_units)
|
104
67
|
return if (self.units.eql?(new_units) || !UNIT_SPECIFIC_DEFAULTS.keys.include?(new_units))
|
105
68
|
k = (self.units == 'in') ? 25.4 : 0.039370079
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'hashie/mash'
|
2
|
+
require 'prawn/measurement_extensions'
|
3
|
+
require 'pdf/core/page_geometry'
|
4
|
+
|
5
|
+
class Laser::Cutter::PageManager < Struct.new(:units)
|
6
|
+
SIZES = PDF::Core::PageGeometry::SIZES.clone.freeze
|
7
|
+
|
8
|
+
def all_page_sizes
|
9
|
+
output = ""
|
10
|
+
page_size_values.each do |k|
|
11
|
+
output << sprintf("\t%10s:\t%6.1f x %6.1f\n", *k)
|
12
|
+
end
|
13
|
+
output
|
14
|
+
end
|
15
|
+
|
16
|
+
# if from_units is nil, we expect it to be in dots per inch (default
|
17
|
+
# measurements for Prawn
|
18
|
+
def value_from_units value, from_units = nil
|
19
|
+
multiplier = if from_units.nil?
|
20
|
+
if units.eql?('in')
|
21
|
+
1.0 / 72.0 # PDF units per inch
|
22
|
+
else
|
23
|
+
25.4 * 1.0 / 72.0
|
24
|
+
end
|
25
|
+
elsif self.units.eql?(from_units)
|
26
|
+
1.0
|
27
|
+
elsif self.units.eql?('in') && from_units.eql?('mm')
|
28
|
+
(1.0 / 25.4)
|
29
|
+
else
|
30
|
+
25.4
|
31
|
+
end
|
32
|
+
value.to_f * multiplier
|
33
|
+
end
|
34
|
+
|
35
|
+
def page_size_values
|
36
|
+
h = SIZES
|
37
|
+
array = []
|
38
|
+
h.keys.sort.each do |k|
|
39
|
+
array << [k, value_from_units(h[k][0].to_f), value_from_units(h[k][1].to_f)]
|
40
|
+
end
|
41
|
+
array
|
42
|
+
end
|
43
|
+
end
|
@@ -1,19 +1,14 @@
|
|
1
1
|
module Laser
|
2
2
|
module Cutter
|
3
3
|
module Renderer
|
4
|
-
class AbstractRenderer < Struct.new(:subject, :options)
|
5
|
-
def render pdf = nil
|
6
|
-
raise 'Abstract method'
|
7
|
-
end
|
8
4
|
|
9
|
-
def units
|
10
|
-
options.units.to_sym || :mm
|
11
|
-
end
|
12
|
-
end
|
13
5
|
end
|
14
6
|
end
|
15
7
|
end
|
16
8
|
|
9
|
+
require 'laser-cutter/renderer/base'
|
17
10
|
require 'laser-cutter/renderer/line_renderer'
|
18
11
|
require 'laser-cutter/renderer/rect_renderer'
|
19
12
|
require 'laser-cutter/renderer/box_renderer'
|
13
|
+
require 'laser-cutter/renderer/meta_renderer'
|
14
|
+
require 'laser-cutter/renderer/layout_renderer'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Laser
|
2
|
+
module Cutter
|
3
|
+
module Renderer
|
4
|
+
class Base
|
5
|
+
BLACK = "000000"
|
6
|
+
BLUE = "4090E0"
|
7
|
+
|
8
|
+
attr_accessor :config, :subject, :enclosure, :page_manager
|
9
|
+
|
10
|
+
def initialize(config, subject = nil)
|
11
|
+
self.config = config
|
12
|
+
self.subject = subject
|
13
|
+
self.page_manager = Laser::Cutter::PageManager.new(config.units)
|
14
|
+
end
|
15
|
+
|
16
|
+
def render
|
17
|
+
raise 'Abstract method'
|
18
|
+
end
|
19
|
+
|
20
|
+
def units
|
21
|
+
config.units.to_sym || :mm
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -3,96 +3,30 @@ require 'json'
|
|
3
3
|
module Laser
|
4
4
|
module Cutter
|
5
5
|
module Renderer
|
6
|
-
class BoxRenderer <
|
6
|
+
class BoxRenderer < Base
|
7
7
|
alias_method :box, :subject
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
self.options = options
|
13
|
-
self.subject = Laser::Cutter::Box.new(options)
|
9
|
+
def initialize(config)
|
10
|
+
super(config)
|
11
|
+
self.subject = Laser::Cutter::Box.new(config)
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
header = <<-EOF
|
21
|
-
|
22
|
-
Made with Laser Cutter Ruby Gem (v#{Laser::Cutter::VERSION})
|
23
|
-
Credits to Prawn for ruby PDF generation,
|
24
|
-
and BoxMaker for inspiration.
|
14
|
+
def ensure_space_for(rect)
|
15
|
+
coords = [ rect.p2.x, rect.p2.y ].map{|a| page_manager.value_from_units(a)}
|
16
|
+
box.metadata = Geometry::Point.new(coords)
|
17
|
+
end
|
25
18
|
|
26
|
-
Online: http://makeabox.io/
|
27
|
-
https://github.com/kigster/laser-cutter
|
28
|
-
EOF
|
29
19
|
|
20
|
+
def render pdf = nil
|
30
21
|
renderer = self
|
31
|
-
|
32
|
-
meta_color = "4090E0"
|
33
|
-
meta_top_height = 50
|
34
|
-
metadata = renderer.options.to_hash
|
35
|
-
metadata.delete_if { |k| %w(verbose metadata open file).include?(k) }
|
36
|
-
if options.metadata
|
37
|
-
coords = [ META_RECT.p2.x, META_RECT.p2.y ].map{|a| options.value_from_units(a)}
|
38
|
-
box.metadata = Geometry::Point.new(coords)
|
39
|
-
end
|
40
22
|
pdf.instance_eval do
|
41
|
-
self.line_width = renderer.
|
42
|
-
|
43
|
-
float do
|
44
|
-
bounding_box([0, META_RECT.h], :width => META_RECT.w, :height => META_RECT.h) do
|
45
|
-
stroke_color meta_color
|
46
|
-
stroke_bounds
|
47
|
-
indent 10 do
|
48
|
-
font('Helvetica', :size => 6) do
|
49
|
-
text header, :color => meta_color
|
50
|
-
end
|
51
|
-
end
|
52
|
-
float do
|
53
|
-
bounding_box([0, META_RECT.h - meta_top_height],
|
54
|
-
:width => META_RECT.w,
|
55
|
-
:height => META_RECT.h - meta_top_height) do
|
56
|
-
stroke_color meta_color
|
57
|
-
stroke_bounds
|
58
|
-
float do
|
59
|
-
bounding_box([0, META_RECT.h - meta_top_height], :width => 70, :height => META_RECT.h - meta_top_height) do
|
60
|
-
indent 10 do
|
61
|
-
font('Helvetica', :size => 6) do
|
62
|
-
out = JSON.pretty_generate(metadata).gsub(/[\{\}",]/, '').gsub(/:.*\n/x, "\n")
|
63
|
-
text out, :color => meta_color, align: :right
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
float do
|
69
|
-
bounding_box([60, META_RECT.h - meta_top_height], :width => 70, :height => META_RECT.h - meta_top_height) do
|
70
|
-
indent 10 do
|
71
|
-
font('Helvetica', :size => 6) do
|
72
|
-
out = JSON.pretty_generate(metadata).gsub(/[\{\}",]/, '').gsub(/\n?.*:/x, "\n:")
|
73
|
-
text out, :color => meta_color
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
stroke_color "000000"
|
23
|
+
self.line_width = renderer.config.stroke.send(renderer.config.units.to_sym)
|
24
|
+
stroke_color BLACK
|
84
25
|
renderer.box.notches.each do |notch|
|
85
|
-
LineRenderer.new(
|
26
|
+
LineRenderer.new(renderer.config, notch).render(self)
|
86
27
|
end
|
87
|
-
|
88
|
-
render_file(renderer.options.file)
|
89
|
-
end
|
90
|
-
|
91
|
-
if options.verbose
|
92
|
-
puts "file #{options.file} has been written."
|
93
28
|
end
|
94
29
|
end
|
95
|
-
|
96
30
|
end
|
97
31
|
end
|
98
32
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'json'
|
3
|
+
module Laser
|
4
|
+
module Cutter
|
5
|
+
module Renderer
|
6
|
+
class LayoutRenderer < Base
|
7
|
+
def initialize(config)
|
8
|
+
self.config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def render
|
12
|
+
renderer = self
|
13
|
+
|
14
|
+
meta_renderer = MetaRenderer.new(config)
|
15
|
+
box_renderer = BoxRenderer.new(config)
|
16
|
+
box_renderer.ensure_space_for(meta_renderer.enclosure) if config.metadata
|
17
|
+
|
18
|
+
page_size = config.page_size || 'LETTER' # TODO: auto-detect page size based on box dimensions.
|
19
|
+
|
20
|
+
pdf = Prawn::Document.new(:margin => config.margin.to_f.send(config.units.to_sym),
|
21
|
+
:page_size => page_size,
|
22
|
+
:page_layout => config.page_layout.to_sym)
|
23
|
+
|
24
|
+
pdf.instance_eval do
|
25
|
+
if renderer.config.metadata
|
26
|
+
meta_renderer.render(self)
|
27
|
+
end
|
28
|
+
box_renderer.render(self)
|
29
|
+
render_file(renderer.config.file)
|
30
|
+
end
|
31
|
+
|
32
|
+
if config.verbose
|
33
|
+
puts "PDF saved to #{config.file}."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
module Laser
|
2
2
|
module Cutter
|
3
3
|
module Renderer
|
4
|
-
class LineRenderer <
|
4
|
+
class LineRenderer < Base
|
5
5
|
alias_method :line, :subject
|
6
6
|
def render pdf = nil
|
7
7
|
pdf.stroke { pdf.line [line.p1.x, line.p1.y].map{ |p| p.send(units) },
|
8
8
|
[line.p2.x, line.p2.y].map{ |p| p.send(units) }}
|
9
|
+
end
|
9
10
|
|
11
|
+
def enclosure
|
12
|
+
self.line
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'json'
|
3
|
+
class Laser::Cutter::Renderer::MetaRenderer < Laser::Cutter::Renderer::Base
|
4
|
+
|
5
|
+
def initialize(config = {})
|
6
|
+
self.config = config
|
7
|
+
self.enclosure = Laser::Cutter::Geometry::Rect.create(Laser::Cutter::Geometry::Point[1, 1], 140, 150)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render pdf = nil
|
11
|
+
banner = <<-EOF
|
12
|
+
|
13
|
+
Made with Laser Cutter Ruby Gem (v#{Laser::Cutter::VERSION})
|
14
|
+
Credits to Prawn for ruby PDF generation,
|
15
|
+
and BoxMaker for inspiration.
|
16
|
+
|
17
|
+
Online: http://makeabox.io/
|
18
|
+
Source: https://github.com/kigster/laser-cutter
|
19
|
+
EOF
|
20
|
+
|
21
|
+
meta_color = BLUE
|
22
|
+
meta_top_height = 50
|
23
|
+
|
24
|
+
metadata = config.to_hash
|
25
|
+
metadata.delete_if { |k| %w(verbose metadata open file).include?(k) }
|
26
|
+
|
27
|
+
rect = self.enclosure
|
28
|
+
|
29
|
+
pdf.instance_eval do
|
30
|
+
self.line_width = 0.5.mm
|
31
|
+
float do
|
32
|
+
bounding_box([rect.p1.x, rect.h + rect.p1.y], :width => rect.w, :height => rect.h) do
|
33
|
+
stroke_color meta_color
|
34
|
+
stroke_bounds
|
35
|
+
|
36
|
+
# Print banner
|
37
|
+
indent 10 do
|
38
|
+
font('Helvetica', :size => 6) do
|
39
|
+
text banner, :color => meta_color
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# print values of the config, in two parts – keys right aligned first,
|
44
|
+
# values left aligned second.
|
45
|
+
float do
|
46
|
+
# parse out meta keys and then values
|
47
|
+
meta_fields = JSON.pretty_generate(metadata).gsub(/[\{\}",]/, '').gsub(/:.*\n/x, "\n")
|
48
|
+
meta_values = JSON.pretty_generate(metadata).gsub(/[\{\}",]/, '').gsub(/\n?.*:/x, "\n:")
|
49
|
+
|
50
|
+
bounding_box([0, rect.h - meta_top_height],
|
51
|
+
:width => rect.w,
|
52
|
+
:height => rect.h - meta_top_height) do
|
53
|
+
float do
|
54
|
+
bounding_box([0, rect.h - meta_top_height], :width => 70, :height => rect.h - meta_top_height) do
|
55
|
+
indent 10 do
|
56
|
+
font('Helvetica', :size => 7) do
|
57
|
+
text meta_fields, :color => meta_color, align: :right
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
float do
|
63
|
+
bounding_box([60, rect.h - meta_top_height], :width => 70, :height => rect.h - meta_top_height) do
|
64
|
+
indent 10 do
|
65
|
+
font('Helvetica', :size => 7) do
|
66
|
+
text meta_values, :color => meta_color
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module Laser
|
2
2
|
module Cutter
|
3
3
|
module Renderer
|
4
|
-
class RectRenderer <
|
4
|
+
class RectRenderer < Base
|
5
5
|
alias_method :rect, :subject
|
6
|
-
|
7
6
|
def render pdf
|
8
7
|
rect.sides.each do |side|
|
9
|
-
LineRenderer.new(
|
8
|
+
LineRenderer.new(config, side).render(pdf)
|
10
9
|
end
|
11
10
|
end
|
12
11
|
end
|
data/lib/laser-cutter/version.rb
CHANGED
data/spec/configuration_spec.rb
CHANGED
@@ -31,49 +31,15 @@ module Laser
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
context '#list_page_sizes' do
|
35
|
-
context 'formatting of output' do
|
36
|
-
context 'when using inches' do
|
37
|
-
let(:opts) { {"units" => "in"} }
|
38
|
-
it 'should return the list in inches' do
|
39
|
-
expect(config.all_page_sizes).to match %r(.*B10\:\s+1\.2\s+x\s+1\.7)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
context 'when using mm' do
|
43
|
-
let(:opts) { {"units" => "mm"} }
|
44
|
-
it 'should return the list in mm' do
|
45
|
-
expect(config.all_page_sizes).to match %r(.*B10\:\s+31\.0\s+x\s+44\.0)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
34
|
|
51
35
|
context 'when invalid units are provided' do
|
52
36
|
let(:opts) { {"size" => "2x3x2/0.125/0.5", "units" => 'xx'} }
|
53
|
-
it 'should default to
|
54
|
-
expect(config.units).to eql('
|
37
|
+
it 'should default to inches' do
|
38
|
+
expect(config.units).to eql('in')
|
55
39
|
end
|
56
40
|
end
|
57
41
|
|
58
42
|
context 'when converting between units' do
|
59
|
-
context 'a single value' do
|
60
|
-
context 'to inches' do
|
61
|
-
let(:opts) { {'units' => 'in'} }
|
62
|
-
it 'should be correct' do
|
63
|
-
expect(config.value_from_units(150)).to be_within(0.0001).of(150.0/72.0)
|
64
|
-
expect(config.value_from_units(150, 'mm')).to be_within(0.0001).of(150.0/25.4)
|
65
|
-
expect(config.value_from_units(150, 'in')).to be_within(0.0001).of(150.0)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
context 'to mm' do
|
69
|
-
let(:opts) { {'units' => 'mm'} }
|
70
|
-
it 'should be correct' do
|
71
|
-
expect(config.value_from_units(150)).to be_within(0.0001).of(25.4 * 150.0 / 72.0)
|
72
|
-
expect(config.value_from_units(150, 'in')).to be_within(0.0001).of(150.0 * 25.4)
|
73
|
-
expect(config.value_from_units(150, 'mm')).to be_within(0.0001).of(150.0)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
43
|
context 'all config values' do
|
78
44
|
context "to mm" do
|
79
45
|
let(:opts) { {'size' => "2.0x3x2/0.125/0.5", 'padding' => '4.2', "units" => 'in'} }
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
module Laser
|
4
|
+
module Cutter
|
5
|
+
describe PageManager do
|
6
|
+
let(:pm) { Laser::Cutter::PageManager.new(units) }
|
7
|
+
|
8
|
+
context 'a single value' do
|
9
|
+
context 'to inches' do
|
10
|
+
let(:units) { 'in' }
|
11
|
+
it 'should be correct' do
|
12
|
+
expect(pm.value_from_units(150)).to be_within(0.0001).of(150.0/72.0)
|
13
|
+
expect(pm.value_from_units(150, 'mm')).to be_within(0.0001).of(150.0/25.4)
|
14
|
+
expect(pm.value_from_units(150, 'in')).to be_within(0.0001).of(150.0)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
context 'to mm' do
|
18
|
+
let(:units) { 'mm' }
|
19
|
+
it 'should be correct' do
|
20
|
+
expect(pm.value_from_units(150)).to be_within(0.0001).of(25.4 * 150.0 / 72.0)
|
21
|
+
expect(pm.value_from_units(150, 'in')).to be_within(0.0001).of(150.0 * 25.4)
|
22
|
+
expect(pm.value_from_units(150, 'mm')).to be_within(0.0001).of(150.0)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context '#list_page_sizes' do
|
28
|
+
context 'formatting of output' do
|
29
|
+
context 'when using inches' do
|
30
|
+
let(:units) { "in" }
|
31
|
+
it 'should return the list in inches' do
|
32
|
+
expect(pm.all_page_sizes).to match %r(.*B10\:\s+1\.2\s+x\s+1\.7)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
context 'when using mm' do
|
36
|
+
let(:units) { "mm" }
|
37
|
+
it 'should return the list in mm' do
|
38
|
+
expect(pm.all_page_sizes).to match %r(.*B10\:\s+31\.0\s+x\s+44\.0)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/renderer_spec.rb
CHANGED
@@ -3,19 +3,22 @@ require_relative 'spec_helper'
|
|
3
3
|
module Laser
|
4
4
|
module Cutter
|
5
5
|
module Renderer
|
6
|
-
describe
|
6
|
+
describe LayoutRenderer do
|
7
7
|
context '#render' do
|
8
|
-
let(:
|
9
|
-
let(:renderer) { BoxRenderer.new(config) }
|
8
|
+
let(:renderer) { LayoutRenderer.new(config) }
|
10
9
|
let(:file) { File.expand_path("../../laser-cutter-pdf-test.#{$$}.pdf", __FILE__) }
|
11
10
|
|
12
11
|
def render_file filename
|
12
|
+
config.validate!
|
13
13
|
expect(!File.exists?(filename))
|
14
14
|
renderer.render
|
15
15
|
expect(File.exist?(filename))
|
16
16
|
expect(File.size(filename) > 0)
|
17
|
+
rescue Exception => e
|
18
|
+
STDERR.puts e.backtrace.join("\n")
|
19
|
+
fail e.message
|
17
20
|
ensure
|
18
|
-
File.delete(filename)
|
21
|
+
File.delete(filename) rescue nil
|
19
22
|
expect(!File.exists?(filename))
|
20
23
|
end
|
21
24
|
|
@@ -38,7 +41,7 @@ module Laser
|
|
38
41
|
|
39
42
|
it 'should be able to generate a PDF file' do
|
40
43
|
render_file file
|
41
|
-
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
context 'margins and padding are defaults' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: laser-cutter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Gredeskoul
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prawn
|
@@ -158,15 +158,20 @@ files:
|
|
158
158
|
- lib/laser-cutter/geometry/shape/line.rb
|
159
159
|
- lib/laser-cutter/geometry/shape/rect.rb
|
160
160
|
- lib/laser-cutter/geometry/tuple.rb
|
161
|
+
- lib/laser-cutter/page_manager.rb
|
161
162
|
- lib/laser-cutter/renderer.rb
|
163
|
+
- lib/laser-cutter/renderer/base.rb
|
162
164
|
- lib/laser-cutter/renderer/box_renderer.rb
|
165
|
+
- lib/laser-cutter/renderer/layout_renderer.rb
|
163
166
|
- lib/laser-cutter/renderer/line_renderer.rb
|
167
|
+
- lib/laser-cutter/renderer/meta_renderer.rb
|
164
168
|
- lib/laser-cutter/renderer/rect_renderer.rb
|
165
169
|
- lib/laser-cutter/version.rb
|
166
170
|
- spec/box_spec.rb
|
167
171
|
- spec/configuration_spec.rb
|
168
172
|
- spec/dimensions_spec.rb
|
169
173
|
- spec/line_spec.rb
|
174
|
+
- spec/page_manager_spec.rb
|
170
175
|
- spec/path_generator_spec.rb
|
171
176
|
- spec/point_spec.rb
|
172
177
|
- spec/rect_spec.rb
|
@@ -202,8 +207,10 @@ test_files:
|
|
202
207
|
- spec/configuration_spec.rb
|
203
208
|
- spec/dimensions_spec.rb
|
204
209
|
- spec/line_spec.rb
|
210
|
+
- spec/page_manager_spec.rb
|
205
211
|
- spec/path_generator_spec.rb
|
206
212
|
- spec/point_spec.rb
|
207
213
|
- spec/rect_spec.rb
|
208
214
|
- spec/renderer_spec.rb
|
209
215
|
- spec/spec_helper.rb
|
216
|
+
has_rdoc:
|