class ImageProcessing::Vips::Processor

def add_alpha(image)

Port of libvips' vips_addalpha().
def add_alpha(image)
  max_alpha = (image.interpretation == :grey16 || image.interpretation == :rgb16) ? 65535 : 255
  image.bandjoin(max_alpha)
end

def apply_operation(name, image, *args)

def apply_operation(name, image, *args)
  result = super
  result.is_a?(::Vips::Image) ? result : image
end

def default_dimensions(width, height)

def default_dimensions(width, height)
  raise Error, "either width or height must be specified" unless width || height
  [width || MAX_COORD, height || MAX_COORD]
end

def has_alpha?(image)

Port of libvips' vips_hasalpha().
def has_alpha?(image)
  image.bands == 2 ||
  (image.bands == 4 && image.interpretation != :cmyk) ||
  image.bands > 4
end

def load_image(path_or_image, autorot: true, **options)

def load_image(path_or_image, autorot: true, **options)
  if path_or_image.is_a?(::Vips::Image)
    image = path_or_image
  else
    source_path = path_or_image
    options     = select_valid_loader_options(source_path, options)
    image = ::Vips::Image.new_from_file(source_path, fail: true, **options)
  end
  image = image.autorot if autorot
  image
end

def resize_and_pad(image, width, height, gravity: "centre", extend: nil, background: nil, alpha: nil, **options)

def resize_and_pad(image, width, height, gravity: "centre", extend: nil, background: nil, alpha: nil, **options)
  embed_options = { extend: extend, background: background }
  embed_options.reject! { |name, value| value.nil? }
  image = image.thumbnail_image(width, height: height, **options)
  image = add_alpha(image) if alpha && !has_alpha?(image)
  image.gravity(gravity, width, height, **embed_options)
end

def resize_to_fill(image, width, height, **options)

def resize_to_fill(image, width, height, **options)
  image.thumbnail_image(width, height: height, crop: :centre, **options)
end

def resize_to_fit(image, width, height, **options)

def resize_to_fit(image, width, height, **options)
  width, height = default_dimensions(width, height)
  image.thumbnail_image(width, height: height, **options)
end

def resize_to_limit(image, width, height, **options)

def resize_to_limit(image, width, height, **options)
  width, height = default_dimensions(width, height)
  image.thumbnail_image(width, height: height, size: :down, **options)
end

def save_image(image, destination_path, **options)

def save_image(image, destination_path, **options)
  options = select_valid_saver_options(destination_path, options)
  image.write_to_file(destination_path, **options)
end

def select_valid_loader_options(source_path, options)

def select_valid_loader_options(source_path, options)
  loader = ::Vips.vips_foreign_find_load(source_path)
  loader ? select_valid_options(loader, options) : options
end

def select_valid_options(operation_name, options)

def select_valid_options(operation_name, options)
  operation = ::Vips::Operation.new(operation_name)
  operation_options = operation.get_construct_args
    .select { |name, flags| (flags & ::Vips::ARGUMENT_INPUT)    != 0 }
    .select { |name, flags| (flags & ::Vips::ARGUMENT_REQUIRED) == 0 }
    .map(&:first).map(&:to_sym)
  options.select { |name, value| operation_options.include?(name) }
end

def select_valid_saver_options(destination_path, options)

def select_valid_saver_options(destination_path, options)
  saver = ::Vips.vips_foreign_find_save(destination_path)
  saver ? select_valid_options(saver, options) : options
end