diff --git a/CHANGELOG.md b/CHANGELOG.md
index c311774..792814e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,9 @@ Squib follows [semantic versioning](http://semver.org).
## v0.6.0 / Unreleased
Features:
-* Upgraded roo (Excel parsing) to 2.0.0. Nothing major for Squib users, just keeping up with the times.
+* Added `data` field to `svg` to allow for manipulating SVG XML data directly. Works nicely with my new `game_icons` [gem](https://github.com/andymeneely/game_icons) (#65)
* Added `stroke_width` and `stroke_color` to the `text` method to outlines text. (#51)
+* Upgraded roo (Excel parsing) to 2.0.0. Nothing major for Squib users, just keeping up with the times.
Bugs:
* Fixed global text hinting (#63)
diff --git a/lib/squib/api/image.rb b/lib/squib/api/image.rb
index a2caff6..41a886d 100644
--- a/lib/squib/api/image.rb
+++ b/lib/squib/api/image.rb
@@ -34,7 +34,7 @@ module Squib
end
end
- # Renders an entire svg file at the given location. Uses the SVG-specified units and DPI to determine the pixel width and height.
+ # Renders an entire svg file at the given location. Uses the SVG-specified units and DPI to determine the pixel width and height. If neither data nor file are specified for a given card, this method does nothing.
#
# See {file:samples/load-images.rb samples/load-images.rb} and {file:samples/tgc-overlay.rb samples/tgc-overlay.rb} as examples.
# @example
@@ -42,6 +42,7 @@ module Squib
#
# @option opts range [Enumerable, :all] (:all) the range of cards over which this will be rendered. See {file:README.md#Specifying_Ranges Specifying Ranges}
# @option opts file [String] ('') file(s) to read in. If it's a single file, then it's use for every card in range. If the parameter is an Array of files, then each file is looked up for each card. If any of them are nil or '', nothing is done. See {file:README.md#Specifying_Files Specifying Files}. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
+ # @option opts data [String] (nil) render from an SVG XML string. Overrides file if both are specified (a warning is shown) . If it's a single file, then it's use for every card in range. If the parameter is an Array of files, then each file is looked up for each card. If any of them are nil or '', nothing is done. See {file:README.md#Specifying_Files Specifying Files}. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}.
# @option opts id [String] (nil) if set, then only render the SVG element with the given id. Prefix '#' is optional. Note: the x-y coordinates are still relative to the SVG document's page. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts force_id [Boolean] (false) if set, then this svg will not be rendered at all if the id is empty or nil. If not set, the entire SVG is rendered. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts x [Integer] (0) the x-coordinate to place. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}. Supports Unit Conversion, see {file:README.md#Units Units}.
@@ -56,12 +57,13 @@ module Squib
# @return [nil] Returns nil
# @api public
def svg(opts = {})
- p = needs(opts,[:range, :files, :svgid, :force_svgid, :x, :y, :width, :height, :layout, :alpha, :blend, :angle, :mask])
+ p = needs(opts,[:range, :files, :svgdata, :svgid, :force_svgid, :x, :y, :width, :height,
+ :layout, :alpha, :blend, :angle, :mask])
Dir.chdir(img_dir) do
@progress_bar.start('Loading SVG(s)', p[:range].size) do |bar|
p[:range].each do |i|
unless p[:force_id][i] && p[:id][i].to_s.empty?
- @cards[i].svg(p[:file][i], p[:id][i], p[:x][i], p[:y][i],
+ @cards[i].svg(p[:file][i], p[:data][i], p[:id][i], p[:x][i], p[:y][i],
p[:width][i], p[:height][i], p[:alpha][i], p[:blend][i], p[:angle][i],p[:mask][i])
end
bar.increment
diff --git a/lib/squib/api/text_embed.rb b/lib/squib/api/text_embed.rb
index 033d6b9..15c1ed3 100644
--- a/lib/squib/api/text_embed.rb
+++ b/lib/squib/api/text_embed.rb
@@ -30,7 +30,7 @@ module Squib
# TODO: add input validation here. We need the key for example.
rule = {type: :svg}.merge(opts)
rule[:draw] = Proc.new do |card, x,y|
- card.svg(rule[:file], rule[:id], x, y, rule[:width], rule[:height],
+ card.svg(rule[:file], rule[:data], rule[:id], x, y, rule[:width], rule[:height],
rule[:alpha], rule[:blend], rule[:angle], rule[:mask])
end
@rules[opts[:key]] = rule
diff --git a/lib/squib/constants.rb b/lib/squib/constants.rb
index 2b4a675..87c8a6c 100644
--- a/lib/squib/constants.rb
+++ b/lib/squib/constants.rb
@@ -14,6 +14,7 @@ module Squib
:cx2 => 0,
:cy1 => 0,
:cy2 => 0,
+ :data => nil,
:default_font => 'Arial 36',
:dir => '_output',
:dx => 0, # delta
@@ -107,6 +108,7 @@ module Squib
:str => :str,
:stroke_color => :stroke_color,
:stroke_width => :stroke_width,
+ :svgdata => :data,
:svgid => :id,
:valign => :valign,
:width => :width,
diff --git a/lib/squib/graphics/image.rb b/lib/squib/graphics/image.rb
index 6b7631b..b3f7295 100644
--- a/lib/squib/graphics/image.rb
+++ b/lib/squib/graphics/image.rb
@@ -41,10 +41,12 @@ module Squib
# :nodoc:
# @api private
- def svg(file, id, x, y, width, height, alpha, blend, angle, mask)
+ def svg(file, data, id, x, y, width, height, alpha, blend, angle, mask)
Squib.logger.debug {"Rendering: #{file}, id: #{id} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
- return if file.nil? or file.eql? ''
- svg = RSVG::Handle.new_from_file(file)
+ Squib.logger.warn 'Both an SVG file and SVG data were specified' unless file.to_s.empty? or data.to_s.empty?
+ return if (file.nil? or file.eql? '') and data.nil? # nothing specified
+ data = File.read(file) if data.to_s.empty?
+ svg = RSVG::Handle.new_from_data(data)
width = svg.width if width == :native
height = svg.height if height == :native
scale_width = width.to_f / svg.width.to_f
diff --git a/samples/embed_text.rb b/samples/embed_text.rb
index 81e93ba..6fddf37 100644
--- a/samples/embed_text.rb
+++ b/samples/embed_text.rb
@@ -61,7 +61,7 @@ Squib::Deck.new do
text(str: embed_text, font: 'Sans 21',
x: 400, y: 320, width: 180, height: 300,
align: :center, ellipsize: false, justify: false, hint: :magenta) do |embed|
- embed.svg key: ':tool:', width: 28, height: 28, file: 'spanner.svg'
+ embed.svg key: ':tool:', width: 28, height: 28, data: File.read('spanner.svg')
embed.svg key: ':health:', width: 28, height: 28, file: 'glass-heart.svg'
embed.png key: ':purse:', width: 28, height: 28, file: 'shiny-purse.png'
end
diff --git a/samples/load_images.rb b/samples/load_images.rb
index 44ab331..095c3a3 100644
--- a/samples/load_images.rb
+++ b/samples/load_images.rb
@@ -17,6 +17,20 @@ Squib::Deck.new(width: 825, height: 1125, cards: 1) do
# Squib prepends a #-sign if one is not specified
svg file: 'spanner.svg', id: 'backdrop', x: 50, y: 450, width: 125, height: 125
+ # We can also load SVGs as a string of XML
+ svg data: File.read('spanner.svg'), x: 50, y: 600, width: 75, height: 75
+
+ # The svg data field works nicely with modifying the SVG XML on-the-fly.
+ # To run this one, do `gem install game_icons` and uncomment the following
+ #
+ # require 'game_icons'
+ # svg data: GameIcons.get('angler-fish').recolor(fg: '#ccc', bg: '#333').string,
+ # x: 150, y: 600, width: 75, height: 75
+ #
+ # More examples at https://github.com/andymeneely/game_icons
+ # (or `gem install game_icons`) to get & manipulate art from game-icons.net
+ # Nokogiri (already included in Squib) is also great for XML manipulation.
+
# WARNING! If you choose to use the SVG ID, the x-y coordinates are still
# relative to the SVG page. See this example in an SVG editor
svg file: 'offset.svg', id: 'thing', x: 0, y: 0, width: 600, height: 600
diff --git a/spec/api/api_image_spec.rb b/spec/api/api_image_spec.rb
index cefdaed..026b3a8 100644
--- a/spec/api/api_image_spec.rb
+++ b/spec/api/api_image_spec.rb
@@ -23,7 +23,7 @@ describe Squib::Deck, 'images' do
it 'calls Card#svg, Dir, and progress bar' do
card = instance_double(Squib::Card)
progress = double(Squib::Progress)
- expect(card).to receive(:svg).with('foo', '#bar', 0, 1, 20, 30, 0.5, :overlay, 0.75, nil).once
+ expect(card).to receive(:svg).with('foo', nil, '#bar', 0, 1, 20, 30, 0.5, :overlay, 0.75, nil).once
expect(Dir).to receive(:chdir).with('.').and_yield.once
expect(progress).to receive(:start).and_yield(progress).once
expect(progress).to receive(:increment).once
diff --git a/spec/data/samples/load_images.rb.txt b/spec/data/samples/load_images.rb.txt
index 6e64b5e..2ed2a0c 100644
--- a/spec/data/samples/load_images.rb.txt
+++ b/spec/data/samples/load_images.rb.txt
@@ -52,6 +52,12 @@ cairo: scale([0.9765625, 0.9765625])
cairo: render_rsvg_handle([RSVG::Handle, "#backdrop"])
cairo: restore([])
cairo: save([])
+cairo: translate([50, 600])
+cairo: rotate([0])
+cairo: scale([0.5859375, 0.5859375])
+cairo: render_rsvg_handle([RSVG::Handle, nil])
+cairo: restore([])
+cairo: save([])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: scale([0.8021390374331551, 0.8032128514056225])
diff --git a/spec/graphics/graphics_images_spec.rb b/spec/graphics/graphics_images_spec.rb
index 6b590d8..42ef5d8 100644
--- a/spec/graphics/graphics_images_spec.rb
+++ b/spec/graphics/graphics_images_spec.rb
@@ -12,7 +12,7 @@ describe Squib::Card do
allow(Cairo::Context).to receive(:new).and_return(context)
allow(Cairo::ImageSurface).to receive(:from_png).and_return(png)
allow(Cairo::ImageSurface).to receive(:new).and_return(png)
- allow(RSVG::Handle).to receive(:new_from_file).and_return(svg)
+ allow(RSVG::Handle).to receive(:new_from_data).and_return(svg)
allow(deck).to receive(:dir).and_return('_output')
allow(deck).to receive(:count_format).and_return('%02d')
allow(deck).to receive(:prefix).and_return('card_')
@@ -58,8 +58,8 @@ describe Squib::Card do
expect(context).to receive(:restore).once
card = Squib::Card.new(deck, 100, 150)
- # svg(file, id, x, y, width, height, alpha, blend, angle)
- card.svg('foo.png', 'id', 37, 38, :native, :native, 0.9, :none, 0.0, nil)
+ # svg(file, data, id, x, y, width, height, alpha, blend, angle)
+ card.svg(nil, '', 'id', 37, 38, :native, :native, 0.9, :none, 0.0, nil)
end
it 'sets blend when needed' do
@@ -68,7 +68,7 @@ describe Squib::Card do
expect(context).to receive(:operator=).with(:overlay).once
card = Squib::Card.new(deck, 100, 150)
- card.svg('foo.png', nil, 37, 38, :native, :native, 0.9, :overlay, 0.0, nil)
+ card.svg(nil, '', nil, 37, 38, :native, :native, 0.9, :overlay, 0.0, nil)
end
it 'sets width & height when needed' do
@@ -78,7 +78,7 @@ describe Squib::Card do
expect(context).to receive(:scale).with(2.0, 3.0).once
card = Squib::Card.new(deck, 100, 150)
- card.svg('foo.png', nil, 37, 38, 200, 300, 0.9, :none, 0.0, nil)
+ card.svg(nil, '', nil, 37, 38, 200, 300, 0.9, :none, 0.0, nil)
end
end
diff --git a/squib.gemspec b/squib.gemspec
index df4ed88..fdeaf65 100644
--- a/squib.gemspec
+++ b/squib.gemspec
@@ -43,5 +43,6 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'coveralls'
spec.add_development_dependency 'byebug'
spec.add_development_dependency 'launchy'
+ spec.add_development_dependency 'game_icons'
end
diff --git a/squib.sublime-project b/squib.sublime-project
index 063a2c8..32f18b3 100644
--- a/squib.sublime-project
+++ b/squib.sublime-project
@@ -40,6 +40,10 @@
"name": "rake run[custom_config]",
"shell_cmd": "rake run[custom_config]",
},
+ {
+ "name": "rake run[load_images]",
+ "shell_cmd": "rake run[load_images]",
+ },
{
"name": "rspec spec/samples/samples_regression_spec.rb",
"shell_cmd": "rspec spec/samples/samples_regression_spec.rb",