Skip to content

Commit

Permalink
Getting ready for publish
Browse files Browse the repository at this point in the history
  • Loading branch information
naps62 committed Nov 30, 2020
1 parent e88fe74 commit 5f8d8e6
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 110 deletions.
131 changes: 125 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# ImageflowEx

**TODO: Add description**
[imageflow-github]: github.com/imazen/imageflow
[imageflow-json-docs]: https://docs.imageflow.io/json/introduction.html
[my-website]: https://naps62.com

Elixir bindings for [Imageflow][imageflow-github], a safe and blazing fast image workflow library.


## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `imageflow_ex` to your list of dependencies in `mix.exs`:
Add the package to your `mix.exs`:

```elixir
def deps do
Expand All @@ -15,7 +19,122 @@ def deps do
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/imageflow_ex](https://hexdocs.pm/imageflow_ex).
## Usage

### Querying an image

```elixir
alias Imageflow.Job

# create a job
{:ok, job} = Job.create()

# add an input file, with id `0`
:ok = Job.add_input_file(job, 0, "input.jpg")

# you could also add input buffers directly from memory
:ok = Job.add_input_buffer(job, 1, <<0x89, 0x50, 0x4E, 0x47, 0x0D, ... >>)

# call `get_image_info` on buffer with id 0
{:ok, resp} = Job.message("v0.1/get_image_info", %{io_id: 0})

IO.inspect(resp)
%{
"code" => 200,
"data" => %{
"image_info" => %{
"frame_decodes_into" => "bgr_32",
"image_height" => 273,
"image_width" => 185,
"preferred_extension" => "jpg",
"preferred_mime_type" => "image/jpeg"
}
},
"message" => "OK",
"success" => true
}
```

### Transforming an image

```elixir
alias Imageflow.Job

{:ok, job} = Job.create()
:ok = Job.add_input_file(job, 0, "input.jpg")

# allocate an output buffer before manipulating the image
:ok = Job.add_output_buffer(job, 2)


# define a JSON task to transform your image (more details below)
task = %{ ... }

# run
{:ok, response} = Job.message(job, "v0.1/execute", task)

