Packages

Bindings to the C++ pHash library (phash.org).

Current section

Files

Jump to
phash lib phash.ex
Raw

lib/phash.ex

defmodule PHash do
use Unsafe.Generator, docs: true
alias PHash.NIFs
@doc """
Reads an image from a path and produces a hash that can be compared
with another hash via `PHash.image_hash_distance/2`.
"""
def image_file_hash(image_path) when is_binary(image_path) do
if File.exists?(image_path) do
if File.dir?(image_path) do
{:error, :eisdir}
else
NIFs.image_hash(image_path)
end
else
{:error, :enoent}
end
end
@doc """
Write the image binary data to a temporary file and produces the same result
as `PHash.image_file_hash/1` using that file.
## Options:
- `extension` - an extension to be added to the temporary file created (e.g. ".gif")
(default: "").
"""
def image_binary_hash(image_data, opts \\ []) when is_binary(image_data) do
Temp.track!()
ext = opts[:extension] || ""
result =
with {:ok, file_path} <-
Temp.open([prefix: "phash", suffix: ext], &IO.binwrite(&1, image_data)) do
image_file_hash(file_path)
end
Temp.cleanup()
result
end
@doc """
Calculates the hamming distance between two image hashes.
"""
def image_hash_distance(hash_a, hash_b)
when is_integer(hash_a) and is_integer(hash_b) and hash_a > 0 and hash_b > 0 do
NIFs.image_hash_distance(hash_a, hash_b)
end
@unsafe [
{:image_file_hash, 1, :unwrap},
{:image_binary_hash, [1, 2], :unwrap}
]
defp unwrap({:ok, result}), do: result
defp unwrap({:error, err}), do: raise(PHash.HashingError, err)
end
defmodule PHash.HashingError do
defexception [:message]
@impl true
def exception(error) do
%PHash.HashingError{
message: "Hashing failed: #{error}"
}
end
end