2009-09-01 03:14:13 +02:00
|
|
|
/***************************************************************************
|
|
|
|
|
|
|
|
effect.cpp
|
|
|
|
|
2018-02-12 02:53:46 +01:00
|
|
|
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
|
2009-09-01 03:14:13 +02:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2011-06-03 02:51:09 +02:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
2011-12-31 03:39:20 +01:00
|
|
|
MA 02110-1301, USA.
|
2009-09-01 03:14:13 +02:00
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define __EFFECT_CPP
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "effect.h"
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
static void get_info(GB_IMAGE img, uint **data, uint *width, uint *height, uint *npixels, bool *inv)
|
|
|
|
{
|
|
|
|
GB_IMG *info = (GB_IMG *)img;
|
|
|
|
|
2010-06-19 14:38:28 +02:00
|
|
|
SYNCHRONIZE_IMAGE(info);
|
|
|
|
|
2009-09-01 03:14:13 +02:00
|
|
|
*data = (uint *)info->data;
|
|
|
|
if (width) *width = info->width;
|
|
|
|
if (height) *height = info->height;
|
|
|
|
if (npixels) *npixels = info->width * info->height;
|
|
|
|
if (inv) *inv = GB_IMAGE_FMT_IS_SWAPPED(info->format); //(info->format == GB_IMAGE_RGBA || info->format == GB_IMAGE_RGBX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int between0And255 (int val)
|
|
|
|
{
|
|
|
|
if (val < 0)
|
|
|
|
return 0;
|
|
|
|
else if (val > 255)
|
|
|
|
return 255;
|
|
|
|
else
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint RGBA(int r, int g, int b, int a)
|
|
|
|
{
|
|
|
|
return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int R(uint rgb ) { return (int)((rgb >> 16) & 0xff); }
|
|
|
|
static inline int G(uint rgb ) { return (int)((rgb >> 8) & 0xff); }
|
|
|
|
static inline int B(uint rgb ) { return (int)(rgb & 0xff); }
|
|
|
|
static inline int A(uint rgb ) { return (int)((rgb >> 24) & 0xff); }
|
|
|
|
|
|
|
|
static inline uint invert(uint col)
|
|
|
|
{
|
|
|
|
return ((col & 0xFF)) << 16 | ((col & 0xFF0000)) >> 16 | (col & 0xFF00FF00);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int myRound(double d)
|
|
|
|
{
|
|
|
|
return d >= 0.0 ? int(d + 0.5) : int( d - ((int)d-1) + 0.5 ) + ((int)d-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int brightness (int base, int strength)
|
|
|
|
{
|
|
|
|
return between0And255(base + strength * 255 / 50);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int contrast (int base, int strength)
|
|
|
|
{
|
|
|
|
return between0And255 ((base - 127) * (strength + 50) / 50 + 127);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int gamma (int base, int strength)
|
|
|
|
{
|
|
|
|
return between0And255 (myRound(255.0 * pow (base / 255.0, 1.0 / pow (10, strength / 50.0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int brightnessContrastGamma(int base, int newBrightness, int newContrast, int newGamma)
|
|
|
|
{
|
|
|
|
return gamma(contrast(brightness(base, newBrightness), newContrast), newGamma);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Effect::balance(GB_IMAGE img, int channels, int brightness, int contrast, int gamma)
|
|
|
|
{
|
|
|
|
uchar transformRed[256], transformGreen[256], transformBlue[256];
|
|
|
|
uint i;
|
|
|
|
uint np;
|
|
|
|
uint *p;
|
|
|
|
bool inv;
|
|
|
|
uint col;
|
|
|
|
|
|
|
|
get_info(img, &p, NULL, NULL, &np, &inv);
|
|
|
|
|
|
|
|
if (!inv)
|
|
|
|
{
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
uchar applied = brightnessContrastGamma(i, brightness, contrast, gamma);
|
|
|
|
|
|
|
|
transformRed[i] = (channels & Red) ? applied : i;
|
|
|
|
transformGreen[i] = (channels & Green) ? applied : i;
|
|
|
|
transformBlue[i] = (channels & Blue) ? applied : i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
uchar applied = brightnessContrastGamma(i, brightness, contrast, gamma);
|
|
|
|
|
|
|
|
transformBlue[i] = (channels & Red) ? applied : i;
|
|
|
|
transformGreen[i] = (channels & Green) ? applied : i;
|
|
|
|
transformRed[i] = (channels & Blue) ? applied : i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < np; i++)
|
|
|
|
{
|
|
|
|
col = p[i];
|
|
|
|
p[i] = RGBA(transformRed[R(col)], transformGreen[G(col)], transformBlue[B(col)], A(col));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Effect::invert(GB_IMAGE img, int channels)
|
|
|
|
{
|
|
|
|
uint np;
|
|
|
|
uint *p;
|
|
|
|
bool inv;
|
|
|
|
uint mask;
|
|
|
|
uint i;
|
|
|
|
|
|
|
|
get_info(img, &p, NULL, NULL, &np, &inv);
|
|
|
|
|
|
|
|
if (!inv)
|
|
|
|
mask = RGBA((channels & Red) ? 0xFF : 0, (channels & Green) ? 0xFF : 0, (channels & Blue) ? 0xFF : 0, 0);
|
|
|
|
else
|
|
|
|
mask = RGBA((channels & Blue) ? 0xFF : 0, (channels & Green) ? 0xFF : 0, (channels & Red) ? 0xFF : 0, 0);
|
|
|
|
|
|
|
|
for (i = 0; i < np; i++)
|
|
|
|
p[i] ^= mask;
|
|
|
|
}
|
|
|
|
|