diff --git a/doc/function/brighten_image.txt b/doc/function/brighten_image.txt new file mode 100644 index 00000000..7d83cb4b --- /dev/null +++ b/doc/function/brighten_image.txt @@ -0,0 +1,17 @@ +Function: brighten_image + +DOC_MSE_VERSION: since 2.6.0 + +--Usage-- +> brighten_image(input: image, amount: brightening amount) + +Brighten or darken an image. + +To brighten use an amount between @0@ (no effect) and @1@ (entire image is pure white). + +To darken use an amount between @0@ (no effect) and @-1@ (entire image is pure black). + +--Parameters-- +! Parameter Type Description +| @input@ [[type:image]] Image to brighten/darken. +| @alpha@ [[type:double]] Brightening factor. diff --git a/doc/function/index.txt b/doc/function/index.txt index 629eff76..b3c8d935 100644 --- a/doc/function/index.txt +++ b/doc/function/index.txt @@ -87,6 +87,7 @@ These functions are built into the program, other [[type:function]]s can be defi | [[fun:set_alpha]] Change the transparency of an image. | [[fun:set_combine]] Change how the image should be combined with the background. | [[fun:saturate_image]] Saturate/desaturate an image. +| [[fun:brighten_image]] Brighten/darken an image. | [[fun:invert_image]] Invert the colors of an image. | [[fun:recolor_image]] Change the colors of an image to match the font color. | [[fun:resize_image]] Stretch or squeeze an image to a given height and width. diff --git a/src/gfx/combine_image.cpp b/src/gfx/combine_image.cpp index 6a14bf16..0ff06c62 100644 --- a/src/gfx/combine_image.cpp +++ b/src/gfx/combine_image.cpp @@ -21,6 +21,7 @@ String combine_to_string(const ImageCombine& combine) { case COMBINE_NORMAL: return "normal"; case COMBINE_ADD: return "add"; case COMBINE_SUBTRACT: return "subtract"; + case COMBINE_AVERAGE: return "average"; case COMBINE_STAMP: return "stamp"; case COMBINE_DIFFERENCE: return "difference"; case COMBINE_NEGATION: return "negation"; @@ -41,6 +42,7 @@ String combine_to_string(const ImageCombine& combine) { case COMBINE_OR: return "or"; case COMBINE_XOR: return "xor"; case COMBINE_SHADOW: return "shadow"; + case COMBINE_OFFSET: return "offset"; case COMBINE_SYMMETRIC_OVERLAY: return "symmetric overlay"; case COMBINE_BRIGHTNESS_TO_ALPHA: return "brightness to alpha"; case COMBINE_DARKNESS_TO_ALPHA: return "darkness to alpha"; @@ -152,6 +154,7 @@ IMPLEMENT_REFLECTION_ENUM(ImageCombine) { VALUE_N("normal", COMBINE_NORMAL); VALUE_N("add", COMBINE_ADD); VALUE_N("subtract", COMBINE_SUBTRACT); + VALUE_N("average", COMBINE_AVERAGE); VALUE_N("stamp", COMBINE_STAMP); VALUE_N("difference", COMBINE_DIFFERENCE); VALUE_N("negation", COMBINE_NEGATION); @@ -172,6 +175,7 @@ IMPLEMENT_REFLECTION_ENUM(ImageCombine) { VALUE_N("or", COMBINE_OR); VALUE_N("xor", COMBINE_XOR); VALUE_N("shadow", COMBINE_SHADOW); + VALUE_N("offset", COMBINE_OFFSET); VALUE_N("symmetric overlay", COMBINE_SYMMETRIC_OVERLAY); VALUE_N("brightness to alpha", COMBINE_BRIGHTNESS_TO_ALPHA); VALUE_N("darkness to alpha", COMBINE_DARKNESS_TO_ALPHA); @@ -294,6 +298,7 @@ template struct Combine { COMBINE_FUN(COMBINE_NORMAL, b) COMBINE_FUN(COMBINE_ADD, top(a + b)) COMBINE_FUN(COMBINE_SUBTRACT, bot(a - b)) +COMBINE_FUN(COMBINE_AVERAGE, (a + b) / 2) COMBINE_FUN(COMBINE_STAMP, col(a - 2 * b + 256)) COMBINE_FUN(COMBINE_DIFFERENCE, abs(a - b)) COMBINE_FUN(COMBINE_NEGATION, 255 - abs(255 - a - b)) @@ -318,6 +323,7 @@ COMBINE_FUN(COMBINE_AND, a & b) COMBINE_FUN(COMBINE_OR, a | b) COMBINE_FUN(COMBINE_XOR, a ^ b) COMBINE_FUN(COMBINE_SHADOW, (b * a * a) / (255 * 255)) +COMBINE_FUN(COMBINE_OFFSET, col(a + b - 128)) COMBINE_FUN(COMBINE_SYMMETRIC_OVERLAY, (Combine::f(a, b) + Combine::f(b, a)) / 2) COMBINE_FUN(COMBINE_BRIGHTNESS_TO_ALPHA, ((255 - a) * a + a * b) / 255) COMBINE_FUN(COMBINE_DARKNESS_TO_ALPHA, (255 * a + (255 - a) * b) / 255) @@ -453,6 +459,7 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) { case COMBINE_NORMAL: a = b; return; // no need to do a per pixel operation DISPATCH(COMBINE_ADD); DISPATCH(COMBINE_SUBTRACT); + DISPATCH(COMBINE_AVERAGE); DISPATCH(COMBINE_STAMP); DISPATCH(COMBINE_DIFFERENCE); DISPATCH(COMBINE_NEGATION); @@ -473,6 +480,7 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) { DISPATCH(COMBINE_OR); DISPATCH(COMBINE_XOR); DISPATCH(COMBINE_SHADOW); + DISPATCH(COMBINE_OFFSET); DISPATCH(COMBINE_SYMMETRIC_OVERLAY); DISPATCH(COMBINE_BRIGHTNESS_TO_ALPHA); DISPATCH(COMBINE_DARKNESS_TO_ALPHA); diff --git a/src/gfx/generated_image.cpp b/src/gfx/generated_image.cpp index e75801ac..02f47de8 100644 --- a/src/gfx/generated_image.cpp +++ b/src/gfx/generated_image.cpp @@ -201,6 +201,19 @@ bool SaturateImage::operator == (const GeneratedImage& that) const { && amount == that2->amount; } +// ----------------------------------------------------------------------------- : BrightenImage + +Image BrightenImage::generate(const Options& opt) { + Image img = image->generate(opt); + brighten(img, amount); + return img; +} +bool BrightenImage::operator == (const GeneratedImage& that) const { + const BrightenImage* that2 = dynamic_cast(&that); + return that2 && *image == *that2->image + && amount == that2->amount; +} + // ----------------------------------------------------------------------------- : InvertImage Image InvertImage::generate(const Options& opt) { diff --git a/src/gfx/generated_image.hpp b/src/gfx/generated_image.hpp index 548f5591..a6074e63 100644 --- a/src/gfx/generated_image.hpp +++ b/src/gfx/generated_image.hpp @@ -203,6 +203,20 @@ private: double amount; }; +// ----------------------------------------------------------------------------- : BrightenImage + +/// Brighten/darken an image +class BrightenImage : public SimpleFilterImage { +public: + inline BrightenImage(const GeneratedImageP& image, double amount) + : SimpleFilterImage(image), amount(amount) + {} + Image generate(const Options& opt) override; + bool operator == (const GeneratedImage& that) const override; +private: + double amount; +}; + // ----------------------------------------------------------------------------- : InvertImage /// Invert an image diff --git a/src/gfx/gfx.hpp b/src/gfx/gfx.hpp index 82b12dcb..ba62955e 100644 --- a/src/gfx/gfx.hpp +++ b/src/gfx/gfx.hpp @@ -93,6 +93,9 @@ void mask_blend(Image& img1, const Image& img2, const Image& mask); /// Saturate an image void saturate(Image& image, double amount); +/// Brighten an image +void brighten(Image& image, double amount); + /// Invert the colors in an image void invert(Image& img); @@ -120,6 +123,7 @@ enum ImageCombine , COMBINE_NORMAL , COMBINE_ADD , COMBINE_SUBTRACT +, COMBINE_AVERAGE , COMBINE_STAMP , COMBINE_DIFFERENCE , COMBINE_NEGATION @@ -140,6 +144,7 @@ enum ImageCombine , COMBINE_OR , COMBINE_XOR , COMBINE_SHADOW +, COMBINE_OFFSET , COMBINE_SYMMETRIC_OVERLAY , COMBINE_BRIGHTNESS_TO_ALPHA , COMBINE_DARKNESS_TO_ALPHA diff --git a/src/gfx/image_effects.cpp b/src/gfx/image_effects.cpp index 4fe86a2f..53c30433 100644 --- a/src/gfx/image_effects.cpp +++ b/src/gfx/image_effects.cpp @@ -65,6 +65,30 @@ void saturate(Image& image, double amount) { } } +// ----------------------------------------------------------------------------- : Brightness + +void brighten(Image& image, double amount) { + if (almost_equal(amount, 0.0)) return; + Byte* pix = image.GetData(); + Byte* end = pix + image.GetWidth() * image.GetHeight() * 3; + amount = min(max(amount, -1.0), 1.0); + if (amount > 0.0) { + double s = 255 * amount; + double t = 1.0 - amount; + while (pix != end) { + pix[0] = s + pix[0] * t; + pix++; + } + } else { + double t = 1.0 + amount; + while (pix != end) { + pix[0] = pix[0] * t; + pix++; + } + } + +} + // ----------------------------------------------------------------------------- : Color inversion void invert(Image& img) { diff --git a/src/script/functions/image.cpp b/src/script/functions/image.cpp index 06c567ec..57e98258 100644 --- a/src/script/functions/image.cpp +++ b/src/script/functions/image.cpp @@ -168,6 +168,12 @@ SCRIPT_FUNCTION(saturate) { return make_intrusive(input, amount); } +SCRIPT_FUNCTION(brighten_image) { + SCRIPT_PARAM_C(GeneratedImageP, input); + SCRIPT_PARAM(double, amount); + return make_intrusive(input, amount); +} + SCRIPT_FUNCTION(invert_image) { SCRIPT_PARAM_C(GeneratedImageP, input); return make_intrusive(input); @@ -345,6 +351,7 @@ void init_script_image_functions(Context& ctx) { ctx.setVariable(_("set_combine"), script_set_combine); ctx.setVariable(_("saturate"), script_saturate); ctx.setVariable(_("saturate_image"), script_saturate); + ctx.setVariable(_("brighten_image"), script_brighten_image); ctx.setVariable(_("invert_image"), script_invert_image); ctx.setVariable(_("recolor_image"), script_recolor_image); ctx.setVariable(_("enlarge"), script_enlarge);