Add RgbMap algorithm option in RGB -> Indexed color mode conversion dialog

This commit is contained in:
Gaspar Capello 2020-04-15 15:36:50 -03:00 committed by David Capello
parent 80cbb2caf5
commit 966daf5e34
10 changed files with 126 additions and 31 deletions

View File

@ -666,6 +666,7 @@ Check in case that you want to establish
the given option as the default option.
END
reset = Reset
advanced_options = Advanced Options
[gif_options]
title = GIF Options
@ -965,7 +966,6 @@ background = Background:
transparent = &Transparent
white = &White
black = &Black
advanced_options = Advanced Options
pixel_ratio = Pixel Aspect Ratio:
square_pixels = Square Pixels (1:1)
double_wide = Double-wide Pixels (2:1)
@ -1262,7 +1262,6 @@ new_palette = Create new palette, color count limit:
replace_palette = Replace current palette
replace_range = Replace current range
alpha_channel = Create entries with alpha component
advanced_options = Advanced Options
[palette_popup]
load = &Load

View File

@ -1,5 +1,5 @@
<!-- Aseprite -->
<!-- Copyright (C) 2019 Igara Studio S.A. -->
<!-- Copyright (C) 2019-2020 Igara Studio S.A. -->
<!-- Copyright (C) 2017 David Capello -->
<gui>
<window id="color_mode" text="@.title">
@ -13,7 +13,15 @@
<slider min="0" max="100" id="factor" minwidth="100" />
<label text="%" />
</hbox>
<check text="@.flatten" id="flatten" />
<check id="advanced_check" text="@general.advanced_options" cell_hspan="2" />
<hbox id="advanced" cell_hspan="2">
<label text="@rgbmap_algorithm_selector.label" />
<hbox id="rgbmap_algorithm_placeholder" />
</hbox>
<separator horizontal="true" />
<hbox>
<slider min="0" max="100" id="progress" minwidth="100" />

View File

@ -1,5 +1,6 @@
<!-- Aseprite -->
<!-- Copyright (C) 2001-2018 by David Capello -->
<!-- Copyright (c) 2020 Igara Studio S.A. -->
<!-- Copyright (c) 2001-2018 David Capello -->
<gui>
<window id="new_sprite" text="@.title">
<box vertical="true">
@ -26,7 +27,7 @@
<item text="@.black" icon="icon_black" />
</buttonset>
<check id="advanced_check" text="@.advanced_options" />
<check id="advanced_check" text="@general.advanced_options" />
<vbox id="advanced">
<label text="@.pixel_ratio" />
<combobox id="pixel_ratio" cell_align="horizontal">

View File

