Browse Source

Added blending operators to png and svg

Also refactored to start using save/restore more often
dev
Andy Meneely 12 years ago
parent
commit
b3eb3b6876
  1. 11
      lib/squib/api/image.rb
  2. 62
      lib/squib/card.rb
  3. 2
      lib/squib/constants.rb
  4. 7
      lib/squib/graphics/background.rb
  5. 19
      lib/squib/graphics/image.rb
  6. 64
      lib/squib/graphics/shapes.rb
  7. 37
      lib/squib/graphics/text.rb
  8. BIN
      samples/ball.png
  9. BIN
      samples/grit.png
  10. 6
      samples/load_images.rb
  11. BIN
      samples/shiny-purse.png

11
lib/squib/api/image.rb

@ -14,13 +14,14 @@ module Squib
# @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 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}
# @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]) opts = needs(opts, [:range, :files, :x, :y, :alpha, :layout, :blend])
@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], opts[:alpha][i]) @cards[i].png(opts[:file][i], opts[:x][i], opts[:y][i], opts[:alpha][i], opts[:blend][i])
bar.increment bar.increment
end end
end end
@ -40,14 +41,16 @@ module Squib
# @option opts width [Integer] (:native) the pixel width that the image should scale to. SVG scaling is done with vectors, so the scaling should be smooth. 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 width [Integer] (:native) the pixel width that the image should scale to. SVG scaling is done with vectors, so the scaling should be smooth. 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. SVG scaling is done with vectors, so the scaling should be smooth. 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. SVG scaling is done with vectors, so the scaling should be smooth. 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 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}
# @return [nil] Returns nil # @return [nil] Returns nil
# @api public # @api public
def svg(opts = {}) def svg(opts = {})
p = needs(opts,[:range, :files, :svgid, :x, :y, :width, :height, :layout]) p = needs(opts,[:range, :files, :svgid, :x, :y, :width, :height, :layout, :alpha, :blend])
@progress_bar.start("Loading SVG(s)", p[:range].size) do |bar| @progress_bar.start("Loading SVG(s)", p[:range].size) do |bar|
p[:range].each do |i| p[:range].each do |i|
@cards[i].svg(p[:file][i], p[:id][i], p[:x][i], p[:y][i], @cards[i].svg(p[:file][i], p[:id][i], p[:x][i], p[:y][i],
p[:width][i], p[:height][i]) p[:width][i], p[:height][i], p[:alpha][i], p[:blend][i])
bar.increment bar.increment
end end
end end

62
lib/squib/card.rb

@ -2,35 +2,41 @@ require 'cairo'
require 'squib/input_helpers' require 'squib/input_helpers'
module Squib module Squib
# Back end graphics. Private. # Back end graphics. Private.
class Card class Card
include Squib::InputHelpers include Squib::InputHelpers
# :nodoc: # :nodoc:
# @api private # @api private
attr_reader :width, :height attr_reader :width, :height
# :nodoc: # :nodoc:
# @api private # @api private
attr_accessor :cairo_surface, :cairo_context attr_accessor :cairo_surface, :cairo_context
# :nodoc: # :nodoc:
# @api private # @api private
def initialize(deck, width, height) def initialize(deck, width, height)
@deck=deck; @width=width; @height=height @deck=deck; @width=width; @height=height
@cairo_surface = Cairo::ImageSurface.new(width,height) @cairo_surface = Cairo::ImageSurface.new(width,height)
@cairo_context = Cairo::Context.new(@cairo_surface) @cairo_context = Cairo::Context.new(@cairo_surface)
end end
######################## def use_cairo(&block)
### BACKEND GRAPHICS ### @cairo_context.save
######################## block.yield(@cairo_context)
require 'squib/graphics/background' @cairo_context.restore
require 'squib/graphics/image' end
require 'squib/graphics/save_doc'
require 'squib/graphics/save_images' ########################
require 'squib/graphics/shapes' ### BACKEND GRAPHICS ###
require 'squib/graphics/text' ########################
require 'squib/graphics/background'
end require 'squib/graphics/image'
end require 'squib/graphics/save_doc'
require 'squib/graphics/save_images'
require 'squib/graphics/shapes'
require 'squib/graphics/text'
end
end

2
lib/squib/constants.rb

