squib 0.14.3.pre1 → 0.16.0.pre.preview1

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +22 -0
  3. data/CHANGELOG.md +58 -2
  4. data/Dockerfile +27 -0
  5. data/Guardfile +8 -0
  6. data/README.md +24 -6
  7. data/RELEASE TODO.md +1 -0
  8. data/Rakefile +3 -0
  9. data/lib/squib.rb +3 -1
  10. data/lib/squib/args/arg_loader.rb +109 -106
  11. data/lib/squib/args/box.rb +52 -48
  12. data/lib/squib/args/card_range.rb +26 -24
  13. data/lib/squib/args/color_validator.rb +4 -9
  14. data/lib/squib/args/coords.rb +39 -25
  15. data/lib/squib/args/csv_opts.rb +13 -16
  16. data/lib/squib/args/dir_validator.rb +7 -12
  17. data/lib/squib/args/draw.rb +69 -68
  18. data/lib/squib/args/embed_adjust.rb +12 -15
  19. data/lib/squib/args/embed_key.rb +6 -11
  20. data/lib/squib/args/hand_special.rb +25 -25
  21. data/lib/squib/args/import.rb +54 -27
  22. data/lib/squib/args/input_file.rb +22 -26
  23. data/lib/squib/args/paint.rb +30 -31
  24. data/lib/squib/args/paragraph.rb +95 -93
  25. data/lib/squib/args/save_batch.rb +50 -48
  26. data/lib/squib/args/scale_box.rb +43 -39
  27. data/lib/squib/args/sheet.rb +147 -149
  28. data/lib/squib/args/showcase_special.rb +32 -29
  29. data/lib/squib/args/sprue_file.rb +30 -30
  30. data/lib/squib/args/svg_special.rb +26 -26
  31. data/lib/squib/args/transform.rb +48 -54
  32. data/lib/squib/args/typographer.rb +88 -92
  33. data/lib/squib/args/unit_conversion.rb +6 -8
  34. data/lib/squib/args/xywh_shorthands.rb +56 -0
  35. data/lib/squib/builtin/projects/advanced/config.yml +3 -6
  36. data/lib/squib/builtin/projects/basic/config.yml +3 -6
  37. data/lib/squib/commands/make_sprue.rb +2 -0
  38. data/lib/squib/conf.rb +5 -5
  39. data/lib/squib/deck.rb +34 -12
  40. data/lib/squib/dsl/background.rb +35 -0
  41. data/lib/squib/dsl/circle.rb +39 -0
  42. data/lib/squib/dsl/csv.rb +42 -0
  43. data/lib/squib/dsl/curve.rb +35 -0
  44. data/lib/squib/dsl/cut_zone.rb +47 -0
  45. data/lib/squib/dsl/ellipse.rb +37 -0
  46. data/lib/squib/dsl/grid.rb +35 -0
  47. data/lib/squib/{api → dsl}/groups.rb +0 -0
  48. data/lib/squib/dsl/hand.rb +42 -0
  49. data/lib/squib/dsl/line.rb +35 -0
  50. data/lib/squib/dsl/png.rb +56 -0
  51. data/lib/squib/dsl/polygon.rb +36 -0
  52. data/lib/squib/dsl/rect.rb +37 -0
  53. data/lib/squib/dsl/safe_zone.rb +48 -0
  54. data/lib/squib/dsl/save.rb +21 -0
  55. data/lib/squib/dsl/save_pdf.rb +50 -0
  56. data/lib/squib/dsl/save_png.rb +47 -0
  57. data/lib/squib/dsl/save_sheet.rb +53 -0
  58. data/lib/squib/dsl/showcase.rb +43 -0
  59. data/lib/squib/dsl/star.rb +37 -0
  60. data/lib/squib/dsl/svg.rb +62 -0
  61. data/lib/squib/dsl/text.rb +54 -0
  62. data/lib/squib/dsl/text_embed.rb +78 -0
  63. data/lib/squib/dsl/triangle.rb +35 -0
  64. data/lib/squib/{api → dsl}/units.rb +10 -0
  65. data/lib/squib/dsl/xlsx.rb +40 -0
  66. data/lib/squib/dsl/yaml.rb +40 -0
  67. data/lib/squib/errors_warnings/warn_unexpected_params.rb +14 -0
  68. data/lib/squib/graphics/cairo_context_wrapper.rb +2 -2
  69. data/lib/squib/graphics/image.rb +0 -6
  70. data/lib/squib/graphics/save_images.rb +3 -3
  71. data/lib/squib/graphics/save_sprue.rb +39 -12
  72. data/lib/squib/graphics/showcase.rb +1 -1
  73. data/lib/squib/graphics/text.rb +37 -9
  74. data/lib/squib/import/csv_importer.rb +45 -0
  75. data/lib/squib/import/quantity_exploder.rb +18 -0
  76. data/lib/squib/import/xlsx_importer.rb +28 -0
  77. data/lib/squib/import/yaml_importer.rb +30 -0
  78. data/lib/squib/layout_parser.rb +24 -7
  79. data/lib/squib/sprues/crop_line.rb +6 -6
  80. data/lib/squib/sprues/crop_line_dash.rb +6 -6
  81. data/lib/squib/sprues/sprue.rb +19 -14
  82. data/lib/squib/sprues/sprue_schema.rb +4 -2
  83. data/lib/squib/version.rb +1 -1
  84. data/samples/autoscale_font/_autoscale_font.rb +77 -8
  85. data/samples/colors/_colors.rb +11 -5
  86. data/samples/colors/_switch_color.rb +33 -0
  87. data/samples/data/_excel.rb +1 -1
  88. data/samples/images/_more_load_images.rb +1 -1
  89. data/samples/ranges/_ranges.rb +1 -1
  90. data/samples/saves/_save_filenames.rb +28 -0
  91. data/samples/saves/_save_pdf.rb +1 -1
  92. data/samples/saves/_saves.rb +2 -1
  93. data/samples/shapes/_draw_shapes.rb +2 -2
  94. data/samples/sprues/_advanced_sprues.rb +4 -3
  95. data/samples/sprues/_builtin_sprues.rb +1 -0
  96. data/samples/sprues/_fold_sheet.rb +4 -1
  97. data/samples/text/_text.rb +6 -1
  98. data/samples/text/_text_options.rb +2 -1
  99. data/samples/units/_cells.rb +51 -0
  100. data/samples/units/_shorthands.rb +49 -0
  101. data/samples/units/_units.rb +7 -0
  102. data/squib.gemspec +19 -13
  103. metadata +151 -61
  104. data/.travis.yml +0 -19
  105. data/appveyor.yml +0 -24
  106. data/lib/squib/api/background.rb +0 -15
  107. data/lib/squib/api/data.rb +0 -137
  108. data/lib/squib/api/image.rb +0 -49
  109. data/lib/squib/api/save.rb +0 -83
  110. data/lib/squib/api/shapes.rb +0 -124
  111. data/lib/squib/api/text.rb +0 -25
  112. data/lib/squib/api/text_embed.rb +0 -71
  113. data/samples/bug256/_bug256.rb +0 -13
@@ -1,63 +1,65 @@
1
1
  require_relative 'arg_loader'
2
2
  require_relative 'dir_validator'
3
3
 
4
- module Squib
5
- # @api private
6
- module Args
7
- class SaveBatch
8
- include ArgLoader
9
- include DirValidator
10
-
11
- def initialize
12
- end
4
+ module Squib::Args
5
+ module_function def extract_save_batch(opts, deck)
6
+ SaveBatch.new.extract! opts, deck
7
+ end
13
8
 
14
- def self.parameters
15
- {
16
- angle: 0,
17
- count_format: '%02d',
18
- dir: '_output',
19
- prefix: 'card_',
20
- rotate: false,
21
- trim_radius: 0,
22
- trim: 0,
23
- }
24
- end
9
+ class SaveBatch
10
+ include ArgLoader
11
+ include DirValidator
25
12
 
26
- def self.expanding_parameters
27
- self.parameters.keys # all of them
28
- end
13
+ def initialize
14
+ end
29
15
 
30
- def self.params_with_units
31
- [:trim, :trim_radius]
32
- end
16
+ def self.parameters
17
+ {
18
+ angle: 0,
19
+ count_format: '%02d',
20
+ dir: '_output',
21
+ prefix: 'card_',
22
+ rotate: false,
23
+ suffix: '',
24
+ trim_radius: 0,
25
+ trim: 0,
26
+ }
27
+ end
33
28
 
