Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom anchors for PNGs and SVGs #392

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/dsl/png.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ file

file(s) to read in. As in :doc:`/arrays`, if this a single file, then it's use for every card in range. If the parameter is an Array of files, then each file is looked up for each card. If any of them are nil or '', nothing is done for that card.

.. include:: /args/anchor.rst

.. include:: /args/xy.rst

width
Expand Down
2 changes: 2 additions & 0 deletions docs/dsl/svg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ file

By default, if ``file`` is not found, a warning is logged. This behavior can be configured in :doc:`/config`

.. include:: /args/anchor.rst

.. include:: /args/xy.rst

data
Expand Down
8 changes: 7 additions & 1 deletion lib/squib/args/scale_box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class ScaleBox
def self.parameters
{
x: 0, y: 0,
width: :native, height: :native
width: :native, height: :native,
anchor: :top_left
}
end

Expand Down Expand Up @@ -52,6 +53,11 @@ def validate_height(arg, i)
raise 'height must be a number, :scale, :native, or :deck'
end

def validate_anchor(arg, i)
raise 'anchor must be one of :top_left, :top_right, :bottom_left, :bottom_right, or :center/:middle' unless [:top_left, :top_right, :bottom_left, :bottom_right, :center, :middle].include? arg
arg
end

end

end
2 changes: 1 addition & 1 deletion lib/squib/dsl/png.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def initialize(deck, dsl_method)
def self.accepted_params
%i(
file
x y width height
x y width height anchor
alpha blend mask angle
crop_x crop_y crop_width crop_height
crop_corner_radius crop_corner_x_radius crop_corner_y_radius
Expand Down
2 changes: 1 addition & 1 deletion lib/squib/dsl/svg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def initialize(deck, dsl_method)
def self.accepted_params
%i(
file
x y width height
x y width height anchor
blend mask
crop_x crop_y crop_width crop_height
crop_corner_radius crop_corner_x_radius crop_corner_y_radius
Expand Down
64 changes: 54 additions & 10 deletions lib/squib/graphics/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,42 @@ def png(file, box, paint, trans)
Squib.logger.debug {"RENDERING PNG: \n file: #{file}\n box: #{box}\n paint: #{paint}\n trans: #{trans}"}
return if file.nil? or file.eql? ''
png = Squib.cache_load_image(file)
box.width = png.width.to_f if box.width == :native
box.height = png.height.to_f if box.height == :native
box.width = png.width.to_f * box.height.to_f / png.height.to_f if box.width == :scale
box.height = png.height.to_f * box.width.to_f / png.width.to_f if box.height == :scale

scale_width = box.width.to_f / png.width.to_f
scale_height = box.height.to_f / png.height.to_f
warn_png_scale(file, scale_width, scale_height)

rotate_offset_x = 0
rotate_offset_y = 0
if [:top_right, :bottom_right].include? box.anchor
box.x = box.x - box.width
rotate_offset_x = box.width
end
if [:bottom_left, :bottom_right].include? box.anchor
box.y = box.y - box.height
rotate_offset_y = box.height
end
if [:center, :middle].include? box.anchor
rotate_offset_x = (box.width / 2.0)
box.x = box.x - rotate_offset_x
rotate_offset_y = (box.height / 2.0)
box.y = box.y - rotate_offset_y
end

use_cairo do |cc|
cc.translate(box.x, box.y)
box.width = png.width.to_f if box.width == :native
box.height = png.height.to_f if box.height == :native
box.width = png.width.to_f * box.height.to_f / png.height.to_f if box.width == :scale
box.height = png.height.to_f * box.width.to_f / png.width.to_f if box.height == :scale

scale_width = box.width.to_f / png.width.to_f
scale_height = box.height.to_f / png.height.to_f
warn_png_scale(file, scale_width, scale_height)
cc.scale(scale_width, scale_height)

cc.rotate(trans.angle)
if box.anchor == :top_left
# Avoid doing useless translate([0, 0]) in Cairo and break regression tests
cc.rotate(trans.angle)
else
cc.rotate_about(rotate_offset_x, rotate_offset_y, trans.angle)
end
cc.flip(trans.flip_vertical, trans.flip_horizontal, box.width / 2, box.height / 2)
cc.translate(-box.x, -box.y)

Expand Down Expand Up @@ -94,10 +117,31 @@ def svg(file, svg_args, box, paint, trans)
box.height = svg.height.to_f * box.width.to_f / svg.width.to_f if box.height == :scale
scale_width = box.width.to_f / svg.width.to_f
scale_height = box.height.to_f / svg.height.to_f
rotate_offset_x = 0
rotate_offset_y = 0
if [:top_right, :bottom_right].include? box.anchor
box.x = box.x - box.width
rotate_offset_x = box.width
end
if [:bottom_left, :bottom_right].include? box.anchor
box.y = box.y - box.height
rotate_offset_y = box.height
end
if [:center, :middle].include? box.anchor
rotate_offset_x = (box.width / 2.0)
box.x = box.x - rotate_offset_x
rotate_offset_y = (box.height / 2.0)
box.y = box.y - rotate_offset_y
end
use_cairo do |cc|
cc.translate(box.x, box.y)
cc.flip(trans.flip_vertical, trans.flip_horizontal, box.width / 2, box.height / 2)
cc.rotate(trans.angle)
if box.anchor == :top_left
# Avoid doing useless translate([0, 0]) in Cairo and break regression tests
cc.rotate(trans.angle)
else
cc.rotate_about(rotate_offset_x, rotate_offset_y, trans.angle)
end
cc.scale(scale_width, scale_height)

trans.crop_width = box.width if trans.crop_width == :native
Expand Down
12 changes: 11 additions & 1 deletion samples/images/_images.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'squib'
require 'squib/sample_helpers'

Squib::Deck.new(width: 1000, height: 3000) do
Squib::Deck.new(width: 1000, height: 3200) do
draw_graph_paper width, height

sample "This a PNG.\nNo scaling is done by default." do |x, y|
Expand Down Expand Up @@ -99,6 +99,16 @@
png file: 'with-alpha.png', mask: mask, x: x + 150, y: y, width: 150, height: :scale
end

sample 'PNGs and SVGs are top-left-anchored by default but this can be changed.' do |x,y|
rect x: x, y: y, width: 100, height: 100, # draw the crop line
dash: '3 3', stroke_color: 'red', stroke_width: 3
png x: x + 50, y: y + 50, width: 100, height: 100, file: 'angler-fish.png',
anchor: :center, angle: - Math::PI / 4 - 0.2
rect x: x + 150, y: y, width: 100, height: 100, # draw the crop line
dash: '3 3', stroke_color: 'red', stroke_width: 3
svg x: x + 250, y: y + 100, width: 100, height: 100, file: 'robot-golem.svg',
anchor: :bottom_right, angle: Math::PI / 5
end

save_png prefix: '_images_'
end
11 changes: 11 additions & 0 deletions spec/args/scale_box_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@
expect { Squib::Args.extract_scale_box args, deck }.to raise_error('height must be a number, :scale, :native, or :deck')
end

it 'allows setting anchors' do
args = { anchor: :middle }
box = Squib::Args.extract_scale_box args, deck
expect(box).to have_attributes(anchor: [:middle])
end

it 'disallows setting incorrect anchors' do
args = { anchor: :midle }
expect { Squib::Args.extract_scale_box args, deck }.to raise_error('anchor must be one of :top_left, :top_right, :bottom_left, :bottom_right, or :center/:middle')
end

end


Expand Down