@ -5,6 +5,7 @@ module Squib
SYSTEM_DEFAULTS = { SYSTEM_DEFAULTS = {
:align => :left, :align => :left,
:alpha => 1.0, :alpha => 1.0,
:blend => :none,
:color => :black, :color => :black,
:default_font => 'Arial 36', :default_font => 'Arial 36',
:dir => "_output", :dir => "_output",
@ -64,6 +65,7 @@ module Squib
EXPANDING_PARAMS = { EXPANDING_PARAMS = {
:align => :align, :align => :align,
:alpha => :alpha, :alpha => :alpha,
:blend => :blend,
:circle_radius => :radius, :circle_radius => :radius,
:color => :color, :color => :color,
:ellipsize => :ellipsize, :ellipsize => :ellipsize,

7
lib/squib/graphics/background.rb

@ -4,9 +4,10 @@ module Squib
# :nodoc: # :nodoc:
# @api private # @api private
def background(color) def background(color)
cc = cairo_context use_cairo do |cc|
cc.set_source_color(color) cc.set_source_color(color)
cc.paint cc.paint
end
end end
end end

19
lib/squib/graphics/image.rb

@ -14,17 +14,19 @@ module Squib
# :nodoc: # :nodoc:
# @api private # @api private
def png(file, x, y, alpha) def png(file, x, y, alpha, blend)
return if file.nil? or file.eql? '' return if file.nil? or file.eql? ''
cc = cairo_context
png = Squib.cache_load_image(file) png = Squib.cache_load_image(file)
cc.set_source(png, x, y) use_cairo do |cc|
cc.paint(alpha) cc.set_source(png, x, y)
cc.operator = blend unless blend == :none
cc.paint(alpha)
end
end end
# :nodoc: # :nodoc:
# @api private # @api private
def svg(file, id, x, y, width, height) def svg(file, id, x, y, width, height, alpha, blend)
return if file.nil? or file.eql? '' return if file.nil? or file.eql? ''
svg = RSVG::Handle.new_from_file(file) svg = RSVG::Handle.new_from_file(file)
width = svg.width if width == :native width = svg.width if width == :native
@ -33,8 +35,11 @@ module Squib
tmp_cc = Cairo::Context.new(tmp) tmp_cc = Cairo::Context.new(tmp)
tmp_cc.scale(width.to_f / svg.width.to_f, height.to_f / svg.height.to_f) tmp_cc.scale(width.to_f / svg.width.to_f, height.to_f / svg.height.to_f)
tmp_cc.render_rsvg_handle(svg, id) tmp_cc.render_rsvg_handle(svg, id)
cairo_context.set_source(tmp, x, y) use_cairo do |cc|
cairo_context.paint cc.set_source(tmp, x, y)
cc.operator = blend unless blend == :none
cc.paint(alpha)
end
end end
end end

64
lib/squib/graphics/shapes.rb

@ -5,51 +5,55 @@ module Squib
# @api private # @api private
def rect(x, y, width, height, x_radius, y_radius, fill_color, stroke_color, stroke_width) def rect(x, y, width, height, x_radius, y_radius, fill_color, stroke_color, stroke_width)
width=@width if width==:native; height=@height if height==:native width=@width if width==:native; height=@height if height==:native
cc = cairo_context use_cairo do |cc|
cc.rounded_rectangle(x, y, width, height, x_radius, y_radius) cc.rounded_rectangle(x, y, width, height, x_radius, y_radius)
cc.set_source_color(stroke_color) cc.set_source_color(stroke_color)
cc.set_line_width(stroke_width) cc.set_line_width(stroke_width)
cc.stroke cc.stroke
cc.rounded_rectangle(x, y, width, height, x_radius, y_radius) cc.rounded_rectangle(x, y, width, height, x_radius, y_radius)
cc.set_source_color(fill_color) cc.set_source_color(fill_color)
cc.fill cc.fill
end
end end
# :nodoc: # :nodoc:
# @api private # @api private
def circle(x, y, radius, fill_color, stroke_color, stroke_width) def circle(x, y, radius, fill_color, stroke_color, stroke_width)
cc = cairo_context use_cairo do |cc|
cc.circle(x, y, radius) cc.circle(x, y, radius)
cc.set_source_color(stroke_color) cc.set_source_color(stroke_color)
cc.set_line_width(stroke_width) cc.set_line_width(stroke_width)
cc.stroke cc.stroke
cc.circle(x, y, radius) cc.circle(x, y, radius)
cc.set_source_color(fill_color) cc.set_source_color(fill_color)
cc.fill cc.fill
end
end end
# :nodoc: # :nodoc:
# @api private # @api private
def triangle(x1, y1, x2, y2, x3, y3, fill_color, stroke_color, stroke_width) def triangle(x1, y1, x2, y2, x3, y3, fill_color, stroke_color, stroke_width)
cc = cairo_context use_cairo do |cc|
cc.triangle(x1, y1, x2, y2, x3, y3) cc.triangle(x1, y1, x2, y2, x3, y3)
cc.set_source_color(stroke_color) cc.set_source_color(stroke_color)
cc.set_line_width(stroke_width) cc.set_line_width(stroke_width)
cc.stroke cc.stroke
cc.triangle(x1, y1, x2, y2, x3, y3) cc.triangle(x1, y1, x2, y2, x3, y3)
cc.set_source_color(fill_color) cc.set_source_color(fill_color)
cc.fill cc.fill
end
end end
# :nodoc: # :nodoc:
# @api private # @api private
def line(x1, y1, x2, y2, stroke_color, stroke_width) def line(x1, y1, x2, y2, stroke_color, stroke_width)
cc = cairo_context use_cairo do |cc|
cc.move_to(x1, y1) cc.move_to(x1, y1)
cc.line_to(x2, y2) cc.line_to(x2, y2)
cc.set_source_color(stroke_color) cc.set_source_color(stroke_color)
cc.set_line_width(stroke_width) cc.set_line_width(stroke_width)
cc.stroke cc.stroke
end
end end
end end

37
lib/squib/graphics/text.rb

@ -89,24 +89,25 @@ module Squib
x, y, width, height, x, y, width, height,
markup, justify, wrap, ellipsize, markup, justify, wrap, ellipsize,
spacing, align, valign, hint) spacing, align, valign, hint)
Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, etc. (TODO FILL THIS IN WITH METAPROGRAMMING)"} Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, etc."}
cc = cairo_context use_cairo do |cc|
cc.set_source_color(color) cc.set_source_color(color)
cc.move_to(x,y) cc.move_to(x,y)
layout = cc.create_pango_layout layout = cc.create_pango_layout
layout.font_description = Pango::FontDescription.new(font) layout.font_description = Pango::FontDescription.new(font)
layout.text = str.to_s layout.text = str.to_s
layout.markup = str.to_s if markup layout.markup = str.to_s if markup
layout = setwh(layout, width, height) layout = setwh(layout, width, height)
layout = wrap(layout, wrap) layout = wrap(layout, wrap)
layout = ellipsize(layout, ellipsize) layout = ellipsize(layout, ellipsize)
layout = align(layout, align) layout = align(layout, align)
layout.justify = justify unless justify.nil? layout.justify = justify unless justify.nil?
layout.spacing = spacing * Pango::SCALE unless spacing.nil? layout.spacing = spacing * Pango::SCALE unless spacing.nil?
cc.update_pango_layout(layout) cc.update_pango_layout(layout)
valign(cc, layout, x,y, valign) valign(cc, layout, x,y, valign)
cc.update_pango_layout(layout) ; cc.show_pango_layout(layout) cc.update_pango_layout(layout) ; cc.show_pango_layout(layout)
draw_text_hint(x,y,layout,hint) draw_text_hint(x,y,layout,hint)
end
end end
end end

BIN
samples/ball.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
samples/grit.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

6
samples/load_images.rb

@ -1,7 +1,7 @@
require 'squib' require 'squib'
Squib::Deck.new(width: 825, height: 1125, cards: 1) do Squib::Deck.new(width: 825, height: 1125, cards: 1) do
background color: :white 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
@ -19,5 +19,9 @@ Squib::Deck.new(width: 825, height: 1125, cards: 1) do
# relative to the SVG page. See this example in an SVG editor # 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 svg file: 'offset.svg', id: 'thing', x: 0, y: 0, width: 600, height: 600
# Over 15 different blending operators are supported. See http://cairographics.org/operators
png file: 'ball.png', x: 50, y: 700
png file: 'grit.png', x: 70, y: 750, blend: :color_burn
save prefix: 'load_images_', format: :png save prefix: 'load_images_', format: :png
end end

BIN
samples/shiny-purse.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Loading…
Cancel
Save