34
- def validate_dir(arg, _i)
35
- ensure_dir_created(arg)
36
- end
29
+ def self.expanding_parameters
30
+ self.parameters.keys # all of them
31
+ end
37
32
 
38
- def validate_rotate(arg, i)
39
- case arg
40
- when true, :clockwise
41
- angle[i] = 0.5 * Math::PI
42
- return true
43
- when :counterclockwise
44
- angle[i] = 1.5 * Math::PI
45
- return true
46
- when false
47
- false
48
- else
49
- raise 'invalid option to rotate: only [true, false, :clockwise, :counterclockwise]'
50
- end
51
- end
33
+ def self.params_with_units
34
+ [:trim, :trim_radius]
35
+ end
52
36
 
53
- def full_filename(i)
54
- "#{dir[i]}/#{prefix[i]}#{count_format[i] % i}.png"
55
- end
37
+ def validate_dir(arg, _i)
38
+ ensure_dir_created(arg)
39
+ end
56
40
 
57
- def summary
58
- "#{dir[0]}/#{prefix[0]}_*"
41
+ def validate_rotate(arg, i)
42
+ case arg
43
+ when true, :clockwise
44
+ angle[i] = 0.5 * Math::PI
45
+ return true
46
+ when :counterclockwise
47
+ angle[i] = 1.5 * Math::PI
48
+ return true
49
+ when false
50
+ false
51
+ else
52
+ raise 'invalid option to rotate: only [true, false, :clockwise, :counterclockwise]'
59
53
  end
54
+ end
55
+
56
+ def full_filename(i)
57
+ "#{dir[i]}/#{prefix[i]}#{count_format[i] % i}#{suffix[i]}.png"
58
+ end
60
59
 
60
+ def summary
61
+ "#{dir[0]}/#{prefix[0]}_*#{suffix[0]}"
61
62
  end
63
+
62
64
  end
63
65
  end
@@ -1,53 +1,57 @@
1
1
  require_relative 'arg_loader'
2
+ require_relative 'xywh_shorthands'
2
3
 
3
- module Squib
4
- # @api private
5
- module Args
6
-
7
- class ScaleBox
8
- include ArgLoader
4
+ module Squib::Args
5
+ module_function def extract_scale_box(opts, deck)
6
+ ScaleBox.new.extract!(opts, deck)
7
+ end
9
8
 
10
- def initialize(deck)
11
- @deck = deck
12
- end
9
+ class ScaleBox
10
+ include ArgLoader
11
+ include XYWHShorthands
13
12
 
14
- def self.parameters
15
- { x: 0, y: 0,
16
- width: :native, height: :native
17
- }
18
- end
13
+ def self.parameters
14
+ {
15
+ x: 0, y: 0,
16
+ width: :native, height: :native
17
+ }
18
+ end
19
19
 
20
- def self.expanding_parameters
21
- parameters.keys # all of them
22
- end
20
+ def self.expanding_parameters
21
+ parameters.keys # all of them
22
+ end
23
23
 
24
- def self.params_with_units
25
- parameters.keys # all of them
26
- end
24
+ def self.params_with_units
25
+ parameters.keys # all of them
26
+ end
27
27
 
28
- def validate_width(arg, i)
29
- return @deck.width if arg.to_s == 'deck'
30
- return :native if arg.to_s == 'native'
31
- return arg if arg.respond_to? :to_f
32
- if arg.to_s == 'scale'
33
- raise 'if width is :scale, height must be a number' unless height[i].respond_to? :to_f
34
- return arg
35
- end
36
- raise 'width must be a number, :scale, :native, or :deck'
28
+ def validate_x(arg, i) apply_shorthands(arg, @deck, axis: :x) end
29
+ def validate_y(arg,_i) apply_shorthands(arg, @deck, axis: :y) end
30
+
31
+ def validate_width(arg, i)
32
+ return @deck.width if arg.to_s == 'deck'
33
+ return :native if arg.to_s == 'native'
34
+ arg = apply_shorthands(arg, @deck, axis: :x)
35
+ return arg if arg.respond_to? :to_f
36
+ if arg.to_s == 'scale'
37
+ raise 'if width is :scale, height must be a number' unless height[i].respond_to? :to_f
38
+ return arg
37
39
  end
40
+ raise 'width must be a number, :scale, :native, or :deck'
41
+ end
38
42
 
