squib 0.5.1 → 0.6.0

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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +62 -14
  5. data/Gemfile +1 -1
  6. data/README.md +16 -10
  7. data/RELEASE TODO.md +2 -1
  8. data/Rakefile +11 -0
  9. data/lib/squib/api/data.rb +3 -3
  10. data/lib/squib/api/image.rb +7 -5
  11. data/lib/squib/api/save.rb +31 -2
  12. data/lib/squib/api/settings.rb +1 -1
  13. data/lib/squib/api/shapes.rb +86 -0
  14. data/lib/squib/api/text.rb +6 -2
  15. data/lib/squib/api/text_embed.rb +7 -5
  16. data/lib/squib/args/typographer.rb +22 -16
  17. data/lib/squib/card.rb +5 -5
  18. data/lib/squib/conf.rb +111 -0
  19. data/lib/squib/constants.rb +11 -31
  20. data/lib/squib/deck.rb +15 -48
  21. data/lib/squib/graphics/cairo_context_wrapper.rb +3 -1
  22. data/lib/squib/graphics/gradient_regex.rb +1 -0
  23. data/lib/squib/graphics/hand.rb +43 -0
  24. data/lib/squib/graphics/image.rb +5 -3
  25. data/lib/squib/graphics/save_doc.rb +1 -1
  26. data/lib/squib/graphics/shapes.rb +74 -0
  27. data/lib/squib/graphics/showcase.rb +5 -2
  28. data/lib/squib/graphics/text.rb +18 -7
  29. data/lib/squib/input_helpers.rb +2 -2
  30. data/lib/squib/version.rb +1 -1
  31. data/samples/csv_import.rb +3 -5
  32. data/samples/custom-config.yml +0 -1
  33. data/samples/custom_config.rb +1 -1
  34. data/samples/draw_shapes.rb +11 -0
  35. data/samples/embed_text.rb +1 -1
  36. data/samples/hand.rb +24 -0
  37. data/samples/load_images.rb +14 -0
  38. data/samples/sample.csv +3 -3
  39. data/samples/text_options.rb +4 -0
  40. data/spec/api/api_data_spec.rb +19 -0
  41. data/spec/api/api_image_spec.rb +1 -1
  42. data/spec/api/api_settings_spec.rb +18 -0
  43. data/spec/api/api_text_spec.rb +3 -3
  44. data/spec/conf_spec.rb +29 -0
  45. data/spec/data/conf/basic.yml +0 -0
  46. data/spec/data/conf/empty.yml +1 -0
  47. data/spec/data/samples/csv_import.rb.txt +4 -38
  48. data/spec/data/samples/custom_config.rb.txt +4 -0
  49. data/spec/data/samples/draw_shapes.rb.txt +57 -0
  50. data/spec/data/samples/hand.rb.txt +514 -0
  51. data/spec/data/samples/load_images.rb.txt +6 -0
  52. data/spec/data/samples/text_options.rb.txt +81 -0
  53. data/spec/data/xlsx/basic.xlsx +0 -0
  54. data/spec/data/xlsx/formulas.xlsx +0 -0
  55. data/spec/graphics/graphics_images_spec.rb +49 -48
  56. data/spec/graphics/graphics_shapes_spec.rb +43 -41
  57. data/spec/graphics/graphics_text_spec.rb +25 -11
  58. data/spec/samples/_diffs/gitkeep.txt +0 -0
  59. data/spec/samples/expected/autoscale_00.png +0 -0
  60. data/spec/samples/expected/autoscale_01.png +0 -0
  61. data/spec/samples/expected/autoscale_02.png +0 -0
  62. data/spec/samples/expected/backend_00.png +0 -0
  63. data/spec/samples/expected/backend_00.svg +78 -0
  64. data/spec/samples/expected/backend_01.png +0 -0
  65. data/spec/samples/expected/backend_01.svg +78 -0
  66. data/spec/samples/expected/basic_00.png +0 -0
  67. data/spec/samples/expected/basic_01.png +0 -0
  68. data/spec/samples/expected/basic_02.png +0 -0
  69. data/spec/samples/expected/cairo_access_00.png +0 -0
  70. data/spec/samples/expected/cairo_access_01.png +0 -0
  71. data/spec/samples/expected/card_00.png +0 -0
  72. data/spec/samples/expected/card_01.png +0 -0
  73. data/spec/samples/expected/colors_00.png +0 -0
  74. data/spec/samples/expected/config_disable_text_00.png +0 -0
  75. data/spec/samples/expected/config_text_00.png +0 -0
  76. data/spec/samples/expected/custom-config_00.png +0 -0
  77. data/spec/samples/expected/embed_00.png +0 -0
  78. data/spec/samples/expected/embed_multi_00.png +0 -0
  79. data/spec/samples/expected/embed_multi_01.png +0 -0
  80. data/spec/samples/expected/embed_multi_02.png +0 -0
  81. data/spec/samples/expected/embed_multisheet_00.png +0 -0
  82. data/spec/samples/expected/gitkeep.txt +0 -0
  83. data/spec/samples/expected/gradient_00.png +0 -0
  84. data/spec/samples/expected/hand.png +0 -0
  85. data/spec/samples/expected/hand_pretty.png +0 -0
  86. data/spec/samples/expected/landscape_00.png +0 -0
  87. data/spec/samples/expected/layout2_00.png +0 -0
  88. data/spec/samples/expected/layout_00.png +0 -0
  89. data/spec/samples/expected/layout_builtin_hand_00.png +0 -0
  90. data/spec/samples/expected/layout_builtin_playing_card_00.png +0 -0
  91. data/spec/samples/expected/load_images_00.png +0 -0
  92. data/spec/samples/expected/portrait_00.png +0 -0
  93. data/spec/samples/expected/ranges_00.png +0 -0
  94. data/spec/samples/expected/ranges_01.png +0 -0
  95. data/spec/samples/expected/ranges_02.png +0 -0
  96. data/spec/samples/expected/sample_csv_00.png +0 -0
  97. data/spec/samples/expected/sample_csv_01.png +0 -0
  98. data/spec/samples/expected/sample_excel_00.png +0 -0
  99. data/spec/samples/expected/sample_excel_01.png +0 -0
  100. data/spec/samples/expected/sample_excel_02.png +0 -0
  101. data/spec/samples/expected/save_sheet_00.png +0 -0
  102. data/spec/samples/expected/save_sheet_01.png +0 -0
  103. data/spec/samples/expected/save_sheet_range_00.png +0 -0
  104. data/spec/samples/expected/save_sheet_range_01.png +0 -0
  105. data/spec/samples/expected/save_single_sheet_00.png +0 -0
  106. data/spec/samples/expected/saves_notrim_01.png +0 -0
  107. data/spec/samples/expected/shape_00.png +0 -0
  108. data/spec/samples/expected/showcase.png +0 -0
  109. data/spec/samples/expected/showcase2.png +0 -0
  110. data/spec/samples/expected/showcase_individual_00.png +0 -0
  111. data/spec/samples/expected/showcase_individual_01.png +0 -0
  112. data/spec/samples/expected/showcase_individual_02.png +0 -0
  113. data/spec/samples/expected/showcase_individual_03.png +0 -0
  114. data/spec/samples/expected/text_00.png +0 -0
  115. data/spec/samples/expected/text_01.png +0 -0
  116. data/spec/samples/expected/text_02.png +0 -0
  117. data/spec/samples/expected/tgc_sample_00.png +0 -0
  118. data/spec/samples/expected/units_00.png +0 -0
  119. data/spec/samples/samples_regression_spec.rb +7 -5
  120. data/spec/samples/sanity.html.erb +28 -0
  121. data/spec/samples/sanity.rb +70 -0
  122. data/spec/spec_helper.rb +15 -1
  123. data/squib.gemspec +3 -1
  124. data/squib.sublime-project +27 -40
  125. metadata +177 -4
