From 16e7264ebf25acb9f836ccb5903b01331e91f289 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 02:12:08 +0000 Subject: [PATCH 01/12] added support for previewing image in Livebook with Kino --- Makefile | 1 + lib/stb_image.ex | 198 +++++++++++++++++++++++++++++++++++++++++++++++ mix.exs | 1 + mix.lock | 2 + 4 files changed, 202 insertions(+) diff --git a/Makefile b/Makefile index 7b7c4c9..ccc809e 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ endif .DEFAULT_GLOBAL := build build: $(STB_IMAGE_NIF_SO) + @ echo > /dev/null $(STB_IMAGE_NIF_SO): @ mkdir -p $(PRIV_DIR) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index b33c9a4..8143dea 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -20,6 +20,8 @@ defmodule StbImage do There are also specific functions for working with GIFs. """ + require Logger + @doc """ The `StbImage` struct. @@ -103,6 +105,202 @@ defmodule StbImage do "unsupported tensor shape: #{inspect(shape)} (expected height-width-channel)" ) + @compile {:no_warn_undefined, Kino} + + @default_kino_render_encoding Application.compile_env(:stb_image, :kino_render_encoding, :png) + @doc """ + Get preferred image encoding when rendering in Kino. + + Default value is `Application.compile_env(:stb_image, :kino_render_encoding, :png)`. + """ + @spec kino_render_encoding(atom()) :: term() + def kino_render_encoding(encoding \\ nil) + + def kino_render_encoding(nil) do + Process.get(:stb_image_kino_render_encoding, @default_kino_render_encoding) + end + + def kino_render_encoding(encoding) when encoding in [:png, :jpg, :jpeg] do + encoding = + if encoding == :jpeg do + :jpg + else + encoding + end + + Process.put(:stb_image_kino_render_encoding, encoding) + end + + def kino_render_encoding(unsupported_encoding) do + raise RuntimeError, "Encoding #{inspect(unsupported_encoding)} is not supported." + end + + @default_kino_render_max_size Application.compile_env( + :stb_image, + :kino_render_max_size, + {8192, 8192} + ) + @doc """ + Get the maximum allowed image size to render in Kino. + + Default value is `Application.compile_env(:stb_image, :kino_render_max_size, {8192, 8192})`. + """ + @spec kino_render_max_size({integer(), integer()} | nil) :: term() + def kino_render_max_size(max_size \\ nil) + + def kino_render_max_size(nil) do + Process.get(:stb_image_kino_render_max_size, @default_kino_render_max_size) + end + + def kino_render_max_size({height, width}) when is_integer(height) and is_integer(width) do + Process.put(:stb_image_kino_render_max_size, {height, width}) + end + + def kino_render_max_size(unsupported_max_size) do + raise RuntimeError, """ + Invalid parameter for max size, expecting a 2-tuple, {height, width}, + where height and width are both integers. However, got `#{inspect(unsupported_max_size)}` + """ + end + + @supported_kino_render_tab_order if Code.ensure_loaded?(Nx) do + [:image, :raw, :numerical] + else + [:image, :raw] + end + @kino_render_tab_order Enum.uniq( + Application.compile_env( + :stb_image, + :kino_render_tab_order, + @supported_kino_render_tab_order + ) + ) + @doc """ + Get preferred order of Kino.Layout tabs for `StbImage` in Livebook. + + Default value is `Enum.uniq(Application.compile_env(:stb_image, :kino_render_tab_order, @supported_kino_render_tab_order))`. + + where `@supported_kino_render_tab_order` is `[:image, :raw, :numerical]` if `:nx` is available, + otherwise `[:image, :raw]` + """ + @spec kino_render_tab_order([atom()] | nil) :: term() + def kino_render_tab_order(order \\ nil) + + def kino_render_tab_order(nil) do + Process.get(:stb_image_kino_render_tab_order, @kino_render_tab_order) + end + + def kino_render_tab_order(order) when is_list(order) do + render_types = + Enum.map(order, fn t -> + supported? = Enum.member?(@supported_kino_render_tab_order, t) + + if !supported? do + Logger.warning(""" + Unknown type `#{inspect(t)}` found in `config :stb_image, kino_render_tab_order`. + Supported types are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. + """) + + nil + else + t + end + end) + |> Enum.reject(fn a -> a == nil end) + + Process.put(:stb_image_kino_render_tab_order, render_types) + end + + def set_kino_render_tab_order(types) do + raise RuntimeError, """ + Unknown order `#{inspect(types)}`. + Supported orders are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. + """ + end + + if Code.ensure_loaded?(Kino.Render) do + defimpl Kino.Render do + require Logger + + defp within_maximum_size(image) do + {max_height, max_width} = StbImage.kino_render_max_size() + + case image.shape do + {h, w} -> + h <= max_height and w <= max_width + + {h, w, _c} -> + h <= max_height and w <= max_width + + _ -> + false + end + end + + @spec to_livebook(StbImage.t()) :: Kino.Output.t() + def to_livebook(image) when is_struct(image, StbImage) do + render_types = StbImage.kino_render_tab_order() + + Enum.map(render_types, fn + :raw -> + {"Raw", Kino.Inspect.new(image)} + + :numerical -> + if Code.ensure_loaded?(Nx) do + {"Numerical", Kino.Inspect.new(StbImage.to_nx(image))} + else + {"Numerical", + Kino.Markdown.new(""" + Numerical tab require application `:nx`, please add `{:nx, "~> 0.4"}` to the dependency list. + """)} + end + + :image -> + {stb_format, kino_format} = + case StbImage.kino_render_encoding() do + :jpg -> + {:jpg, :jpeg} + + :jpeg -> + {:jpg, :jpeg} + + :png -> + {:png, :png} + + unknown -> + raise RuntimeError, "Cannot render image with encoding `#{inspect(unknown)}`" + end + + with true <- within_maximum_size(image), + encoded <- StbImage.to_binary(image, stb_format), + true <- is_binary(encoded) do + {"Image", Kino.Image.new(encoded, kino_format)} + else + _ -> + nil + end + end) + |> Enum.reject(fn a -> a == nil end) + |> to_livebook_tabs(render_types, image) + end + + defp to_livebook_tabs([], [:image], image) do + Kino.Layout.tabs([{"Raw", Kino.Inspect.new(image)}]) + |> Kino.Render.to_livebook() + end + + defp to_livebook_tabs(_tabs, [], image) do + Kino.Inspect.new(image) + |> Kino.Render.to_livebook() + end + + defp to_livebook_tabs(tabs, _types, _mat) do + Kino.Layout.tabs(tabs) + |> Kino.Render.to_livebook() + end + end + end + @doc """ Reads image from file at `path`. diff --git a/mix.exs b/mix.exs index 0c3fe52..c5ef0e9 100644 --- a/mix.exs +++ b/mix.exs @@ -30,6 +30,7 @@ defmodule StbImage.MixProject do [ {:elixir_make, "~> 0.6"}, {:nx, "~> 0.1", optional: true}, + {:kino, "~> 0.7", optional: true}, {:ex_doc, "~> 0.23", only: :docs, runtime: false} ] end diff --git a/mix.lock b/mix.lock index def45d8..a4241f2 100644 --- a/mix.lock +++ b/mix.lock @@ -3,9 +3,11 @@ "earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, + "kino": {:hex, :kino, "0.7.0", "98d2623bebf8d1c4d761c5ed9741c6aae2f1909706baec501f2fdad347cb9d92", [:mix], [{:table, "~> 0.1.2", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "3dd1ee761c241caa30364333e3102a954d68188414a46e867f95c858d745f3fd"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "nx": {:hex, :nx, "0.2.0", "ae550cd72bca2e56f90fc63d59f2f11ac17ed3c4a9cd0968397f4ef9b795b3d6", [:mix], [{:complex, "~> 0.4.0", [hex: :complex, repo: "hexpm", optional: false]}], "hexpm", "31d4936d2cf78a0b147830f0e6fca45bd3ed4b1e592e2bcd61a85f81e892617c"}, + "table": {:hex, :table, "0.1.2", "87ad1125f5b70c5dea0307aa633194083eb5182ec537efc94e96af08937e14a8", [:mix], [], "hexpm", "7e99bc7efef806315c7e65640724bf165c3061cdc5d854060f74468367065029"}, } From f8712cf258e3a759c8abe254063990c4391e63e0 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 02:26:39 +0000 Subject: [PATCH 02/12] added support for previewing image in Livebook with Kino --- lib/stb_image.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 8143dea..2926609 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -163,11 +163,11 @@ defmodule StbImage do """ end - @supported_kino_render_tab_order if Code.ensure_loaded?(Nx) do - [:image, :raw, :numerical] - else - [:image, :raw] - end + @supported_kino_render_tab_order (if Code.ensure_loaded?(Nx) do + [:image, :raw, :numerical] + else + [:image, :raw] + end) @kino_render_tab_order Enum.uniq( Application.compile_env( :stb_image, From 3c7f91b35a75ad51d74d85751c40746f9e6ba8d8 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 05:31:57 +0000 Subject: [PATCH 03/12] fix a copy-paste mistake: set_kino_render_tab_order => kino_render_tab_order --- lib/stb_image.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 2926609..c8a6933 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -211,7 +211,7 @@ defmodule StbImage do Process.put(:stb_image_kino_render_tab_order, render_types) end - def set_kino_render_tab_order(types) do + def kino_render_tab_order(types) do raise RuntimeError, """ Unknown order `#{inspect(types)}`. Supported orders are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. From 95e823453553ccc4a068ed59f3bfb62e661f09a4 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 09:09:03 +0000 Subject: [PATCH 04/12] optionally define kino_render related functions --- lib/stb_image.ex | 202 +++++++++++++++++++++++------------------------ 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index c8a6933..c481956 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -107,123 +107,123 @@ defmodule StbImage do @compile {:no_warn_undefined, Kino} - @default_kino_render_encoding Application.compile_env(:stb_image, :kino_render_encoding, :png) - @doc """ - Get preferred image encoding when rendering in Kino. + if Code.ensure_loaded?(Kino.Render) do + defimpl Kino.Render do + require Logger - Default value is `Application.compile_env(:stb_image, :kino_render_encoding, :png)`. - """ - @spec kino_render_encoding(atom()) :: term() - def kino_render_encoding(encoding \\ nil) + @default_kino_render_encoding Application.compile_env(:stb_image, :kino_render_encoding, :png) + @doc """ + Get preferred image encoding when rendering in Kino. - def kino_render_encoding(nil) do - Process.get(:stb_image_kino_render_encoding, @default_kino_render_encoding) - end + Default value is `Application.compile_env(:stb_image, :kino_render_encoding, :png)`. + """ + @spec kino_render_encoding(atom()) :: term() + def kino_render_encoding(encoding \\ nil) - def kino_render_encoding(encoding) when encoding in [:png, :jpg, :jpeg] do - encoding = - if encoding == :jpeg do - :jpg - else - encoding + def kino_render_encoding(nil) do + Process.get(:stb_image_kino_render_encoding, @default_kino_render_encoding) end - Process.put(:stb_image_kino_render_encoding, encoding) - end - - def kino_render_encoding(unsupported_encoding) do - raise RuntimeError, "Encoding #{inspect(unsupported_encoding)} is not supported." - end + def kino_render_encoding(encoding) when encoding in [:png, :jpg, :jpeg] do + encoding = + if encoding == :jpeg do + :jpg + else + encoding + end - @default_kino_render_max_size Application.compile_env( - :stb_image, - :kino_render_max_size, - {8192, 8192} - ) - @doc """ - Get the maximum allowed image size to render in Kino. - - Default value is `Application.compile_env(:stb_image, :kino_render_max_size, {8192, 8192})`. - """ - @spec kino_render_max_size({integer(), integer()} | nil) :: term() - def kino_render_max_size(max_size \\ nil) - - def kino_render_max_size(nil) do - Process.get(:stb_image_kino_render_max_size, @default_kino_render_max_size) - end - - def kino_render_max_size({height, width}) when is_integer(height) and is_integer(width) do - Process.put(:stb_image_kino_render_max_size, {height, width}) - end - - def kino_render_max_size(unsupported_max_size) do - raise RuntimeError, """ - Invalid parameter for max size, expecting a 2-tuple, {height, width}, - where height and width are both integers. However, got `#{inspect(unsupported_max_size)}` - """ - end + Process.put(:stb_image_kino_render_encoding, encoding) + end - @supported_kino_render_tab_order (if Code.ensure_loaded?(Nx) do - [:image, :raw, :numerical] - else - [:image, :raw] - end) - @kino_render_tab_order Enum.uniq( - Application.compile_env( - :stb_image, - :kino_render_tab_order, - @supported_kino_render_tab_order - ) - ) - @doc """ - Get preferred order of Kino.Layout tabs for `StbImage` in Livebook. + def kino_render_encoding(unsupported_encoding) do + raise RuntimeError, "Encoding #{inspect(unsupported_encoding)} is not supported." + end - Default value is `Enum.uniq(Application.compile_env(:stb_image, :kino_render_tab_order, @supported_kino_render_tab_order))`. + @default_kino_render_max_size Application.compile_env( + :stb_image, + :kino_render_max_size, + {8192, 8192} + ) + @doc """ + Get the maximum allowed image size to render in Kino. + + Default value is `Application.compile_env(:stb_image, :kino_render_max_size, {8192, 8192})`. + """ + @spec kino_render_max_size({integer(), integer()} | nil) :: term() + def kino_render_max_size(max_size \\ nil) + + def kino_render_max_size(nil) do + Process.get(:stb_image_kino_render_max_size, @default_kino_render_max_size) + end - where `@supported_kino_render_tab_order` is `[:image, :raw, :numerical]` if `:nx` is available, - otherwise `[:image, :raw]` - """ - @spec kino_render_tab_order([atom()] | nil) :: term() - def kino_render_tab_order(order \\ nil) + def kino_render_max_size({height, width}) when is_integer(height) and is_integer(width) do + Process.put(:stb_image_kino_render_max_size, {height, width}) + end - def kino_render_tab_order(nil) do - Process.get(:stb_image_kino_render_tab_order, @kino_render_tab_order) - end + def kino_render_max_size(unsupported_max_size) do + raise RuntimeError, """ + Invalid parameter for max size, expecting a 2-tuple, {height, width}, + where height and width are both integers. However, got `#{inspect(unsupported_max_size)}` + """ + end - def kino_render_tab_order(order) when is_list(order) do - render_types = - Enum.map(order, fn t -> - supported? = Enum.member?(@supported_kino_render_tab_order, t) + @supported_kino_render_tab_order (if Code.ensure_loaded?(Nx) do + [:image, :raw, :numerical] + else + [:image, :raw] + end) + @kino_render_tab_order Enum.uniq( + Application.compile_env( + :stb_image, + :kino_render_tab_order, + @supported_kino_render_tab_order + ) + ) + @doc """ + Get preferred order of Kino.Layout tabs for `StbImage` in Livebook. + + Default value is `Enum.uniq(Application.compile_env(:stb_image, :kino_render_tab_order, @supported_kino_render_tab_order))`. + + where `@supported_kino_render_tab_order` is `[:image, :raw, :numerical]` if `:nx` is available, + otherwise `[:image, :raw]` + """ + @spec kino_render_tab_order([atom()] | nil) :: term() + def kino_render_tab_order(order \\ nil) + + def kino_render_tab_order(nil) do + Process.get(:stb_image_kino_render_tab_order, @kino_render_tab_order) + end - if !supported? do - Logger.warning(""" - Unknown type `#{inspect(t)}` found in `config :stb_image, kino_render_tab_order`. - Supported types are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. - """) + def kino_render_tab_order(order) when is_list(order) do + render_types = + Enum.map(order, fn t -> + supported? = Enum.member?(@supported_kino_render_tab_order, t) - nil - else - t - end - end) - |> Enum.reject(fn a -> a == nil end) + if !supported? do + Logger.warning(""" + Unknown type `#{inspect(t)}` found in `config :stb_image, kino_render_tab_order`. + Supported types are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. + """) - Process.put(:stb_image_kino_render_tab_order, render_types) - end + nil + else + t + end + end) + |> Enum.reject(fn a -> a == nil end) - def kino_render_tab_order(types) do - raise RuntimeError, """ - Unknown order `#{inspect(types)}`. - Supported orders are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. - """ - end + Process.put(:stb_image_kino_render_tab_order, render_types) + end - if Code.ensure_loaded?(Kino.Render) do - defimpl Kino.Render do - require Logger + def kino_render_tab_order(types) do + raise RuntimeError, """ + Unknown order `#{inspect(types)}`. + Supported orders are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. + """ + end defp within_maximum_size(image) do - {max_height, max_width} = StbImage.kino_render_max_size() + {max_height, max_width} = kino_render_max_size() case image.shape do {h, w} -> @@ -239,7 +239,7 @@ defmodule StbImage do @spec to_livebook(StbImage.t()) :: Kino.Output.t() def to_livebook(image) when is_struct(image, StbImage) do - render_types = StbImage.kino_render_tab_order() + render_types = kino_render_tab_order() Enum.map(render_types, fn :raw -> @@ -257,7 +257,7 @@ defmodule StbImage do :image -> {stb_format, kino_format} = - case StbImage.kino_render_encoding() do + case kino_render_encoding() do :jpg -> {:jpg, :jpeg} From 71dc9f2af9fa6a800a1512117ef95f4cb815eca0 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 09:10:12 +0000 Subject: [PATCH 05/12] mix format --- lib/stb_image.ex | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index c481956..1251839 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -111,7 +111,11 @@ defmodule StbImage do defimpl Kino.Render do require Logger - @default_kino_render_encoding Application.compile_env(:stb_image, :kino_render_encoding, :png) + @default_kino_render_encoding Application.compile_env( + :stb_image, + :kino_render_encoding, + :png + ) @doc """ Get preferred image encoding when rendering in Kino. @@ -173,12 +177,12 @@ defmodule StbImage do [:image, :raw] end) @kino_render_tab_order Enum.uniq( - Application.compile_env( - :stb_image, - :kino_render_tab_order, - @supported_kino_render_tab_order - ) - ) + Application.compile_env( + :stb_image, + :kino_render_tab_order, + @supported_kino_render_tab_order + ) + ) @doc """ Get preferred order of Kino.Layout tabs for `StbImage` in Livebook. From 6c947c0c2ddfa9b2d4d47b7e4140037217c9e4ec Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 09:15:30 +0000 Subject: [PATCH 06/12] updated the prompt message when :nx is not available but `:numerical` tab is specified in tab_order --- lib/stb_image.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 1251839..6dcd7a5 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -255,7 +255,7 @@ defmodule StbImage do else {"Numerical", Kino.Markdown.new(""" - Numerical tab require application `:nx`, please add `{:nx, "~> 0.4"}` to the dependency list. + The `Numerical` tab requires application `:nx`, please add `{:nx, "~> 0.4"}` to the dependency list. """)} end From 851a49ca9ea3e94b59ba781a28efb398611c6d05 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Sun, 6 Nov 2022 09:34:46 +0000 Subject: [PATCH 07/12] Update lib/stb_image.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/stb_image.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 6dcd7a5..89d3492 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -105,8 +105,6 @@ defmodule StbImage do "unsupported tensor shape: #{inspect(shape)} (expected height-width-channel)" ) - @compile {:no_warn_undefined, Kino} - if Code.ensure_loaded?(Kino.Render) do defimpl Kino.Render do require Logger From 020332e0b23af5d7475c00c74c1fd45668607f74 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Mon, 7 Nov 2022 14:57:37 +0000 Subject: [PATCH 08/12] using `Application.fetch_env!/2` --- lib/stb_image.ex | 155 +++++++++-------------------------------------- mix.exs | 5 ++ 2 files changed, 34 insertions(+), 126 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 89d3492..bbba957 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -109,139 +109,33 @@ defmodule StbImage do defimpl Kino.Render do require Logger - @default_kino_render_encoding Application.compile_env( - :stb_image, - :kino_render_encoding, - :png - ) - @doc """ - Get preferred image encoding when rendering in Kino. - - Default value is `Application.compile_env(:stb_image, :kino_render_encoding, :png)`. - """ - @spec kino_render_encoding(atom()) :: term() - def kino_render_encoding(encoding \\ nil) - - def kino_render_encoding(nil) do - Process.get(:stb_image_kino_render_encoding, @default_kino_render_encoding) - end - - def kino_render_encoding(encoding) when encoding in [:png, :jpg, :jpeg] do - encoding = - if encoding == :jpeg do - :jpg - else - encoding - end - - Process.put(:stb_image_kino_render_encoding, encoding) - end - - def kino_render_encoding(unsupported_encoding) do - raise RuntimeError, "Encoding #{inspect(unsupported_encoding)} is not supported." - end - - @default_kino_render_max_size Application.compile_env( - :stb_image, - :kino_render_max_size, - {8192, 8192} - ) - @doc """ - Get the maximum allowed image size to render in Kino. - - Default value is `Application.compile_env(:stb_image, :kino_render_max_size, {8192, 8192})`. - """ - @spec kino_render_max_size({integer(), integer()} | nil) :: term() - def kino_render_max_size(max_size \\ nil) - - def kino_render_max_size(nil) do - Process.get(:stb_image_kino_render_max_size, @default_kino_render_max_size) - end - - def kino_render_max_size({height, width}) when is_integer(height) and is_integer(width) do - Process.put(:stb_image_kino_render_max_size, {height, width}) - end - - def kino_render_max_size(unsupported_max_size) do - raise RuntimeError, """ - Invalid parameter for max size, expecting a 2-tuple, {height, width}, - where height and width are both integers. However, got `#{inspect(unsupported_max_size)}` - """ - end - - @supported_kino_render_tab_order (if Code.ensure_loaded?(Nx) do - [:image, :raw, :numerical] - else - [:image, :raw] - end) - @kino_render_tab_order Enum.uniq( - Application.compile_env( - :stb_image, - :kino_render_tab_order, - @supported_kino_render_tab_order - ) - ) - @doc """ - Get preferred order of Kino.Layout tabs for `StbImage` in Livebook. - - Default value is `Enum.uniq(Application.compile_env(:stb_image, :kino_render_tab_order, @supported_kino_render_tab_order))`. - - where `@supported_kino_render_tab_order` is `[:image, :raw, :numerical]` if `:nx` is available, - otherwise `[:image, :raw]` - """ - @spec kino_render_tab_order([atom()] | nil) :: term() - def kino_render_tab_order(order \\ nil) - - def kino_render_tab_order(nil) do - Process.get(:stb_image_kino_render_tab_order, @kino_render_tab_order) - end + defp within_maximum_size(image) do + max_size = Application.fetch_env!(:stb_image, :kino_render_max_size) - def kino_render_tab_order(order) when is_list(order) do - render_types = - Enum.map(order, fn t -> - supported? = Enum.member?(@supported_kino_render_tab_order, t) + case max_size do + {max_height, max_width} when is_integer(max_height) and is_integer(max_width) -> + case image.shape do + {h, w} -> + h <= max_height and w <= max_width - if !supported? do - Logger.warning(""" - Unknown type `#{inspect(t)}` found in `config :stb_image, kino_render_tab_order`. - Supported types are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. - """) + {h, w, _c} -> + h <= max_height and w <= max_width - nil - else - t + _ -> + false end - end) - |> Enum.reject(fn a -> a == nil end) - - Process.put(:stb_image_kino_render_tab_order, render_types) - end - - def kino_render_tab_order(types) do - raise RuntimeError, """ - Unknown order `#{inspect(types)}`. - Supported orders are `#{inspect(@supported_kino_render_tab_order)}` and their combinations. - """ - end - - defp within_maximum_size(image) do - {max_height, max_width} = kino_render_max_size() - - case image.shape do - {h, w} -> - h <= max_height and w <= max_width - - {h, w, _c} -> - h <= max_height and w <= max_width _ -> - false + raise """ + Invalid configuration for max size, expecting a 2-tuple, {height, width}, + where height and width are both integers. However, got `#{inspect(max_size)}` + """ end end @spec to_livebook(StbImage.t()) :: Kino.Output.t() def to_livebook(image) when is_struct(image, StbImage) do - render_types = kino_render_tab_order() + render_types = Application.fetch_env!(:stb_image, :kino_render_tab_order) Enum.map(render_types, fn :raw -> @@ -258,8 +152,14 @@ defmodule StbImage do end :image -> + render_encoding = Application.fetch_env!(:stb_image, :kino_render_encoding) + + if render_encoding not in [:png, :jpg, :jpeg] do + raise "Invalid value for :kino_render_encoding. Expected one of :png, :jpg, :jpeg, got #{inspect(render_encoding)}" + end + {stb_format, kino_format} = - case kino_render_encoding() do + case render_encoding do :jpg -> {:jpg, :jpeg} @@ -268,9 +168,6 @@ defmodule StbImage do :png -> {:png, :png} - - unknown -> - raise RuntimeError, "Cannot render image with encoding `#{inspect(unknown)}`" end with true <- within_maximum_size(image), @@ -281,6 +178,12 @@ defmodule StbImage do _ -> nil end + + type -> + raise """ + Unknown type `#{inspect(type)}`. The set of supported types is `[:image, :raw, :numerical]`. + You can specify any valid subset of it. However, note that `:numerical` one depends on `:nx`. + """ end) |> Enum.reject(fn a -> a == nil end) |> to_livebook_tabs(render_types, image) diff --git a/mix.exs b/mix.exs index c5ef0e9..7a9ec95 100644 --- a/mix.exs +++ b/mix.exs @@ -22,6 +22,11 @@ defmodule StbImage.MixProject do def application do [ + env: [ + kino_render_encoding: :png, + kino_render_max_size: {8192, 8192}, + kino_render_tab_order: [:image, :raw] + ], extra_applications: [:logger] ] end From cb4775448e783274e07e5f92780f348af66b9085 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Mon, 7 Nov 2022 15:10:21 +0000 Subject: [PATCH 09/12] remove `require Logger` --- lib/stb_image.ex | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index bbba957..a6271b1 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -20,8 +20,6 @@ defmodule StbImage do There are also specific functions for working with GIFs. """ - require Logger - @doc """ The `StbImage` struct. @@ -107,8 +105,6 @@ defmodule StbImage do if Code.ensure_loaded?(Kino.Render) do defimpl Kino.Render do - require Logger - defp within_maximum_size(image) do max_size = Application.fetch_env!(:stb_image, :kino_render_max_size) From acf4682011f7e65948a3f3a276309dba400e0da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 8 Nov 2022 12:37:59 +0100 Subject: [PATCH 10/12] Apply suggestions from code review --- lib/stb_image.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index a6271b1..489ef5c 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -123,8 +123,8 @@ defmodule StbImage do _ -> raise """ - Invalid configuration for max size, expecting a 2-tuple, {height, width}, - where height and width are both integers. However, got `#{inspect(max_size)}` + invalid :kino_render_max_size configuration. Expected a 2-tuple, {height, width}, + where height and width are both integers. Got: #{inspect(max_size)} """ end end @@ -151,7 +151,7 @@ defmodule StbImage do render_encoding = Application.fetch_env!(:stb_image, :kino_render_encoding) if render_encoding not in [:png, :jpg, :jpeg] do - raise "Invalid value for :kino_render_encoding. Expected one of :png, :jpg, :jpeg, got #{inspect(render_encoding)}" + raise "invalid :kino_render_encoding value. Expected one of :png, :jpg, or :jpeg. Got: #{inspect(render_encoding)}" end {stb_format, kino_format} = @@ -177,8 +177,8 @@ defmodule StbImage do type -> raise """ - Unknown type `#{inspect(type)}`. The set of supported types is `[:image, :raw, :numerical]`. - You can specify any valid subset of it. However, note that `:numerical` one depends on `:nx`. + invalid :kino_render_tab_order configuration. The set of supported types are [:image, :raw, :numerical]. + Got: #{inspect(type)} """ end) |> Enum.reject(fn a -> a == nil end) From 706b5180f99a427af19c224ada807ba831d15a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 8 Nov 2022 12:53:47 +0100 Subject: [PATCH 11/12] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonatan Kłosko --- lib/stb_image.ex | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 489ef5c..9650536 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -150,10 +150,6 @@ defmodule StbImage do :image -> render_encoding = Application.fetch_env!(:stb_image, :kino_render_encoding) - if render_encoding not in [:png, :jpg, :jpeg] do - raise "invalid :kino_render_encoding value. Expected one of :png, :jpg, or :jpeg. Got: #{inspect(render_encoding)}" - end - {stb_format, kino_format} = case render_encoding do :jpg -> @@ -164,6 +160,9 @@ defmodule StbImage do :png -> {:png, :png} + + _ -> + raise "invalid :kino_render_encoding configuration. Expected one of :png, :jpg, or :jpeg. Got: #{inspect(render_encoding)}" end with true <- within_maximum_size(image), @@ -181,7 +180,7 @@ defmodule StbImage do Got: #{inspect(type)} """ end) - |> Enum.reject(fn a -> a == nil end) + |> Enum.reject(&is_nil/1) |> to_livebook_tabs(render_types, image) end From 5f55c463612350f6697d416277152f80af482f0b Mon Sep 17 00:00:00 2001 From: Cocoa Date: Tue, 8 Nov 2022 12:08:03 +0000 Subject: [PATCH 12/12] Remove redundant matching `image.shape` is always `{h, w ,c}` --- lib/stb_image.ex | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/stb_image.ex b/lib/stb_image.ex index 9650536..9900aae 100644 --- a/lib/stb_image.ex +++ b/lib/stb_image.ex @@ -110,16 +110,8 @@ defmodule StbImage do case max_size do {max_height, max_width} when is_integer(max_height) and is_integer(max_width) -> - case image.shape do - {h, w} -> - h <= max_height and w <= max_width - - {h, w, _c} -> - h <= max_height and w <= max_width - - _ -> - false - end + {h, w, _c} = image.shape + h <= max_height and w <= max_width _ -> raise """