39
- def validate_height(arg, i)
40
- return @deck.height if arg.to_s == 'deck'
41
- return :native if arg.to_s == 'native'
42
- return arg if arg.respond_to? :to_f
43
- if arg.to_s == 'scale'
44
- raise 'if height is \'scale\', width must be a number' unless width[i].respond_to? :to_f
45
- return arg
46
- end
47
- raise 'height must be a number, :scale, :native, or :deck'
43
+ def validate_height(arg, i)
44
+ return @deck.height if arg.to_s == 'deck'
45
+ return :native if arg.to_s == 'native'
46
+ arg = apply_shorthands(arg, @deck, axis: :y)
47
+ return arg if arg.respond_to? :to_f
48
+ if arg.to_s == 'scale'
49
+ raise 'if height is \'scale\', width must be a number' unless width[i].respond_to? :to_f
50
+ return arg
48
51
  end
49
-
52
+ raise 'height must be a number, :scale, :native, or :deck'
50
53
  end
51
54
 
52
55
  end
56
+
53
57
  end
@@ -3,170 +3,168 @@ require_relative 'arg_loader'
3
3
  require_relative 'color_validator'
4
4
  require_relative 'dir_validator'
5
5
 
6
- module Squib
7
- # @api private
8
- module Args
9
-
10
- class Sheet
11
- include ArgLoader
12
- include ColorValidator
13
- include DirValidator
14
-
15
- def initialize(custom_colors = {}, dsl_method_defaults = {}, deck_size = 1, dpi = 300)
16
- @custom_colors = custom_colors
17
- @dsl_method_defaults = dsl_method_defaults
18
- @deck_size = deck_size
19
- @dpi = dpi
20
- end
6
+ module Squib::Args
7
+ module_function def extract_sheet(opts, deck, dsl_method_defaults = {})
8
+ Sheet.new(dsl_method_defaults).extract! opts, deck
9
+ end
21
10
 
22
- def self.parameters
23
- {
24
- count_format: '%02d',
25
- crop_margin_bottom: 0,
26
- crop_margin_left: 0,
27
- crop_margin_right: 0,
28
- crop_margin_top: 0,
29
- crop_marks: false,
30
- crop_stroke_color: :black,
31
- crop_stroke_dash: '',
32
- crop_stroke_width: 1.5,
33
- dir: '_output',
34
- file: 'sheet.png',
35
- fill_color: :white,
36
- gap: 0,
37
- height: 2550,
38
- margin: 75,
39
- prefix: 'sheet_',
40
- rows: :infinite,
41
- columns: 5,
42
- trim_radius: 38,
43
- trim: 0,
44
- width: 3300,
45
- range: :all,
46
- rtl: false,
47
- }
48
- end
11
+ class Sheet
12
+ include ArgLoader
13
+ include ColorValidator
14
+ include DirValidator
49
15
 
50
- def self.expanding_parameters
51
- [] # none of them
52
- end
16
+ def initialize(dsl_method_defaults = {})
17
+ @dsl_method_defaults = dsl_method_defaults
18
+ end
53
19
 
54
- def self.params_with_units
55
- [ :crop_margin_bottom, :crop_margin_left, :crop_margin_right,
56
- :crop_margin_top, :gap, :height, :margin, :trim_radius, :trim,
57
- :width
58
- ]
59
- end
20
+ def self.parameters
21
+ {
22
+ count_format: '%02d',
23
+ crop_margin_bottom: 0,
24
+ crop_margin_left: 0,
25
+ crop_margin_right: 0,
26
+ crop_margin_top: 0,
27
+ crop_marks: false,
28
+ crop_stroke_color: :black,
29
+ crop_stroke_dash: '',
30
+ crop_stroke_width: 1.5,
31
+ dir: '_output',
32
+ file: 'sheet.png',
33
+ fill_color: :white,
34
+ gap: 0,
35
+ height: 2550,
36
+ margin: 75,
37
+ prefix: 'sheet_',
38
+ suffix: '',
39
+ rows: :infinite,
40
+ columns: 5,
41
+ trim_radius: 0,
42
+ trim: 0,
43
+ width: 3300,
44
+ range: :all,
45
+ rtl: false,
46
+ }
47
+ end
60
48
 
61
- def validate_crop_stroke_dash(arg)
62
- arg.to_s.split.collect do |x|
63
- UnitConversion.parse(x, @dpi).to_f
64
- end
65
- end
49
+ def self.expanding_parameters
50
+ [] # none of them
51
+ end
66
52
 