@@ -4,6 +4,7 @@ require 'squib/graphics/gradient_regex'
4
4
  module Squib
5
5
  module Graphics
6
6
  # Wrapper class for the Cairo context. Private.
7
+ # @api private
7
8
  class CairoContextWrapper
8
9
  extend Forwardable
9
10
 
@@ -22,7 +23,8 @@ module Squib
22
23
  :show_pango_layout, :rounded_rectangle, :set_line_width, :stroke, :fill,
23
24
  :set_source, :scale, :render_rsvg_handle, :circle, :triangle, :line_to,
24
25
  :operator=, :show_page, :clip, :transform, :mask, :create_pango_layout,
25
- :antialias=, :curve_to, :matrix, :matrix=, :identity_matrix
26
+ :antialias=, :curve_to, :matrix, :matrix=, :identity_matrix, :pango_layout_path,
27
+ :stroke_preserve, :target, :new_path, :fill_preserve, :close_path
26
28
 
27
29
  # :nodoc:
28
30
  # @api private
@@ -1,4 +1,5 @@
1
1
  module Squib
2
+ # @api private
2
3
  module Graphics
3
4
  STOPS = / # used to capture the stops
4
5
  \s* # leading whitespace is ok
@@ -0,0 +1,43 @@
1
+ require 'squib/graphics/cairo_context_wrapper'
2
+
3
+ module Squib
4
+ class Deck
5
+
6
+ # Draw cards in a fan.
7
+ # @api private
8
+ def render_hand(range, radius, angle_range, trim, trim_radius, margin,
9
+ fill_color, dir, file)
10
+ cards = range.collect { |i| @cards[i] }
11
+ center_x = width / 2.0
12
+ center_y = radius + height
13
+ out_size = 3.0 * center_y
14
+ angle_delta = (angle_range.last - angle_range.first) / cards.size
15
+ cxt = Cairo::Context.new(Cairo::RecordingSurface.new(0, 0, out_size, out_size))
16
+ cxt.translate(out_size / 2.0, out_size / 2.0)
17
+ cxt.rotate(angle_range.first)
18
+ cxt.translate(-width, -width)
19
+ cards.each_with_index do |card, i|
20
+ cxt.translate(center_x, center_y)
21
+ cxt.rotate(angle_delta)
22
+ cxt.translate(-center_x, -center_y)
23
+ card.use_cairo do |card_cxt|
24
+ cxt.rounded_rectangle(trim, trim,
25
+ width - (2 * trim), height - (2 * trim),
26
+ trim_radius, trim_radius)
27
+ cxt.clip
28
+ cxt.set_source(card_cxt.target)
29
+ cxt.paint
30
+ cxt.reset_clip
31
+ end
32
+ end
33
+ x, y, w, h = cxt.target.ink_extents # I love Ruby assignment ;)
34
+ png_cxt = Squib::Graphics::CairoContextWrapper.new(Cairo::Context.new(Cairo::ImageSurface.new(w + 2*margin, h + 2*margin)))
35
+ png_cxt.set_source_squibcolor(fill_color)
36
+ png_cxt.paint
37
+ png_cxt.translate(-x + margin, -y + margin)
38
+ png_cxt.set_source(cxt.target)
39
+ png_cxt.paint
40
+ png_cxt.target.write_to_png("#{dir}/#{file}")
41
+ end
42
+ end
43
+ end
@@ -41,10 +41,12 @@ module Squib
41
41
 
