Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept image loader options as keyword list #171

Merged
merged 1 commit into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 35 additions & 23 deletions lib/vix/vips/image.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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 """
Expand Down Expand Up @@ -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
23 changes: 22 additions & 1 deletion test/vix/vips/image_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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(<<>>)

Expand Down
Loading