lib/squib/graphics/save_images.rb in squib-0.16.0 vs lib/squib/graphics/save_images.rb in squib-0.17.0

- old
+ new

@@ -1,52 +1,91 @@ +require_relative 'cairo_context_wrapper' + module Squib class Card # :nodoc: # @api private - def save_png(batch) - surface = if preprocess_save?(batch) + def save_png(batch, shadow) + surface = if preprocess_save?(batch, shadow) w, h = compute_dimensions(batch.rotate, batch.trim) - preprocessed_save(w, h, batch) + preprocessed_save(w, h, batch, shadow) else @cairo_surface end write_png(surface, index, batch) end # :nodoc: # @api private - def preprocess_save?(batch) - batch.rotate != false || batch.trim > 0 + def preprocess_save?(batch, shadow) + batch.rotate != false || batch.trim > 0 || !(shadow.shadow_radius.nil?) end def compute_dimensions(rotate, trim) if rotate [ @height - 2 * trim, @width - 2 * trim ] else [ @width - 2 * trim, @height - 2 * trim ] end end - def preprocessed_save(width, height, batch) - new_cc = Cairo::Context.new(Cairo::ImageSurface.new(width, height)) + def preprocessed_save(w, h, batch, shadow) + new_cc = Cairo::Context.new(Cairo::ImageSurface.new(w, h)) trim_radius = batch.trim_radius if batch.rotate != false - new_cc.translate(width * 0.5, height * 0.5) - new_cc.rotate(batch.angle) - new_cc.translate(height * -0.5, width * -0.5) - new_cc.rounded_rectangle(0, 0, height, width, trim_radius, trim_radius) + new_cc.translate w * 0.5, h * 0.5 + new_cc.rotate batch.angle + new_cc.translate h * -0.5, w * -0.5 + new_cc.rounded_rectangle(0, 0, h, w, trim_radius, trim_radius) else - new_cc.rounded_rectangle(0, 0, width, height, trim_radius, trim_radius) + new_cc.rounded_rectangle(0, 0, w, h, trim_radius, trim_radius) end new_cc.clip new_cc.set_source(@cairo_surface, -batch.trim, -batch.trim) new_cc.paint + new_cc.reset_clip + new_cc = drop_shadow(new_cc, shadow, batch) unless shadow.shadow_radius.nil? return new_cc.target end + # pseudo-blur behave weirdly with a radius of 0 - wrapping + def blur(cc, r, &block) + if r == 0 + yield(block) + else + cc.pseudo_blur(r, &block) + end + end + + def drop_shadow(cc, s, batch) + off_x = s.shadow_offset_x + off_y = s.shadow_offset_y + s_trim = s.shadow_trim + s_rad = s.shadow_radius + new_w = cc.target.width + off_x + 3 * s_rad - (2 * s_trim) + new_h = cc.target.height + off_y + 3 * s_rad - (2 * s_trim) + new_cc = Squib::Graphics::CairoContextWrapper.new( + Cairo::Context.new(Cairo::ImageSurface.new(new_w, new_h))) + blur(new_cc, s_rad) do + # fill in with shadow color + new_cc.set_source_squibcolor s.shadow_color + new_cc.rectangle 0, 0, new_cc.target.width, new_cc.target.height + new_cc.fill + # then, paint but blend with :dest_in to get a shadow-shaped drawing + new_cc.set_source cc.target, s_rad + off_x, s_rad + off_y + new_cc.operator = :dest_in # see https://www.cairographics.org/operators/ + new_cc.paint + end + new_cc.set_source cc.target, s_rad, s_rad + new_cc.operator = :over + new_cc.paint + return new_cc + end + def write_png(surface, i, b) - surface.write_to_png("#{b.dir}/#{b.prefix}#{b.count_format % i}#{b.suffix}.png") + filename = "#{b.dir}/#{b.prefix}#{b.count_format % i}#{b.suffix}.png" + surface.write_to_png filename end end end