42
42
  # :nodoc:
43
43
  # @api private
44
- def svg(file, id, x, y, width, height, alpha, blend, angle, mask)
44
+ def svg(file, data, id, x, y, width, height, alpha, blend, angle, mask)
45
45
  Squib.logger.debug {"Rendering: #{file}, id: #{id} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
46
- return if file.nil? or file.eql? ''
47
- svg = RSVG::Handle.new_from_file(file)
46
+ Squib.logger.warn 'Both an SVG file and SVG data were specified' unless file.to_s.empty? or data.to_s.empty?
47
+ return if (file.nil? or file.eql? '') and data.nil? # nothing specified
48
+ data = File.read(file) if data.to_s.empty?
49
+ svg = RSVG::Handle.new_from_data(data)
48
50
  width = svg.width if width == :native
49
51
  height = svg.height if height == :native
50
52
  scale_width = width.to_f / svg.width.to_f
@@ -33,7 +33,7 @@ module Squib
33
33
  cc.translate(x,y)
34
34
  cc.rectangle(p[:trim], p[:trim], card_width, card_height)
35
35
  cc.clip
36
- case card.backend
36
+ case card.backend.downcase.to_sym
37
37
  when :memory
38
38
  cc.set_source(card.cairo_surface, 0, 0)
39
39
  cc.paint
@@ -1,4 +1,5 @@
1
1
  module Squib
2
+ # @api private
2
3
  class Card
3
4
 
4
5
  # :nodoc:
@@ -32,6 +33,34 @@ module Squib
32
33
  end
33
34
  end
34
35
 
36
+ # Ellipse drawing taken from looking at the control points in Inkscape
37
+ # Think of it like a rectangle. Curves go from mid-points of the sides
38
+ # of the rectangle. Control points are at 1/4 and 3/4 of the side.
39
+ # :nodoc:
40
+ # @api private
41
+ def ellipse(x, y, w, h, fill_color, stroke_color, stroke_width)
42
+ use_cairo do |cc|
43
+ cc.move_to(x, y + 0.5*h) # start west
44
+ cc.curve_to(x, y + 0.25*h, # west to north
45
+ x + 0.25*w, y,
46
+ x + 0.5*w, y)
47
+ cc.curve_to(x + 0.75*w, y, # north to east
48
+ x + w, y + 0.25*h,
49
+ x + w, y + 0.5*h)
50
+ cc.curve_to(x + w, y + 0.75*h, # east to south
51
+ x + 0.75*w, y + h,
52
+ x + 0.5*w, y + h)
53
+ cc.curve_to(x + 0.25*w, y + h, # south to west
54
+ x, y + 0.75*h,
55
+ x, y + 0.5*h)
56
+ cc.set_source_squibcolor(stroke_color)
57
+ cc.set_line_width(stroke_width)
58
+ cc.stroke_preserve
59
+ cc.set_source_squibcolor(fill_color)
60
+ cc.fill
61
+ end
62
+ end
63
+
35
64
  # :nodoc:
36
65
  # @api private
37
66
  def triangle(x1, y1, x2, y2, x3, y3, fill_color, stroke_color, stroke_width)
@@ -74,5 +103,50 @@ module Squib
74
103
  end
75
104
  end
76
105
 
106
+ # :nodoc:
107
+ # @api private
108
+ def star(x, y, n, angle, inner_radius, outer_radius, fill_color, stroke_color, stroke_width)
109
+ use_cairo do |cc|
110
+ cc.translate(x, y)
111
+ cc.rotate(angle)
112
+ cc.translate(-x, -y)
113
+ cc.move_to(x + outer_radius, y) #i = 0, so cos(0)=1 and sin(0)=0
114
+ theta = Math::PI / n.to_f # i.e. (2*pi) / (2*n)
115
+ 0.upto(2 * n) do |i|
116
+ radius = i.even? ? outer_radius : inner_radius
117
+ cc.line_to(x + radius * Math::cos(i * theta),
118
+ y + radius * Math::sin(i * theta))
119
+ end
120
+ cc.close_path
121
+ cc.set_source_squibcolor(stroke_color)
122
+ cc.set_line_width(stroke_width)
123
+ cc.fill_preserve
124
+ cc.set_source_squibcolor(fill_color)
125
+ cc.stroke
126
+ end
127
+ end
128
+
129
+ # :nodoc:
130
+ # @api private
131
+ def polygon(x, y, n, angle, radius, fill_color, stroke_color, stroke_width)
132
+ use_cairo do |cc|
133
+ cc.translate(x, y)
134
+ cc.rotate(angle)
135
+ cc.translate(-x, -y)
136
+ cc.move_to(x + radius, y) # i = 0, so cos(0)=1 and sin(0)=0
137
+ theta = (2 * Math::PI) / n.to_f
138
+ 0.upto(n) do |i|
139
+ cc.line_to(x + radius * Math::cos(i * theta),
140
+ y + radius * Math::sin(i * theta))
141
+ end
142
+ cc.close_path
143
+ cc.set_source_squibcolor(stroke_color)
144
+ cc.set_line_width(stroke_width)
145
+ cc.fill_preserve
146
+ cc.set_source_squibcolor(fill_color)
147
+ cc.stroke
148
+ end
149
+ end
150
+
77
151
  end
78
152
  end
@@ -1,3 +1,5 @@
1
+ require 'squib/graphics/cairo_context_wrapper'
2
+
1
3
  module Squib
2
4
  class Deck
3
5
 
@@ -16,8 +18,9 @@ module Squib
16
18
  out_width = range.size * ((@width - 2*trim) * scale * offset) + 2*margin
17
19
  out_height = reflect_offset + (1.0 + reflect_percent) * (@height - 2*trim) + 2*margin
18
20
  out_cc = Cairo::Context.new(Cairo::ImageSurface.new(out_width, out_height))
19
- out_cc.set_source_color(fill_color)
20
- out_cc.paint
21
+ wrapper = Squib::Graphics::CairoContextWrapper.new(out_cc)
22
+ wrapper.set_source_squibcolor(fill_color)
23
+ wrapper.paint
21
24
 
22
25
  cards = range.collect { |i| @cards[i] }
23
26
  cards.each_with_index do |card, i|
@@ -6,8 +6,8 @@ module Squib
6
6
 
7
7
  # :nodoc:
8
8
  # @api private
9
- def draw_text_hint(cc,x,y,layout, color,angle)
10
- color = @deck.text_hint if color.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
9
+ def draw_text_hint(cc, x, y, layout, color)
10
+ color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
11
11
  return if color.to_s.eql? 'off' or color.nil?
12
12
  # when w,h < 0, it was never set. extents[1] are ink extents
13
13
  w = layout.width / Pango::SCALE
@@ -78,7 +78,7 @@ module Squib
78
78
 
79
79
  def set_font_rendering_opts!(layout)
80
80
  font_options = Cairo::FontOptions.new
81
- font_options.antialias = ANTIALIAS_OPTS[(@deck.antialias.downcase)] || 'gray'
81
+ font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase]
82
82
  font_options.hint_metrics = 'on' # TODO make this configurable
