aseprite/tests/scripts/inks.lua

518 lines
15 KiB
Lua
Raw Normal View History

-- Copyright (C) 2020-2023 Igara Studio S.A.
--
-- This file is released under the terms of the MIT license.
-- Read LICENSE.txt for more information.
dofile('./test_utils.lua')
local colorModes = { ColorMode.RGB,
ColorMode.GRAY,
ColorMode.INDEXED }
local pencil = "pencil"
local pc = app.pixelColor
local function gray(g)
return pc.graya(g, 255)
end
function test_inks(colorMode)
-- Test ink over a transparent sprite
local s = Sprite(3, 3, colorMode)
local p, a, b, c, d
if colorMode == ColorMode.GRAY then
p = s.palettes[1]
a, b, c, d = gray(0), gray(64), gray(128), gray(255)
else
p = Palette()
p:resize(4)
p:setColor(0, Color(0, 0, 0))
p:setColor(1, Color(64, 64, 64))
p:setColor(2, Color(128, 128, 128))
p:setColor(3, Color(255, 255, 255))
s:setPalette(p)
a, b, c, d = 0, 1, 2, 3
if colorMode == ColorMode.RGB then
a = p:getColor(a).rgbaPixel
b = p:getColor(b).rgbaPixel
c = p:getColor(c).rgbaPixel
d = p:getColor(d).rgbaPixel
end
end
-- With simple ink opacity doesn't have affect (always the color)
local opacities = { 0, 128, 255 }
for i = 1,#opacities do
expect_img(app.activeImage,
{ 0, 0, 0,
0, 0, 0,
0, 0, 0 })
app.useTool{ tool=pencil, color=d, points={ Point(0, 0), Point(2, 2) },
ink=Ink.SIMPLE, opacity=opacities[i] }
expect_img(app.activeImage,
{ d, 0, 0,
0, d, 0,
0, 0, d })
if i < #opacities then app.undo() end
end
-- Check that painting with transparent index (color) on a
-- transparent layer (using any value of opacity) with alpha
-- compositing doesn't modify pixels
for i = 1,#opacities do
app.useTool{ tool=pencil, color=0, points={ Point(1, 1) },
ink=Ink.ALPHA_COMPOSITING, opacity=opacities[i] }
expect_img(app.activeImage,
{ d, 0, 0,
0, d, 0,
0, 0, d })
end
-- Convert to background layer
app.bgColor = Color{ index=0 }
app.command.BackgroundFromLayer()
app.useTool{ tool=pencil, color=d, points={ Point(0, 1), Point(2, 1) },
ink=Ink.ALPHA_COMPOSITING, opacity=64 }
expect_img(app.activeImage,
{ d, a, a,
b, d, b,
a, a, d })
app.useTool{ tool=pencil, color=d, points={ Point(0, 1) },
ink=Ink.ALPHA_COMPOSITING, opacity=86 }
expect_img(app.activeImage,
{ d, a, a,
c, d, b,
a, a, d })
----------------------------------------------------------------------
-- Inks with custom brushes
function test_custom_brush_inks(brushColorMode)
-- Colors in the brush image (ba, bb, bc, bd)
local ba, bb, bc, bd
if brushColorMode == ColorMode.RGB then
ba = Color(0, 0, 0)
bb = Color(64, 64, 64)
bc = Color(128, 128, 128)
bd = Color(255, 255, 255)
elseif brushColorMode == ColorMode.GRAY then
ba, bb, bc, bd = gray(0), gray(64), gray(128), gray(255)
else
ba, bb, bc, bd = 0, 1, 2, 3
end
local brushImage = Image(2, 2, brushColorMode)
array_to_pixels({ 0, bd,
bc, 0 }, brushImage)
local brush = Brush(brushImage)
-- da, db, dc, dd are the final result after painting the custom
-- brush in the sprite
local ra, rb, rc, rd
if s.colorMode ~= ColorMode.INDEXED and
brushColorMode == ColorMode.INDEXED then
-- For indexed images we take the index of the brush and use the
-- sprite palette, we are not sure if this in the future might
-- change, e.g. having the original palette that was used to
-- create the brush integrated to the brush itself, in that case
-- we should convert the brush index using the same brush
-- palette (instead of the sprite palette).
--
-- TODO check BrushInkProcessingBase comment for more information
if s.colorMode == ColorMode.RGB then
ra, rb, rc, rd =
p:getColor(ba).rgbaPixel,
p:getColor(bb).rgbaPixel,
p:getColor(bc).rgbaPixel,
p:getColor(bd).rgbaPixel
else
ra, rb, rc, rd =
p:getColor(ba).grayPixel,
p:getColor(bb).grayPixel,
p:getColor(bc).grayPixel,
p:getColor(bd).grayPixel
end
else
ra, rb, rc, rd = a, b, c, d
end
array_to_pixels({ a, a, a,
a, a, a,
a, a, a }, app.activeImage)
-- Simple
expect_img(app.activeImage,
{ a, a, a,
a, a, a,
a, a, a })
app.useTool{ tool=pencil, brush=brush, points={ Point(2, 2) },
ink=Ink.SIMPLE }
expect_img(app.activeImage,
{ a, a, a,
a, a, rd,
a, rc, a })
-- Alpha Compositing
app.useTool{ tool=pencil, brush=brush, points={ Point(1, 1) },
ink=Ink.ALPHA_COMPOSITING, opacity=255 }
expect_img(app.activeImage,
{ a, rd, a,
rc, a, rd,
a, rc, a })
local qc, qd
if s.colorMode == ColorMode.GRAY and
brushColorMode == ColorMode.INDEXED then
qc = gray(pc.grayaV(rc)/2)
qd = gray(pc.grayaV(rd)/2)
else
qc, qd = rb, rc
end
app.useTool{ tool=pencil, brush=brush, points={ Point(1, 2) },
ink=Ink.ALPHA_COMPOSITING, opacity=128 }
expect_img(app.activeImage,
{ a, rd, a,
rc, qd, rd,
qc, rc, a })
-- TODO test Lock Alpha, Copy Color+Alpha, Shading...
end
for j = 1,#colorModes do
test_custom_brush_inks(colorModes[j])
end
end
function test_alpha_compositing_on_indexed_with_full_opacity_and_repeated_colors_in_palette()
local s = Sprite(1, 1, ColorMode.INDEXED)
local p = Palette()
p:resize(5)
p:setColor(0, Color(0, 0, 0))
p:setColor(1, Color(64, 64, 64))
p:setColor(2, Color(128, 128, 128))
p:setColor(3, Color(128, 128, 128))
p:setColor(4, Color(255, 255, 255))
s:setPalette(p)
local inks = { Ink.SIMPLE, Ink.ALPHA_COMPOSITING }
-- k=1 -> transparent layer
-- k=2 -> background layer
for k=1,2 do
if k == 2 then app.command.BackgroundFromLayer() end
-- i=1 -> simple ink
-- i=2 -> alpha compositing ink
for i = 1,2 do
-- j=color index
for j = 0,4 do
expect_img(app.activeImage, { 0 })
app.useTool{ tool="pencil", color=j, points={ Point(0, 0) },
ink=inks[i], opacity=255 }
expect_img(app.activeImage, { j })
app.undo()
end
end
end
end
for i = 1,#colorModes do
test_inks(colorModes[i])
end
test_alpha_compositing_on_indexed_with_full_opacity_and_repeated_colors_in_palette()
----------------------------------------------------------------------
-- Test painting with transparent color on indexed
----------------------------------------------------------------------
do
local s = Sprite(2, 2, ColorMode.INDEXED)
s.transparentColor = 0
app.bgColor = 0
2022-03-03 00:37:30 +00:00
app.command.BackgroundFromLayer()
assert(app.activeLayer.isBackground)
expect_img(app.activeImage, { 0, 0,
0, 0 })
app.useTool{ tool="pencil", color=Color{r=0,g=0,b=0},
points={ Point(0, 0) },
ink=Ink.SIMPLE }
expect_img(app.activeImage, { 0, 0,
0, 0 })
-- Test that painting in the background layer with transparent color
-- with alpha compositing and all opacity=255, will use the transparent
-- index anyway. Reported here: https://github.com/aseprite/aseprite/issues/3047
app.useTool{ tool="pencil", color=0,
points={ Point(0, 0) },
ink=Ink.ALPHA_COMPOSITING,
opacity=255 }
expect_img(app.activeImage, { 0, 0,
0, 0 })
-- Other cases should keep working
local p = s.palettes[1]
-- palette with only 3 colors: white, gray (50%), black
p:setColor(0, Color{ r=255, g=255, b=255 })
p:setColor(1, Color{ r=128, g=128, b=128 })
p:setColor(2, Color{ r=0, g=0, b=0 })
app.useTool{ tool="paint_bucket", color=2,
points={ Point(0, 0) },
ink=Ink.SIMPLE }
2022-03-03 00:37:30 +00:00
expect_img(app.activeImage, { 2, 2,
2, 2 })
-- White over black w/opacity=50% => gray
app.useTool{ tool="pencil", color=0,
points={ Point(0, 0) },
ink=Ink.ALPHA_COMPOSITING,
opacity=128 }
expect_img(app.activeImage, { 1, 2,
2, 2 })
-- White over gray w/opacity=51% => white
app.useTool{ tool="pencil", color=0,
points={ Point(0, 0) },
ink=Ink.ALPHA_COMPOSITING,
opacity=129 }
expect_img(app.activeImage, { 0, 2,
2, 2 })
end
----------------------------------------------------------------------
-- Tests for Paint Bucket Tool with image brush and
-- pattern alignment SRC (ORIGIN) vs DST (TARGET)
----------------------------------------------------------------------
do
local s = Sprite(3, 3, ColorMode.INDEXED)
array_to_pixels({ 0, 0, 0,
0, 0, 0,
0, 0, 0 }, app.activeImage)
local brushImage = Image(2, 2, ColorMode.INDEXED)
array_to_pixels({ 0, 1,
2, 0 }, brushImage)
brush = Brush{
image=brushImage,
pattern=BrushPattern.ORIGIN
}
app.useTool{ tool="paint_bucket", brush=brush, points={ Point(0, 0) } }
expect_img(app.activeImage,
{ 0, 1, 0,
2, 0, 2,
0, 1, 0 })
app.undo()
app.useTool{ tool="paint_bucket", brush=brush, points={ Point(1, 0) } }
expect_img(app.activeImage,
{ 0, 1, 0,
2, 0, 2,
0, 1, 0 })
app.undo()
brush = Brush{
image=brushImage,
pattern=BrushPattern.TARGET
}
app.useTool{ tool="paint_bucket", brush=brush, points={ Point(1, 1) } }
expect_img(app.activeImage,
{ 0, 1, 0,
2, 0, 2,
0, 1, 0 })
app.undo()
app.useTool{ tool="paint_bucket", brush=brush, points={ Point(2, 1) } }
expect_img(app.activeImage,
{ 1, 0, 1,
0, 2, 0,
1, 0, 1})
Fix transparent color is possible on opaque sprites (fix #4370) To reproduce the error before this fix on RGBA/Grayscale Color Mode: - New 100x100 RGBA/Grayscale opaque sprite (white background). - Draw something with some gray color in the palette. - Keep the selected gray color as primary color. - Configure as secondary color the mask color (#000000 alpha=0). - Pick 'eraser' tool and erase over the gray color with right click. - Result: The sprite doesn't look more opaque, which is wrong. Also, if we export this sprite, the transparent parts will turn black. A similar problem occurs in Indexed Color Mode, but getting a transparent color in a Background sprite is inevitable if the color of a palette entry is transparent or semi-transparent, since the index must be set as is. This could be fixed in the future at the render stage, however, this could lead to other perceived inconsistencies. For now it'll be left as is. Original issue description: Downloaded PNG in RGB mode fails to support transparency: erase uses secondary color and export PNG replaces transparent color with black Added tests for 'eraser' in 'Replace Color Mode' To make the eraser work in 'Replace Color Mode' within the tests, was implemented the possibility of using the right button in the creation of the point vector. During testing with UI available it was observed that the 'bg' color was copied from the 'fg'. Changed this to be compatible with the way the default value of 'fg' is assigned when it is not specified. This last modification resulted in errors during 'tilemap.lua' due to incompatibility of the type of 'bg' color. This was corrected considering the color type of 'fg' color. Furthermore, it was found that the command 'app.range.tiles = { 1 }' did not finish assigning the tile picks to the activeSite, then 'assert(1, #app.range.tiles)' was failing. This was fixed too.
2024-08-22 14:07:54 +00:00
end
----------------------------------------------------------------------
-- Tests for Eraser Tool, normal erase and replace color erasing
----------------------------------------------------------------------
do
-- Indexed image + background layer +
-- the mask color is in the palette and it's defined as
-- transparent color
local s = Sprite(3, 3, ColorMode.INDEXED)
local p = s.palettes[1]
p:setColor(0, Color{ r=0 , g=0 , b=0 , a=255 })
p:setColor(1, Color{ r=255, g=0 , b=0 , a=255 })
p:setColor(2, Color{ r=0 , g=255, b=0 , a=255 })
p:setColor(3, Color{ r=0 , g=0 , b=255, a=255 })
p:setColor(4, Color{ r=255, g=255, b=0 , a=255 })
p:setColor(5, Color{ r=255, g=255, b=255, a=255 })
p:setColor(6, Color{ r=0 , g=0 , b=0 , a=0 })
p:resize(7)
app.fgColor = 0
app.bgColor = 0
app.command.BackgroundFromLayer()
expect_img(app.activeImage,
{ 0, 0, 0,
0, 0, 0,
0, 0, 0 })
s.transparentColor = 6 -- mask color as transparent color
app.fgColor = 1
app.bgColor = 3
app.useTool{ tool='pencil',
points={ Point(0, 0), Point(2, 0)} }
app.useTool{ tool='pencil',
color=2,
points={ Point(0, 1), Point(2, 1)} }
app.useTool{ tool='pencil',
button=MouseButton.RIGHT,
points={ Point(0, 2), Point(2, 2)} }
expect_img(app.activeImage,
{ 1, 1, 1,
2, 2, 2,
3, 3, 3 })
app.fgColor = 2
app.bgColor = 6 -- (mask color)
app.useTool{ tool='eraser',
button=MouseButton.LEFT,
points={ Point(0, 0), Point(0, 2) } }
expect_img(app.activeImage,
{ 6, 1, 1,
6, 2, 2,
6, 3, 3 })
app.useTool{ tool='eraser',
button=MouseButton.RIGHT,
points={ Point(1, 0), Point(1, 2) } }
expect_img(app.activeImage,
{ 6, 1, 1,
6, 6, 2,
6, 3, 3 })
end
-- Tests for Eraser Tool with RGBA image + background layer
do
local s = Sprite(3, 3, ColorMode.RGB)
local p = s.palettes[1]
local c0 = pc.rgba(0 , 0, 0, 255)
local c1 = pc.rgba(255, 0, 0, 255)
local c2 = pc.rgba(0 , 255, 0, 255)
local c3 = pc.rgba(0 , 0, 255, 255)
local c4 = pc.rgba(255, 255, 0, 255)
local c5 = pc.rgba(255, 255, 255, 255)
local c6 = pc.rgba(0 , 0, 0, 0)
Fix transparent color is possible on opaque sprites (fix #4370) To reproduce the error before this fix on RGBA/Grayscale Color Mode: - New 100x100 RGBA/Grayscale opaque sprite (white background). - Draw something with some gray color in the palette. - Keep the selected gray color as primary color. - Configure as secondary color the mask color (#000000 alpha=0). - Pick 'eraser' tool and erase over the gray color with right click. - Result: The sprite doesn't look more opaque, which is wrong. Also, if we export this sprite, the transparent parts will turn black. A similar problem occurs in Indexed Color Mode, but getting a transparent color in a Background sprite is inevitable if the color of a palette entry is transparent or semi-transparent, since the index must be set as is. This could be fixed in the future at the render stage, however, this could lead to other perceived inconsistencies. For now it'll be left as is. Original issue description: Downloaded PNG in RGB mode fails to support transparency: erase uses secondary color and export PNG replaces transparent color with black Added tests for 'eraser' in 'Replace Color Mode' To make the eraser work in 'Replace Color Mode' within the tests, was implemented the possibility of using the right button in the creation of the point vector. During testing with UI available it was observed that the 'bg' color was copied from the 'fg'. Changed this to be compatible with the way the default value of 'fg' is assigned when it is not specified. This last modification resulted in errors during 'tilemap.lua' due to incompatibility of the type of 'bg' color. This was corrected considering the color type of 'fg' color. Furthermore, it was found that the command 'app.range.tiles = { 1 }' did not finish assigning the tile picks to the activeSite, then 'assert(1, #app.range.tiles)' was failing. This was fixed too.
2024-08-22 14:07:54 +00:00
p:setColor(0, c0)
p:setColor(1, c1)
p:setColor(2, c2)
p:setColor(3, c3)
p:setColor(4, c4)
p:setColor(5, c5)
p:setColor(6, c6)
p:resize(7)
app.fgColor = c0
app.bgColor = c0
app.command.BackgroundFromLayer()
expect_img(app.activeImage,
{ c0, c0, c0,
c0, c0, c0,
c0, c0, c0 })
app.fgColor = c1
app.bgColor = c3
app.useTool{ tool='pencil',
points={ Point(0, 0), Point(2, 0)} }
app.useTool{ tool='pencil',
color=c2,
points={ Point(0, 1), Point(2, 1)} }
app.useTool{ tool='pencil',
button=MouseButton.RIGHT,
points={ Point(0, 2), Point(2, 2)} }
expect_img(app.activeImage,
{ c1, c1, c1,
c2, c2, c2,
c3, c3, c3 })
app.fgColor = c2
app.bgColor = c6
app.useTool{ tool='eraser',
button=MouseButton.LEFT,
points={ Point(0, 0), Point(0, 2) } }
expect_img(app.activeImage,
{ c0, c1, c1,
c0, c2, c2,
c0, c3, c3 })
app.useTool{ tool='eraser',
button=MouseButton.RIGHT,
points={ Point(1, 0), Point(1, 2) } }
expect_img(app.activeImage,
{ c0, c1, c1,
c0, c0, c2,
c0, c3, c3 })
end
-- Tests for Eraser Tool with GRAYSCALE image + background layer
do
local s = Sprite(3, 3, ColorMode.GRAYSCALE)
local p = s.palettes[1]
local c0 = pc.graya( 0, 255)
local c1 = pc.graya( 63, 255)
local c2 = pc.graya(127, 255)
local c3 = pc.graya(191, 255)
local c4 = pc.graya(255, 255)
local c5 = pc.graya( 0, 0)
Fix transparent color is possible on opaque sprites (fix #4370) To reproduce the error before this fix on RGBA/Grayscale Color Mode: - New 100x100 RGBA/Grayscale opaque sprite (white background). - Draw something with some gray color in the palette. - Keep the selected gray color as primary color. - Configure as secondary color the mask color (#000000 alpha=0). - Pick 'eraser' tool and erase over the gray color with right click. - Result: The sprite doesn't look more opaque, which is wrong. Also, if we export this sprite, the transparent parts will turn black. A similar problem occurs in Indexed Color Mode, but getting a transparent color in a Background sprite is inevitable if the color of a palette entry is transparent or semi-transparent, since the index must be set as is. This could be fixed in the future at the render stage, however, this could lead to other perceived inconsistencies. For now it'll be left as is. Original issue description: Downloaded PNG in RGB mode fails to support transparency: erase uses secondary color and export PNG replaces transparent color with black Added tests for 'eraser' in 'Replace Color Mode' To make the eraser work in 'Replace Color Mode' within the tests, was implemented the possibility of using the right button in the creation of the point vector. During testing with UI available it was observed that the 'bg' color was copied from the 'fg'. Changed this to be compatible with the way the default value of 'fg' is assigned when it is not specified. This last modification resulted in errors during 'tilemap.lua' due to incompatibility of the type of 'bg' color. This was corrected considering the color type of 'fg' color. Furthermore, it was found that the command 'app.range.tiles = { 1 }' did not finish assigning the tile picks to the activeSite, then 'assert(1, #app.range.tiles)' was failing. This was fixed too.
2024-08-22 14:07:54 +00:00
p:setColor(0, c0)
p:setColor(1, c1)
p:setColor(2, c2)
p:setColor(3, c3)
p:setColor(4, c4)
p:setColor(5, c5)
p:resize(6)
app.fgColor = c0
app.bgColor = c0
app.command.BackgroundFromLayer()
expect_img(app.activeImage,
{ c0, c0, c0,
c0, c0, c0,
c0, c0, c0 })
app.fgColor = c1
app.bgColor = c3
app.useTool{ tool='pencil',
points={ Point(0, 0), Point(2, 0)} }
app.useTool{ tool='pencil',
color=c2,
points={ Point(0, 1), Point(2, 1)} }
app.useTool{ tool='pencil',
button=MouseButton.RIGHT,
points={ Point(0, 2), Point(2, 2)} }
expect_img(app.activeImage,
{ c1, c1, c1,
c2, c2, c2,
c3, c3, c3 })
app.fgColor = c2
app.bgColor = c5
app.useTool{ tool='eraser',
button=MouseButton.LEFT,
points={ Point(0, 0), Point(0, 2) } }
expect_img(app.activeImage,
{ c0, c1, c1,
c0, c2, c2,
c0, c3, c3 })
app.useTool{ tool='eraser',
button=MouseButton.RIGHT,
points={ Point(1, 0), Point(1, 2) } }
expect_img(app.activeImage,
{ c0, c1, c1,
c0, c0, c2,
c0, c3, c3 })
end