diff --git a/c_src/vips_foreign.c b/c_src/vips_foreign.c index 3d8659f..4eaa2b2 100644 --- a/c_src/vips_foreign.c +++ b/c_src/vips_foreign.c @@ -135,6 +135,71 @@ ERL_NIF_TERM nif_foreign_find_save(ErlNifEnv *env, int argc, return ret; } + +ERL_NIF_TERM nif_foreign_find_load_source(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]) { + ASSERT_ARGC(argc, 1); + + ErlNifTime start; + ERL_NIF_TERM ret; + VipsSource *source; + const char *name; + + start = enif_monotonic_time(ERL_NIF_USEC); + + if (!erl_term_to_g_object(env, argv[0], (GObject **)&source)) { + ret = make_error(env, "Failed to get VipsSource"); + goto exit; + } + + name = vips_foreign_find_load_source(source); + + if (!name) { + error("Failed to find the loader for the source. error: %s", vips_error_buffer()); + vips_error_clear(); + ret = make_error(env, "Failed to find loader for the source"); + goto exit; + } + + ret = make_ok(env, make_binary(env, name)); + +exit: + notify_consumed_timeslice(env, start, enif_monotonic_time(ERL_NIF_USEC)); + return ret; +} + +ERL_NIF_TERM nif_foreign_find_save_target(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]) { + ASSERT_ARGC(argc, 1); + + ErlNifTime start; + ERL_NIF_TERM ret; + char suffix[VIPS_PATH_MAX]; + const char *name; + + start = enif_monotonic_time(ERL_NIF_USEC); + + if (!get_binary(env, argv[0], suffix, VIPS_PATH_MAX)) { + ret = make_error(env, "Failed to get suffix"); + goto exit; + } + + name = vips_foreign_find_save_target(suffix); + + if (!name) { + error("Failed to find saver for the target. error: %s", vips_error_buffer()); + vips_error_clear(); + ret = make_error(env, "Failed to find saver for the target"); + goto exit; + } + + ret = make_ok(env, make_binary(env, name)); + +exit: + notify_consumed_timeslice(env, start, enif_monotonic_time(ERL_NIF_USEC)); + return ret; +} + ERL_NIF_TERM nif_foreign_get_suffixes(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ASSERT_ARGC(argc, 0); diff --git a/c_src/vips_foreign.h b/c_src/vips_foreign.h index 665384a..83bb426 100644 --- a/c_src/vips_foreign.h +++ b/c_src/vips_foreign.h @@ -15,6 +15,12 @@ ERL_NIF_TERM nif_foreign_find_load(ErlNifEnv *env, int argc, ERL_NIF_TERM nif_foreign_find_save(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM nif_foreign_find_load_source(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM nif_foreign_find_save_target(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); + ERL_NIF_TERM nif_foreign_get_suffixes(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); diff --git a/c_src/vix.c b/c_src/vix.c index 5b44531..afc9f0c 100644 --- a/c_src/vix.c +++ b/c_src/vix.c @@ -153,10 +153,12 @@ static ErlNifFunc nif_funcs[] = { 0}, /* VipsForeign */ - {"nif_foreign_find_load", 1, nif_foreign_find_load, 0}, + {"nif_foreign_find_load", 1, nif_foreign_find_load, ERL_NIF_DIRTY_JOB_IO_BOUND}, // it might read bytes form the file {"nif_foreign_find_save", 1, nif_foreign_find_save, 0}, {"nif_foreign_find_load_buffer", 1, nif_foreign_find_load_buffer, 0}, {"nif_foreign_find_save_buffer", 1, nif_foreign_find_save_buffer, 0}, + {"nif_foreign_find_load_source", 1, nif_foreign_find_load_source, ERL_NIF_DIRTY_JOB_IO_BOUND}, // it might read bytes from source + {"nif_foreign_find_save_target", 1, nif_foreign_find_save_target, 0}, {"nif_foreign_get_suffixes", 0, nif_foreign_get_suffixes, 0}, {"nif_foreign_get_loader_suffixes", 0, nif_foreign_get_loader_suffixes, 0}, diff --git a/lib/vix/nif.ex b/lib/vix/nif.ex index 588e34a..739d342 100644 --- a/lib/vix/nif.ex +++ b/lib/vix/nif.ex @@ -186,6 +186,12 @@ defmodule Vix.Nif do def nif_foreign_find_save(_filename), do: :erlang.nif_error(:nif_library_not_loaded) + def nif_foreign_find_load_source(_source), + do: :erlang.nif_error(:nif_library_not_loaded) + + def nif_foreign_find_save_target(_suffix), + do: :erlang.nif_error(:nif_library_not_loaded) + def nif_foreign_get_suffixes, do: :erlang.nif_error(:nif_library_not_loaded) diff --git a/lib/vix/vips/foreign.ex b/lib/vix/vips/foreign.ex index 825244c..da48660 100644 --- a/lib/vix/vips/foreign.ex +++ b/lib/vix/vips/foreign.ex @@ -1,23 +1,46 @@ defmodule Vix.Vips.Foreign do - alias Vix.Nif @moduledoc false + alias Vix.Nif + + @type operation_name :: String.t() + + @spec find_load_buffer(binary) :: {:ok, operation_name} | {:error, String.t()} def find_load_buffer(bin) do Nif.nif_foreign_find_load_buffer(bin) end + @spec find_save_buffer(String.t()) :: {:ok, operation_name} | {:error, String.t()} def find_save_buffer(suffix) do Nif.nif_foreign_find_save_buffer(suffix) end + @doc """ + Returns Vips operation name which can load the passed file + """ + @spec find_load(String.t()) :: {:ok, operation_name} | {:error, String.t()} def find_load(filename) do Nif.nif_foreign_find_load(filename) end + @doc """ + Returns Vips operation name which can save an image to passed format + """ + @spec find_save(String.t()) :: {:ok, operation_name} | {:error, String.t()} def find_save(filename) do Nif.nif_foreign_find_save(filename) end + @spec find_load_source(Vix.Vips.Source.t()) :: {:ok, operation_name} | {:error, String.t()} + def find_load_source(source) do + Nif.nif_foreign_find_load_source(source) + end + + @spec find_save_target(String.t()) :: {:ok, operation_name} | {:error, String.t()} + def find_save_target(suffix) do + Nif.nif_foreign_find_save_target(suffix) + end + def get_suffixes do with {:ok, suffixes} <- Nif.nif_foreign_get_suffixes() do {:ok, Enum.uniq(suffixes)} diff --git a/test/vix/foreign_test.exs b/test/vix/foreign_test.exs index b08165c..72bb1ef 100644 --- a/test/vix/foreign_test.exs +++ b/test/vix/foreign_test.exs @@ -20,4 +20,18 @@ defmodule Vix.Vips.ForeignTest do test "find_save" do assert {:ok, "VipsForeignSaveJpegFile"} = Foreign.find_save("puppies.jpg") end + + test "find_load_source" do + bin = File.read!(img_path("puppies.jpg")) + + assert {pipe, source} = Vix.SourcePipe.new() + assert :ok = Vix.SourcePipe.write(pipe, bin) + assert :ok = Vix.SourcePipe.stop(pipe) + + assert {:ok, "VipsForeignLoadJpegSource"} = Foreign.find_load_source(source) + end + + test "find_save_target" do + assert {:ok, "VipsForeignSaveJpegTarget"} = Foreign.find_save_target(".jpg") + end end