83
83
  font_options.hint_style = 'full' # TODO make this configurable
84
84
  layout.context.font_options = font_options
@@ -127,7 +127,7 @@ module Squib
127
127
  while (key = next_embed(embed.rules.keys, clean_str)) != nil
128
128
  rule = embed.rules[key]
129
129
  spacing = rule[:width] * Pango::SCALE
130
- index = clean_str.index(key)
130
+ index = clean_str.index(key)
131
131
  index = clean_str[0..index].bytesize #convert to byte index (bug #57)
132
132
  str = str.sub(key, "<span size=\"#{ZERO_WIDTH_CHAR_SIZE}\">a<span letter_spacing=\"#{spacing.to_i}\">a</span>a</span>")
133
133
  layout.markup = str
@@ -143,12 +143,22 @@ module Squib
143
143
  return draw_calls
144
144
  end
145
145
 
146
+ def stroke_outline!(cc, layout, stroke_width, stroke_color)
147
+ if stroke_width > 0
148
+ cc.set_source_squibcolor(stroke_color)
149
+ cc.set_line_width(stroke_width)
150
+ cc.pango_layout_path(layout)
151
+ cc.stroke
152
+ end
153
+ end
154
+
146
155
  # :nodoc:
147
156
  # @api private
148
157
  def text(embed,str, font, font_size, color,
149
158
  x, y, width, height,
150
159
  markup, justify, wrap, ellipsize,
151
- spacing, align, valign, hint, angle)
160
+ spacing, align, valign, hint, angle,
161
+ stroke_color, stroke_width)
152
162
  Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, angle: #{angle} etc."}
