Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions lib/image/pixel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -525,26 +525,20 @@ defmodule Image.Pixel do
end
end

# Encoders grouped by their alpha band's max value
@alpha_max_255 [:uchar_rgb, :uchar_cmyk, :uchar_hsv, :uchar_grey, :float_lab, :float_lch, :short_lab]
@alpha_max_65535 [:ushort_rgb, :ushort_grey]

# The alpha band uses the same numeric type as the rest of the
# interpretation: 0..255 for uchar, 0..65535 for ushort, 0.0..1.0
# for float-typed bands. LABS / Lab / LCH happen to be float-typed
# interpretations whose alpha band is also a float in [0, 1].
# for float-typed bands. scRGB is the only float interpretation whose
# alpha is in [0, 1]. LABS / Lab / LCH carry a 0..255 alpha band
# despite their float/short color bands.
defp scale_alpha_to_encoder(alpha, encoder) do
case encoder do
e when e in [:uchar_rgb, :uchar_cmyk, :uchar_hsv, :uchar_grey] ->
scale(alpha, 255)

e when e in [:ushort_rgb, :ushort_grey] ->
scale(alpha, 65_535)

:float_rgb ->
alpha * 1.0

e when e in [:float_lab, :float_lch] ->
alpha * 1.0

:short_lab ->
round(alpha * 65_535)
e when e in @alpha_max_255 -> scale(alpha, 255)
e when e in @alpha_max_65535 -> scale(alpha, 65_535)
:float_rgb -> alpha * 1.0
end
end

Expand Down
33 changes: 33 additions & 0 deletions test/pixel_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,39 @@ defmodule Image.PixelTest do
end
end

describe "to_pixel/3 alpha scale matches the interpretation's max alpha" do
defp with_alpha(colorspace) do
{:ok, srgba} = Image.new(2, 2, color: [10, 20, 30, 255])
{:ok, image} = Image.to_colorspace(srgba, colorspace)
image
end

test "opaque alpha resolves to 255 for every 0..255-scale interpretation" do
for colorspace <- [:srgb, :cmyk, :hsv, :bw, :lab, :lch, :labs] do
image = with_alpha(colorspace)
{:ok, pixel} = Pixel.to_pixel(image, :red, alpha: :opaque)
assert List.last(pixel) == 255, "#{colorspace} opaque alpha was #{List.last(pixel)}"
end
end

test "scRGB opaque alpha stays 1.0" do
image = with_alpha(:scrgb)
assert {:ok, [_r, _g, _b, alpha]} = Pixel.to_pixel(image, :red, alpha: :opaque)
assert alpha == 1.0
end

test "a plain color (no explicit :alpha) also synthesizes opaque 255 on Lab" do
image = with_alpha(:lab)
assert {:ok, [_l, _a, _b, 255]} = Pixel.to_pixel(image, :red)
end

test "alpha 0.5 resolves to 128 on Lab" do
image = with_alpha(:lab)
assert {:ok, [_l, _a, _b, alpha]} = Pixel.to_pixel(image, :red, alpha: 0.5)
assert alpha == 128
end
end

describe "to_pixel/3 against a CMYK image" do
setup do
{:ok, image} = Image.new(2, 2, color: :black)
Expand Down