Skip to content

Commit

Permalink
Merge pull request #188 from akash-akya/dev
Browse files Browse the repository at this point in the history
Make new_from_enum and write_to_stream accept keyword opts
  • Loading branch information
akash-akya authored Jan 3, 2025
2 parents aeeb849 + 27aec2e commit b06f447
Show file tree
Hide file tree
Showing 17 changed files with 382 additions and 169 deletions.
3 changes: 2 additions & 1 deletion c_src/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,12 @@ static bool cancel_select(ErlNifEnv *env, int *fd) {

static void fd_rt_dtor(ErlNifEnv *env, void *obj) {
debug("fd_rt_dtor called");
int *fd = (int *)obj;
close_fd(fd);
}

static void fd_rt_stop(ErlNifEnv *env, void *obj, int fd, int is_direct_call) {
debug("fd_rt_stop called %d", fd);
close_fd(&fd);
}

static void fd_rt_down(ErlNifEnv *env, void *obj, ErlNifPid *pid,
Expand Down
66 changes: 66 additions & 0 deletions c_src/vips_foreign.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,72 @@ 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);
Expand Down
6 changes: 6 additions & 0 deletions c_src/vips_foreign.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[]);

Expand Down
7 changes: 6 additions & 1 deletion c_src/vix.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,13 @@ static ErlNifFunc nif_funcs[] = {
/* VipsForeign */
{"nif_foreign_find_load", 1, nif_foreign_find_load, 0},
{"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_load_buffer", 1, nif_foreign_find_load_buffer,
ERL_NIF_DIRTY_JOB_IO_BOUND},
// it might read bytes form the file
{"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},

Expand Down
6 changes: 6 additions & 0 deletions lib/vix/nif.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
9 changes: 8 additions & 1 deletion lib/vix/source_pipe.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule Vix.SourcePipe do
defstruct bin: [], client_pid: nil
end

@spec new() :: {pid, Vix.Vips.Source.t()}
def new do
{:ok, pipe} = GenServer.start_link(__MODULE__, nil)
source = GenServer.call(pipe, :source, :infinity)
Expand All @@ -37,7 +38,13 @@ defmodule Vix.SourcePipe do
def handle_continue(nil, _) do
case Nif.nif_source_new() do
{:ok, {fd, source}} ->
{:noreply, %SourcePipe{fd: fd, pending: %Pending{}, source: source}}
source_pipe = %SourcePipe{
fd: fd,
pending: %Pending{},
source: %Vix.Vips.Source{ref: source}
}

{:noreply, source_pipe}

{:error, reason} ->
{:stop, reason, nil}
Expand Down
33 changes: 24 additions & 9 deletions lib/vix/target_pipe.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ defmodule Vix.TargetPipe do

@moduledoc false

@type t() :: struct

defstruct [:fd, :pending, :task_result, :task_pid]

defmodule Pending do
@moduledoc false
defstruct size: nil, client_pid: nil
defstruct size: nil, client_pid: nil, opts: []
end

@default_buffer_size 65_535

def new(vips_image, suffix) do
GenServer.start_link(__MODULE__, %{image: vips_image, suffix: suffix})
@spec new(Vix.Vips.Image.t(), String.t(), keyword) :: GenServer.on_start()
def new(image, suffix, opts) do
GenServer.start_link(__MODULE__, %{image: image, suffix: suffix, opts: opts})
end

def read(process, max_size \\ @default_buffer_size)
Expand All @@ -31,15 +34,15 @@ defmodule Vix.TargetPipe do

# Server

def init(%{image: image, suffix: suffix}) do
def init(%{image: image, suffix: suffix, opts: opts}) do
Process.flag(:trap_exit, true)
{:ok, nil, {:continue, %{image: image, suffix: suffix}}}
{:ok, nil, {:continue, %{image: image, suffix: suffix, opts: opts}}}
end

def handle_continue(%{image: image, suffix: suffix}, _) do
def handle_continue(%{image: image, suffix: suffix, opts: opts}, _) do
case Nif.nif_target_new() do
{:ok, {fd, target}} ->
pid = start_task(image, target, suffix)
pid = start_task(image, %Vix.Vips.Target{ref: target}, suffix, opts)
{:noreply, %TargetPipe{fd: fd, task_pid: pid, pending: %Pending{}}}

{:error, reason} ->
Expand Down Expand Up @@ -98,9 +101,21 @@ defmodule Vix.TargetPipe do
{:noreply, state}
end

defp start_task(image, target, suffix) do
@spec start_task(Vix.Vips.Image.t(), Vix.Vips.Target.t(), String.t(), keyword) :: pid
defp start_task(%Vix.Vips.Image{} = image, target, suffix, []) do
spawn_link(fn ->
result = Nif.nif_image_to_target(image, target, suffix)
result = Nif.nif_image_to_target(image.ref, target.ref, suffix)
Process.exit(self(), result)
end)
end

defp start_task(image, target, suffix, opts) do
spawn_link(fn ->
result =
with {:ok, saver} <- Vix.Vips.Foreign.find_save_target(suffix) do
Vix.Vips.Operation.Helper.operation_call(saver, [image, target], opts)
end

Process.exit(self(), result)
end)
end
Expand Down
25 changes: 24 additions & 1 deletion lib/vix/vips/foreign.ex
Original file line number Diff line number Diff line change
@@ -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(%Vix.Vips.Source{ref: vips_source}) do
Nif.nif_foreign_find_load_source(vips_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)}
Expand Down
Loading

0 comments on commit b06f447

Please sign in to comment.