I have the following code to check whether a certain Vix.Vips.Image
consists only of a single colour:
defmodule Spritesheet do
def single_color_tile?(%Vix.Vips.Image{} = image) do
initial_colour = Image.get_pixel!(image, 0, 0) |> dbg()
coordinates =
for x <- 0..(Image.width(image) - 1), y <- 0..(Image.height(image) - 1), do: {x, y}
Enum.all?(coordinates, fn {x, y} -> Image.get_pixel!(image, x, y) == initial_colour end)
end
end
It works, but it is slow: Checking a 128x128 px image takes a few seconds. The following testcases need 7 seconds to finish on my machine.
describe "single_color_tile?" do
test "all transparent black" do
assert Spritesheet.single_color_tile?(Image.new!(128, 128, color: [0, 0, 0, 0]))
end
test "all solid green" do
assert Spritesheet.single_color_tile?(Image.new!(128, 128, color: [0, 255, 0, 255]))
end
test "red solid circle on transparent background" do
refute Spritesheet.single_color_tile?(
Image.new!(16, 16, color: [0, 0, 0, 0])
|> Image.Draw.circle!(7, 7, 7, color: [255, 0, 0, 255])
)
end
end
I was initially quite hopeful that I could trick Image.dominant_color
into computing this, but I probably missunderstand the purpose of that function: For me it only returns colours that are not part of the given image:
> Image.new!(1, 1, color: [0, 0, 0, 0]) |> Image.dominant_color!(bins: 1)
[128, 128, 128]
> Image.new!(1, 1, color: [0, 0, 0, 0]) |> Image.dominant_color!(bins: 16)
[8, 8, 8]
> Image.new!(1, 1, color: [0, 0, 0, 0]) |> Image.dominant_color!(bins: 255)
[1, 234, 1]
Is there a builtin Image
function that I am overlooking? Or a way to access the raw image data for more efficient iteration?