@ -12,7 +12,7 @@
<separator horizontal="true" cell_hspan="2" />
<check id="alpha_channel" text="@.alpha_channel" cell_hspan="2" />
<check id="advanced_check" text="@.advanced_options" cell_hspan="2" />
<check id="advanced_check" text="@general.advanced_options" cell_hspan="2" />
<hbox id="advanced" cell_hspan="2">
<label text="@rgbmap_algorithm_selector.label" />
<hbox id="rgbmap_algorithm_placeholder" />

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -69,6 +69,7 @@ private:
SetPixelFormat::SetPixelFormat(Sprite* sprite,
const PixelFormat newFormat,
const render::Dithering& dithering,
const doc::RgbMapAlgorithm mapAlgorithm,
render::TaskDelegate* delegate)
: WithSprite(sprite)
, m_oldFormat(sprite->pixelFormat())
@ -78,6 +79,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
return;
SuperDelegate superDel(sprite->uniqueCels().size(), delegate);
const auto rgbMapFor = sprite->rgbMapForSprite();
for (Cel* cel : sprite->uniqueCels()) {
ImageRef old_image = cel->imageRef();
@ -85,7 +87,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
render::convert_pixel_format
(old_image.get(), nullptr, newFormat,
dithering,
sprite->rgbMap(cel->frame()),
sprite->rgbMap(cel->frame(), rgbMapFor, mapAlgorithm),
sprite->palette(cel->frame()),
cel->layer()->isBackground(),
old_image->maskColor(),

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -12,6 +12,7 @@
#include "app/cmd/with_sprite.h"
#include "app/cmd_sequence.h"
#include "doc/pixel_format.h"
#include "doc/rgbmap_algorithm.h"
namespace doc {
class Sprite;
@ -31,6 +32,7 @@ namespace cmd {
SetPixelFormat(doc::Sprite* sprite,
const doc::PixelFormat newFormat,
const render::Dithering& dithering,
const doc::RgbMapAlgorithm mapAlgorithm,
render::TaskDelegate* delegate);
protected:

View File

@ -26,6 +26,7 @@
#include "app/ui/dithering_selector.h"
#include "app/ui/editor/editor.h"
#include "app/ui/editor/editor_render.h"
#include "app/ui/rgbmap_algorithm_selector.h"
#include "app/ui/skin/skin_theme.h"
#include "base/bind.h"
#include "base/thread.h"
@ -79,6 +80,7 @@ public:
const doc::frame_t frame,
const doc::PixelFormat pixelFormat,
const render::Dithering& dithering,
const doc::RgbMapAlgorithm rgbMapAlgorithm,
const gfx::Point& pos,
const bool newBlend)
: m_image(dstImage)
@ -91,10 +93,12 @@ public:
sprite, frame,
pixelFormat,
dithering,
rgbMapAlgorithm,
newBlend]() { // Copy the matrix
run(sprite, frame,
pixelFormat,
dithering,
rgbMapAlgorithm,
newBlend);
})
{
@ -118,6 +122,7 @@ private:
const doc::frame_t frame,
const doc::PixelFormat pixelFormat,
const render::Dithering& dithering,
const doc::RgbMapAlgorithm rgbMapAlgorithm,
const bool newBlend) {
doc::ImageRef tmp(
Image::create(sprite->pixelFormat(),
@ -138,7 +143,9 @@ private:
m_image.get(),
pixelFormat,
dithering,
sprite->rgbMap(frame),
sprite->rgbMap(frame,
sprite->rgbMapForSprite(),
rgbMapAlgorithm),
sprite->palette(frame),
(sprite->backgroundLayer() != nullptr),
0,
@ -174,9 +181,11 @@ public:
, m_imageBuffer(new doc::ImageBuffer)
, m_selectedItem(nullptr)
, m_ditheringSelector(nullptr)
, m_mapAlgorithmSelector(nullptr)
, m_imageJustCreated(true)
{
doc::PixelFormat from = m_editor->sprite()->pixelFormat();
const auto& pref = Preferences::instance();
const doc::PixelFormat from = m_editor->sprite()->pixelFormat();
// Add the color mode in the window title
switch (from) {
@ -194,22 +203,48 @@ public:
m_ditheringSelector = new DitheringSelector(DitheringSelector::SelectBoth);
m_ditheringSelector->setExpansive(true);
m_mapAlgorithmSelector = new RgbMapAlgorithmSelector;
m_mapAlgorithmSelector->setExpansive(true);
// Select default dithering method
{
int index = m_ditheringSelector->findItemIndex(
Preferences::instance().quantization.ditheringAlgorithm());
pref.quantization.ditheringAlgorithm());
if (index >= 0)
m_ditheringSelector->setSelectedItemIndex(index);
}
m_ditheringSelector->Change.connect(
base::Bind<void>(&ColorModeWindow::onDithering, this));
ditheringPlaceholder()->addChild(m_ditheringSelector);
// Select default RgbMap algorithm
m_mapAlgorithmSelector->algorithm(pref.experimental.rgbmapAlgorithm());
factor()->Change.connect(base::Bind<void>(&ColorModeWindow::onDithering, this));
ditheringPlaceholder()->addChild(m_ditheringSelector);
rgbmapAlgorithmPlaceholder()->addChild(m_mapAlgorithmSelector);
const bool adv = pref.quantization.advanced();
advancedCheck()->setSelected(adv);
advanced()->setVisible(adv);
// Signals
m_ditheringSelector->Change.connect(
base::Bind<void>(&ColorModeWindow::onIndexParamChange, this));
m_mapAlgorithmSelector->Change.connect(
base::Bind<void>(&ColorModeWindow::onIndexParamChange, this));
factor()->Change.connect(
base::Bind<void>(&ColorModeWindow::onIndexParamChange, this));
advancedCheck()->Click.connect(
[this](ui::Event&){
advanced()->setVisible(advancedCheck()->isSelected());
const gfx::Rect origBounds = bounds();
setBounds(gfx::Rect(bounds().origin(), sizeHint()));
manager()->invalidateRect(origBounds);
});
}
else {
amount()->setVisible(false);
advancedCheck()->setVisible(false);
advanced()->setVisible(false);
}
if (from != IMAGE_GRAYSCALE)
colorMode()->addChild(new ConversionItem(IMAGE_GRAYSCALE));
@ -224,7 +259,7 @@ public:
progress()->setReadOnly(true);
// Default dithering factor
factor()->setValue(Preferences::instance().quantization.ditheringFactor());
factor()->setValue(pref.quantization.ditheringFactor());
// Select first option
colorMode()->selectIndex(0);
@ -249,24 +284,36 @@ public:
return d;
}
doc::RgbMapAlgorithm rgbMapAlgorithm() const {
if (m_mapAlgorithmSelector)
return m_mapAlgorithmSelector->algorithm();
else
return doc::RgbMapAlgorithm::DEFAULT;
}
bool flattenEnabled() const {
return flatten()->isSelected();
}
// Save the dithering method used for the future
void saveDitheringOptions() {
void saveOptions() {
auto& pref = Preferences::instance();
// Save the dithering method used for the future
if (m_ditheringSelector) {
if (auto item = m_ditheringSelector->getSelectedItem()) {
Preferences::instance().quantization.ditheringAlgorithm(
pref.quantization.ditheringAlgorithm(
item->text());
if (m_ditheringSelector->ditheringAlgorithm() ==
render::DitheringAlgorithm::ErrorDiffusion) {
Preferences::instance().quantization.ditheringFactor(
pref.quantization.ditheringFactor(
factor()->getValue());
}
}
}
if (m_mapAlgorithmSelector)
pref.quantization.advanced(advancedCheck()->isSelected());
}
private:
@ -336,13 +383,14 @@ private:
m_editor->frame(),
dstPixelFormat,
dithering(),
rgbMapAlgorithm(),
visibleBounds.origin(),
Preferences::instance().experimental.newBlend()));
m_timer.start();
}
void onDithering() {
void onIndexParamChange() {
stop();
m_selectedItem = nullptr;
onChangeColorMode();
@ -382,6 +430,7 @@ private:
std::unique_ptr<ConvertThread> m_bgThread;
ConversionItem* m_selectedItem;
DitheringSelector* m_ditheringSelector;
RgbMapAlgorithmSelector* m_mapAlgorithmSelector;
bool m_imageJustCreated;
};
@ -402,6 +451,7 @@ private:
bool m_useUI;
doc::PixelFormat m_format;
render::Dithering m_dithering;
doc::RgbMapAlgorithm m_rgbmap;
};
ChangePixelFormatCommand::ChangePixelFormatCommand()
@ -410,6 +460,7 @@ ChangePixelFormatCommand::ChangePixelFormatCommand()
m_useUI = true;
m_format = IMAGE_RGB;
m_dithering = render::Dithering();
m_rgbmap = doc::RgbMapAlgorithm::DEFAULT;
}
void ChangePixelFormatCommand::onLoadParams(const Params& params)
@ -454,6 +505,15 @@ void ChangePixelFormatCommand::onLoadParams(const Params& params)
// TODO object slicing here (from BayerMatrix -> DitheringMatrix)
m_dithering.matrix(render::BayerMatrix(8));
}
// TODO change this with NewParams as in ColorQuantizationParams
std::string rgbmap = params.get("rgbmap");
if (rgbmap == "octree")
m_rgbmap = doc::RgbMapAlgorithm::OCTREE;
else if (rgbmap == "rgb5a3")
m_rgbmap = doc::RgbMapAlgorithm::RGB5A3;
else
m_rgbmap = doc::RgbMapAlgorithm::DEFAULT;
}
bool ChangePixelFormatCommand::onEnabled(Context* context)
@ -518,9 +578,10 @@ void ChangePixelFormatCommand::onExecute(Context* context)
m_format = window.pixelFormat();
m_dithering = window.dithering();
m_rgbmap = window.rgbMapAlgorithm();
flatten = window.flattenEnabled();
window.saveDitheringOptions();
window.saveOptions();
}
#endif // ENABLE_UI
@ -554,6 +615,7 @@ void ChangePixelFormatCommand::onExecute(Context* context)
new cmd::SetPixelFormat(
sprite, m_format,
m_dithering,
m_rgbmap,
&job)); // SpriteJob is a render::TaskDelegate
});
job.waitJob();

