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

Make new_from_enum and write_to_stream accept keyword opts #188

Merged
merged 5 commits into from
Jan 3, 2025
Merged
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
3 changes: 2 additions & 1 deletion c_src/pipe.c
Original file line number Diff line number Diff line change
@@ -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,
66 changes: 66 additions & 0 deletions c_src/vips_foreign.c
Original file line number Diff line number Diff line change
@@ -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);
6 changes: 6 additions & 0 deletions c_src/vips_foreign.h
Original file line number Diff line number Diff line change
@@ -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[]);

7 changes: 6 additions & 1 deletion c_src/vix.c
Original file line number Diff line number Diff line change
@@ -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},

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

9 changes: 8 additions & 1 deletion lib/vix/source_pipe.ex
Original file line number Diff line number Diff line change
@@ -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)
@@ -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}
33 changes: 24 additions & 9 deletions lib/vix/target_pipe.ex
Original file line number Diff line number Diff line change
@@ -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)
@@ -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} ->
@@ -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
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)}
Loading
Loading