mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-28 15:20:15 +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
|
||||
mapAlgorithm,
|
||||
toGray,
|
||||
&superDel);
|
||||
&superDel,
|
||||
fitCriteria);
|
||||
}
|
||||
superDel.nextImage();
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ namespace cmd {
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate,
|
||||
const doc::FitCriteria fitCriteria = doc::FitCriteria::DEFAULT);
|
||||
const doc::FitCriteria fitCriteria);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
|
@ -668,9 +668,10 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
window.saveOptions();
|
||||
}
|
||||
else {
|
||||
// TO DO: in a first approach a simple conversion to indexed color mode
|
||||
// it's just via the old fit criteria (Euclidean color distance).
|
||||
m_fitCriteria = FitCriteria::DEFAULT;
|
||||
if (m_format == IMAGE_INDEXED) {
|
||||
m_rgbmap = Preferences::instance().quantization.rgbmapAlgorithm();
|
||||
m_fitCriteria = Preferences::instance().quantization.fitCriteria();
|
||||
}
|
||||
}
|
||||
|
||||
// No conversion needed
|
||||
|
@ -263,6 +263,11 @@ void NewFileCommand::onExecute(Context* ctx)
|
||||
else
|
||||
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
|
||||
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// 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()
|
||||
// works correctly.
|
||||
if (sample.sprite()->pixelFormat() != textureImage->pixelFormat()) {
|
||||
RgbMapAlgorithm rgbmapAlgo =
|
||||
Preferences::instance().quantization.rgbmapAlgorithm();
|
||||
FitCriteria fc =
|
||||
Preferences::instance().quantization.fitCriteria();
|
||||
cmd::SetPixelFormat(
|
||||
sample.sprite(),
|
||||
textureImage->pixelFormat(),
|
||||
render::Dithering(),
|
||||
Sprite::DefaultRgbMapAlgorithm(), // TODO add rgbmap algorithm preference
|
||||
rgbmapAlgo,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -290,6 +290,13 @@ bool AseFormat::onLoad(FileOp* fop)
|
||||
return false;
|
||||
|
||||
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);
|
||||
|
||||
if (sprite->colorSpace() != nullptr &&
|
||||
|
@ -1356,6 +1356,11 @@ ImageRef FileOp::sequenceImageToLoad(
|
||||
// Add the 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
|
||||
createDocument(sprite);
|
||||
m_seq.layer = layer;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// 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
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -25,6 +25,7 @@ void FileOpConfig::fillFromPreferences()
|
||||
defaultSliceColor = pref.slices.defaultColor();
|
||||
workingCS = get_working_rgb_space_from_preferences();
|
||||
rgbMapAlgorithm = pref.quantization.rgbmapAlgorithm();
|
||||
fitCriteria = pref.quantization.fitCriteria();
|
||||
cacheCompressedTilesets = pref.tileset.cacheCompressedTilesets();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// 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
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -33,9 +33,14 @@ namespace app {
|
||||
|
||||
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;
|
||||
|
||||
// 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
|
||||
// .aseprite file, the compressed data will be stored on memory to
|
||||
// make the save operation faster (as we can re-use the already
|
||||
|
@ -67,14 +67,6 @@ Preferences::Preferences()
|
||||
|
||||
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
|
||||
// bounds to sync the default grid bounds for new sprites in the
|
||||
// "doc" layer.
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
namespace doc {
|
||||
|
||||
static RgbMapAlgorithm g_rgbMapAlgorithm = RgbMapAlgorithm::DEFAULT;
|
||||
static gfx::Rect g_defaultGridBounds(0, 0, 16, 16);
|
||||
|
||||
// static
|
||||
@ -56,18 +55,6 @@ void Sprite::SetDefaultGridBounds(const gfx::Rect& defGridBounds)
|
||||
g_defaultGridBounds.h = 1;
|
||||
}
|
||||
|
||||
// static
|
||||
RgbMapAlgorithm Sprite::DefaultRgbMapAlgorithm()
|
||||
{
|
||||
return g_rgbMapAlgorithm;
|
||||
}
|
||||
|
||||
// static
|
||||
void Sprite::SetDefaultRgbMapAlgorithm(const RgbMapAlgorithm mapAlgo)
|
||||
{
|
||||
g_rgbMapAlgorithm = mapAlgo;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Constructors/Destructor
|
||||
|
||||
@ -441,7 +428,7 @@ RgbMap* Sprite::rgbMap(const frame_t frame,
|
||||
const RgbMapFor forLayer) const
|
||||
{
|
||||
FitCriteria fc = FitCriteria::DEFAULT;
|
||||
RgbMapAlgorithm algo = g_rgbMapAlgorithm;
|
||||
RgbMapAlgorithm algo = RgbMapAlgorithm::DEFAULT;
|
||||
if (m_rgbMap) {
|
||||
fc = m_rgbMap->fitCriteria();
|
||||
algo = m_rgbMap->rgbmapAlgorithm();
|
||||
|
Loading…
Reference in New Issue
Block a user