@@ -0,0 +1,39 @@
|
||||
require_relative 'color_validator'
|
||||
|
||||
module Squib::Args
|
||||
module_function def extract_drop_shadow(opts, deck)
|
||||
DropShadow.new(deck.custom_colors).extract! opts, deck
|
||||
end
|
||||
|
||||
class DropShadow
|
||||
include ArgLoader
|
||||
include ColorValidator
|
||||
|
||||
def initialize(custom_colors)
|
||||
@custom_colors = custom_colors
|
||||
end
|
||||
|
||||
def self.parameters
|
||||
{
|
||||
shadow_color: :black,
|
||||
shadow_offset_x: 3,
|
||||
shadow_offset_y: 3,
|
||||
shadow_radius: nil,
|
||||
shadow_trim: 0,
|
||||
}
|
||||
end
|
||||
|
||||
def self.expanding_parameters
|
||||
self.parameters.keys # all of them
|
||||
end
|
||||
|
||||
def self.params_with_units
|
||||
[:shadow_offset_x, :shadow_offset_y, :shadow_radius, :shadow_trim]
|
||||
end
|
||||
|
||||
def validate_shadow_color(arg, _i)
|
||||
colorify(arg, @custom_colors)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,7 @@
|
||||
require_relative '../errors_warnings/warn_unexpected_params'
|
||||
|
||||
require_relative '../args/card_range'
|
||||
require_relative '../args/save_batch'
|
||||
require_relative '../args/drop_shadow'
|
||||
|
||||
module Squib
|
||||
class Deck
|
||||
@@ -24,6 +26,7 @@ module Squib
|
||||
range
|
||||
dir prefix suffix count_format
|
||||
rotate trim trim_radius
|
||||
shadow_offset_x shadow_offset_y shadow_radius shadow_color shadow_trim
|
||||
)
|
||||
end
|
||||
|
||||
@@ -31,9 +34,10 @@ module Squib
|
||||
warn_if_unexpected opts
|
||||
range = Args.extract_range opts, deck
|
||||
batch = Args.extract_save_batch opts, deck
|
||||
shadow = Args.extract_drop_shadow opts, deck
|
||||
@bar.start("Saving PNGs to #{batch.summary}", deck.size) do |bar|
|
||||
range.map do |i|
|
||||
deck.cards[i].save_png(batch[i])
|
||||
deck.cards[i].save_png(batch[i], shadow[i])
|
||||
bar.increment
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,12 +20,14 @@ module Squib
|
||||
|
||||
def_delegators :cairo_cxt, :save, :set_source_color, :paint, :restore,
|
||||
:translate, :rotate, :move_to, :update_pango_layout, :width, :height,
|
||||
:show_pango_layout, :rectangle, :rounded_rectangle, :set_line_width, :stroke, :fill,
|
||||
:set_source, :scale, :render_rsvg_handle, :circle, :triangle, :line_to,
|
||||
:operator=, :show_page, :clip, :transform, :mask, :create_pango_layout,
|
||||
:antialias=, :curve_to, :matrix, :matrix=, :identity_matrix, :pango_layout_path,
|
||||
:stroke_preserve, :target, :new_path, :new_sub_path, :reset_clip, :fill_preserve, :close_path,
|
||||
:set_line_join, :set_line_cap, :set_dash, :arc, :arc_negative
|
||||
:show_pango_layout, :rectangle, :rounded_rectangle, :set_line_width,
|
||||
:stroke, :fill, :set_source, :scale, :render_rsvg_handle, :circle,
|
||||
:triangle, :line_to, :operator=, :show_page, :clip, :transform, :mask,
|
||||
:create_pango_layout, :antialias=, :curve_to, :matrix, :matrix=,
|
||||
:identity_matrix, :pango_layout_path, :stroke_preserve, :target,
|
||||
:new_path, :new_sub_path, :reset_clip, :fill_preserve, :close_path,
|
||||
:set_line_join, :set_line_cap, :set_dash, :arc, :arc_negative,
|
||||
:pseudo_blur
|
||||
|
||||
# :nodoc:
|
||||
# @api private
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
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
|
||||
@@ -15,8 +17,8 @@ module Squib
|
||||
|
||||
# :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)
|
||||
@@ -27,25 +29,62 @@ module Squib
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user