When we are in Indexed mode we can have a specific index as the
transparent color, if we convert the sprite to RGB, that transparent
color is lost, so we have to save it (in a cmd::SetTransparentColor)
to restore it correctly when we undo the ChangePixelFormatCommand.
Original issue title: When using a background layer, switching to
Indexed Color Mode fills all layer bounding rectangles with
Color 0.
Conditions to reproduce the original issue:
- Opaque RGBA sprite, i.e. the bottom layer is 'Background'.
- There is a second layer with an ellipse (for example).
- There is a mask color #000000 alpha=0 is in the palette.
- The mask color index is greater and not equal than 0.
- Go to Sprite > Color Mode > Indexed.
Result: the transparent color of the second layer will change to
index color = 0 (usually black).
Also added test for RGBA->INDEXED conversion
Before this fix, the lua command:
app.command.ExportSpriteSheet
could not process a layer within a group when the layer name
was expressed using the layer hierarchy path, for example:
layer = "Group1/Layer1"
We can select the default color or tile from preferences depending if
we're going to paint pixels or tiles
Fixes a confusing logic from 4a91d150af
where the bg color was obtained from preferences only when the fg
color type (rgb/gray/index/hsv/tile/etc.) was equal to the bg color
type from the preferences (rgb/gray/index/hsv/tile/etc.).
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.
Added other color comparison criterias (fit criteria) during
color mode conversion RGBA to Indexed or Grayscale to Indexed.
The 'fit criteria' will help us to recolor an RGB image with
a limited color palette taking into account different color
perception criteria (color spaces: RGB, linearized RGB,
CIE XYZ, CIE LAB).
Before this fix, a multi-layer mask movement/scaling (with mixed layer
types: normal layer and tilemap layers with different grids) caused
loss of drawing areas.
The heart of this solution is to correctly align the 'selection mask'
and 'transform data' according to the layer's grid, and also, forcing
'site' TilemapMode/TilesetMode before each
reproduceAllTransformationsWithInnerCmds() iteration.
During the life of a PixelMovement object there is a tilemap mode lock.
Additionally arrow keys now work to move a selected area in
TilemapMode::Tiles.
This was originated for #1279 (CLI-only Aseprite) which can be
achieved with LAF_BACKEND=none anyway.
In this way we simplify the development process, and checking for the
availability of the GUI can be done in run-time through App::isGui()
or Context::isUIAvailable().
Now we use the LAF_BACKEND=none/skia to detect if it's going to be the
CLI/GUI version of the program. The ENABLE_UI flag is still defined at
compile-time just to avoid removing all #ifdef/endif conditional
directives right now.
Before this fix, the 'Cancel' command did not work in the following
specific situation:
As soon as Aseprite was started and without hitting the 'Esc' key,
the 'app.command.Cancel()' command did not perform any operation.
It was discovered that the Cancel command is started only once per
session and retains the 'm_type' throughout the session. Only
a specific:
app.command.Cancel {type = "all"} or
app.command.Cancel {type = "noop"}
could change the command type.
With this change we are reusing the cached/loaded matrix on each
DitheringMatrixInfo struct, calling the
load_dithering_matrix_from_sprite() function just one time (not on
each brush preview/mouse movement).
We made an attempt to change the "+" character with an icon, but we
cannot use an existing style to do this kind of change in themes (as
third-party themes will be using the old version of the style, not the
updated one).
We're reverting part of the change introduced in
e0ff51947a to use the "+" character for
this "New Frame" button in the status bar.
This 1) hides user themes whose name is the same as the default,
and are present in the user folders (i.e. 'extensions' and
'data/themes' folders), and 2) doesn't allow to install themes with
the same content/ID of the default aseprite-theme (fix#4226)
This fixes a violation of module layers (circular dependency)
introduced in e6cd13d7e1 where doc-lib
started to depend on app-lib (which cannot happen, as app-lib depends
on doc-lib).
This DocFormat/SerialFormat was used only from app-lib previously, but
when properties were introduced in user data, the serialization format
version was needed to read user properties too. So now it makes sense
to move this type/its values to the doc-lib.
A couple of extra issues were found in this refactor:
1) The recursive call inside read_layer() didn't receive this "serial"
argument
2) read_grid() doesn't need the setId parameter
There is a third-party translation (and can happen with our own
translations) that a fmt format string is ill-formed in the .ini file
of the translation (this could happen even if the en.ini file was
manually modified/broken by hand).
This patch includes a refactor of the Strings class so we can:
1) Static check at compile-time about the number of required arguments
to format a string (no need to call fmt::format() directly with
arbitrary number of args)
2) If a string is not valid for the fmt library, the runtime exception
is caught and the default (English) string is returned.