Class: DynamicImage::ImageSizing

Inherits:
Object
  • Object
show all
Defined in:
lib/dynamic_image/image_sizing.rb

Overview

DynamicImage Image Sizing

Calculates cropping and fitting for image sizes. The helpers use it to work out the dimensions of a rendered image, and it can be used on its own when you need the size without rendering anything: reserving space in a layout, filling in og:image:width, or laying out a PDF.

Examples:

sizing = DynamicImage::ImageSizing.new(image)
sizing.fit("400x400") # => Vector2d(400.0, 250.0)

Instance Method Summary collapse

Constructor Details

#initialize(record, options = {}) ⇒ ImageSizing

Returns a new instance of ImageSizing.

Parameters:

Options Hash (options):

  • :uncropped (Boolean)

    Ignore any crop stored on the record and size against the original image



17
18
19
20
# File 'lib/dynamic_image/image_sizing.rb', line 17

def initialize(record, options = {})
  @record = record
  @uncropped = options[:uncropped] ? true : false
end

Instance Method Details

#available_width(ratio = nil) ⇒ Integer

Returns the widest the image can be rendered at, in pixels.

Without a ratio this is the image's own width. With one it is the width of the largest crop matching that ratio.

Examples:

image = Image.find(params[:id]) # 320x200 image
sizing = DynamicImage::ImageSizing.new(image)

sizing.available_width           # => 320
sizing.available_width(16.0 / 9) # => 320
sizing.available_width(9.0 / 16) # => 113

Parameters:

  • ratio (Numeric, Vector2d, String, nil) (defaults to: nil)

    the aspect ratio, in any form Ratio understands

Returns:

  • (Integer)


65
66
67
68
69
70
# File 'lib/dynamic_image/image_sizing.rb', line 65

def available_width(ratio = nil)
  ratio = DynamicImage::Ratio.parse(ratio)
  return size.x.floor unless ratio

  crop_geometry(vector(ratio, 1)).first.x.floor
end

#crop_geometry(ratio_vector) ⇒ Array(Vector2d, Vector2d)

Calculates crop geometry. The given vector is scaled to match the image size, since cropping happens before resizing.

The crop is positioned to keep the record's crop gravity as close to the center as possible, clamped to the bounds of the image.

Examples:

image = Image.find(params[:id]) # 320x200 image
sizing = DynamicImage::ImageSizing.new(image)

sizing.crop_geometry(Vector2d(100, 100))
# => [Vector2d(200, 200), Vector2d(60, 0)]

Parameters:

  • ratio_vector (Vector2d)

    the aspect ratio to crop to

Returns:

  • (Array(Vector2d, Vector2d))

    the crop size and crop start



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/dynamic_image/image_sizing.rb', line 37

def crop_geometry(ratio_vector)
  # Maximize the crop area to fit the image size
  crop_size = ratio_vector.fit(size).round

  # Ignore pixels outside the pre-cropped area for now
  center = crop_gravity - crop_start

  start = center - (crop_size / 2).floor
  start = clamp(start, crop_size, size)

  [crop_size, (start + crop_start)]
end

#fit(fit_size, options = {}) ⇒ Vector2d

Adjusts fit_size to fit the image dimensions. Any dimension set to zero will be ignored.

Examples:

image = Image.find(params[:id]) # 320x200 image
sizing = DynamicImage::ImageSizing.new(image)

sizing.fit(Vector2d(0, 100))
# => Vector2d(160.0, 100.0)

sizing.fit(Vector2d(500, 500))
# => Vector2d(320.0, 200.0)

sizing.fit(Vector2d(500, 500), crop: true)
# => Vector2d(200.0, 200.0)

sizing.fit(Vector2d(500, 500), upscale: true)
# => Vector2d(500.0, 312.5)

Parameters:

  • fit_size (Vector2d, String)

    the size to fit within, either a vector or a "{width}x{height}" string. Either dimension may be omitted for a fixed width or height.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :crop (Boolean)

    Don't keep aspect ratio. This will allow the image to be cropped to the requested size.

  • :upscale (Boolean)

    Don't limit to the size of the image. Images smaller than the given size will be scaled up.

Returns:

  • (Vector2d)

    the resulting size

Raises:



99
100
101
102
103
104
105
# File 'lib/dynamic_image/image_sizing.rb', line 99

def fit(fit_size, options = {})
  fit_size = parse_vector(fit_size)
  require_dimensions!(fit_size)     if options[:crop]
  fit_size = size.fit(fit_size)     unless options[:crop]
  fit_size = size.contain(fit_size) unless options[:upscale]
  fit_size
end