diff --git a/lib/squib/api/image.rb b/lib/squib/api/image.rb index 96c49aa..6b7ff05 100644 --- a/lib/squib/api/image.rb +++ b/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 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 # @api public 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| 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 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 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 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 # @api public 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| p[:range].each do |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 end end diff --git a/lib/squib/card.rb b/lib/squib/card.rb index 8c7c3e6..ae818b7 100644 --- a/lib/squib/card.rb +++ b/lib/squib/card.rb @@ -2,35 +2,41 @@ require 'cairo' require 'squib/input_helpers' module Squib - # Back end graphics. Private. - class Card - include Squib::InputHelpers + # Back end graphics. Private. + class Card + include Squib::InputHelpers - # :nodoc: - # @api private - attr_reader :width, :height + # :nodoc: + # @api private + attr_reader :width, :height - # :nodoc: - # @api private - attr_accessor :cairo_surface, :cairo_context + # :nodoc: + # @api private + attr_accessor :cairo_surface, :cairo_context - # :nodoc: - # @api private - def initialize(deck, width, height) - @deck=deck; @width=width; @height=height - @cairo_surface = Cairo::ImageSurface.new(width,height) - @cairo_context = Cairo::Context.new(@cairo_surface) - end + # :nodoc: + # @api private + def initialize(deck, width, height) + @deck=deck; @width=width; @height=height + @cairo_surface = Cairo::ImageSurface.new(width,height) + @cairo_context = Cairo::Context.new(@cairo_surface) + end - ######################## - ### BACKEND GRAPHICS ### - ######################## - require 'squib/graphics/background' - require 'squib/graphics/image' - require 'squib/graphics/save_doc' - require 'squib/graphics/save_images' - require 'squib/graphics/shapes' - require 'squib/graphics/text' - - end - end \ No newline at end of file + def use_cairo(&block) + @cairo_context.save + block.yield(@cairo_context) + @cairo_context.restore + end + + ######################## + ### BACKEND GRAPHICS ### + ######################## + require 'squib/graphics/background' + require 'squib/graphics/image' + require 'squib/graphics/save_doc' + require 'squib/graphics/save_images' + require 'squib/graphics/shapes' + require 'squib/graphics/text' + + end +end \ No newline at end of file diff --git a/lib/squib/constants.rb b/lib/squib/constants.rb index 10ffa1e..5cf5ea0 100644 --- a/lib/squib/constants.rb +++ b/lib/squib/constants.rb @@ -5,6 +5,7 @@ module Squib SYSTEM_DEFAULTS = { :align => :left, :alpha => 1.0, + :blend => :none, :color => :black, :default_font => 'Arial 36', :dir => "_output", @@ -64,6 +65,7 @@ module Squib EXPANDING_PARAMS = { :align => :align, :alpha => :alpha, + :blend => :blend, :circle_radius => :radius, :color => :color, :ellipsize => :ellipsize, diff --git a/lib/squib/graphics/background.rb b/lib/squib/graphics/background.rb index d4950d2..19d816d 100644 --- a/lib/squib/graphics/background.rb +++ b/lib/squib/graphics/background.rb @@ -4,9 +4,10 @@ module Squib # :nodoc: # @api private def background(color) - cc = cairo_context - cc.set_source_color(color) - cc.paint + use_cairo do |cc| + cc.set_source_color(color) + cc.paint + end end end diff --git a/lib/squib/graphics/image.rb b/lib/squib/graphics/image.rb index 505e656..465f0e0 100644 --- a/lib/squib/graphics/image.rb +++ b/lib/squib/graphics/image.rb @@ -14,17 +14,19 @@ module Squib # :nodoc: # @api private - def png(file, x, y, alpha) + def png(file, x, y, alpha, blend) return if file.nil? or file.eql? '' - cc = cairo_context png = Squib.cache_load_image(file) - cc.set_source(png, x, y) - cc.paint(alpha) + use_cairo do |cc| + cc.set_source(png, x, y) + cc.operator = blend unless blend == :none + cc.paint(alpha) + end end # :nodoc: # @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? '' svg = RSVG::Handle.new_from_file(file) width = svg.width if width == :native @@ -33,8 +35,11 @@ module Squib 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.render_rsvg_handle(svg, id) - cairo_context.set_source(tmp, x, y) - cairo_context.paint + use_cairo do |cc| + cc.set_source(tmp, x, y) + cc.operator = blend unless blend == :none + cc.paint(alpha) + end end end diff --git a/lib/squib/graphics/shapes.rb b/lib/squib/graphics/shapes.rb index 95a7753..1c42591 100644 --- a/lib/squib/graphics/shapes.rb +++ b/lib/squib/graphics/shapes.rb @@ -5,51 +5,55 @@ module Squib # @api private 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 - cc = cairo_context - cc.rounded_rectangle(x, y, width, height, x_radius, y_radius) - cc.set_source_color(stroke_color) - cc.set_line_width(stroke_width) - cc.stroke - cc.rounded_rectangle(x, y, width, height, x_radius, y_radius) - cc.set_source_color(fill_color) - cc.fill + use_cairo do |cc| + cc.rounded_rectangle(x, y, width, height, x_radius, y_radius) + cc.set_source_color(stroke_color) + cc.set_line_width(stroke_width) + cc.stroke + cc.rounded_rectangle(x, y, width, height, x_radius, y_radius) + cc.set_source_color(fill_color) + cc.fill + end end # :nodoc: # @api private def circle(x, y, radius, fill_color, stroke_color, stroke_width) - cc = cairo_context - cc.circle(x, y, radius) - cc.set_source_color(stroke_color) - cc.set_line_width(stroke_width) - cc.stroke - cc.circle(x, y, radius) - cc.set_source_color(fill_color) - cc.fill + use_cairo do |cc| + cc.circle(x, y, radius) + cc.set_source_color(stroke_color) + cc.set_line_width(stroke_width) + cc.stroke + cc.circle(x, y, radius) + cc.set_source_color(fill_color) + cc.fill + end end # :nodoc: # @api private def triangle(x1, y1, x2, y2, x3, y3, fill_color, stroke_color, stroke_width) - cc = cairo_context - cc.triangle(x1, y1, x2, y2, x3, y3) - cc.set_source_color(stroke_color) - cc.set_line_width(stroke_width) - cc.stroke - cc.triangle(x1, y1, x2, y2, x3, y3) - cc.set_source_color(fill_color) - cc.fill + use_cairo do |cc| + cc.triangle(x1, y1, x2, y2, x3, y3) + cc.set_source_color(stroke_color) + cc.set_line_width(stroke_width) + cc.stroke + cc.triangle(x1, y1, x2, y2, x3, y3) + cc.set_source_color(fill_color) + cc.fill + end end # :nodoc: # @api private def line(x1, y1, x2, y2, stroke_color, stroke_width) - cc = cairo_context - cc.move_to(x1, y1) - cc.line_to(x2, y2) - cc.set_source_color(stroke_color) - cc.set_line_width(stroke_width) - cc.stroke + use_cairo do |cc| + cc.move_to(x1, y1) + cc.line_to(x2, y2) + cc.set_source_color(stroke_color) + cc.set_line_width(stroke_width) + cc.stroke + end end end diff --git a/lib/squib/graphics/text.rb b/lib/squib/graphics/text.rb index 6b90533..d178d1a 100644 --- a/lib/squib/graphics/text.rb +++ b/lib/squib/graphics/text.rb @@ -89,24 +89,25 @@ module Squib x, y, width, height, markup, justify, wrap, ellipsize, spacing, align, valign, hint) - Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, etc. (TODO FILL THIS IN WITH METAPROGRAMMING)"} - cc = cairo_context - cc.set_source_color(color) - cc.move_to(x,y) - layout = cc.create_pango_layout - layout.font_description = Pango::FontDescription.new(font) - layout.text = str.to_s - layout.markup = str.to_s if markup - layout = setwh(layout, width, height) - layout = wrap(layout, wrap) - layout = ellipsize(layout, ellipsize) - layout = align(layout, align) - layout.justify = justify unless justify.nil? - layout.spacing = spacing * Pango::SCALE unless spacing.nil? - cc.update_pango_layout(layout) - valign(cc, layout, x,y, valign) - cc.update_pango_layout(layout) ; cc.show_pango_layout(layout) - draw_text_hint(x,y,layout,hint) + Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, etc."} + use_cairo do |cc| + cc.set_source_color(color) + cc.move_to(x,y) + layout = cc.create_pango_layout + layout.font_description = Pango::FontDescription.new(font) + layout.text = str.to_s + layout.markup = str.to_s if markup + layout = setwh(layout, width, height) + layout = wrap(layout, wrap) + layout = ellipsize(layout, ellipsize) + layout = align(layout, align) + layout.justify = justify unless justify.nil? + layout.spacing = spacing * Pango::SCALE unless spacing.nil? + cc.update_pango_layout(layout) + valign(cc, layout, x,y, valign) + cc.update_pango_layout(layout) ; cc.show_pango_layout(layout) + draw_text_hint(x,y,layout,hint) + end end end diff --git a/samples/ball.png b/samples/ball.png new file mode 100644 index 0000000..cf990bd Binary files /dev/null and b/samples/ball.png differ diff --git a/samples/grit.png b/samples/grit.png new file mode 100644 index 0000000..1cdbff3 Binary files /dev/null and b/samples/grit.png differ diff --git a/samples/load_images.rb b/samples/load_images.rb index d76ffab..e52a7b3 100644 --- a/samples/load_images.rb +++ b/samples/load_images.rb @@ -1,7 +1,7 @@ require 'squib' 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 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 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 end diff --git a/samples/shiny-purse.png b/samples/shiny-purse.png index ac3ae19..477ef93 100644 Binary files a/samples/shiny-purse.png and b/samples/shiny-purse.png differ