67
- def validate_crop_marks(arg)
68
- arg.to_s.downcase.to_sym unless arg == false
69
- end
53
+ def self.params_with_units
54
+ [ :crop_margin_bottom, :crop_margin_left, :crop_margin_right,
55
+ :crop_margin_top, :gap, :height, :margin, :trim_radius, :trim,
56
+ :width
57
+ ]
58
+ end
70
59
 
71
- def validate_fill_color(arg)
72
- colorify(arg, @custom_colors)
60
+ def validate_crop_stroke_dash(arg)
61
+ arg.to_s.split.collect do |x|
62
+ UnitConversion.parse(x, @deck.dpi, @deck.cell_px).to_f
73
63
  end
64
+ end
74
65
 
75
- def validate_dir(arg)
76
- ensure_dir_created(arg)
77
- end
66
+ def validate_crop_marks(arg)
67
+ arg.to_s.downcase.to_sym unless arg == false
68
+ end
78
69
 
79
- def validate_columns(arg)
80
- raise 'columns must be an integer' unless arg.respond_to? :to_i
81
- arg.to_i
82
- end
70
+ def validate_fill_color(arg)
71
+ colorify(arg, @deck.custom_colors)
72
+ end
83
73
 
84
- def validate_rows(arg)
85
- raise 'columns must be an integer' unless columns.respond_to? :to_i
86
- count = if range == :all
87
- @deck_size
88
- else
89
- count = range.to_a.length
90
- end
91
- return 1 if count <= columns
92
- return arg if arg.respond_to? :to_i
93
- (count.to_f / columns.to_f).ceil
94
- end
74
+ def validate_dir(arg)
75
+ ensure_dir_created(arg)
76
+ end
95
77
 
96
- def full_filename(i=nil)
97
- if i.nil?
98
- "#{dir}/#{file}"
99
- else
100
- "#{dir}/#{prefix}#{count_format % i}.png"
101
- end
102
- end
78
+ def validate_columns(arg)
79
+ raise 'columns must be an integer' unless arg.respond_to? :to_i
80
+ arg.to_i
81
+ end
103
82
 
104
- def crop_coords(x, y, deck_w, deck_h)
105
- case crop_marks
106
- when false
107
- []
108
- when :full
109
- [
110
- {
111
- # Vertical, Left
112
- x1: x + trim + crop_margin_left, y1: 0,
113
- x2: x + trim + crop_margin_left, y2: height - margin + 1
114
- },
115
- {
116
- # Vertical, Right
117
- x1: x + deck_w - trim - crop_margin_right, y1: 0,
118
- x2: x + deck_w - trim - crop_margin_right, y2: height - margin + 1
119
- },
120
- {
121
- # Horizontal, Top
122
- x1: 0 , y1: y + trim + crop_margin_top,
123
- x2: width - margin + 1, y2: y + trim + crop_margin_top
124
- },
125
- {
126
- # Horizontal, Bottom
127
- x1: 0 , y1: y + deck_h - trim - crop_margin_bottom,
128
- x2: width - margin + 1, y2: y + deck_h - trim - crop_margin_bottom
129
- },
130
- ]
131
- else # e.g. :margin
132
- [
133
- { # Vertical, Upper-left
134
- x1: x + trim + crop_margin_left, y1: 0,
135
- x2: x + trim + crop_margin_left, y2: margin - 1
136
- },
137
- { # Vertical , Upper-right
138
- x1: x + deck_w - trim - crop_margin_right, y1: 0,
139
- x2: x + deck_w - trim - crop_margin_right, y2: margin - 1
140
- },
141
- { # Vertical , Lower-left
142
- x1: x + trim + crop_margin_left, y1: height,
143
- x2: x + trim + crop_margin_left, y2: height - margin + 1
144
- },
145
- { # Vertical , Lower-right
146
- x1: x + deck_w - trim - crop_margin_right, y1: height,
147
- x2: x + deck_w - trim - crop_margin_right, y2: height - margin + 1
148
- },
149
- { # Horizontal, Upper-left
150
- x1: 0 , y1: y + trim + crop_margin_top,
151
- x2: margin - 1, y2: y + trim + crop_margin_top
152
- },
153
- { # Horizontal, Upper-Right
154
- x1: width , y1: y + trim + crop_margin_top,
155
- x2: width - margin + 1, y2: y + trim + crop_margin_top
156
- },
157
- { # Horizontal, Lower-Left
158
- x1: 0 , y1: y + deck_h - trim - crop_margin_bottom,
159
- x2: margin - 1, y2: y + deck_h - trim - crop_margin_bottom
160
- },
161
- { # Horizontal, Lower-Right
162
- x1: width, y1: y + deck_h - trim - crop_margin_bottom,
163
- x2: width - margin + 1, y2: y + deck_h - trim - crop_margin_bottom
164
- },
165
- ]
166
- end
83
+ def validate_rows(arg)
84
+ raise 'columns must be an integer' unless columns.respond_to? :to_i
85
+ count = if range == :all
86
+ @deck.size
87
+ else
88
+ count = range.to_a.length
89
+ end
90
+ return 1 if count <= columns
91
+ return arg if arg.respond_to? :to_i
92
+ (count.to_f / columns.to_f).ceil
93
+ end
94
+
95
+ def full_filename(i=nil)
96
+ if i.nil?
97
+ "#{dir}/#{file}"
98
+ else
99
+ "#{dir}/#{prefix}#{count_format % i}#{suffix}.png"
167
100
  end
