lib/delivery/builders/image_transformation_builder.rb
require 'delivery/query_parameters/query_string'
module Kontent
module Ai
module Delivery
module Builders
# Provides methods for manipulating the URL of an asset to adjust the image's
# size, cropping behavior, background color, output format, and quality.
#
# See https://kontent.ai/learn/reference/image-transformation/ and
# https://github.com/kontent-ai/delivery-sdk-ruby#image-transformation.
class ImageTransformationBuilder
FIT_MODE_CLIP = 'clip'.freeze
FIT_MODE_SCALE = 'scale'.freeze
FIT_MODE_CROP = 'crop'.freeze
FORMAT_GIF = 'gif'.freeze
FORMAT_PNG = 'png'.freeze
FORMAT_PNG8 = 'png8'.freeze
FORMAT_JPG = 'jpg'.freeze
FORMAT_PJPG = 'pjpg'.freeze
FORMAT_WEBP = 'webp'.freeze
class << self
def transform(url)
AssetURL.new url
end
end
end
class AssetURL
INVALID_PARAMS = 'One or more of the parameters is invalid. '\
'See https://kontent.ai/learn/reference/image-transformation/#a-focal-point-crop'\
'for more information.'.freeze
ONE_TO_100 = 'Quality parameter must be between 1 and 100.'.freeze
BOOLEAN_PARAM = 'The parameter must be a boolean, 0, or 1.'.freeze
# Constructor. Generally, you obtain an +AssetURL+ object by calling
# Kontent::Ai::Delivery::Builders::ImageTransformationBuilder.transform
# instead of using this constructor.
def initialize(url)
@url = url
@query_string = Kontent::Ai::Delivery::QueryParameters::QueryString.new
end
# Applies all transformation options to the asset URL.
#
# * *Returns*:
# - +string+ The full URL to the asset with all query string parameters set
def url
@url + @query_string.to_s
end
# Sets the width of the image
#
# * *Args*:
# - *width*
# - +integer+ Width in pixels, between 1 and 8192.
# - +float+ Width in percentage, between 0 and 1.
#
# * *Returns*:
# - +self+
def with_width(width)
@query_string.set_param 'w', width
self
end
# Sets the height of the image
#
# * *Args*:
# - *height*
# - +integer+ Height in pixels, between 1 and 8192.
# - +float+ Height in percentage, between 0 and 1.
#
# * *Returns* :
# - +self+
def with_height(height)
@query_string.set_param 'h', height
self
end
# Sets the device pixel ratio. Either width or height
# (or both) must be set.
#
# * *Args*:
# - *dpr* (+float+) Pixel ratio between 0 and 5.
#
# * *Returns*:
# - +self+
def with_pixel_ratio(dpr)
@query_string.set_param 'dpr', dpr
self
end
# Defines how the image is constrained while resizing. Either width
# or height (or both) must be set.
#
# * *Args*:
# - *fit* (+string+) Use constants from Kontent::Ai::Delivery::Builders::ImageTransformationBuilder
#
# * *Returns*:
# - +self+
def with_fit_mode(fit)
@query_string.set_param 'fit', fit
self
end
# Selects a region of the image to perform transformations on.
# Setting this will remove focal point cropping from the image,
# as the two options are incompatible.
#
# * *Args*:
# - *x*
# - +integer+ The left border of the rect in pixels
# - +float+ The left border of the rect as a percentage between 0 and 1
# - *y*
# - +integer+ The top border of the rect in pixels
# - +float+ The top border of the rect as a percentage between 0 and 1
# - *width*
# - +integer+ The width of the rect in pixels
# - +float+ The width of the rect as a percentage between 0 and 1
# - *height*
# - +integer+ The height of the rect in pixels
# - +float+ The height of the rect as a percentage between 0 and 1
#
# * *Returns*:
# - +self+
def with_rect(x, y, width, height)
@query_string.remove_param 'fp-x'
@query_string.remove_param 'fp-y'
@query_string.remove_param 'fp-z'
@query_string.remove_param 'fit'
@query_string.remove_param 'crop'
@query_string.set_param 'rect', "#{x},#{y},#{width},#{height}"
self
end
# Sets the point of interest when cropping the image.
# Setting this will remove the source rectangle region,
# as the two options are incompatible. It also automatically sets the
# crop to "focalpoint" and fit to "crop"
#
# * *Args*:
# - *x* (+float+) Percentage of the image's width between 0 and 1
# - *y* (+float+) Percentage of the image's height between 0 and 1
# - *z* (+integer+) Amount of zoom to apply. A value of 1 is the default zoom, and each step represents 100% additional zoom.
#
# * *Returns*:
# - +self+
def with_focal_point(x, y, z)
raise ArgumentError, INVALID_PARAMS unless valid_dims?(x, y, z)
@query_string.remove_param 'rect'
@query_string.set_param 'fp-x', x
@query_string.set_param 'fp-y', y
@query_string.set_param 'fp-z', z
@query_string.set_param 'fit', ImageTransformationBuilder::FIT_MODE_CROP
@query_string.set_param 'crop', 'focalpoint'
self
end
# Sets the background color of any transparent areas of the image.
#
# * *Args*:
# - *color* (+string+) A valid 3, 4, 6, or 8 digit hexadecimal color, without the # symbol
#
# * *Returns*:
# - +self+
def with_background_color(color)
@query_string.set_param 'bg', color
self
end
# Sets the output format of the request for the image.
#
# * *Args*:
# - *format* (+string+) Use constants from Kontent::Ai::Delivery::Builders::ImageTransformationBuilder
#
# * *Returns*:
# - +self+
def with_output_format(format)
@query_string.set_param 'fm', format
self
end
# Configure the amount of compression for lossy file formats. Lower quality
# images will have a smaller file size. Only affects *jpg*, *pjpg*, and
# *webp* files.
#
# When no quality is specified for an image transformation, the default
# value of 85 is used.
#
# * *Args*:
# - *quality* (+integer+) The quality of the image between 1 and 100
#
# * *Returns*:
# - +self+
#
# * *Raises*:
# - +ArgumentError+ if +quality+ is not between 1 and 100 inclusive
def with_quality(quality)
raise ArgumentError, ONE_TO_100 unless quality.to_i >= 1 && quality.to_i <= 100
@query_string.set_param 'q', quality
self
end
# Sets the lossless parameter. If +true+, automatically sets the format
# to WebP.
#
# * *Args*:
# - *lossless*
# - +integer+ Either 1 or 0
# - +bool+ Either +true+ or +false+
# - +string+ Either 'true' or 'false'
#
# * *Returns*:
# - +self+
#
# * *Raises*:
# - +ArgumentError+ if +lossless+ cannot be parsed as a boolean
def with_lossless(lossless)
lossless = lossless.to_s.downcase
raise ArgumentError, BOOLEAN_PARAM unless bool? lossless
@query_string.set_param 'lossless', lossless
@query_string.set_param 'fm', Kontent::Ai::Delivery::Builders::ImageTransformationBuilder::FORMAT_WEBP if %w[true 1].include? lossless
self
end
# Enables or disables automatic format selection. If enabled, it will
# override the format parameter and deliver WebP instead. If the browser
# does not support WebP, the value of the format parameter will be used.
#
# * *Args*:
# - *auto*
# - +integer+ Either 1 or 0
# - +bool+ Either +true+ or +false+
# - +string+ Either 'true' or 'false'
#
# * *Returns*:
# - +self+
#
# * *Raises*:
# - +ArgumentError+ if +auto+ cannot be parsed as a boolean
def with_auto_format_selection(auto)
auto = auto.to_s.downcase
raise ArgumentError, BOOLEAN_PARAM unless bool? auto
if %w[true 1].include? auto
@query_string.set_param 'auto', 'format'
else
@query_string.remove_param 'auto'
end
self
end
private
def valid_dims?(x, y, z)
(x.to_f >= 0.0 && x.to_f <= 1.0) &&
(y.to_f >= 0.0 && y.to_f <= 1.0) &&
(z.to_i >= 1)
end
def bool?(value)
%w[true false 0 1].include? value
end
end
end
end
end
end