mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 05:22:23 +00:00
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).
This commit is contained in:
parent
3cc1c63274
commit
e1bd7990a3
@ -130,7 +130,8 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
|
|||||||
false, // TODO is background? it depends of the layer where this tileset is used
|
false, // TODO is background? it depends of the layer where this tileset is used
|
||||||
mapAlgorithm,
|
mapAlgorithm,
|
||||||
toGray,
|
toGray,
|
||||||
&superDel);
|
&superDel,
|
||||||
|
fitCriteria);
|
||||||
}
|
}
|
||||||
superDel.nextImage();
|
superDel.nextImage();
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ namespace cmd {
|
|||||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||||
doc::rgba_to_graya_func toGray,
|
doc::rgba_to_graya_func toGray,
|
||||||
render::TaskDelegate* delegate,
|
render::TaskDelegate* delegate,
|
||||||
const doc::FitCriteria fitCriteria = doc::FitCriteria::DEFAULT);
|
const doc::FitCriteria fitCriteria);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onExecute() override;
|
void onExecute() override;
|
||||||
|
@ -668,9 +668,10 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
|||||||
window.saveOptions();
|
window.saveOptions();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TO DO: in a first approach a simple conversion to indexed color mode
|
if (m_format == IMAGE_INDEXED) {
|
||||||
// it's just via the old fit criteria (Euclidean color distance).
|
m_rgbmap = Preferences::instance().quantization.rgbmapAlgorithm();
|
||||||
m_fitCriteria = FitCriteria::DEFAULT;
|
m_fitCriteria = Preferences::instance().quantization.fitCriteria();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No conversion needed
|
// No conversion needed
|
||||||
|
@ -263,6 +263,11 @@ void NewFileCommand::onExecute(Context* ctx)
|
|||||||
else
|
else
|
||||||
layer->setName(fmt::format("{} {}", Strings::commands_NewLayer_Layer(), 1));
|
layer->setName(fmt::format("{} {}", Strings::commands_NewLayer_Layer(), 1));
|
||||||
}
|
}
|
||||||
|
if (sprite->pixelFormat() == IMAGE_INDEXED) {
|
||||||
|
sprite->rgbMap(0, Sprite::RgbMapFor(!layer->isBackground()),
|
||||||
|
Preferences::instance().quantization.rgbmapAlgorithm(),
|
||||||
|
Preferences::instance().quantization.fitCriteria());
|
||||||
|
}
|
||||||
|
|
||||||
// Show the sprite to the user
|
// Show the sprite to the user
|
||||||
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
|
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -1289,13 +1289,18 @@ void DocExporter::renderTexture(Context* ctx,
|
|||||||
// Make the sprite compatible with the texture so the render()
|
// Make the sprite compatible with the texture so the render()
|
||||||
// works correctly.
|
// works correctly.
|
||||||
if (sample.sprite()->pixelFormat() != textureImage->pixelFormat()) {
|
if (sample.sprite()->pixelFormat() != textureImage->pixelFormat()) {
|
||||||
|
RgbMapAlgorithm rgbmapAlgo =
|
||||||
|
Preferences::instance().quantization.rgbmapAlgorithm();
|
||||||
|
FitCriteria fc =
|
||||||
|
Preferences::instance().quantization.fitCriteria();
|
||||||
cmd::SetPixelFormat(
|
cmd::SetPixelFormat(
|
||||||
sample.sprite(),
|
sample.sprite(),
|
||||||
textureImage->pixelFormat(),
|
textureImage->pixelFormat(),
|
||||||
render::Dithering(),
|
render::Dithering(),
|
||||||
Sprite::DefaultRgbMapAlgorithm(), // TODO add rgbmap algorithm preference
|
rgbmapAlgo,
|
||||||
nullptr, // toGray is not needed because the texture is Indexed or RGB
|
nullptr, // toGray is not needed because the texture is Indexed or RGB
|
||||||
nullptr) // TODO add a delegate to show progress
|
nullptr, // TODO add a delegate to show progress
|
||||||
|
fc)
|
||||||
.execute(ctx);
|
.execute(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +290,13 @@ bool AseFormat::onLoad(FileOp* fop)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Sprite* sprite = delegate.sprite();
|
Sprite* sprite = delegate.sprite();
|
||||||
|
|
||||||
|
// Assign RgbMap
|
||||||
|
if (sprite->pixelFormat() == IMAGE_INDEXED)
|
||||||
|
sprite->rgbMap(0, Sprite::RgbMapFor(sprite->isOpaque()),
|
||||||
|
fop->config().rgbMapAlgorithm,
|
||||||
|
fop->config().fitCriteria);
|
||||||
|
|
||||||
fop->createDocument(sprite);
|
fop->createDocument(sprite);
|
||||||
|
|
||||||
if (sprite->colorSpace() != nullptr &&
|
if (sprite->colorSpace() != nullptr &&
|
||||||
|
@ -1356,6 +1356,11 @@ ImageRef FileOp::sequenceImageToLoad(
|
|||||||
// Add the layer
|
// Add the layer
|
||||||
sprite->root()->addLayer(layer);
|
sprite->root()->addLayer(layer);
|
||||||
|
|
||||||
|
// Assign RgbMap
|
||||||
|
if (sprite->pixelFormat() == IMAGE_INDEXED)
|
||||||
|
sprite->rgbMap(0, Sprite::RgbMapFor(sprite->isOpaque()),
|
||||||
|
m_config.rgbMapAlgorithm,
|
||||||
|
m_config.fitCriteria);
|
||||||
// Done
|
// Done
|
||||||
createDocument(sprite);
|
createDocument(sprite);
|
||||||
m_seq.layer = layer;
|
m_seq.layer = layer;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -25,6 +25,7 @@ void FileOpConfig::fillFromPreferences()
|
|||||||
defaultSliceColor = pref.slices.defaultColor();
|
defaultSliceColor = pref.slices.defaultColor();
|
||||||
workingCS = get_working_rgb_space_from_preferences();
|
workingCS = get_working_rgb_space_from_preferences();
|
||||||
rgbMapAlgorithm = pref.quantization.rgbmapAlgorithm();
|
rgbMapAlgorithm = pref.quantization.rgbmapAlgorithm();
|
||||||
|
fitCriteria = pref.quantization.fitCriteria();
|
||||||
cacheCompressedTilesets = pref.tileset.cacheCompressedTilesets();
|
cacheCompressedTilesets = pref.tileset.cacheCompressedTilesets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -33,9 +33,14 @@ namespace app {
|
|||||||
|
|
||||||
app::Color defaultSliceColor = app::Color::fromRgb(0, 0, 255);
|
app::Color defaultSliceColor = app::Color::fromRgb(0, 0, 255);
|
||||||
|
|
||||||
// Algorithm used to create a palette from RGB files.
|
// Algorithm used to fit any color into the available palette colors in
|
||||||
|
// Indexed Color Mode.
|
||||||
doc::RgbMapAlgorithm rgbMapAlgorithm = doc::RgbMapAlgorithm::DEFAULT;
|
doc::RgbMapAlgorithm rgbMapAlgorithm = doc::RgbMapAlgorithm::DEFAULT;
|
||||||
|
|
||||||
|
// Fit criteria used to compare colors during the conversion to
|
||||||
|
// Indexed Color Mode.
|
||||||
|
doc::FitCriteria fitCriteria = doc::FitCriteria::DEFAULT;
|
||||||
|
|
||||||
// Cache compressed tilesets. When we load a tileset from a
|
// Cache compressed tilesets. When we load a tileset from a
|
||||||
// .aseprite file, the compressed data will be stored on memory to
|
// .aseprite file, the compressed data will be stored on memory to
|
||||||
// make the save operation faster (as we can re-use the already
|
// make the save operation faster (as we can re-use the already
|
||||||
|
@ -67,14 +67,6 @@ Preferences::Preferences()
|
|||||||
|
|
||||||
load();
|
load();
|
||||||
|
|
||||||
// Create a connection with the default RgbMapAlgorithm preferences
|
|
||||||
// to change the default algorithm in the "doc" layer.
|
|
||||||
quantization.rgbmapAlgorithm.AfterChange.connect(
|
|
||||||
[](const doc::RgbMapAlgorithm& newValue){
|
|
||||||
doc::Sprite::SetDefaultRgbMapAlgorithm(newValue);
|
|
||||||
});
|
|
||||||
doc::Sprite::SetDefaultRgbMapAlgorithm(quantization.rgbmapAlgorithm());
|
|
||||||
|
|
||||||
// Create a connection with the default document preferences grid
|
// Create a connection with the default document preferences grid
|
||||||
// bounds to sync the default grid bounds for new sprites in the
|
// bounds to sync the default grid bounds for new sprites in the
|
||||||
// "doc" layer.
|
// "doc" layer.
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
namespace doc {
|
namespace doc {
|
||||||
|
|
||||||
static RgbMapAlgorithm g_rgbMapAlgorithm = RgbMapAlgorithm::DEFAULT;
|
|
||||||
static gfx::Rect g_defaultGridBounds(0, 0, 16, 16);
|
static gfx::Rect g_defaultGridBounds(0, 0, 16, 16);
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -56,18 +55,6 @@ void Sprite::SetDefaultGridBounds(const gfx::Rect& defGridBounds)
|
|||||||
g_defaultGridBounds.h = 1;
|
g_defaultGridBounds.h = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
RgbMapAlgorithm Sprite::DefaultRgbMapAlgorithm()
|
|
||||||
{
|
|
||||||
return g_rgbMapAlgorithm;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void Sprite::SetDefaultRgbMapAlgorithm(const RgbMapAlgorithm mapAlgo)
|
|
||||||
{
|
|
||||||
g_rgbMapAlgorithm = mapAlgo;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Constructors/Destructor
|
// Constructors/Destructor
|
||||||
|
|
||||||
@ -441,7 +428,7 @@ RgbMap* Sprite::rgbMap(const frame_t frame,
|
|||||||
const RgbMapFor forLayer) const
|
const RgbMapFor forLayer) const
|
||||||
{
|
{
|
||||||
FitCriteria fc = FitCriteria::DEFAULT;
|
FitCriteria fc = FitCriteria::DEFAULT;
|
||||||
RgbMapAlgorithm algo = g_rgbMapAlgorithm;
|
RgbMapAlgorithm algo = RgbMapAlgorithm::DEFAULT;
|
||||||
if (m_rgbMap) {
|
if (m_rgbMap) {
|
||||||
fc = m_rgbMap->fitCriteria();
|
fc = m_rgbMap->fitCriteria();
|
||||||
algo = m_rgbMap->rgbmapAlgorithm();
|
algo = m_rgbMap->rgbmapAlgorithm();
|
||||||
|
Loading…
Reference in New Issue
Block a user