10 changed files with 6115 additions and 29 deletions
@ -0,0 +1,83 @@
|
||||
module Squib |
||||
class Deck |
||||
|
||||
# So the Cairo people have said over and over again that they won't support the 3x3 matrices that would handle perspective transforms. |
||||
# Since our perspective transform needs are a bit simpler, we can use a "striping method" that does the job for us. |
||||
# It's a little bit involved, but it works well enough for limited ranges of our parameters. |
||||
# These were also helpful: |
||||
# http://kapo-cpp.blogspot.com/2008/01/perspective-effect-using-cairo.html |
||||
# http://zetcode.com/gui/pygtk/drawingII/ |
||||
# :nodoc: |
||||
# @api private |
||||
def render_showcase(range, |
||||
trim, trim_radius, scale, offset, fill_color, |
||||
reflect_offset, reflect_percent, reflect_strength, margin, face_right, |
||||
dir, file_to_save) |
||||
out_width = range.size * ((@width - 2*trim) * scale * offset) + 2*margin |
||||
out_height = reflect_offset + (1.0 + reflect_percent) * (@height - 2*trim) + 2*margin |
||||
out_cc = Cairo::Context.new(Cairo::ImageSurface.new(out_width, out_height)) |
||||
out_cc.set_source_color(fill_color) |
||||
out_cc.paint |
||||
|
||||
cards = range.collect { |i| @cards[i] } |
||||
cards.each_with_index do |card, i| |
||||
trimmed = trim_rounded(card.cairo_surface, trim, trim_radius) |
||||
reflected = reflect(trimmed, reflect_offset, reflect_percent, reflect_strength) |
||||
perspectived = perspective(reflected, scale, face_right) |
||||
out_cc.set_source(perspectived, margin + i * perspectived.width * offset, margin) |
||||
out_cc.paint |
||||
end |
||||
out_cc.target.write_to_png("#{dir}/#{file_to_save}") |
||||
end |
||||
|
||||
# :nodoc: |
||||
# @api private |
||||
def trim_rounded(src, trim, radius) |
||||
trim_cc = Cairo::Context.new(Cairo::ImageSurface.new(src.width-2.0*trim, src.height-2.0*trim)) |
||||
trim_cc.rounded_rectangle(0, 0, trim_cc.target.width, trim_cc.target.height, radius, radius) |
||||
trim_cc.set_source(src, -1 * trim, -1 * trim) |
||||
trim_cc.clip |
||||
trim_cc.paint |
||||
return trim_cc.target |
||||
end |
||||
|
||||
# :nodoc: |
||||
# @api private |
||||
def reflect(src, roffset, rpercent, rstrength) |
||||
tmp_cc = Cairo::Context.new(Cairo::ImageSurface.new(src.width, src.height * (1.0 + rpercent) + roffset)) |
||||
tmp_cc.set_source(src, 0, 0) |
||||
tmp_cc.paint |
||||
# Flip affine magic from: http://cairographics.org/matrix_transform/ |
||||
matrix = Cairo::Matrix.new(1, 0, 0, -1, 0, 2 * src.height + roffset) |
||||
tmp_cc.transform(matrix) # flips the coordinate system |
||||
top_y = src.height # top of the reflection |
||||
bottom_y = src.height * (1.0 - rpercent) + roffset # bottom of the reflection |
||||
gradient = Cairo::LinearPattern.new(0,top_y, 0,bottom_y) |
||||
gradient.add_color_stop_rgba(0.0, 0,0,0, rstrength) # start a little reflected |
||||
gradient.add_color_stop_rgba(1.0, 0,0,0, 0.0) # fade to nothing |
||||
tmp_cc.set_source(src, 0, 0) |
||||
tmp_cc.mask(gradient) |
||||
return tmp_cc.target |
||||
end |
||||
|
||||
def perspective(src, scale, face_right) |
||||
dest_cxt = Cairo::Context.new(Cairo::ImageSurface.new(src.width * scale, src.height)) |
||||
in_thickness = 1 # Take strip 1 pixel-width at a time |
||||
out_thickness = 3 # Scale it to 3 pixels wider to cover any gaps |
||||
(0..src.width).step(in_thickness) do |i| |
||||
percentage = i / src.width.to_f |
||||
i = src.width - i if face_right |
||||
factor = scale + (percentage * (1.0 - scale)) #linear interpolation |
||||
dest_cxt.save |
||||
dest_cxt.translate 0, src.height / 2.0 * (1.0 - factor) |
||||
dest_cxt.scale factor * scale, factor |
||||
dest_cxt.set_source src, 0, 0 |
||||
dest_cxt.rounded_rectangle i, 0, out_thickness, src.height, 0,0 |
||||
dest_cxt.fill |
||||
dest_cxt.restore |
||||
end |
||||
return dest_cxt.target |
||||
end |
||||
|
||||
end |
||||
end |
||||
@ -0,0 +1,25 @@
|
||||
require 'squib' |
||||
|
||||
# Showcases are a neat way to show off your cards in a modern way, using a |
||||
# reflection and a persepctive effect to make them look 3D |
||||
Squib::Deck.new(cards: 4) do |
||||
background color: '#CE534D' |
||||
rect fill_color: '#DED4B9', x: 78, y: 78, |
||||
width: '2.25in', height: '3.25in', radius: 32 |
||||
text str: %w(Grifter Thief Thug Kingpin), |
||||
font: 'Helvetica,Sans weight=800 120', |
||||
x: 78, y: 78, width: '2.25in', align: :center |
||||
svg file: 'spanner.svg', x: (825-500)/2, y: 500, width: 500, height: 500 |
||||
|
||||
# Defaults are pretty sensible. |
||||
showcase file: 'showcase.png' |
||||
|
||||
# Here's a more complete example. |
||||
# Tons of ways to tweak it if you like - check the docs. |
||||
showcase trim: 32, trim_radius: 32, margin: 100, face: :right, |
||||
scale: 0.85, offset: 0.95, fill_color: :black, |
||||
reflect_offset: 25, reflect_strength: 0.1, reflect_percent: 0.4, |
||||
file: 'showcase2.png' |
||||
|
||||
save_png prefix: 'showcase_individual_' # to show that they're not trimmed |
||||
end |
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue