Class: Retouch::Geometry

Inherits:
Object
  • Object
show all
Defined in:
lib/retouch/geometry.rb,
sig/retouch.rbs

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(width, height, offset_x, offset_y, mode) ⇒ Geometry

Returns a new instance of Geometry.



30
31
32
33
34
35
36
# File 'lib/retouch/geometry.rb', line 30

def initialize(width, height, offset_x, offset_y, mode)
  @width = width
  @height = height
  @offset_x = offset_x
  @offset_y = offset_y
  @mode = mode
end

Instance Attribute Details

#height ⇒ Integer, ... (readonly)

Returns the value of attribute height.

Returns:

  • (Integer, Float, nil)


5
6
7
# File 'lib/retouch/geometry.rb', line 5

def height
  @height
end

#mode ⇒ Symbol (readonly)

Returns the value of attribute mode.

Returns:

  • (Symbol)


5
6
7
# File 'lib/retouch/geometry.rb', line 5

def mode
  @mode
end

#offset_x ⇒ Integer (readonly)

Returns the value of attribute offset_x.

Returns:

  • (Integer)


5
6
7
# File 'lib/retouch/geometry.rb', line 5

def offset_x
  @offset_x
end

#offset_y ⇒ Integer (readonly)

Returns the value of attribute offset_y.

Returns:

  • (Integer)


5
6
7
# File 'lib/retouch/geometry.rb', line 5

def offset_y
  @offset_y
end

#width ⇒ Integer, ... (readonly)

Returns the value of attribute width.

Returns:

  • (Integer, Float, nil)


5
6
7
# File 'lib/retouch/geometry.rb', line 5

def width
  @width
end

Class Method Details

.parse(value) ⇒ Geometry

Parameters:

  • value (String)

Returns:

Raises:

  • (ArgumentError)


7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/retouch/geometry.rb', line 7

def self.parse(value)
  text = String(value)
  match = /\A(?:(?<width>\d+(?:\.\d+)?%?)?x(?<height>\d+(?:\.\d+)?%?)?|(?<single>\d+(?:\.\d+)?%))(?<mode>[!^>])?(?<x>[+-]\d+)?(?<y>[+-]\d+)?\z/.match(text)
  raise ArgumentError, "invalid geometry: #{text}" unless match

  width = match[:width] || match[:single]
  height = match[:height] || match[:single]
  raise ArgumentError, "geometry needs at least one dimension" unless width || height

  mode = { "!" => :stretch, "^" => :cover, ">" => :shrink }.fetch(match[:mode], :fit)
  raise ArgumentError, "geometry needs both offsets" if match[:x].nil? != match[:y].nil?

  new(width && dimension(width), height && dimension(height), (match[:x] || 0).to_i, (match[:y] || 0).to_i, mode)
end

Instance Method Details

#crop_size(source_width, source_height) ⇒ [Integer, Integer]

Parameters:

  • source_width (Integer)
  • source_height (Integer)

Returns:

  • ([Integer, Integer])

Raises:

  • (ArgumentError)


38
39
40
41
42
# File 'lib/retouch/geometry.rb', line 38

def crop_size(source_width, source_height)
  raise ArgumentError, "crop geometry needs both dimensions" unless width && height

  [scaled_dimension(source_width, width), scaled_dimension(source_height, height)]
end

#target_size(source_width, source_height) ⇒ [Integer, Integer]

Parameters:

  • source_width (Integer)
  • source_height (Integer)

Returns:

  • ([Integer, Integer])


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/retouch/geometry.rb', line 44

def target_size(source_width, source_height)
  width_ratio = width.is_a?(Float) ? width : nil
  height_ratio = height.is_a?(Float) ? height : nil
  target_width = width_ratio ? source_width * width_ratio : width
  target_height = height_ratio ? source_height * height_ratio : height
  return [scaled_dimension(source_width, width_ratio), scaled_dimension(source_height, height_ratio)] if width_ratio && height_ratio
  return [scaled_dimension(source_width, target_width), scaled_dimension(source_height, target_height)] if mode == :stretch && target_width && target_height

  scale = if target_width && target_height
            horizontal = target_width.to_f / source_width
            vertical = target_height.to_f / source_height
            mode == :cover ? [horizontal, vertical].max : [horizontal, vertical].min
          elsif target_width
            target_width.to_f / source_width
          elsif target_height
            target_height.to_f / source_height
          else
            1.0
          end
  scale = [scale, 1.0].min if mode == :shrink
  [(source_width * scale).round.clamp(1, 1_000_000), (source_height * scale).round.clamp(1, 1_000_000)]
end