mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 03:39:51 +00:00
Add Hue/Saturation filter (fix #1186)
Added new gfx::Hsl class to handle HSL color model(related to #707 and #1102)
This commit is contained in:
parent
b4ea90a266
commit
239ac42378
@ -27,7 +27,6 @@
|
||||
</key>
|
||||
<!-- Edit -->
|
||||
<key command="Undo" shortcut="Ctrl+Z" mac="Cmd+Z" />
|
||||
<key command="Undo" shortcut="Ctrl+U" mac="Cmd+U" />
|
||||
<key command="Redo" shortcut="Ctrl+Y" mac="Cmd+Y" />
|
||||
<key command="Redo" shortcut="Ctrl+R" mac="Cmd+R" />
|
||||
<key command="Redo" shortcut="Ctrl+Shift+Z" mac="Cmd+Shift+Z" />
|
||||
@ -49,6 +48,7 @@
|
||||
<param name="orientation" value="vertical" />
|
||||
</key>
|
||||
<key command="ReplaceColor" shortcut="Shift+R" />
|
||||
<key command="HueSaturation" shortcut="Ctrl+U" mac="Cmd+U" />
|
||||
<key command="ConvolutionMatrix" shortcut="F9" />
|
||||
<key command="ColorCurve" shortcut="Ctrl+M" mac="Cmd+M" />
|
||||
<key command="ColorCurve" shortcut="F10" />
|
||||
@ -627,7 +627,8 @@
|
||||
<item command="NewSpriteFromSelection" text="&New Sprite from Selection" />
|
||||
<separator />
|
||||
<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="F&X" id="fx_popup">
|
||||
<item command="ConvolutionMatrix" text="Convolution &Matrix" />
|
||||
<item command="ColorCurve" text="&Color Curve" />
|
||||
|
@ -173,6 +173,11 @@ recent_files = Recent files:
|
||||
recent_folders = Recent folders:
|
||||
news = News:
|
||||
|
||||
[hue_saturation]
|
||||
h = H:
|
||||
s = S:
|
||||
l = L:
|
||||
|
||||
[import_sprite_sheet]
|
||||
title = Import Sprite Sheet
|
||||
select_file = Select File
|
||||
|
11
data/widgets/hue_saturation.xml
Normal file
11
data/widgets/hue_saturation.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2017 by David Capello -->
|
||||
<gui>
|
||||
<vbox expansive="true" id="hue_saturation">
|
||||
<grid expansive="true" columns="2">
|
||||
<label text="@.h" /><slider min="-180" max="180" id="hue" width="128" />
|
||||
<label text="@.s" /><slider min="-100" max="100" id="saturation" />
|
||||
<label text="@.l" /><slider min="-100" max="100" id="lightness" />
|
||||
</grid>
|
||||
</vbox>
|
||||
</gui>
|
@ -344,6 +344,7 @@ add_library(app-lib
|
||||
commands/filters/cmd_color_curve.cpp
|
||||
commands/filters/cmd_convolution_matrix.cpp
|
||||
commands/filters/cmd_despeckle.cpp
|
||||
commands/filters/cmd_hue_saturation.cpp
|
||||
commands/filters/cmd_invert_color.cpp
|
||||
commands/filters/cmd_replace_color.cpp
|
||||
commands/filters/color_curve_editor.cpp
|
||||
|
@ -56,6 +56,7 @@ FOR_EACH_COMMAND(GotoPreviousLayer)
|
||||
FOR_EACH_COMMAND(GotoPreviousTab)
|
||||
FOR_EACH_COMMAND(GridSettings)
|
||||
FOR_EACH_COMMAND(Home)
|
||||
FOR_EACH_COMMAND(HueSaturation)
|
||||
FOR_EACH_COMMAND(ImportSpriteSheet)
|
||||
FOR_EACH_COMMAND(InvertColor)
|
||||
FOR_EACH_COMMAND(InvertMask)
|
||||
|
111
src/app/commands/filters/cmd_hue_saturation.cpp
Normal file
111
src/app/commands/filters/cmd_hue_saturation.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
// 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 "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "filters/hue_saturation_filter.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/widget.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
#include "hue_saturation.xml.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
static const char* ConfigSection = "HueSaturation";
|
||||
|
||||
class HueSaturationWindow : public FilterWindow {
|
||||
public:
|
||||
HueSaturationWindow(HueSaturationFilter& filter,
|
||||
FilterManagerImpl& filterMgr)
|
||||
: FilterWindow("Hue/Saturation", ConfigSection, &filterMgr,
|
||||
WithChannelsSelector,
|
||||
WithoutTiledCheckBox)
|
||||
, m_filter(filter)
|
||||
{
|
||||
getContainer()->addChild(&m_controls);
|
||||
|
||||
m_controls.hue()->setValue(0);
|
||||
m_controls.saturation()->setValue(0);
|
||||
m_controls.lightness()->setValue(0);
|
||||
|
||||
m_controls.hue()->Change.connect(base::Bind(&HueSaturationWindow::onChangeControls, this));
|
||||
m_controls.saturation()->Change.connect(base::Bind(&HueSaturationWindow::onChangeControls, this));
|
||||
m_controls.lightness()->Change.connect(base::Bind(&HueSaturationWindow::onChangeControls, this));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void onChangeControls() {
|
||||
m_filter.setHue(double(m_controls.hue()->getValue()));
|
||||
m_filter.setSaturation(m_controls.saturation()->getValue() / 100.0);
|
||||
m_filter.setLightness(m_controls.lightness()->getValue() / 100.0);
|
||||
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
HueSaturationFilter& m_filter;
|
||||
app::gen::HueSaturation m_controls;
|
||||
};
|
||||
|
||||
class HueSaturationCommand : public Command {
|
||||
public:
|
||||
HueSaturationCommand();
|
||||
Command* clone() const override { return new HueSaturationCommand(*this); }
|
||||
|
||||
protected:
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
};
|
||||
|
||||
HueSaturationCommand::HueSaturationCommand()
|
||||
: Command("HueSaturation",
|
||||
"Hue Saturation",
|
||||
CmdRecordableFlag)
|
||||
{
|
||||
}
|
||||
|
||||
bool HueSaturationCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::HasActiveSprite);
|
||||
}
|
||||
|
||||
void HueSaturationCommand::onExecute(Context* context)
|
||||
{
|
||||
HueSaturationFilter filter;
|
||||
FilterManagerImpl filterMgr(context, &filter);
|
||||
filterMgr.setTarget(TARGET_RED_CHANNEL |
|
||||
TARGET_GREEN_CHANNEL |
|
||||
TARGET_BLUE_CHANNEL |
|
||||
TARGET_GRAY_CHANNEL);
|
||||
|
||||
HueSaturationWindow window(filter, filterMgr);
|
||||
window.doModal();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createHueSaturationCommand()
|
||||
{
|
||||
return new HueSaturationCommand;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -1,11 +1,12 @@
|
||||
# Aseprite
|
||||
# Copyright (C) 2001-2016 David Capello
|
||||
# Copyright (C) 2001-2017 David Capello
|
||||
|
||||
add_library(filters-lib
|
||||
color_curve.cpp
|
||||
color_curve_filter.cpp
|
||||
convolution_matrix.cpp
|
||||
convolution_matrix_filter.cpp
|
||||
hue_saturation_filter.cpp
|
||||
invert_color_filter.cpp
|
||||
median_filter.cpp
|
||||
replace_color_filter.cpp)
|
||||
|
192
src/filters/hue_saturation_filter.cpp
Normal file
192
src/filters/hue_saturation_filter.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
// 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/hue_saturation_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* HueSaturationFilter::getName()
|
||||
{
|
||||
return "Hue Saturation Color";
|
||||
}
|
||||
|
||||
HueSaturationFilter::HueSaturationFilter()
|
||||
: m_h(0.0)
|
||||
, m_s(0.0)
|
||||
, m_l(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
void HueSaturationFilter::setHue(double h)
|
||||
{
|
||||
m_h = h;
|
||||
}
|
||||
|
||||
void HueSaturationFilter::setSaturation(double s)
|
||||
{
|
||||
m_s = s;
|
||||
}
|
||||
|
||||
void HueSaturationFilter::setLightness(double l)
|
||||
{
|
||||
m_l = l;
|
||||
}
|
||||
|
||||
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();
|
||||
int x, c, r, g, b, a;
|
||||
|
||||
for (x=0; x<w; x++) {
|
||||
if (filterMgr->skipPixel()) {
|
||||
++src_address;
|
||||
++dst_address;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = *(src_address++);
|
||||
|
||||
r = rgba_getr(c);
|
||||
g = rgba_getg(c);
|
||||
b = rgba_getb(c);
|
||||
a = rgba_geta(c);
|
||||
|
||||
{
|
||||
gfx::Hsl hsl(gfx::Rgb(r, g, b));
|
||||
|
||||
double h = hsl.hue() + m_h;
|
||||
while (h < 0.0)
|
||||
h += 360.0;
|
||||
h = std::fmod(h, 360.0);
|
||||
|
||||
double s = hsl.saturation() + m_s;
|
||||
s = MID(0.0, s, 1.0);
|
||||
|
||||
double l = hsl.lightness() + m_l;
|
||||
l = MID(0.0, l, 1.0);
|
||||
|
||||
hsl.hue(h);
|
||||
hsl.saturation(s);
|
||||
hsl.lightness(l);
|
||||
gfx::Rgb rgb(hsl);
|
||||
|
||||
if (target & TARGET_RED_CHANNEL ) r = rgb.red();
|
||||
if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
|
||||
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
|
||||
}
|
||||
|
||||
*(dst_address++) = rgba(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
int x, c, k, a;
|
||||
|
||||
for (x=0; x<w; x++) {
|
||||
if (filterMgr->skipPixel()) {
|
||||
++src_address;
|
||||
++dst_address;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = *(src_address++);
|
||||
|
||||
k = graya_getv(c);
|
||||
a = graya_geta(c);
|
||||
|
||||
{
|
||||
gfx::Hsl hsl(gfx::Rgb(k, k, k));
|
||||
|
||||
double l = hsl.lightness() + m_l;
|
||||
l = MID(0.0, l, 1.0);
|
||||
|
||||
hsl.lightness(l);
|
||||
gfx::Rgb rgb(hsl);
|
||||
|
||||
if (target & TARGET_GRAY_CHANNEL) k = rgb.red();
|
||||
}
|
||||
|
||||
*(dst_address++) = graya(k, a);
|
||||
}
|
||||
}
|
||||
|
||||
void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr)
|
||||
{
|
||||
const uint8_t* src_address = (uint8_t*)filterMgr->getSourceAddress();
|
||||
uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress();
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
{
|
||||
gfx::Hsl hsl(gfx::Rgb(r, g, b));
|
||||
|
||||
double h = hsl.hue() + m_h;
|
||||
while (h < 0.0) h += 360.0;
|
||||
h = std::fmod(h, 360.0);
|
||||
|
||||
double s = hsl.saturation() + m_s;
|
||||
s = MID(0.0, s, 1.0);
|
||||
|
||||
double l = hsl.lightness() + m_l;
|
||||
l = MID(0.0, l, 1.0);
|
||||
|
||||
hsl.hue(h);
|
||||
hsl.saturation(s);
|
||||
hsl.lightness(l);
|
||||
gfx::Rgb rgb(hsl);
|
||||
|
||||
if (target & TARGET_RED_CHANNEL ) r = rgb.red();
|
||||
if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
|
||||
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
|
||||
}
|
||||
|
||||
c = rgbmap->mapColor(r, g, b, a);
|
||||
*(dst_address++) = c;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filters
|
35
src/filters/hue_saturation_filter.h
Normal file
35
src/filters/hue_saturation_filter.h
Normal file
@ -0,0 +1,35 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef FILTERS_HUE_SATURATION_FILTER_H_INCLUDED
|
||||
#define FILTERS_HUE_SATURATION_FILTER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "filters/filter.h"
|
||||
|
||||
namespace filters {
|
||||
|
||||
class HueSaturationFilter : public Filter {
|
||||
public:
|
||||
HueSaturationFilter();
|
||||
|
||||
void setHue(double h);
|
||||
void setSaturation(double s);
|
||||
void setLightness(double v);
|
||||
|
||||
// Filter implementation
|
||||
const char* getName();
|
||||
void applyToRgba(FilterManager* filterMgr);
|
||||
void applyToGrayscale(FilterManager* filterMgr);
|
||||
void applyToIndexed(FilterManager* filterMgr);
|
||||
|
||||
private:
|
||||
double m_h, m_s, m_l;
|
||||
};
|
||||
|
||||
} // namespace filters
|
||||
|
||||
#endif
|
@ -1,7 +1,8 @@
|
||||
# Aseprite
|
||||
# Copyright (C) 2001-2016 David Capello
|
||||
# Copyright (C) 2001-2017 David Capello
|
||||
|
||||
add_library(gfx-lib
|
||||
hsl.cpp
|
||||
hsv.cpp
|
||||
packing_rects.cpp
|
||||
region.cpp
|
||||
|
92
src/gfx/hsl.cpp
Normal file
92
src/gfx/hsl.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
// Aseprite Gfx Library
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gfx/hsl.h"
|
||||
#include "gfx/rgb.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace gfx {
|
||||
|
||||
using namespace std;
|
||||
|
||||
Hsl::Hsl(double hue, double saturation, double lightness)
|
||||
: m_hue(hue)
|
||||
, m_saturation(saturation)
|
||||
, m_lightness(lightness)
|
||||
{
|
||||
while (m_hue < 0.0)
|
||||
m_hue += 360.0;
|
||||
m_hue = std::fmod(m_hue, 360.0);
|
||||
|
||||
assert(hue >= 0.0 && hue <= 360.0);
|
||||
assert(saturation >= 0.0 && saturation <= 1.0);
|
||||
assert(lightness >= 0.0 && lightness <= 1.0);
|
||||
}
|
||||
|
||||
Hsl::Hsl(const Rgb& rgb)
|
||||
{
|
||||
int M = rgb.maxComponent();
|
||||
int m = rgb.minComponent();
|
||||
int c = M - m;
|
||||
double chroma = double(c) / 255.0;
|
||||
double hue_prime = 0.0;
|
||||
double h, s, l;
|
||||
double r, g, b;
|
||||
|
||||
l = double((M + m) / 255.0) / 2.0;
|
||||
|
||||
if (c == 0) {
|
||||
h = 0.0; // Undefined Hue because max == min
|
||||
s = 0.0;
|
||||
}
|
||||
else {
|
||||
r = double(rgb.red()) / 255.0;
|
||||
g = double(rgb.green()) / 255.0;
|
||||
b = double(rgb.blue()) / 255.0;
|
||||
s = chroma / (1-std::fabs(2.0*l-1.0));
|
||||
|
||||
if (M == rgb.red()) {
|
||||
hue_prime = (g - b) / chroma;
|
||||
|
||||
while (hue_prime < 0.0)
|
||||
hue_prime += 6.0;
|
||||
hue_prime = std::fmod(hue_prime, 6.0);
|
||||
}
|
||||
else if (M == rgb.green()) {
|
||||
hue_prime = ((b - r) / chroma) + 2.0;
|
||||
}
|
||||
else if (M == rgb.blue()) {
|
||||
hue_prime = ((r - g) / chroma) + 4.0;
|
||||
}
|
||||
|
||||
h = hue_prime * 60.0;
|
||||
}
|
||||
|
||||
m_hue = h;
|
||||
m_saturation = s;
|
||||
m_lightness = l;
|
||||
}
|
||||
|
||||
int Hsl::hueInt() const
|
||||
{
|
||||
return int(floor(m_hue + 0.5));
|
||||
}
|
||||
|
||||
int Hsl::saturationInt() const
|
||||
{
|
||||
return int(floor(m_saturation*100.0 + 0.5));
|
||||
}
|
||||
|
||||
int Hsl::lightnessInt() const
|
||||
{
|
||||
return int(floor(m_lightness*100.0 + 0.5));
|
||||
}
|
||||
|
||||
} // namespace gfx
|
84
src/gfx/hsl.h
Normal file
84
src/gfx/hsl.h
Normal file
@ -0,0 +1,84 @@
|
||||
// Aseprite Gfx Library
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef GFX_HSL_H_INCLUDED
|
||||
#define GFX_HSL_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace gfx {
|
||||
|
||||
class Rgb;
|
||||
|
||||
class Hsl {
|
||||
public:
|
||||
Hsl()
|
||||
: m_hue(0.0)
|
||||
, m_saturation(0.0)
|
||||
, m_lightness(0.0)
|
||||
{ }
|
||||
|
||||
Hsl(double hue, double saturation, double lightness);
|
||||
|
||||
Hsl(const Hsl& hsl)
|
||||
: m_hue(hsl.hue())
|
||||
, m_saturation(hsl.saturation())
|
||||
, m_lightness(hsl.lightness())
|
||||
{ }
|
||||
|
||||
// RGB to HSL conversion
|
||||
explicit Hsl(const Rgb& rgb);
|
||||
|
||||
// Returns color's hue, a value from 0 to 360
|
||||
double hue() const { return m_hue; }
|
||||
|
||||
// Returns color's saturation, a value from 0 to 100
|
||||
double saturation() const { return m_saturation; }
|
||||
|
||||
// Returns color's lightness, a value from 0 to 100
|
||||
double lightness() const { return m_lightness; }
|
||||
|
||||
// Integer getters, hue=[0,360), saturation=[0,100], value=[0,100]
|
||||
int hueInt() const;
|
||||
int saturationInt() const;
|
||||
int lightnessInt() const;
|
||||
|
||||
void hue(double hue) {
|
||||
assert(hue >= 0.0 && hue <= 360.0);
|
||||
m_hue = hue;
|
||||
}
|
||||
|
||||
void saturation(double saturation) {
|
||||
assert(saturation >= 0.0 && saturation <= 1.0);
|
||||
m_saturation = saturation;
|
||||
}
|
||||
|
||||
void lightness(double lightness) {
|
||||
assert(lightness >= 0.0 && lightness <= 1.0);
|
||||
m_lightness = lightness;
|
||||
}
|
||||
|
||||
// The comparison is done through the integer value of each component.
|
||||
bool operator==(const Hsl& other) const {
|
||||
return (hueInt() == other.hueInt() &&
|
||||
saturationInt() == other.saturationInt() &&
|
||||
lightnessInt() == other.lightnessInt());
|
||||
}
|
||||
|
||||
bool operator!=(const Hsl& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_hue;
|
||||
double m_saturation;
|
||||
double m_lightness;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Gfx Library
|
||||
// Copyright (C) 2001-2013 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -23,7 +23,7 @@ Hsv::Hsv(double hue, double saturation, double value)
|
||||
{
|
||||
while (m_hue < 0.0)
|
||||
m_hue += 360.0;
|
||||
m_hue = fmod(hue, 360.0);
|
||||
m_hue = std::fmod(m_hue, 360.0);
|
||||
|
||||
assert(hue >= 0.0 && hue <= 360.0);
|
||||
assert(saturation >= 0.0 && saturation <= 1.0);
|
||||
@ -58,7 +58,7 @@ Hsv::Hsv(const Rgb& rgb)
|
||||
|
||||
while (hue_prime < 0.0)
|
||||
hue_prime += 6.0;
|
||||
hue_prime = fmod(hue_prime, 6.0);
|
||||
hue_prime = std::fmod(hue_prime, 6.0);
|
||||
}
|
||||
else if (M == rgb.green()) {
|
||||
hue_prime = ((b - r) / chroma) + 2.0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Gfx Library
|
||||
// Copyright (C) 2001-2013 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -14,8 +14,7 @@ namespace gfx {
|
||||
|
||||
class Rgb;
|
||||
|
||||
class Hsv
|
||||
{
|
||||
class Hsv {
|
||||
public:
|
||||
Hsv()
|
||||
: m_hue(0.0)
|
||||
@ -35,19 +34,13 @@ public:
|
||||
explicit Hsv(const Rgb& rgb);
|
||||
|
||||
// Returns color's hue, a value from 0 to 360
|
||||
double hue() const {
|
||||
return m_hue;
|
||||
}
|
||||
double hue() const { return m_hue; }
|
||||
|
||||
// Returns color's saturation, a value from 0 to 100
|
||||
double saturation() const {
|
||||
return m_saturation;
|
||||
}
|
||||
double saturation() const { return m_saturation; }
|
||||
|
||||
// Returns color's brightness, a value from 0 to 100
|
||||
double value() const {
|
||||
return m_value;
|
||||
}
|
||||
double value() const { return m_value; }
|
||||
|
||||
// Integer getters, hue=[0,360), saturation=[0,100], value=[0,100]
|
||||
int hueInt() const;
|
||||
|
@ -1,10 +1,12 @@
|
||||
// Aseprite Gfx Library
|
||||
// Copyright (C) 2001-2013 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "gfx/rgb.h"
|
||||
|
||||
#include "gfx/hsl.h"
|
||||
#include "gfx/hsv.h"
|
||||
#include <cmath>
|
||||
|
||||
@ -17,7 +19,7 @@ Rgb::Rgb(const Hsv& hsv)
|
||||
{
|
||||
double chroma = hsv.value() * hsv.saturation();
|
||||
double hue_prime = hsv.hue() / 60.0;
|
||||
double x = chroma * (1.0 - fabs(fmod(hue_prime, 2.0) - 1.0));
|
||||
double x = chroma * (1.0 - std::fabs(std::fmod(hue_prime, 2.0) - 1.0));
|
||||
double r, g, b;
|
||||
|
||||
r = g = b = 0.0;
|
||||
@ -63,6 +65,56 @@ Rgb::Rgb(const Hsv& hsv)
|
||||
m_blue = int(b*255.0+0.5);
|
||||
}
|
||||
|
||||
Rgb::Rgb(const Hsl& hsl)
|
||||
{
|
||||
double chroma = (1.0 - std::fabs(2.0*hsl.lightness() - 1.0)) * hsl.saturation();
|
||||
double hue_prime = hsl.hue() / 60.0;
|
||||
double x = chroma * (1.0 - std::fabs(std::fmod(hue_prime, 2.0) - 1.0));
|
||||
double r, g, b;
|
||||
|
||||
r = g = b = 0.0;
|
||||
|
||||
switch (int(hue_prime)) {
|
||||
|
||||
case 6:
|
||||
case 0:
|
||||
r = chroma;
|
||||
g = x;
|
||||
break;
|
||||
case 1:
|
||||
r = x;
|
||||
g = chroma;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
g = chroma;
|
||||
b = x;
|
||||
break;
|
||||
case 3:
|
||||
g = x;
|
||||
b = chroma;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
b = chroma;
|
||||
r = x;
|
||||
break;
|
||||
case 5:
|
||||
b = x;
|
||||
r = chroma;
|
||||
break;
|
||||
}
|
||||
|
||||
double m = hsl.lightness() - chroma/2.0;
|
||||
r += m;
|
||||
g += m;
|
||||
b += m;
|
||||
|
||||
m_red = int(r*255.0+0.5);
|
||||
m_green = int(g*255.0+0.5);
|
||||
m_blue = int(b*255.0+0.5);
|
||||
}
|
||||
|
||||
int Rgb::maxComponent() const
|
||||
{
|
||||
if (m_red > m_green)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Gfx Library
|
||||
// Copyright (C) 2001-2013 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -13,9 +13,9 @@
|
||||
namespace gfx {
|
||||
|
||||
class Hsv;
|
||||
class Hsl;
|
||||
|
||||
class Rgb
|
||||
{
|
||||
class Rgb {
|
||||
public:
|
||||
Rgb()
|
||||
: m_red(0)
|
||||
@ -39,8 +39,9 @@ public:
|
||||
, m_blue(rgb.blue())
|
||||
{ }
|
||||
|
||||
// HSV to RGB conversion
|
||||
// Conversions
|
||||
explicit Rgb(const Hsv& hsv);
|
||||
explicit Rgb(const Hsl& hsl);
|
||||
|
||||
int red() const {
|
||||
return m_red;
|
||||
|
Loading…
x
Reference in New Issue
Block a user