153
163
  extents = nil
154
164
  str = str.to_s
@@ -164,7 +174,7 @@ module Squib
164
174
  layout.font_description = font_desc
165
175
  layout.text = str
166
176
  if markup
167
- str = Args::Typographer.new(@deck.quote_chars).process(layout.text)
177
+ str = @deck.typographer.process(layout.text)
168
178
  layout.markup = str
169
179
  end
170
180
 
@@ -185,6 +195,7 @@ module Squib
185
195
 
186
196
  cc.update_pango_layout(layout)
187
197
  cc.show_pango_layout(layout)
198
+ stroke_outline!(cc, layout, stroke_width, stroke_color)
188
199
  begin
189
200
  embed_draws.each { |ed| ed[:draw].call(self, ed[:x], ed[:y] + vertical_start) }
190
201
  rescue Exception => e
@@ -194,7 +205,7 @@ module Squib
194
205
  puts "=================="
195
206
  raise e
196
207
  end
197
- draw_text_hint(cc, x, y, layout, hint, angle)
208
+ draw_text_hint(cc, x, y, layout, hint)
198
209
  extents = { width: layout.extents[1].width / Pango::SCALE,
199
210
  height: layout.extents[1].height / Pango::SCALE }
200
211
  end
@@ -130,8 +130,8 @@ module Squib
130
130
  def colorify(opts, nillable=false, key=:color)
131
131
  opts[key].each_with_index do |color, i|