# save the output buffer to a file
:ok = Job.save_output_to_file(job, 1, "output.jpg")
```

### Defining tasks

Imageflow accepts JSON task definitions. Since this package is only a binding to
imageflow, the most reliable documentation on the JSON api available is from the
[here, in the crate docs][imageflow-json-docs]


Here's a simple example, which defines a task that takes buffer `0` as input,
constrains the image to 50px of width, and saves the output to buffer `1`:

```elixir
task = %{
"framewise" => %{
"steps" => [
# first step is to decode buffer 0
%{
"decode" => %{
"io_id" => 0
}
},
# then constrain with to 50px
%{
"constrain" => %{
"mode" => "within",
"w" => 50
}
},
# and encode current result to buffer 1
%{
"encode" => %{
"io_id" => 1,
"preset" => %{
"pngquant" => %{"quality" => 80}
}
}
}
]
}
}
```

### More complex use cases

As you can probably guess from the API so far, imageflow isn't constrained to
a single input/output per job.
A common use case for web development would be to generate multiple sizes of an
image for a responsive frontend.
More details on details can be found in the [imageflow repo][imageflow-github]

## Contributing

Feel free to contribute. Either by opening an issue, a Pull Request, or contacting the
[team](mailto:mpalhas@gmail.com) directly

If you found a bug, please open an issue. You can also open a PR for bugs or new
features. PRs will be reviewed and subject to our style guide and linters.

# About

This project was developed by [Miguel Palhas][my-website], and is published
under the ISC license.
49 changes: 1 addition & 48 deletions lib/imageflow.ex
Original file line number Diff line number Diff line change
@@ -1,52 +1,5 @@
defmodule Imageflow do
alias Imageflow.{Native, Job}

def get_long_version_string(), do: Native.get_long_version_string()

@input "input.jpg"
@output "output.png"

@steps %{
framewise: %{
steps: [
%{
decode: %{
io_id: 0
}
},
%{
constrain: %{
mode: "within",
w: 50
}
},
%{
encode: %{
io_id: 1,
preset: %{
pngquant: %{quality: 80}
}
}
}
]
}
}

def test do
{:ok, job} = Job.create()

job
|> Job.add_input_file(0, @input)
|> Job.add_output_buffer(1)
|> Job.message("v0.1/execute", @steps)
|> Job.save_output_to_file(1, @output)

{:ok, out} =
Job.get_output_buffer(job, 1)
|> IO.inspect()

File.write!("out2.png", out, [:binary])

Job.destroy(job)
end
def get_long_version_string, do: Native.get_long_version_string()
end
41 changes: 24 additions & 17 deletions lib/imageflow/job.ex
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
defmodule Imageflow.Job do
alias Imageflow.Native

defstruct [:id]
@type t :: %__MODULE__{}
@type native_ret_t :: :ok | {:error, binary}

defstruct id: nil

@spec create :: {:ok, t}
def create do
{:ok, id} = Native.job_create()

{:ok, %__MODULE__{id: id}}
end

@spec create! :: t
def create! do
{:ok, job} = __MODULE__.create()

job
end

def destroy(%__MODULE__{id: id}), do: Native.job_destroy(id)

def add_input_buffer(%__MODULE__{id: id} = job, io_id, bytes) do
@spec add_input_buffer(t, number, binary) :: native_ret_t
def add_input_buffer(%__MODULE__{id: id}, io_id, bytes) do
Native.job_add_input_buffer(id, io_id, bytes)

job
end

def add_input_file(%__MODULE__{id: id} = job, io_id, path) do
@spec add_input_file(t, number, binary) :: native_ret_t
def add_input_file(%__MODULE__{id: id}, io_id, path) do
Native.job_add_input_file(id, io_id, path)

job
end

def add_output_buffer(%__MODULE__{id: id} = job, io_id) do
@spec add_output_buffer(t, number) :: native_ret_t
def add_output_buffer(%__MODULE__{id: id}, io_id) do
Native.job_add_output_buffer(id, io_id)

job
end

def save_output_to_file(%__MODULE__{id: id} = job, io_id, path) do
@spec save_output_to_file(t, number, binary) :: native_ret_t
def save_output_to_file(%__MODULE__{id: id}, io_id, path) do
Native.job_save_output_to_file(id, io_id, path)

job
end

@spec get_output_buffer(t, number) :: {:ok, binary} | {:error, binary}
def get_output_buffer(%__MODULE__{id: id} = _job, io_id) do
Native.job_get_output_buffer(id, io_id)
end

def message(%__MODULE__{id: id} = job, method, message) do
@spec message(t, binary, binary) :: {:ok, any} | {:error, binary}
def message(%__MODULE__{id: id}, method, message) do
with {:ok, resp} <- Native.job_message(id, method, Jason.encode!(message)) do
Jason.decode(resp)
{:ok, Jason.decode!(resp)}
end

job
end
end
37 changes: 33 additions & 4 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
defmodule Imageflow.MixProject do
use Mix.Project

@version "0.1.0"

def project do
[
app: :imageflow,
version: "0.1.0",
elixir: "~> 1.9",
version: @version,
elixir: "~> 1.8",
start_permanent: Mix.env() == :prod,
rustler_crates: rustler_crates(),
deps: deps()
deps: deps(),
description: description(),
package: package(),
docs: docs()
]
end

Expand All @@ -22,8 +27,10 @@ defmodule Imageflow.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:rustler, "~> 0.21.0"},
{:rustler, github: "hansihe/rustler", sparse: "rustler_mix"},
{:jason, "~> 1.2"}
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end

Expand All @@ -38,4 +45,26 @@ defmodule Imageflow.MixProject do

defp rustc_mode(:prod), do: :release
defp rustc_mode(_), do: :debug

defp description do
"Elixir bindings for imageflow"
end

defp package do
[
maintainers: ["Miguel Palhas"],
licenses: ["ISC"],
links: %{"GitHub" => "https://github.com/naps62/imageflow_ex"},
files: ~w(.formatter.exs mix.exs README.md lib native LICENSE)
]
end

defp docs do
[
extras: ["README.md"],
main: "readme",
source_url: "https://github.com/naps62/imageflow_ex",
source_ref: "v#{@version}"
]
end
end
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
%{
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"rustler": {:hex, :rustler, "0.21.1", "5299980be32da997c54382e945bacaa015ed97a60745e1e639beaf6a7b278c65", [:mix], [{:toml, "~> 0.5.2", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "6ee1651e10645b2b2f3bb70502bf180341aa058709177e9bc28c105934094bc6"},
"rustler": {:git, "https://github.com/hansihe/rustler.git", "fa221b9292332955ece4d5733e61cf9054efbc23", [sparse: "rustler_mix"]},
"toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm", "f1e3dabef71fb510d015fad18c0e05e7c57281001141504c6b69d94e99750a07"},
}
7 changes: 5 additions & 2 deletions native/imageflow_ex/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ impl Job {
ctx.add_copied_input_buffer(io_id, bytes).unwrap();
}

pub fn add_input_file(&self, io_id: i32, path: &String) {
pub fn add_input_file(&self, io_id: i32, path: &String) -> Result<(), FlowError> {
let mut ctx = self.inner.lock().unwrap();

ctx.add_file(io_id, IoDirection::In, path.as_str()).unwrap();
match ctx.add_file(io_id, IoDirection::In, path.as_str()) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}

pub fn add_output_buffer(&self, io_id: i32) {
Expand Down
Loading

0 comments on commit 5f8d8e6

Please sign in to comment.