mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-10 10:13:35 +00:00
Add Brightness/Contrast menu option
This commit is contained in:
parent
f15430ce88
commit
cca9ff702a
12
data/gui.xml
12
data/gui.xml
@ -641,12 +641,14 @@
|
|||||||
<separator />
|
<separator />
|
||||||
<item command="ReplaceColor" text="R&eplace Color..." />
|
<item command="ReplaceColor" text="R&eplace Color..." />
|
||||||
<item command="InvertColor" text="&Invert..." />
|
<item command="InvertColor" text="&Invert..." />
|
||||||
<item command="HueSaturation" text="Ad&just Hue/Saturation..." />
|
<menu text="Adjustments">
|
||||||
|
<item command="BrightnessContrast" text="&Brightness/Contrast..." />
|
||||||
|
<item command="HueSaturation" text="&Hue/Saturation..." />
|
||||||
|
<item command="ColorCurve" text="&Color Curve..." />
|
||||||
|
</menu>
|
||||||
<menu text="F&X" id="fx_popup">
|
<menu text="F&X" id="fx_popup">
|
||||||
<item command="ConvolutionMatrix" text="Convolution &Matrix" />
|
<item command="ConvolutionMatrix" text="Convolution &Matrix..." />
|
||||||
<item command="ColorCurve" text="&Color Curve" />
|
<item command="Despeckle" text="&Despeckle (Median Filter)..." />
|
||||||
<separator />
|
|
||||||
<item command="Despeckle" text="&Despeckle (median filter)" />
|
|
||||||
</menu>
|
</menu>
|
||||||
<item command="PasteText" text="Insert Text" />
|
<item command="PasteText" text="Insert Text" />
|
||||||
<!--menu text="Scripts">
|
<!--menu text="Scripts">
|
||||||
|
@ -350,6 +350,7 @@ add_library(app-lib
|
|||||||
commands/cmd_zoom.cpp
|
commands/cmd_zoom.cpp
|
||||||
commands/command.cpp
|
commands/command.cpp
|
||||||
commands/commands.cpp
|
commands/commands.cpp
|
||||||
|
commands/filters/cmd_brightness_contrast.cpp
|
||||||
commands/filters/cmd_color_curve.cpp
|
commands/filters/cmd_color_curve.cpp
|
||||||
commands/filters/cmd_convolution_matrix.cpp
|
commands/filters/cmd_convolution_matrix.cpp
|
||||||
commands/filters/cmd_despeckle.cpp
|
commands/filters/cmd_despeckle.cpp
|
||||||
@ -494,6 +495,7 @@ add_library(app-lib
|
|||||||
ui/skin/skin_slider_property.cpp
|
ui/skin/skin_slider_property.cpp
|
||||||
ui/skin/skin_theme.cpp
|
ui/skin/skin_theme.cpp
|
||||||
ui/slice_window.cpp
|
ui/slice_window.cpp
|
||||||
|
ui/slider2.cpp
|
||||||
ui/status_bar.cpp
|
ui/status_bar.cpp
|
||||||
ui/tabs.cpp
|
ui/tabs.cpp
|
||||||
ui/timeline/ani_controls.cpp
|
ui/timeline/ani_controls.cpp
|
||||||
|
@ -9,6 +9,7 @@ FOR_EACH_COMMAND(AddColor)
|
|||||||
FOR_EACH_COMMAND(AdvancedMode)
|
FOR_EACH_COMMAND(AdvancedMode)
|
||||||
FOR_EACH_COMMAND(AutocropSprite)
|
FOR_EACH_COMMAND(AutocropSprite)
|
||||||
FOR_EACH_COMMAND(BackgroundFromLayer)
|
FOR_EACH_COMMAND(BackgroundFromLayer)
|
||||||
|
FOR_EACH_COMMAND(BrightnessContrast)
|
||||||
FOR_EACH_COMMAND(Cancel)
|
FOR_EACH_COMMAND(Cancel)
|
||||||
FOR_EACH_COMMAND(CanvasSize)
|
FOR_EACH_COMMAND(CanvasSize)
|
||||||
FOR_EACH_COMMAND(CelProperties)
|
FOR_EACH_COMMAND(CelProperties)
|
||||||
|
109
src/app/commands/filters/cmd_brightness_contrast.cpp
Normal file
109
src/app/commands/filters/cmd_brightness_contrast.cpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/color.h"
|
||||||
|
#include "app/commands/command.h"
|
||||||
|
#include "app/commands/filters/filter_manager_impl.h"
|
||||||
|
#include "app/commands/filters/filter_window.h"
|
||||||
|
#include "app/context.h"
|
||||||
|
#include "app/ini_file.h"
|
||||||
|
#include "app/modules/gui.h"
|
||||||
|
#include "app/ui/color_button.h"
|
||||||
|
#include "app/ui/color_sliders.h"
|
||||||
|
#include "app/ui/slider2.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "doc/image.h"
|
||||||
|
#include "doc/mask.h"
|
||||||
|
#include "doc/sprite.h"
|
||||||
|
#include "filters/brightness_contrast_filter.h"
|
||||||
|
#include "ui/button.h"
|
||||||
|
#include "ui/label.h"
|
||||||
|
#include "ui/widget.h"
|
||||||
|
#include "ui/window.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
static const char* ConfigSection = "BrightnessContrast";
|
||||||
|
|
||||||
|
class BrightnessContrastWindow : public FilterWindow {
|
||||||
|
public:
|
||||||
|
BrightnessContrastWindow(BrightnessContrastFilter& filter,
|
||||||
|
FilterManagerImpl& filterMgr)
|
||||||
|
: FilterWindow("Brightness/Contrast", ConfigSection, &filterMgr,
|
||||||
|
WithChannelsSelector,
|
||||||
|
WithoutTiledCheckBox)
|
||||||
|
, m_brightness(-100, 100, 0)
|
||||||
|
, m_contrast(-100, 100, 0)
|
||||||
|
, m_filter(filter)
|
||||||
|
{
|
||||||
|
getContainer()->addChild(new ui::Label("Brightness:"));
|
||||||
|
getContainer()->addChild(&m_brightness);
|
||||||
|
getContainer()->addChild(new ui::Label("Contrast:"));
|
||||||
|
getContainer()->addChild(&m_contrast);
|
||||||
|
m_brightness.Change.connect(base::Bind<void>(&BrightnessContrastWindow::onChange, this));
|
||||||
|
m_contrast.Change.connect(base::Bind<void>(&BrightnessContrastWindow::onChange, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void onChange() {
|
||||||
|
m_filter.setBrightness(m_brightness.getValue() / 100.0);
|
||||||
|
m_filter.setContrast(m_contrast.getValue() / 100.0);
|
||||||
|
restartPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider2 m_brightness;
|
||||||
|
Slider2 m_contrast;
|
||||||
|
BrightnessContrastFilter& m_filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BrightnessContrastCommand : public Command {
|
||||||
|
public:
|
||||||
|
BrightnessContrastCommand();
|
||||||
|
Command* clone() const override { return new BrightnessContrastCommand(*this); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onEnabled(Context* context) override;
|
||||||
|
void onExecute(Context* context) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
BrightnessContrastCommand::BrightnessContrastCommand()
|
||||||
|
: Command("BrightnessContrast",
|
||||||
|
"Brightness Contrast",
|
||||||
|
CmdRecordableFlag)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BrightnessContrastCommand::onEnabled(Context* context)
|
||||||
|
{
|
||||||
|
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||||
|
ContextFlags::HasActiveSprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastCommand::onExecute(Context* context)
|
||||||
|
{
|
||||||
|
BrightnessContrastFilter filter;
|
||||||
|
FilterManagerImpl filterMgr(context, &filter);
|
||||||
|
filterMgr.setTarget(TARGET_RED_CHANNEL |
|
||||||
|
TARGET_GREEN_CHANNEL |
|
||||||
|
TARGET_BLUE_CHANNEL |
|
||||||
|
TARGET_GRAY_CHANNEL |
|
||||||
|
TARGET_ALPHA_CHANNEL);
|
||||||
|
|
||||||
|
BrightnessContrastWindow window(filter, filterMgr);
|
||||||
|
window.doModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createBrightnessContrastCommand()
|
||||||
|
{
|
||||||
|
return new BrightnessContrastCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
127
src/app/ui/slider2.cpp
Normal file
127
src/app/ui/slider2.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/ui/slider2.h"
|
||||||
|
|
||||||
|
#include "app/ui/skin/skin_property.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "ui/manager.h"
|
||||||
|
#include "ui/message.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
// TODO merge this code with ColorEntry in color_sliders.cpp
|
||||||
|
Slider2::Slider2Entry::Slider2Entry(ui::Slider* slider)
|
||||||
|
: ui::Entry(4, "0")
|
||||||
|
, m_slider(slider)
|
||||||
|
, m_recentFocus(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Slider2::Slider2Entry::onProcessMessage(ui::Message* msg)
|
||||||
|
{
|
||||||
|
switch (msg->type()) {
|
||||||
|
|
||||||
|
case ui::kFocusEnterMessage:
|
||||||
|
m_recentFocus = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ui::kKeyDownMessage:
|
||||||
|
if (ui::Entry::onProcessMessage(msg))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hasFocus()) {
|
||||||
|
int scancode = static_cast<ui::KeyMessage*>(msg)->scancode();
|
||||||
|
|
||||||
|
switch (scancode) {
|
||||||
|
// Enter just remove the focus
|
||||||
|
case ui::kKeyEnter:
|
||||||
|
case ui::kKeyEnterPad:
|
||||||
|
releaseFocus();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ui::kKeyDown:
|
||||||
|
case ui::kKeyUp: {
|
||||||
|
int value = textInt();
|
||||||
|
if (scancode == ui::kKeyDown)
|
||||||
|
--value;
|
||||||
|
else
|
||||||
|
++value;
|
||||||
|
|
||||||
|
setTextf("%d", MID(minValue(), value, maxValue()));
|
||||||
|
selectAllText();
|
||||||
|
|
||||||
|
onChange();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process focus movement key here because if our
|
||||||
|
// CustomizedGuiManager catches this kKeyDownMessage it
|
||||||
|
// will process it as a shortcut to switch the Timeline.
|
||||||
|
//
|
||||||
|
// Note: The default ui::Manager handles focus movement
|
||||||
|
// shortcuts only for foreground windows.
|
||||||
|
// TODO maybe that should change
|
||||||
|
if (hasFocus() &&
|
||||||
|
manager()->processFocusMovementMessage(msg))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = Entry::onProcessMessage(msg);
|
||||||
|
|
||||||
|
if (msg->type() == ui::kMouseDownMessage && m_recentFocus) {
|
||||||
|
m_recentFocus = false;
|
||||||
|
selectAllText();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider2::Slider2(int min, int max, int value)
|
||||||
|
: m_slider(min, max, value)
|
||||||
|
, m_entry(&m_slider)
|
||||||
|
{
|
||||||
|
m_slider.setExpansive(true);
|
||||||
|
m_slider.setSizeHint(gfx::Size(128, 0));
|
||||||
|
skin::get_skin_property(&m_entry)->setLook(skin::MiniLook);
|
||||||
|
|
||||||
|
m_slider.Change.connect(base::Bind<void>(&Slider2::onSliderChange, this));
|
||||||
|
m_entry.Change.connect(base::Bind<void>(&Slider2::onEntryChange, this));
|
||||||
|
|
||||||
|
addChild(&m_slider);
|
||||||
|
addChild(&m_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slider2::onChange()
|
||||||
|
{
|
||||||
|
Change();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slider2::onSliderChange()
|
||||||
|
{
|
||||||
|
m_entry.setTextf("%d", m_slider.getValue());
|
||||||
|
if (m_entry.hasFocus())
|
||||||
|
m_entry.selectAllText();
|
||||||
|
onChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slider2::onEntryChange()
|
||||||
|
{
|
||||||
|
int v = m_entry.textInt();
|
||||||
|
v = MID(m_slider.getMinValue(), v, m_slider.getMaxValue());
|
||||||
|
m_slider.setValue(v);
|
||||||
|
|
||||||
|
onChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
59
src/app/ui/slider2.h
Normal file
59
src/app/ui/slider2.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_UI_SLIDER2_H_INCLUDED
|
||||||
|
#define APP_UI_SLIDER2_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/box.h"
|
||||||
|
#include "ui/entry.h"
|
||||||
|
#include "ui/slider.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
// TODO merge this with IntEntry?
|
||||||
|
// It looks like there are 3 different modes to input values:
|
||||||
|
//
|
||||||
|
// 1. An entry field (Entry)
|
||||||
|
// 2. An entry field with a popup slider (IntEntry)
|
||||||
|
// 3. A slider + entry field (Slider2, ColorSliders+ColorEntry)
|
||||||
|
//
|
||||||
|
// We might merge all these modes in just on responsive widget, but
|
||||||
|
// I'm not sure.
|
||||||
|
class Slider2 : public ui::HBox {
|
||||||
|
public:
|
||||||
|
Slider2(int min, int max, int value);
|
||||||
|
|
||||||
|
int getValue() const { return m_slider.getValue(); }
|
||||||
|
|
||||||
|
// Signals
|
||||||
|
obs::signal<void()> Change;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void onChange();
|
||||||
|
void onSliderChange();
|
||||||
|
void onEntryChange();
|
||||||
|
|
||||||
|
class Slider2Entry : public ui::Entry {
|
||||||
|
public:
|
||||||
|
Slider2Entry(ui::Slider* slider);
|
||||||
|
private:
|
||||||
|
int minValue() const { return m_slider->getMinValue(); }
|
||||||
|
int maxValue() const { return m_slider->getMaxValue(); }
|
||||||
|
bool onProcessMessage(ui::Message* msg) override;
|
||||||
|
ui::Slider* m_slider;
|
||||||
|
// TODO remove this calling setFocus() in
|
||||||
|
// Widget::onProcessMessage() instead of
|
||||||
|
// Manager::handleWindowZOrder()
|
||||||
|
bool m_recentFocus;
|
||||||
|
};
|
||||||
|
ui::Slider m_slider;
|
||||||
|
Slider2Entry m_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
@ -2,6 +2,7 @@
|
|||||||
# Copyright (C) 2001-2017 David Capello
|
# Copyright (C) 2001-2017 David Capello
|
||||||
|
|
||||||
add_library(filters-lib
|
add_library(filters-lib
|
||||||
|
brightness_contrast_filter.cpp
|
||||||
color_curve.cpp
|
color_curve.cpp
|
||||||
color_curve_filter.cpp
|
color_curve_filter.cpp
|
||||||
convolution_matrix.cpp
|
convolution_matrix.cpp
|
||||||
|
208
src/filters/brightness_contrast_filter.cpp
Normal file
208
src/filters/brightness_contrast_filter.cpp
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "filters/brightness_contrast_filter.h"
|
||||||
|
|
||||||
|
#include "doc/image.h"
|
||||||
|
#include "doc/palette.h"
|
||||||
|
#include "doc/rgbmap.h"
|
||||||
|
#include "filters/filter_indexed_data.h"
|
||||||
|
#include "filters/filter_manager.h"
|
||||||
|
#include "gfx/hsl.h"
|
||||||
|
#include "gfx/rgb.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace filters {
|
||||||
|
|
||||||
|
using namespace doc;
|
||||||
|
|
||||||
|
const char* BrightnessContrastFilter::getName()
|
||||||
|
{
|
||||||
|
return "Brightness Contrast";
|
||||||
|
}
|
||||||
|
|
||||||
|
BrightnessContrastFilter::BrightnessContrastFilter()
|
||||||
|
: m_brightness(0.0)
|
||||||
|
, m_contrast(0.0)
|
||||||
|
, m_cmap(256)
|
||||||
|
{
|
||||||
|
updateMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::setBrightness(double brightness)
|
||||||
|
{
|
||||||
|
m_brightness = brightness;
|
||||||
|
updateMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::setContrast(double contrast)
|
||||||
|
{
|
||||||
|
m_contrast = contrast;
|
||||||
|
updateMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::applyToRgba(FilterManager* filterMgr)
|
||||||
|
{
|
||||||
|
FilterIndexedData* fid = filterMgr->getIndexedData();
|
||||||
|
|
||||||
|
if (filterMgr->isFirstRow()) {
|
||||||
|
m_picks = fid->getPalettePicks();
|
||||||
|
m_usePalette = (m_picks.picks() > 0);
|
||||||
|
if (m_usePalette)
|
||||||
|
applyToPalette(filterMgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Palette* pal = fid->getPalette();
|
||||||
|
const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress();
|
||||||
|
uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress();
|
||||||
|
const int w = filterMgr->getWidth();
|
||||||
|
const Target target = filterMgr->getTarget();
|
||||||
|
|
||||||
|
for (int x=0; x<w; x++) {
|
||||||
|
if (filterMgr->skipPixel()) {
|
||||||
|
++src_address;
|
||||||
|
++dst_address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_t c = *(src_address++);
|
||||||
|
|
||||||
|
if (m_usePalette) {
|
||||||
|
int i =
|
||||||
|
pal->findExactMatch(rgba_getr(c),
|
||||||
|
rgba_getg(c),
|
||||||
|
rgba_getb(c),
|
||||||
|
rgba_geta(c), -1);
|
||||||
|
if (i >= 0)
|
||||||
|
c = fid->getNewPalette()->getEntry(i);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
applyFilterToRgb(target, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
*(dst_address++) = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::applyToGrayscale(FilterManager* filterMgr)
|
||||||
|
{
|
||||||
|
const uint16_t* src_address = (uint16_t*)filterMgr->getSourceAddress();
|
||||||
|
uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress();
|
||||||
|
const int w = filterMgr->getWidth();
|
||||||
|
const Target target = filterMgr->getTarget();
|
||||||
|
|
||||||
|
for (int x=0; x<w; x++) {
|
||||||
|
if (filterMgr->skipPixel()) {
|
||||||
|
++src_address;
|
||||||
|
++dst_address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_t c = *(src_address++);
|
||||||
|
int k = graya_getv(c);
|
||||||
|
int a = graya_geta(c);
|
||||||
|
|
||||||
|
if (target & TARGET_GRAY_CHANNEL) k = m_cmap[k];
|
||||||
|
|
||||||
|
*(dst_address++) = graya(k, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::applyToIndexed(FilterManager* filterMgr)
|
||||||
|
{
|
||||||
|
FilterIndexedData* fid = filterMgr->getIndexedData();
|
||||||
|
|
||||||
|
// Apply filter to color palette if there is no selection
|
||||||
|
if (!filterMgr->isMaskActive()) {
|
||||||
|
if (!filterMgr->isFirstRow())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_picks = fid->getPalettePicks();
|
||||||
|
if (m_picks.picks() == 0)
|
||||||
|
m_picks.all();
|
||||||
|
|
||||||
|
applyToPalette(filterMgr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply filter to color region
|
||||||
|
const Target target = filterMgr->getTarget();
|
||||||
|
const Palette* pal = fid->getPalette();
|
||||||
|
const RgbMap* rgbmap = fid->getRgbMap();
|
||||||
|
const uint8_t* src_address = (uint8_t*)filterMgr->getSourceAddress();
|
||||||
|
uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress();
|
||||||
|
const int w = filterMgr->getWidth();
|
||||||
|
|
||||||
|
for (int x=0; x<w; x++) {
|
||||||
|
if (filterMgr->skipPixel()) {
|
||||||
|
++src_address;
|
||||||
|
++dst_address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_t c = pal->getEntry(*(src_address++));
|
||||||
|
applyFilterToRgb(target, c);
|
||||||
|
*(dst_address++) = rgbmap->mapColor(rgba_getr(c),
|
||||||
|
rgba_getg(c),
|
||||||
|
rgba_getb(c),
|
||||||
|
rgba_geta(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::applyToPalette(FilterManager* filterMgr)
|
||||||
|
{
|
||||||
|
const Target target = filterMgr->getTarget();
|
||||||
|
FilterIndexedData* fid = filterMgr->getIndexedData();
|
||||||
|
const Palette* pal = fid->getPalette();
|
||||||
|
Palette* newPal = fid->getNewPalette();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (bool state : m_picks) {
|
||||||
|
if (!state) {
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
color_t c = pal->getEntry(i);
|
||||||
|
applyFilterToRgb(target, c);
|
||||||
|
newPal->setEntry(i, c);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::applyFilterToRgb(
|
||||||
|
const Target target, doc::color_t& c)
|
||||||
|
{
|
||||||
|
int r = rgba_getr(c);
|
||||||
|
int g = rgba_getg(c);
|
||||||
|
int b = rgba_getb(c);
|
||||||
|
int a = rgba_geta(c);
|
||||||
|
|
||||||
|
if (target & TARGET_RED_CHANNEL ) r = m_cmap[r];
|
||||||
|
if (target & TARGET_GREEN_CHANNEL) g = m_cmap[g];
|
||||||
|
if (target & TARGET_BLUE_CHANNEL ) b = m_cmap[b];
|
||||||
|
|
||||||
|
c = rgba(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrightnessContrastFilter::updateMap()
|
||||||
|
{
|
||||||
|
int max = int(m_cmap.size());
|
||||||
|
for (int u=0; u<max; ++u) {
|
||||||
|
double x = double(u) / double(max-1);
|
||||||
|
double y = (m_contrast+1.0) * (x - 0.5) + 0.5;
|
||||||
|
y = y*(1.0+m_brightness);
|
||||||
|
y = MID(0.0, y, 1.0);
|
||||||
|
m_cmap[u] = int(255.5 * y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace filters
|
46
src/filters/brightness_contrast_filter.h
Normal file
46
src/filters/brightness_contrast_filter.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef FILTERS_BRIGHTNESS_CONTRAST_FILTER_H_INCLUDED
|
||||||
|
#define FILTERS_BRIGHTNESS_CONTRAST_FILTER_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "doc/color.h"
|
||||||
|
#include "doc/palette_picks.h"
|
||||||
|
#include "filters/filter.h"
|
||||||
|
#include "filters/target.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace filters {
|
||||||
|
|
||||||
|
class BrightnessContrastFilter : public Filter {
|
||||||
|
public:
|
||||||
|
BrightnessContrastFilter();
|
||||||
|
|
||||||
|
void setBrightness(double brightness);
|
||||||
|
void setContrast(double contrast);
|
||||||
|
|
||||||
|
// Filter implementation
|
||||||
|
const char* getName();
|
||||||
|
void applyToRgba(FilterManager* filterMgr);
|
||||||
|
void applyToGrayscale(FilterManager* filterMgr);
|
||||||
|
void applyToIndexed(FilterManager* filterMgr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void applyToPalette(FilterManager* filterMgr);
|
||||||
|
void applyFilterToRgb(const Target target, doc::color_t& color);
|
||||||
|
void updateMap();
|
||||||
|
|
||||||
|
double m_brightness, m_contrast;
|
||||||
|
doc::PalettePicks m_picks;
|
||||||
|
bool m_usePalette;
|
||||||
|
std::vector<int> m_cmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filters
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user