132
132
  unless nillable && color.nil?
133
- if @custom_colors.key? color.to_s
134
- color = @custom_colors[color.to_s]
133
+ if custom_colors.key? color.to_s
134
+ color = custom_colors[color.to_s]
135
135
  end
136
136
  opts[key][i] = color
137
137
  end
@@ -6,5 +6,5 @@ module Squib
6
6
  # Most of the time this is in the alpha of the next release.
7
7
  # e.g. v0.0.5a is on its way to becoming v0.0.5
8
8
  #
9
- VERSION = '0.5.1'
9
+ VERSION = '0.6.0'
10
10
  end
@@ -5,15 +5,13 @@ Squib::Deck.new(cards: 2) do
5
5
 
6
6
  # Outputs a hash of arrays with the header names as keys
7
7
  data = csv file: 'sample.csv'
8
-
9
- text str: data['Name'], x: 250, y: 55, font: 'Arial 54'
8
+ text str: data['Type'], x: 250, y: 55, font: 'Arial 54'
10
9
  text str: data['Level'], x: 65, y: 65, font: 'Arial 72'
11
- text str: data['Description'], x: 65, y: 600, font: 'Arial 36'
10
+
11
+ save format: :png, prefix: 'sample_csv_'
12
12
 
13
13
  # You can also specify the sheet, starting at 0
14
14
  data = xlsx file: 'sample.xlsx', sheet: 2
15
-
16
- save format: :png, prefix: 'sample_csv_'
17
15
  end
18
16
 
19
17
  # CSV is also a Squib-module-level function, so this also works:
@@ -1,4 +1,3 @@
1
- dpi: 300
2
1
  progress_bars: true
3
2
  text_hint: '#FF0000'
4
3
  custom_colors:
@@ -4,7 +4,7 @@ Squib::Deck.new(config: 'custom-config.yml') do
4
4
  # Custom color defined in our config
5
5
  background color: :foo
6
6
 
7
- # Hints are turned on in the config file
7
+ # Hints can be turned on in the config file
8
8
  text str: 'The Title', x: 0, y: 78, width: 825,
9
9
  font: 'Arial 72', align: :center
10
10
 
@@ -1,6 +1,7 @@
1
1
  require 'squib'
2
2
 
3
3
  Squib::Deck.new do
4
+ background color: :white
4
5
  rect x: 300, y: 300, width: 400, height: 400,
5
6
  fill_color: :blue, stroke_color: :red, stroke_width: 50.0
6
7
 
@@ -20,5 +21,15 @@ Squib::Deck.new do
20
21
  stroke_width: 12.0, stroke_color: :cyan,
21
22
  fill_color: :burgundy
22
23
 
24
+ ellipse x: 50, y: 925, width: 200, height: 100,
25
+ stroke_width: 5.0, stroke_color: :cyan,
26
+ fill_color: :burgundy
27
+
28
+ star x: 300, y: 1000, n: 5, inner_radius: 10, outer_radius: 25,
29
+ fill_color: :burgundy, stroke_color: :cyan, stroke_width: 3
30
+
31
+ polygon x: 500, y: 1000, n: 5, radius: 25, angle: Math::PI / 2,
32
+ fill_color: :burgundy, stroke_color: :cyan, stroke_width: 2
33
+
23
34
  save_png prefix: 'shape_'
24
35
  end
@@ -61,7 +61,7 @@ Squib::Deck.new do
61
61
  text(str: embed_text, font: 'Sans 21',
62
62
  x: 400, y: 320, width: 180, height: 300,
63
63
  align: :center, ellipsize: false, justify: false, hint: :magenta) do |embed|
64
- embed.svg key: ':tool:', width: 28, height: 28, file: 'spanner.svg'
64
+ embed.svg key: ':tool:', width: 28, height: 28, data: File.read('spanner.svg')
65
65
  embed.svg key: ':health:', width: 28, height: 28, file: 'glass-heart.svg'
66
66
  embed.png key: ':purse:', width: 28, height: 28, file: 'shiny-purse.png'
67
67
  end
