mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-17 08:43:11 +00:00
Modify the color palette when HueSaturationFilter is used in an indexed image
This commit is contained in:
parent
b3c83d6905
commit
6f1f7e41bf
@ -12,11 +12,13 @@
|
||||
|
||||
#include "app/cmd/copy_region.h"
|
||||
#include "app/cmd/patch_cel.h"
|
||||
#include "app/cmd/set_palette.h"
|
||||
#include "app/cmd/unlink_cel.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "doc/algorithm/shrink_bounds.h"
|
||||
@ -50,6 +52,7 @@ FilterManagerImpl::FilterManagerImpl(Context* context, Filter* filter)
|
||||
, m_dst(nullptr)
|
||||
, m_mask(nullptr)
|
||||
, m_previewMask(nullptr)
|
||||
, m_oldPalette(nullptr)
|
||||
, m_progressDelegate(NULL)
|
||||
{
|
||||
m_row = 0;
|
||||
@ -64,6 +67,14 @@ FilterManagerImpl::FilterManagerImpl(Context* context, Filter* filter)
|
||||
init(m_site.cel());
|
||||
}
|
||||
|
||||
FilterManagerImpl::~FilterManagerImpl()
|
||||
{
|
||||
if (m_oldPalette) {
|
||||
restoreSpritePalette();
|
||||
set_current_palette(m_oldPalette.get(), false);
|
||||
}
|
||||
}
|
||||
|
||||
app::Document* FilterManagerImpl::document()
|
||||
{
|
||||
return static_cast<app::Document*>(m_site.document());
|
||||
@ -211,6 +222,7 @@ void FilterManagerImpl::apply(Transaction& transaction)
|
||||
|
||||
void FilterManagerImpl::applyToTarget()
|
||||
{
|
||||
const bool paletteChange = paletteHasChanged();
|
||||
bool cancelled = false;
|
||||
|
||||
ImagesCollector images((m_target & TARGET_ALL_LAYERS ?
|
||||
@ -219,7 +231,7 @@ void FilterManagerImpl::applyToTarget()
|
||||
m_site.frame(),
|
||||
(m_target & TARGET_ALL_FRAMES) == TARGET_ALL_FRAMES,
|
||||
true); // we will write in each image
|
||||
if (images.empty())
|
||||
if (images.empty() && !paletteChange)
|
||||
return;
|
||||
|
||||
// Initialize writting operation
|
||||
@ -232,6 +244,15 @@ void FilterManagerImpl::applyToTarget()
|
||||
|
||||
std::set<ObjectId> visited;
|
||||
|
||||
// Palette change
|
||||
if (paletteChange) {
|
||||
Palette newPalette = *getNewPalette();
|
||||
restoreSpritePalette();
|
||||
transaction.execute(
|
||||
new cmd::SetPalette(m_site.sprite(),
|
||||
m_site.frame(), &newPalette));
|
||||
}
|
||||
|
||||
// For each target image
|
||||
for (auto it = images.begin();
|
||||
it != images.end() && !cancelled;
|
||||
@ -253,6 +274,9 @@ void FilterManagerImpl::applyToTarget()
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
|
||||
// Reset m_oldPalette to avoid restoring the color palette
|
||||
m_oldPalette.reset(nullptr);
|
||||
}
|
||||
|
||||
void FilterManagerImpl::flush()
|
||||
@ -262,6 +286,12 @@ void FilterManagerImpl::flush()
|
||||
if (m_row >= 0 && h > 0) {
|
||||
Editor* editor = current_editor;
|
||||
|
||||
// Redraw the color palette
|
||||
if (m_nextRowToFlush == 0 && paletteHasChanged()) {
|
||||
set_current_palette(getNewPalette(), false);
|
||||
ColorBar::instance()->invalidate();
|
||||
}
|
||||
|
||||
// We expand the region one pixel at the top and bottom of the
|
||||
// region [m_row,m_nextRowToFlush) to be updated on the screen to
|
||||
// avoid screen artifacts when we apply filters like convolution
|
||||
@ -310,16 +340,26 @@ bool FilterManagerImpl::skipPixel()
|
||||
return skip;
|
||||
}
|
||||
|
||||
Palette* FilterManagerImpl::getPalette()
|
||||
const Palette* FilterManagerImpl::getPalette() const
|
||||
{
|
||||
return m_site.sprite()->palette(m_site.frame());
|
||||
if (m_oldPalette)
|
||||
return m_oldPalette.get();
|
||||
else
|
||||
return m_site.sprite()->palette(m_site.frame());
|
||||
}
|
||||
|
||||
RgbMap* FilterManagerImpl::getRgbMap()
|
||||
const RgbMap* FilterManagerImpl::getRgbMap() const
|
||||
{
|
||||
return m_site.sprite()->rgbMap(m_site.frame());
|
||||
}
|
||||
|
||||
Palette* FilterManagerImpl::getNewPalette()
|
||||
{
|
||||
if (!m_oldPalette)
|
||||
m_oldPalette.reset(new Palette(*getPalette()));
|
||||
return m_site.sprite()->palette(m_site.frame());
|
||||
}
|
||||
|
||||
void FilterManagerImpl::init(Cel* cel)
|
||||
{
|
||||
ASSERT(cel);
|
||||
@ -364,4 +404,18 @@ bool FilterManagerImpl::updateBounds(doc::Mask* mask)
|
||||
return !m_bounds.isEmpty();
|
||||
}
|
||||
|
||||
bool FilterManagerImpl::paletteHasChanged()
|
||||
{
|
||||
return
|
||||
(m_oldPalette &&
|
||||
getPalette()->countDiff(getNewPalette(), nullptr, nullptr));
|
||||
}
|
||||
|
||||
void FilterManagerImpl::restoreSpritePalette()
|
||||
{
|
||||
// Restore the original palette to save the undoable "cmd"
|
||||
if (m_oldPalette)
|
||||
m_site.sprite()->setPalette(m_oldPalette.get(), false);
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -69,6 +69,7 @@ namespace app {
|
||||
};
|
||||
|
||||
FilterManagerImpl(Context* context, Filter* filter);
|
||||
~FilterManagerImpl();
|
||||
|
||||
void setProgressDelegate(IProgressDelegate* progressDelegate);
|
||||
|
||||
@ -100,18 +101,22 @@ namespace app {
|
||||
FilterIndexedData* getIndexedData() override { return this; }
|
||||
bool skipPixel() override;
|
||||
const doc::Image* getSourceImage() override { return m_src.get(); }
|
||||
int x() override { return m_bounds.x; }
|
||||
int y() override { return m_bounds.y+m_row; }
|
||||
int x() const override { return m_bounds.x; }
|
||||
int y() const override { return m_bounds.y+m_row; }
|
||||
bool isFirstRow() const override { return m_row == 0; }
|
||||
|
||||
// FilterIndexedData implementation
|
||||
doc::Palette* getPalette() override;
|
||||
doc::RgbMap* getRgbMap() override;
|
||||
const doc::Palette* getPalette() const override;
|
||||
const doc::RgbMap* getRgbMap() const override;
|
||||
doc::Palette* getNewPalette() override;
|
||||
|
||||
private:
|
||||
void init(doc::Cel* cel);
|
||||
void apply(Transaction& transaction);
|
||||
void applyToCel(Transaction& transaction, doc::Cel* cel);
|
||||
bool updateBounds(doc::Mask* mask);
|
||||
bool paletteHasChanged();
|
||||
void restoreSpritePalette();
|
||||
|
||||
Context* m_context;
|
||||
doc::Site m_site;
|
||||
@ -128,6 +133,7 @@ namespace app {
|
||||
doc::ImageBits<doc::BitmapTraits>::iterator m_maskIterator;
|
||||
Target m_targetOrig; // Original targets
|
||||
Target m_target; // Filtered targets
|
||||
base::UniquePtr<doc::Palette> m_oldPalette;
|
||||
|
||||
// Hooks
|
||||
float m_progressBase;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -20,8 +20,12 @@ namespace filters {
|
||||
class FilterIndexedData {
|
||||
public:
|
||||
virtual ~FilterIndexedData() { }
|
||||
virtual doc::Palette* getPalette() = 0;
|
||||
virtual doc::RgbMap* getRgbMap() = 0;
|
||||
virtual const doc::Palette* getPalette() const = 0;
|
||||
virtual const doc::RgbMap* getRgbMap() const = 0;
|
||||
|
||||
// If a filter ask for a new palette, it means that the filter
|
||||
// will modify the palette instead of pixels.
|
||||
virtual doc::Palette* getNewPalette() = 0;
|
||||
};
|
||||
|
||||
} // namespace filters
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -64,10 +64,14 @@ namespace filters {
|
||||
virtual const doc::Image* getSourceImage() = 0;
|
||||
|
||||
// Returns the first X coordinate of the row to apply the filter.
|
||||
virtual int x() = 0;
|
||||
virtual int x() const = 0;
|
||||
|
||||
// Returns the Y coordinate of the row.
|
||||
virtual int y() = 0;
|
||||
virtual int y() const = 0;
|
||||
|
||||
// Returns true if this is the first row. Useful to apply a filter
|
||||
// to the palette in the first row.
|
||||
virtual bool isFirstRow() const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -61,8 +61,8 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr)
|
||||
{
|
||||
const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress();
|
||||
uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress();
|
||||
int w = filterMgr->getWidth();
|
||||
Target target = filterMgr->getTarget();
|
||||
const int w = filterMgr->getWidth();
|
||||
const Target target = filterMgr->getTarget();
|
||||
int x, c, r, g, b, a;
|
||||
|
||||
for (x=0; x<w; x++) {
|
||||
@ -114,8 +114,8 @@ void HueSaturationFilter::applyToGrayscale(FilterManager* filterMgr)
|
||||
{
|
||||
const uint16_t* src_address = (uint16_t*)filterMgr->getSourceAddress();
|
||||
uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress();
|
||||
int w = filterMgr->getWidth();
|
||||
Target target = filterMgr->getTarget();
|
||||
const int w = filterMgr->getWidth();
|
||||
const Target target = filterMgr->getTarget();
|
||||
int x, c, k, a;
|
||||
|
||||
for (x=0; x<w; x++) {
|
||||
@ -151,27 +151,19 @@ void HueSaturationFilter::applyToGrayscale(FilterManager* filterMgr)
|
||||
|
||||
void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr)
|
||||
{
|
||||
const uint8_t* src_address = (uint8_t*)filterMgr->getSourceAddress();
|
||||
uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress();
|
||||
if (!filterMgr->isFirstRow())
|
||||
return;
|
||||
|
||||
const Palette* pal = filterMgr->getIndexedData()->getPalette();
|
||||
const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap();
|
||||
int w = filterMgr->getWidth();
|
||||
Target target = filterMgr->getTarget();
|
||||
int x, c, r, g, b, a;
|
||||
const Target target = filterMgr->getTarget();
|
||||
Palette* newPal = filterMgr->getIndexedData()->getNewPalette();
|
||||
|
||||
for (x=0; x<w; x++) {
|
||||
if (filterMgr->skipPixel()) {
|
||||
++src_address;
|
||||
++dst_address;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = *(src_address++);
|
||||
c = pal->getEntry(c);
|
||||
r = rgba_getr(c);
|
||||
g = rgba_getg(c);
|
||||
b = rgba_getb(c);
|
||||
a = rgba_geta(c);
|
||||
for (int i=0; i<newPal->size(); ++i) {
|
||||
color_t c = pal->getEntry(i);
|
||||
int r = rgba_getr(c);
|
||||
int g = rgba_getg(c);
|
||||
int b = rgba_getb(c);
|
||||
int a = rgba_geta(c);
|
||||
|
||||
{
|
||||
gfx::Hsl hsl(gfx::Rgb(r, g, b));
|
||||
@ -194,13 +186,17 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr)
|
||||
if (target & TARGET_RED_CHANNEL ) r = rgb.red();
|
||||
if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
|
||||
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
|
||||
|
||||
if (a && (target & TARGET_ALPHA_CHANNEL))
|
||||
a = MID(0, a+m_a, 255);
|
||||
|
||||
if (target & (TARGET_RED_CHANNEL |
|
||||
TARGET_GREEN_CHANNEL |
|
||||
TARGET_BLUE_CHANNEL |
|
||||
TARGET_ALPHA_CHANNEL))
|
||||
c = rgba(r, g, b, a);
|
||||
}
|
||||
|
||||
c = rgbmap->mapColor(r, g, b, a);
|
||||
*(dst_address++) = c;
|
||||
newPal->setEntry(i, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user