Browse Source

Support png scaling, but warns on use.

dev
Andy Meneely 11 years ago
parent
commit
f8f65f3de7
  1. 2
      CHANGELOG.md
  2. 8
      lib/squib/api/image.rb
  3. 8
      lib/squib/graphics/image.rb
  4. 6
      samples/load_images.rb
  5. 2
      spec/api/api_image_spec.rb
  6. 8
      spec/data/samples/load_images.rb.txt
  7. 26
      spec/graphics/graphics_images_spec.rb
  8. 1
      spec/samples/samples_regression_spec.rb
  9. 1
      spec/spec_helper.rb

2
CHANGELOG.md

@ -1,5 +1,7 @@
# Squib CHANGELOG # Squib CHANGELOG
* `png` now supports resizing, but warns you about it since it's non-ideal. Documented in yard, tested.
## v0.0.6 ## v0.0.6
* Added a `csv` command that works just like `xslx`. Uses Ruby's CSV inside, with some extra checking and warnings. * Added a `csv` command that works just like `xslx`. Uses Ruby's CSV inside, with some extra checking and warnings.
* Custom layouts now support loading & merging multiple Yaml files! Updated README, docs, and sample to document it. * Custom layouts now support loading & merging multiple Yaml files! Updated README, docs, and sample to document it.

8
lib/squib/api/image.rb

@ -4,7 +4,6 @@ module Squib
# Renders a png file at the given location. # Renders a png file at the given location.
# #
# See {file:samples/image.rb samples/image.rb} and {file:samples/tgc-overlay.rb samples/tgc-overlay.rb} as examples. # See {file:samples/image.rb samples/image.rb} and {file:samples/tgc-overlay.rb samples/tgc-overlay.rb} as examples.
# Note: scaling not currently supported for PNGs.
# @example # @example
# png file: 'img.png', x: 50, y: 50 # png file: 'img.png', x: 50, y: 50
# #
@ -12,6 +11,8 @@ module Squib
# @option opts file [String] ((empty)) 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 file [String] ((empty)) 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 x [Integer] (0) the x-coordinate to place. Supports Arrays, see {file:README#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion} # @option opts x [Integer] (0) the x-coordinate to place. Supports Arrays, see {file:README#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts y [Integer] (0) the y-coordinate to place. Supports Arrays, see {file:README#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion} # @option opts y [Integer] (0) the y-coordinate to place. Supports Arrays, see {file:README#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts width [Integer] (:native) the pixel width that the image should scale to. Scaling PNGs is not recommended for professional-looking cards. When set to `:native`, uses the DPI and units of the loaded SVG document. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts height [Integer] (:native) the pixel width that the image should scale to. Scaling PNGs is not recommended for professional-looking cards. When set to `:native`, uses the DPI and units of the loaded SVG document. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts layout [String, Symbol] (nil) entry in the layout to use as defaults for this command. See {file:README.md#Custom_Layouts Custom Layouts}. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion} # @option opts layout [String, Symbol] (nil) entry in the layout to use as defaults for this command. See {file:README.md#Custom_Layouts Custom Layouts}. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts alpha [Decimal] (1.0) the alpha-transparency percentage used to blend this image. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion} # @option opts alpha [Decimal] (1.0) the alpha-transparency percentage used to blend this image. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts blend [:none, :multiply, :screen, :overlay, :darken, :lighten, :color_dodge, :color_burn, :hard_light, :soft_light, :difference, :exclusion, :hsl_hue, :hsl_saturation, :hsl_color, :hsl_luminosity] (:none) the composite blend operator used when applying this image. See Blend Modes at http://cairographics.org/operators. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion} # @option opts blend [:none, :multiply, :screen, :overlay, :darken, :lighten, :color_dodge, :color_burn, :hard_light, :soft_light, :difference, :exclusion, :hsl_hue, :hsl_saturation, :hsl_color, :hsl_luminosity] (:none) the composite blend operator used when applying this image. See Blend Modes at http://cairographics.org/operators. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
@ -19,11 +20,12 @@ module Squib
# @return [nil] Returns nil # @return [nil] Returns nil
# @api public # @api public
def png(opts = {}) def png(opts = {})
opts = needs(opts, [:range, :files, :x, :y, :alpha, :layout, :blend, :angle]) opts = needs(opts, [:range, :files, :x, :y, :width, :height, :alpha, :layout, :blend, :angle])
Dir.chdir(@img_dir) do Dir.chdir(@img_dir) do
@progress_bar.start('Loading PNG(s)', opts[:range].size) do |bar| @progress_bar.start('Loading PNG(s)', opts[:range].size) do |bar|
opts[:range].each do |i| opts[:range].each do |i|
@cards[i].png(opts[:file][i], opts[:x][i], opts[:y][i], @cards[i].png(opts[:file][i],
opts[:x][i], opts[:y][i], opts[:width][i], opts[:height][i],
opts[:alpha][i], opts[:blend][i], opts[:angle][i]) opts[:alpha][i], opts[:blend][i], opts[:angle][i])
bar.increment bar.increment
end end

