Skip to content

Commit 0d37a96

Browse files
committed
Add Image.from_req_stream/2
1 parent 6631b76 commit 0d37a96

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## Image 0.61.0
4+
5+
This is the changelog for Image version 0.60.0 released on July 2nd, 2025. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-image/image/tags)
6+
7+
### Enhancements
8+
9+
* Adds `Image.from_req_stream/2`. This function returns a `Vix.Vips.Image.t/0` from streaming a `Req` request using the `Req.get/2` option `into: :self`,
10+
311
## Image 0.60.0
412

513
This is the changelog for Image version 0.60.0 released on June 27th, 2025. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-image/image/tags)

lib/image.ex

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,107 @@ defmodule Image do
15381538
end
15391539
end
15401540

1541+
if Code.ensure_loaded?(Req) do
1542+
@default_req_timeout 5000
1543+
1544+
@doc """
1545+
Opens an image as a stream from a URL that will be retrieved
1546+
by [Req](https://github.com/wojtekmach/req) request.
1547+
1548+
The URL is retrieved by `Req.get!(url, into: :self)` which is then
1549+
wrapped in a `Stream.resource/3` and opened as a streaming image.
1550+
1551+
### Arguments
1552+
1553+
* `url` is any URL representing an image or a t:Req.Request.t/1
1554+
1555+
* `options` is a keyword list of options.
1556+
1557+
### Options
1558+
1559+
* `:timeout` is an integer number of milliseconds upon which
1560+
the next chunk of the image stream is waited. If the timeout is
1561+
exceeded then an error is returned. The default is #{@default_req_timeout}
1562+
milliseconds.
1563+
1564+
### Returns
1565+
1566+
* `{:ok, image}` or
1567+
1568+
* `{:error reason}`
1569+
1570+
### Notes
1571+
1572+
* Due to the nature of the interaction between Req and Vix, error
1573+
responses from the embedded `Reg.get/2` are swallowed and a generic
1574+
`{:error, "Failed to find loader for the source"}` may be returned instead.
1575+
1576+
### Example
1577+
1578+
url = "https://files.amoi.no/dog.webp"
1579+
Image.from_req_stream(url)
1580+
{:ok, %Vix.Vips.Image{ref: #Reference<0.3575018002.2188509222.143025>}}
1581+
1582+
"""
1583+
@doc since: "0.61.0"
1584+
1585+
@spec from_req_stream(url_or_request :: binary() | Req.Request.t()) ::
1586+
{:ok, image :: %Vimage{}} | {:error, error_message()}
1587+
1588+
def from_req_stream(url_or_request, options \\ []) do
1589+
timeout = Keyword.get(options, :timeout, @default_req_timeout)
1590+
1591+
body_stream =
1592+
Stream.resource(
1593+
fn ->
1594+
case Req.get(url_or_request, into: :self) do
1595+
{:ok, %Req.Response{status: 200} = resp} -> resp
1596+
other -> other
1597+
end
1598+
end,
1599+
fn
1600+
%Req.Response{status: 200} = resp ->
1601+
case Req.parse_message(resp, get_req_message(timeout)) do
1602+
{:ok, chunks} ->
1603+
data_chunks =
1604+
chunks
1605+
|> Enum.filter(&match?({:data, _}, &1))
1606+
|> Enum.map(fn {:data, binary} -> binary end)
1607+
1608+
if Enum.any?(chunks, &(&1 == :done)) do
1609+
{data_chunks, {:done, resp}}
1610+
else
1611+
{data_chunks, resp}
1612+
end
1613+
end
1614+
1615+
{:done, resp} ->
1616+
{:halt, resp}
1617+
1618+
resp ->
1619+
{:halt, resp}
1620+
end,
1621+
fn
1622+
%Req.Response{} = resp ->
1623+
Req.cancel_async_response(resp)
1624+
other ->
1625+
other
1626+
end
1627+
)
1628+
1629+
Vix.Vips.Image.new_from_enum(body_stream)
1630+
end
1631+
end
1632+
1633+
defp get_req_message(timeout) do
1634+
receive do
1635+
message -> message
1636+
after
1637+
timeout ->
1638+
{:error, :timed_out}
1639+
end
1640+
end
1641+
15411642
@doc """
15421643
Write an image to a file, a stream, an enumerable or
15431644
to memory returning the image or raising an exception.

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Image.MixProject do
22
use Mix.Project
33

4-
@version "0.60.0"
4+
@version "0.61.0"
55

66
@app_name "image"
77

0 Bytes
Binary file not shown.
863 KB
Loading

0 commit comments

Comments
 (0)