@@ -0,0 +1,24 @@
1
+ require 'squib'
2
+
3
+ Squib::Deck.new(cards: 8, layout: 'playing-card.yml') do
4
+ background color: :cyan
5
+ rect x: 37, y: 37, width: 750, height: 1050, fill_color: :black, radius: 25
6
+ rect x: 75, y: 75, width: 675, height: 975, fill_color: :white, radius: 20
7
+ text str: ('A'..'Z').to_a, layout: :bonus_ul, font: 'Sans bold 100'
8
+
9
+ # Defaults are sensible
10
+ hand #saves to _output/hand.png
11
+
12
+ # Here's a prettier version:
13
+ # - Each card is trimmed with rounded corners
14
+ # - Zero radius means cards rotate about the bottom of the card
15
+ # - Cards are shown in reverse order
16
+ hand trim: 37.5, trim_radius: 25,
17
+ radius: 0,
18
+ range: 7.downto(0),
19
+ file: 'hand_pretty.png'
20
+
21
+ # Tip: you can have the top card be on the left by reversing the range
22
+ # angle_range: (Math::PI / 4)..(Math::PI / -4)
23
+ end
24
+
@@ -17,6 +17,20 @@ Squib::Deck.new(width: 825, height: 1125, cards: 1) do
17
17
  # Squib prepends a #-sign if one is not specified
18
18
  svg file: 'spanner.svg', id: 'backdrop', x: 50, y: 450, width: 125, height: 125
19
19
 
20
+ # We can also load SVGs as a string of XML
21
+ svg data: File.read('spanner.svg'), x: 50, y: 600, width: 75, height: 75
22
+
23
+ # The svg data field works nicely with modifying the SVG XML on-the-fly.
24
+ # To run this one, do `gem install game_icons` and uncomment the following
25
+ #
26
+ # require 'game_icons'
27
+ # svg data: GameIcons.get('angler-fish').recolor(fg: '#ccc', bg: '#333').string,
28
+ # x: 150, y: 600, width: 75, height: 75
29
+ #
30
+ # More examples at https://github.com/andymeneely/game_icons
31
+ # (or `gem install game_icons`) to get & manipulate art from game-icons.net
32
+ # Nokogiri (already included in Squib) is also great for XML manipulation.
33
+
20
34
  # WARNING! If you choose to use the SVG ID, the x-y coordinates are still
21
35
  # relative to the SVG page. See this example in an SVG editor
22
36
  svg file: 'offset.svg', id: 'thing', x: 0, y: 0, width: 600, height: 600
@@ -1,3 +1,3 @@
1
- Type,"Quantity"
2
- Thief,2
3
- Mastermind,1
1
+ Type,"Level"
2
+ Thief,1
3
+ Mastermind,2
@@ -78,6 +78,10 @@ Squib::Deck.new(width: 825, height: 1125, cards: 3) do
78
78
  embed.svg key: ':health:', width: 28, height: 28, file: 'glass-heart.svg'
79
79
  end
80
80
 
81
+ text str: "Stroke n <span fgcolor=\"\#ff0000\">fill</span>",
82
+ color: :green, stroke_width: 2.0, stroke_color: :blue,
83
+ x: '1.8in', y: '3in', width: '0.85in', font: 'Sans Bold 26', markup: true
84
+
81
85
  text str: "<b>Markup</b> is <i>quite</i> <s>'easy'</s> <span fgcolor=\"\#ff0000\">awesome</span>. Can't beat those \"smart\" 'quotes', now with 10--20% more en-dashes --- and em-dashes --- with explicit ellipses too...",
82
86
  markup: true,
83
87
  x: 50, y: 1000,
@@ -28,4 +28,23 @@ describe Squib::Deck do
28
28
  })
29
29
  end
30
30
  end
31
+
32
+ context '#xlsx' do
33
+ it 'loads basic xlsx data' do
34
+ expect(Squib.xlsx(file: xlsx_file('basic.xlsx'))).to eq({
35
+ 'Name' => %w(Larry Curly Mo),
36
+ 'General Number' => %w(1 2 3), #general types always get loaded as strings with no conversion
37
+ 'Actual Number' => [4.0, 5.0, 6.0], #numbers get auto-converted to integers
38
+ })
39
+ end
40
+
41
+ it 'loads xlsx with formulas' do
42
+ expect(Squib.xlsx(file: xlsx_file('formulas.xlsx'))).to eq({
43
+ 'A' => %w(1 2),
44
+ 'B' => %w(3 4),
45
+ 'Sum' => %w(4 6),
46
+ })
47
+ end
48
+
49
+ end
31
50
  end