View File

@ -1179,6 +1179,7 @@ void DocExporter::renderTexture(Context* ctx,
sample.sprite(),
textureImage->pixelFormat(),
render::Dithering(),
Sprite::DefaultRgbMapAlgorithm(), // TODO add rgbmap algorithm preference
nullptr) // TODO add a delegate to show progress
.execute(ctx);
}

View File

@ -355,19 +355,34 @@ void Sprite::deletePalette(frame_t frame)
}
}
RgbMap* Sprite::rgbMap(frame_t frame) const
Sprite::RgbMapFor Sprite::rgbMapForSprite() const
{
return rgbMap(frame, backgroundLayer() ? RgbMapFor::OpaqueLayer:
RgbMapFor::TransparentLayer);
return backgroundLayer() ? RgbMapFor::OpaqueLayer:
RgbMapFor::TransparentLayer;
}
RgbMap* Sprite::rgbMap(frame_t frame, RgbMapFor forLayer) const
RgbMap* Sprite::rgbMap(const frame_t frame) const
{
return rgbMap(frame, rgbMapForSprite());
}
RgbMap* Sprite::rgbMap(const frame_t frame,
const RgbMapFor forLayer) const
{
return rgbMap(frame,
forLayer,
g_rgbMapAlgorithm);
}
RgbMap* Sprite::rgbMap(const frame_t frame,
const RgbMapFor forLayer,
const RgbMapAlgorithm mapAlgo) const
{
int maskIndex = (forLayer == RgbMapFor::OpaqueLayer ?
-1: transparentColor());
if (!m_rgbMap || m_rgbMapAlgorithm != g_rgbMapAlgorithm) {
m_rgbMapAlgorithm = g_rgbMapAlgorithm;
if (!m_rgbMap || m_rgbMapAlgorithm != mapAlgo) {
m_rgbMapAlgorithm = mapAlgo;
switch (m_rgbMapAlgorithm) {
case RgbMapAlgorithm::RGB5A3: m_rgbMap.reset(new RgbMapRGB5A3); break;
case RgbMapAlgorithm::OCTREE: m_rgbMap.reset(new OctreeMap); break;

View File

@ -137,8 +137,13 @@ namespace doc {
void deletePalette(frame_t frame);
RgbMap* rgbMap(frame_t frame) const;
RgbMap* rgbMap(frame_t frame, RgbMapFor forLayer) const;
RgbMapFor rgbMapForSprite() const;
RgbMap* rgbMap(const frame_t frame) const;
RgbMap* rgbMap(const frame_t frame,
const RgbMapFor forLayer) const;
RgbMap* rgbMap(const frame_t frame,
const RgbMapFor forLayer,
const RgbMapAlgorithm mapAlgo) const;
////////////////////////////////////////
// Frames