8
lib/squib/graphics/image.rb

@ -14,12 +14,18 @@ module Squib
# :nodoc: # :nodoc:
# @api private # @api private
def png(file, x, y, alpha, blend, angle) def png(file, x, y, width, height, alpha, blend, angle)
Squib.logger.debug {"Rendering: #{file} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}"} Squib.logger.debug {"Rendering: #{file} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}"}
return if file.nil? or file.eql? '' return if file.nil? or file.eql? ''
png = Squib.cache_load_image(file) png = Squib.cache_load_image(file)
use_cairo do |cc| use_cairo do |cc|
cc.translate(x, y) cc.translate(x, y)
if width != :native || height != :native
width == :native && width = png.width.to_f
height == :native && height = png.height.to_f
Squib.logger.warn "PNG scaling results in antialiasing."
cc.scale(width.to_f / png.width.to_f, height.to_f / png.height.to_f)
end
cc.rotate(angle) cc.rotate(angle)
cc.translate(-1 * x, -1 * y) cc.translate(-1 * x, -1 * y)
cc.set_source(png, x, y) cc.set_source(png, x, y)

6
samples/load_images.rb

@ -4,11 +4,13 @@ Squib::Deck.new(width: 825, height: 1125, cards: 1) do
background color: '#0b7c8e' background color: '#0b7c8e'
rect x: 38, y: 38, width: 750, height: 1050, x_radius: 38, y_radius: 38 rect x: 38, y: 38, width: 750, height: 1050, x_radius: 38, y_radius: 38
png file: 'shiny-purse.png', x: 620, y: 75 png file: 'shiny-purse.png', x: 620, y: 75 # no scaling is done by default
svg file: 'spanner.svg', x: 620, y: 218 svg file: 'spanner.svg', x: 620, y: 218
# SVGs can be scaled too # Can be scaled if width and height are set
svg file: 'spanner.svg', x: 50, y: 50, width: 250, height: 250 svg file: 'spanner.svg', x: 50, y: 50, width: 250, height: 250
png file: 'shiny-purse.png', x: 305, y: 50, width: 250, height: 250
#...but PNGs will warn if it's an upscale
# We can also limit our rendering to a single object, if the SVG ID is set # We can also limit our rendering to a single object, if the SVG ID is set
# Squib prepends a #-sign if one is not specified # Squib prepends a #-sign if one is not specified

2
spec/api/api_image_spec.rb

@ -7,7 +7,7 @@ describe Squib::Deck, 'images' do
it 'calls Card#png, Dir, and progress bar' do it 'calls Card#png, Dir, and progress bar' do
card = instance_double(Squib::Card) card = instance_double(Squib::Card)
progress = double(Squib::Progress) progress = double(Squib::Progress)
expect(card).to receive(:png).with('foo', 0, 1, 0.5, :overlay, 0.75).once expect(card).to receive(:png).with('foo', 0, 1, :native, :native, 0.5, :overlay, 0.75).once
expect(Dir).to receive(:chdir).with('.').and_yield.once expect(Dir).to receive(:chdir).with('.').and_yield.once
expect(progress).to receive(:start).and_yield(progress).once expect(progress).to receive(:start).and_yield(progress).once
expect(progress).to receive(:increment).once expect(progress).to receive(:increment).once

8
spec/data/samples/load_images.rb.txt

@ -36,6 +36,14 @@ cairo: translate([-50, -50])
cairo: set_source([MockDouble, 50, 50]) cairo: set_source([MockDouble, 50, 50])
cairo: paint([1.0]) cairo: paint([1.0])
cairo: restore([]) cairo: restore([])
cairo: save([])
cairo: translate([305, 50])
cairo: scale([1.953125, 1.953125])
cairo: rotate([0])
cairo: translate([-305, -50])
cairo: set_source([ImageSurface, 305, 50])
cairo: paint([1.0])
cairo: restore([])
cairo: scale([0.5859375, 0.5859375]) cairo: scale([0.5859375, 0.5859375])
cairo: render_rsvg_handle([RSVG::Handle, "#backdrop"]) cairo: render_rsvg_handle([RSVG::Handle, "#backdrop"])
cairo: save([]) cairo: save([])

26
spec/graphics/graphics_images_spec.rb

