mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-05 18:40:37 +00:00
Add RgbMap algorithm option in RGB -> Indexed color mode conversion dialog
This commit is contained in:
parent
80cbb2caf5
commit
966daf5e34
@ -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
|
||||
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
@ -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" />
|
||||
|
@ -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(),
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user