101
+ end
168
102
 
103
+ def crop_coords(x, y, deck_w, deck_h)
104
+ case crop_marks
105
+ when false
106
+ []
107
+ when :full
108
+ [
109
+ {
110
+ # Vertical, Left
111
+ x1: x + trim + crop_margin_left, y1: 0,
112
+ x2: x + trim + crop_margin_left, y2: height - margin + 1
113
+ },
114
+ {
115
+ # Vertical, Right
116
+ x1: x + deck_w - trim - crop_margin_right, y1: 0,
117
+ x2: x + deck_w - trim - crop_margin_right, y2: height - margin + 1
118
+ },
119
+ {
120
+ # Horizontal, Top
121
+ x1: 0 , y1: y + trim + crop_margin_top,
122
+ x2: width - margin + 1, y2: y + trim + crop_margin_top
123
+ },
124
+ {
125
+ # Horizontal, Bottom
126
+ x1: 0 , y1: y + deck_h - trim - crop_margin_bottom,
127
+ x2: width - margin + 1, y2: y + deck_h - trim - crop_margin_bottom
128
+ },
129
+ ]
130
+ else # e.g. :margin
131
+ [
132
+ { # Vertical, Upper-left
133
+ x1: x + trim + crop_margin_left, y1: 0,
134
+ x2: x + trim + crop_margin_left, y2: margin - 1
135
+ },
136
+ { # Vertical , Upper-right
137
+ x1: x + deck_w - trim - crop_margin_right, y1: 0,
138
+ x2: x + deck_w - trim - crop_margin_right, y2: margin - 1
139
+ },
140
+ { # Vertical , Lower-left
141
+ x1: x + trim + crop_margin_left, y1: height,
142
+ x2: x + trim + crop_margin_left, y2: height - margin + 1
143
+ },
144
+ { # Vertical , Lower-right
145
+ x1: x + deck_w - trim - crop_margin_right, y1: height,
146
+ x2: x + deck_w - trim - crop_margin_right, y2: height - margin + 1
147
+ },
148
+ { # Horizontal, Upper-left
149
+ x1: 0 , y1: y + trim + crop_margin_top,
150
+ x2: margin - 1, y2: y + trim + crop_margin_top
151
+ },
152
+ { # Horizontal, Upper-Right
153
+ x1: width , y1: y + trim + crop_margin_top,
154
+ x2: width - margin + 1, y2: y + trim + crop_margin_top
155
+ },
156
+ { # Horizontal, Lower-Left
157
+ x1: 0 , y1: y + deck_h - trim - crop_margin_bottom,
158
+ x2: margin - 1, y2: y + deck_h - trim - crop_margin_bottom
159
+ },
160
+ { # Horizontal, Lower-Right
161
+ x1: width, y1: y + deck_h - trim - crop_margin_bottom,
162
+ x2: width - margin + 1, y2: y + deck_h - trim - crop_margin_bottom
163
+ },
164
+ ]
165
+ end
169
166
  end
170
167
 
171
168
  end
169
+
172
170
  end