@ -3,14 +3,15 @@ require 'squib'
describe Squib::Card do describe Squib::Card do
before(:each) do before(:example) do
@deck = double(Squib::Deck) @deck = double(Squib::Deck)
@context = double(Cairo::Context) @context = double(Cairo::Context)
@svg = double(RSVG::Handle) @svg = double(RSVG::Handle)
allow(Cairo::Context).to receive(:new).and_return(@context) @png = double(Cairo::ImageSurface)
allow(Cairo::ImageSurface).to receive(:from_png).and_return(nil) allow(Cairo::Context).to receive(:new).and_return(@context)
allow(Cairo::ImageSurface).to receive(:new).and_return(nil) allow(Cairo::ImageSurface).to receive(:from_png).and_return(@png)
allow(RSVG::Handle).to receive(:new_from_file).and_return(@svg) allow(Cairo::ImageSurface).to receive(:new).and_return(@png)
allow(RSVG::Handle).to receive(:new_from_file).and_return(@svg)
end end
context '#png' do context '#png' do
@ -19,13 +20,13 @@ describe Squib::Card do
expect(@context).to receive(:translate).with(-37, -38).once expect(@context).to receive(:translate).with(-37, -38).once
expect(@context).to receive(:rotate).with(0.0).once expect(@context).to receive(:rotate).with(0.0).once
expect(@context).to receive(:translate).with(37, 38).once expect(@context).to receive(:translate).with(37, 38).once
expect(@context).to receive(:set_source).with(nil, 37, 38).once expect(@context).to receive(:set_source).with(@png, 37, 38).once
expect(@context).to receive(:paint).with(0.9).once expect(@context).to receive(:paint).with(0.9).once
expect(@context).to receive(:restore).once expect(@context).to receive(:restore).once
card = Squib::Card.new(@deck, 100, 150) card = Squib::Card.new(@deck, 100, 150)
# png(file, x, y, alpha, blend, angle) # png(file, x, y, alpha, blend, angle)
card.png('foo.png', 37, 38, 0.9, :none, 0.0) card.png('foo.png', 37, 38, :native, :native, 0.9, :none, 0.0)
end end
it 'sets blend when needed' do it 'sets blend when needed' do
@ -33,8 +34,9 @@ describe Squib::Card do
expect(@context).to receive(:operator=).with(:overlay).once expect(@context).to receive(:operator=).with(:overlay).once
card = Squib::Card.new(@deck, 100, 150) card = Squib::Card.new(@deck, 100, 150)
card.png('foo.png', 37, 38, 0.9, :overlay, 0.0) card.png('foo.png', 37, 38, :native, :native, 0.9, :overlay, 0.0)
end end
end end
context '#svg' do context '#svg' do
@ -47,7 +49,7 @@ describe Squib::Card do
expect(@context).to receive(:translate).with(37, 38).once expect(@context).to receive(:translate).with(37, 38).once
expect(@context).to receive(:scale).with(1.0, 1.0).once expect(@context).to receive(:scale).with(1.0, 1.0).once
expect(@context).to receive(:render_rsvg_handle).with(@svg, 'id').once expect(@context).to receive(:render_rsvg_handle).with(@svg, 'id').once
expect(@context).to receive(:set_source).with(nil, 37, 38).once expect(@context).to receive(:set_source).with(@png, 37, 38).once
expect(@context).to receive(:paint).with(0.9).once expect(@context).to receive(:paint).with(0.9).once
expect(@context).to receive(:restore).once expect(@context).to receive(:restore).once

1
spec/samples/samples_regression_spec.rb

@ -12,6 +12,7 @@ describe "Squib samples" do
end end
it 'should execute with no errors' do it 'should execute with no errors' do
allow(Squib.logger).to receive(:warn) {}
allow(ProgressBar).to receive(:create).and_return(Squib::DoNothing.new) allow(ProgressBar).to receive(:create).and_return(Squib::DoNothing.new)
Dir["#{samples_dir}/**/*.rb"].each do |sample| Dir["#{samples_dir}/**/*.rb"].each do |sample|
load sample load sample

1
spec/spec_helper.rb

@ -54,6 +54,7 @@ def mock_cairo(strio)
cxt = double(Cairo::Context) cxt = double(Cairo::Context)
surface = double(Cairo::ImageSurface) surface = double(Cairo::ImageSurface)
pango = double(Pango::Layout) pango = double(Pango::Layout)
allow(Squib.logger).to receive(:warn) {}
allow(ProgressBar).to receive(:create).and_return(Squib::DoNothing.new) allow(ProgressBar).to receive(:create).and_return(Squib::DoNothing.new)
allow(Cairo::ImageSurface).to receive(:new).and_return(surface) allow(Cairo::ImageSurface).to receive(:new).and_return(surface)
allow(surface).to receive(:width).and_return(100) allow(surface).to receive(:width).and_return(100)

Loading…
Cancel
Save