Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

169 lines (144 sloc) 6.354 kB
#--
# $Id: stretchable.rb,v 1.7 2009/02/28 23:52:28 rmagick Exp $
# Copyright (C) 2009 Timothy P. Hunter
#++
module Magick
class RVG
module PreserveAspectRatio
#--
# Included in Stretchable module and Image class
#++
# Specifies how the image within a viewport should be scaled.
# [+align+] a combination of 'xMin', 'xMid', or 'xMax', followed by
# 'YMin', 'YMid', or 'YMax'
# [+meet_or_slice+] one of 'meet' or 'slice'
def preserve_aspect_ratio(align, meet_or_slice='meet')
@align = align.to_s
if @align != 'none'
m = /\A(xMin|xMid|xMax)(YMin|YMid|YMax)\z/.match(@align)
raise(ArgumentError, "unknown alignment specifier: #{@align}") unless m
end
if meet_or_slice
meet_or_slice = meet_or_slice.to_s.downcase
if meet_or_slice == 'meet' || meet_or_slice == 'slice'
@meet_or_slice = meet_or_slice
else
raise(ArgumentError, "specifier must be `meet' or `slice' (got #{meet_or_slice})")
end
end
yield(self) if block_given?
self
end
end # module PreserveAspectRatio
# The methods in this module describe the user-coordinate space.
# RVG and Pattern objects are stretchable.
module Stretchable
private
# Scale to fit
def set_viewbox_none(width, height)
sx, sy = 1.0, 1.0
if @vbx_width
sx = width / @vbx_width
end
if @vbx_height
sy = height / @vbx_height
end
return [sx, sy]
end
# Use align attribute to compute x- and y-offset from viewport's upper-left corner.
def align_to_viewport(width, height, sx, sy)
tx = case @align
when /\AxMin/
0
when NilClass, /\AxMid/
(width - @vbx_width*sx) / 2.0
when /\AxMax/
width - @vbx_width*sx
end
ty = case @align
when /YMin\z/
0
when NilClass, /YMid\z/
(height - @vbx_height*sy) / 2.0
when /YMax\z/
height - @vbx_height*sy
end
return [tx, ty]
end
# Scale to smaller viewbox dimension
def set_viewbox_meet(width, height)
sx = sy = [width / @vbx_width, height / @vbx_height].min
return [sx, sy]
end
# Scale to larger viewbox dimension
def set_viewbox_slice(width, height)
sx = sy = [width / @vbx_width, height / @vbx_height].max
return [sx, sy]
end
# Establish the viewbox as necessary
def add_viewbox_primitives(width, height, gc)
@vbx_width ||= width
@vbx_height ||= height
@vbx_x ||= 0.0
@vbx_y ||= 0.0
if @align == 'none'
sx, sy = set_viewbox_none(width, height)
tx, ty = 0, 0
elsif @meet_or_slice == 'meet'
sx, sy = set_viewbox_meet(width, height)
tx, ty = align_to_viewport(width, height, sx, sy)
else
sx, sy = set_viewbox_slice(width, height)
tx, ty = align_to_viewport(width, height, sx, sy)
end
# Establish clipping path around the current viewport
name = __id__.to_s
gc.define_clip_path(name) do
gc.path("M0,0 l#{width},0 l0,#{height} l-#{width},0 l0,-#{height}z")
end
gc.clip_path(name)
# Add a non-scaled translation if meet or slice
gc.translate(tx, ty) if (tx.abs > 1.0e-10 || ty.abs > 1.0e-10)
# Scale viewbox as necessary
gc.scale(sx, sy) if (sx != 1.0 || sy != 1.0)
# Add a scaled translation if non-0 origin
gc.translate(-@vbx_x, -@vbx_y) if (@vbx_x.abs != 0.0 || @vbx_y.abs != 0)
end
def initialize(*args, &block)
super()
@vbx_x, @vbx_y, @vbx_width, @vbx_height = nil
@meet_or_slice = 'meet'
@align = nil
end
public
include PreserveAspectRatio
# Describe a user coordinate system to be imposed on the viewbox.
# The arguments must be numbers and the +width+ and +height+
# arguments must be positive.
def viewbox(x, y, width, height)
begin
@vbx_x = Float(x)
@vbx_y = Float(y)
@vbx_width = Float(width)
@vbx_height = Float(height)
rescue ArgumentError
raise ArgumentError, "arguments must be convertable to float (got #{x.class}, #{y.class}, #{width.class}, #{height.class})"
end
raise(ArgumentError, "viewbox width must be > 0 (#{width} given)") unless width >= 0
raise(ArgumentError, "viewbox height must be > 0 (#{height} given)") unless height >= 0
# return the user-coordinate space attributes if defined
class << self
if not defined? @redefined then
@redefined = true
define_method(:x) { @vbx_x }
define_method(:y) { @vbx_y }
define_method(:width) { @vbx_width}
define_method(:height) { @vbx_height }
end
end
yield(self) if block_given?
self
end
end # module Stretchable
end # class RVG
end # module Magick
Jump to Line
Something went wrong with that request. Please try again.