From f4888becafebf5691fb29985c1ba7e4bdf508a86 Mon Sep 17 00:00:00 2001 From: Akash Date: Sat, 26 Oct 2024 14:13:24 +0530 Subject: [PATCH] Accept image loader options as keyword list --- lib/vix/vips/image.ex | 58 ++++++++++++++++++++++-------------- test/vix/vips/image_test.exs | 23 +++++++++++++- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/lib/vix/vips/image.ex b/lib/vix/vips/image.ex index 29e0052..5ba8d00 100644 --- a/lib/vix/vips/image.ex +++ b/lib/vix/vips/image.ex @@ -313,38 +313,36 @@ defmodule Vix.Vips.Image do JPEG, FITS, Matlab, OpenEXR, CSV, WebP, Radiance, RAW, PPM and others. - Load options may be appended to filename as "[name=value,...]". For - example: + Optional param `opts` is passed to the image loader. Available + options depends on the file format. You can find all options + available for a format under operation function in + [Operation](./search.html?q=load+-buffer+-filename+-profile) module. + + For example, you can find all of the options supported by + JPEG under `Vix.Vips.Operation.jpegload/2` function documentation. ```elixir - Image.new_from_file("fred.jpg[shrink=2]") + Image.new_from_file("fred.jpg", shrink: 2) ``` - Will open "fred.jpg", downsampling by a factor of two. - The full set of options available depend upon the load operation - that will be executed. Try something like: - - ```shell - $ vips jpegload - ``` + Opens "fred.jpg", downsampling by a factor of two. - at the command-line to see a summary of the available options for - the JPEG loader. + > #### Loading is fast {: .info} + > Only enough of the image is loaded to the memory to be able to + > fill out the header. Pixels will only be decompressed when they are + > needed. - If you want more control over the loader, Use specific format loader + If you want more control over the loader, Use the specific format loader from `Vix.Vips.Operation`. For example for jpeg use `Vix.Vips.Operation.jpegload/2` - - Loading is fast: only enough of the image is loaded to be able to - fill out the header. Pixels will only be decompressed when they are - needed. """ - @spec new_from_file(String.t()) :: {:ok, t()} | {:error, term()} - def new_from_file(path) do - path = Path.expand(path) - - Nif.nif_image_new_from_file(normalize_string(path)) - |> wrap_type() + @spec new_from_file(String.t(), keyword) :: {:ok, t()} | {:error, term()} + def new_from_file(path, opts \\ []) do + with {:ok, path} <- normalize_path(path), + {:ok, loader} <- Vix.Vips.Foreign.find_load(path), + {:ok, {ref, _optional}} <- Operation.Helper.operation_call(loader, [path], opts) do + {:ok, wrap_type(ref)} + end end @doc """ @@ -1331,4 +1329,18 @@ defmodule Vix.Vips.Image do else defp log_warn(msg), do: Logger.warn(msg) end + + @spec normalize_path(String.t()) :: {:ok, String.t()} | {:error, :invalid_path} + defp normalize_path(path) do + path = + path + |> Path.expand() + |> normalize_string() + + if File.exists?(path) do + {:ok, path} + else + {:error, :invalid_path} + end + end end diff --git a/test/vix/vips/image_test.exs b/test/vix/vips/image_test.exs index beff19a..308e54f 100644 --- a/test/vix/vips/image_test.exs +++ b/test/vix/vips/image_test.exs @@ -13,12 +13,33 @@ defmodule Vix.Vips.ImageTest do end test "new_from_file" do - assert {:error, "Failed to read image"} == Image.new_from_file("invalid.jpg") + assert {:error, :invalid_path} == Image.new_from_file("invalid.jpg") + assert {:error, "Failed to find load"} == Image.new_from_file(__ENV__.file) assert {:ok, %Image{ref: ref}} = Image.new_from_file(img_path("puppies.jpg")) assert is_reference(ref) end + test "new_from_file supports optional arguments" do + assert {:ok, %Image{ref: ref} = img1} = Image.new_from_file(img_path("puppies.jpg")) + assert is_reference(ref) + + assert {:ok, %Image{ref: ref} = img2} = + Image.new_from_file(img_path("puppies.jpg"), shrink: 2) + + assert is_reference(ref) + + assert Image.width(img1) == 2 * Image.width(img2) + end + + test "new_from_file ignores invalid options" do + # png does not support `shrink` option + assert {:ok, %Image{ref: ref}} = + Image.new_from_file(img_path("gradient.png"), shrink: 2) + + assert is_reference(ref) + end + test "new_from_buffer", %{dir: dir} do assert {:error, "Failed to find load buffer"} == Image.new_from_buffer(<<>>)