/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2011 Andreas Maschke
This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This software 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this software;
if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jwildfire.transform;
import org.jwildfire.base.Property;
import org.jwildfire.base.PropertyMax;
import org.jwildfire.base.PropertyMin;
import org.jwildfire.base.Tools;
import org.jwildfire.image.Pixel;
import org.jwildfire.image.SimpleImage;
import org.jwildfire.image.WFImage;
public class BalancingTransformer extends Mesh2DTransformer {
@Property(description = "Color correction of the red channel")
@PropertyMin(-255)
@PropertyMax(255)
private int red = 0;
@Property(description = "Color correction of the green channel")
@PropertyMin(-255)
@PropertyMax(255)
private int green = 0;
@Property(description = "Color correction of the blue channel")
@PropertyMin(-255)
@PropertyMax(255)
private int blue = 0;
@Property(description = "Brightness correction")
@PropertyMin(-255)
@PropertyMax(255)
private int brightness = 0;
@Property(description = "Contrast correction")
@PropertyMin(-255)
@PropertyMax(255)
private int contrast = 0;
@Property(description = "Gamma correction")
@PropertyMin(-255)
@PropertyMax(255)
private int gamma = 0;
@Property(description = "Saturation correction")
@PropertyMin(-255)
@PropertyMax(255)
private int saturation = 0;
@Override
protected void performPixelTransformation(WFImage pImg) {
SimpleImage img = (SimpleImage) pImg;
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
final double brMAX = 256.0;
Pixel pixel = new Pixel();
/* saturation */
if (this.saturation != 0) {
int rs = 2990;
int gs = 5880;
int bs = 1130;
rs = (rs * Tools.VPREC) / 10000;
gs = (gs * Tools.VPREC) / 10000;
bs = (bs * Tools.VPREC) / 10000;
int scl = (int) ((double) this.saturation / 255.0 * 1024.0 + 0.5);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
int avg = (rs * pixel.r + gs * pixel.g + bs * pixel.b) >> Tools.SPREC;
pixel.r += ((pixel.r - avg) * scl) >> Tools.SPREC;
if (pixel.r < 0)
pixel.r = 0;
else if (pixel.r > 255)
pixel.r = 255;
pixel.g += ((pixel.g - avg) * scl) >> Tools.SPREC;
if (pixel.g < 0)
pixel.g = 0;
else if (pixel.g > 255)
pixel.g = 255;
pixel.b += ((pixel.b - avg) * scl) >> Tools.SPREC;
if (pixel.b < 0)
pixel.b = 0;
else if (pixel.b > 255)
pixel.b = 255;
img.setRGB(j, i, pixel);
}
}
}
/* gamma */
if (this.gamma != 0) {
double max = 255.0;
double g = (double) 512.0 / (512.0 + (double) this.gamma);
int gamma[] = new int[256];
double da, aa;
da = aa = 1.0 / 255.0;
gamma[0] = 0;
for (int i = 1; i < 256; i++) {
int val = (int) (max * Math.pow(aa, g) + 0.5);
aa += da;
gamma[i] = val;
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
pixel.r = gamma[pixel.r];
pixel.g = gamma[pixel.g];
pixel.b = gamma[pixel.b];
img.setRGB(j, i, pixel);
}
}
}
/* red */
if (this.red != 0) {
int tt = (int) ((double) this.red / (double) brMAX * (double) 255.0 + 0.5);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
pixel.r += tt;
if (pixel.r < 0)
pixel.r = 0;
else if (pixel.r > 255)
pixel.r = 255;
img.setRGB(j, i, pixel);
}
}
}
/* green */
if (this.green != 0) {
int tt = (int) ((double) this.green / (double) brMAX * (double) 255.0 + 0.5);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
pixel.g += tt;
if (pixel.g < 0)
pixel.g = 0;
else if (pixel.g > 255)
pixel.g = 255;
img.setRGB(j, i, pixel);
}
}
}
/* blue */
if (this.blue != 0) {
int tt = (int) ((double) this.blue / (double) brMAX * (double) 255.0 + 0.5);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
pixel.b += tt;
if (pixel.b < 0)
pixel.b = 0;
else if (pixel.b > 255)
pixel.b = 255;
img.setRGB(j, i, pixel);
}
}
}
/* brightness */
if (brightness != 0) {
int tt = (int) ((double) this.brightness / (double) brMAX * (double) 255.0 + 0.5);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
pixel.r += tt;
if (pixel.r < 0)
pixel.r = 0;
else if (pixel.r > 255)
pixel.r = 255;
pixel.g += tt;
if (pixel.g < 0)
pixel.g = 0;
else if (pixel.g > 255)
pixel.g = 255;
pixel.b += tt;
if (pixel.b < 0)
pixel.b = 0;
else if (pixel.b > 255)
pixel.b = 255;
img.setRGB(j, i, pixel);
}
}
}
/* contrast */
if (this.contrast != 0) {
double scale = (double) this.contrast / brMAX;
int sc = (int) (scale * (double) Tools.VPREC + 0.5);
int dc;
if (this.contrast > 0) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
dc = (int) (((int) (pixel.r - (int) 127) * sc) >> Tools.SPREC);
if (dc < (-255))
dc = (-255);
else if (dc > 255)
dc = 255;
pixel.r += dc;
if (pixel.r < 0)
pixel.r = 0;
else if (pixel.r > 255)
pixel.r = 255;
dc = (int) (((int) (pixel.g - (int) 127) * sc) >> Tools.SPREC);
if (dc < (-255))
dc = (-255);
else if (dc > 255)
dc = 255;
pixel.g += dc;
if (pixel.g < 0)
pixel.g = 0;
else if (pixel.g > 255)
pixel.g = 255;
dc = (int) ((int) ((pixel.b - (int) 127) * sc) >> Tools.SPREC);
if (dc < (-255))
dc = (-255);
else if (dc > 255)
dc = 255;
pixel.b += dc;
if (pixel.b < 0)
pixel.b = 0;
else if (pixel.b > 255)
pixel.b = 255;
img.setRGB(j, i, pixel);
}
}
}
else {
int val;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixel.setARGBValue(img.getARGBValue(j, i));
dc = (int) (((int) ((int) pixel.r - (int) 127) * sc) >> Tools.SPREC);
if (dc < (-255))
dc = (-255);
else if (dc > 255)
dc = 255;
val = pixel.r + dc;
if (pixel.r < 127) {
if (val > 127)
val = 127;
}
else {
if (val < 127)
val = 127;
}
pixel.r = val;
dc = (int) ((int) ((pixel.g - (int) 127) * sc) >> Tools.SPREC);
if (dc < (-255))
dc = (-255);
else if (dc > 255)
dc = 255;
val = pixel.g + dc;
if (pixel.g < 127) {
if (val > 127)
val = 127;
}
else {
if (val < 127)
val = 127;
}
pixel.g = val;
dc = (int) ((int) ((pixel.b - (int) 127) * sc) >> Tools.SPREC);
if (dc < (-255))
dc = (-255);
else if (dc > 255)
dc = 255;
val = pixel.b + dc;
if (pixel.b < 127) {
if (val > 127)
val = 127;
}
else {
if (val < 127)
val = 127;
}
pixel.b = val;
img.setRGB(j, i, pixel);
}
}
}
}
}
public int getRed() {
return red;
}
public void setRed(int red) {
this.red = red;
}
public int getGreen() {
return green;
}
public void setGreen(int green) {
this.green = green;
}
public int getBlue() {
return blue;
}
public void setBlue(int blue) {
this.blue = blue;
}
public int getBrightness() {
return brightness;
}
public void setBrightness(int brightness) {
this.brightness = brightness;
}
public int getContrast() {
return contrast;
}
public void setContrast(int contrast) {
this.contrast = contrast;
}
public int getGamma() {
return gamma;
}
public void setGamma(int gamma) {
this.gamma = gamma;
}
public int getSaturation() {
return saturation;
}
public void setSaturation(int saturation) {
this.saturation = saturation;
}
@Override
public void initDefaultParams(WFImage pImg) {
red = green = blue = brightness = contrast = gamma = saturation = 0;
}
}