Skip to content

Commit

Permalink
Add function to get list of supported loader suffixes
Browse files Browse the repository at this point in the history
  • Loading branch information
akash-akya committed Nov 10, 2023
1 parent 200df60 commit 360bae5
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 0 deletions.
105 changes: 105 additions & 0 deletions c_src/vips_foreign.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,108 @@ ERL_NIF_TERM nif_foreign_get_suffixes(ErlNifEnv *env, int argc,
notify_consumed_timeslice(env, start, enif_monotonic_time(ERL_NIF_USEC));
return ret;
}

/**
*
* Based on https://github.com/libvips/libvips/blob/19eba89148695a2780f49b43bc70c426f21fdec1/libvips/foreign/foreign.c#L2056
*
*/
static void *vips_foreign_get_loader_suffixes_count_cb( VipsForeignLoadClass *load_class, void *a, void *b ) {
VipsForeignClass *foreign_class = VIPS_FOREIGN_CLASS( load_class );
int *n_fields = (int *) a;

int i;

if( foreign_class->suffs )
for( i = 0; foreign_class->suffs[i]; i++ )
*n_fields += 1;

return( NULL );
}

static void *vips_foreign_get_loader_suffixes_add_cb( VipsForeignLoadClass *load_class, void *a, void *b )
{
VipsForeignClass *foreign_class = VIPS_FOREIGN_CLASS( load_class );
gchar ***p = (gchar ***) a;

int i;

if( foreign_class->suffs )
for( i = 0; foreign_class->suffs[i]; i++ ) {
**p = g_strdup( foreign_class->suffs[i] );
*p += 1;
}

return( NULL );
}

/**
* vips_foreign_get_loader_suffixes: (method)
*
* Get a %NULL-terminated array listing all the supported loader suffixes.
*
* Free the return result with g_strfreev().
*
* Returns: (transfer full): all supported file extensions, as a
* %NULL-terminated array.
*/
static gchar **vips_foreign_get_loader_suffixes( void ) {
int n_suffs;
gchar **suffs;
gchar **p;

n_suffs = 0;
(void) vips_foreign_map(
"VipsForeignLoad",
(VipsSListMap2Fn) vips_foreign_get_loader_suffixes_count_cb,
&n_suffs, NULL );

suffs = g_new0( gchar *, n_suffs + 1 );
p = suffs;
(void) vips_foreign_map(
"VipsForeignLoad",
(VipsSListMap2Fn) vips_foreign_get_loader_suffixes_add_cb,
&p, NULL );

return( suffs );
}

ERL_NIF_TERM nif_foreign_get_loader_suffixes(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ASSERT_ARGC(argc, 0);

ErlNifTime start;
ERL_NIF_TERM ret;
gchar **loader_suffixes;
ERL_NIF_TERM list;
ERL_NIF_TERM bin;
ssize_t length;
unsigned char *temp;

start = enif_monotonic_time(ERL_NIF_USEC);

loader_suffixes = vips_foreign_get_loader_suffixes();

if (!loader_suffixes) {
error("Failed to fetch loader suffixes. error: %s", vips_error_buffer());
vips_error_clear();
ret = make_error(env, "Failed to fetch loader_suffixes");
goto exit;
}

list = enif_make_list(env, 0);
for (int i = 0; loader_suffixes[i] != NULL; i++) {
length = strlen(loader_suffixes[i]);
temp = enif_make_new_binary(env, length, &bin);
memcpy(temp, loader_suffixes[i], length);

list = enif_make_list_cell(env, bin, list);
}
g_strfreev(loader_suffixes);

ret = make_ok(env, list);

exit:
notify_consumed_timeslice(env, start, enif_monotonic_time(ERL_NIF_USEC));
return ret;
}
3 changes: 3 additions & 0 deletions c_src/vips_foreign.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ ERL_NIF_TERM nif_foreign_find_save(ErlNifEnv *env, int argc,
ERL_NIF_TERM nif_foreign_get_suffixes(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);

ERL_NIF_TERM nif_foreign_get_loader_suffixes(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);

#endif
1 change: 1 addition & 0 deletions c_src/vix.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ static ErlNifFunc nif_funcs[] = {
{"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_get_suffixes", 0, nif_foreign_get_suffixes, 0},
{"nif_foreign_get_loader_suffixes", 0, nif_foreign_get_loader_suffixes, 0},

/* Syscalls */
{"nif_pipe_open", 1, nif_pipe_open, 0},
Expand Down
3 changes: 3 additions & 0 deletions lib/vix/nif.ex
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ defmodule Vix.Nif do
def nif_foreign_get_suffixes,
do: :erlang.nif_error(:nif_library_not_loaded)

def nif_foreign_get_loader_suffixes,
do: :erlang.nif_error(:nif_library_not_loaded)

# OS Specific
def nif_pipe_open(_mode),
do: :erlang.nif_error(:nif_library_not_loaded)
Expand Down
6 changes: 6 additions & 0 deletions lib/vix/vips/foreign.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@ defmodule Vix.Vips.Foreign do
{:ok, Enum.uniq(suffixes)}
end
end

def get_loader_suffixes do
with {:ok, suffixes} <- Nif.nif_foreign_get_loader_suffixes() do
{:ok, Enum.uniq(suffixes)}
end
end
end
7 changes: 7 additions & 0 deletions lib/vix/vips/image.ex
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,13 @@ defmodule Vix.Vips.Image do
@spec supported_saver_suffixes :: {:ok, [String.t()]} | {:error, term}
def supported_saver_suffixes, do: Vix.Vips.Foreign.get_suffixes()

# This function should *NOT* be used to get list of formats vix can load.
# libvips reads the file header to decide the loader to use.
# see: https://github.com/libvips/ruby-vips/issues/186#issuecomment-466763897
@doc false
@spec supported_loader_suffixes :: {:ok, [String.t()]} | {:error, term}
def supported_loader_suffixes, do: Vix.Vips.Foreign.get_loader_suffixes()

# Copy an image to a memory area.
# If image is already a memory buffer, just ref and return. If it's
# a file on disc or a partial, allocate memory and copy the image to
Expand Down
8 changes: 8 additions & 0 deletions test/vix/vips/image_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,14 @@ defmodule Vix.Vips.ImageTest do
end
end

test "supported_loader_suffixes" do

Check failure on line 328 in test/vix/vips/image_test.exs

View workflow job for this annotation

GitHub Actions / Test Compiled - Elixir 1.8.x / OTP 22.x

test supported_loader_suffixes (Vix.Vips.ImageTest)

Check failure on line 328 in test/vix/vips/image_test.exs

View workflow job for this annotation

GitHub Actions / Test Compiled - Elixir 1.10.x / OTP 23.x

test supported_loader_suffixes (Vix.Vips.ImageTest)

Check failure on line 328 in test/vix/vips/image_test.exs

View workflow job for this annotation

GitHub Actions / Test Compiled - Elixir 1.12.x / OTP 23.x

test supported_loader_suffixes (Vix.Vips.ImageTest)

Check failure on line 328 in test/vix/vips/image_test.exs

View workflow job for this annotation

GitHub Actions / Test Compiled - Elixir 1.13.x / OTP 24.x

test supported_loader_suffixes (Vix.Vips.ImageTest)
{:ok, list} = Image.supported_loader_suffixes()

for suffix <- ~w(.jpeg .png .gif .tiff .webp .heif .avif .svg) do
assert suffix in list
end
end

test "new_from_binary and write_to_binary endianness handling", %{dir: dir} do
{width, height} = {125, 125}

Expand Down

0 comments on commit 360bae5

Please sign in to comment.