/*
* Copyright 2016 Laszlo Balazs-Csiki
*
* This file is part of Pixelitor. Pixelitor is free software: you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License, version 3 as published by the Free
* Software Foundation.
*
* Pixelitor 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 Pixelitor. If not, see <http://www.gnu.org/licenses/>.
*/
package pixelitor.filters;
import java.awt.Color;
import java.awt.image.BufferedImage;
/**
* Extracts a channel from the image
*/
public class ExtractChannelFilter extends Filter {
private final RGBPixelOp rgbOp;
public ExtractChannelFilter(RGBPixelOp rgbOp) {
this.rgbOp = rgbOp;
}
@Override
public BufferedImage transform(BufferedImage src, BufferedImage dest) {
return FilterUtils.runRGBPixelOp(rgbOp, src, dest);
}
@Override
public void randomizeSettings() {
// no settings
}
@Override
public boolean supportsGray() {
return false;
}
// static factory methods from here
public static FilterAction getValueChannelFA() {
RGBPixelOp rgbOp = (a, r, g, b) -> {
// value = max(R, G, B)
int maxRGB = (r > g) ? r : g;
if (b > maxRGB) {
maxRGB = b;
}
int value = maxRGB;
r = value;
g = value;
b = value;
return (a << 24) | (r << 16) | (g << 8) | b;
};
String name = "Value = max(R,G,B)";
return rgbOpToFilterAction(rgbOp, name);
}
public static FilterAction getDesaturateChannelFA() {
RGBPixelOp rgbOp = (a, r, g, b) -> {
// achieves desaturation by setting the brightness to [max(R, G, B) + min (R, G, B)] / 2
int maxRGB = (r > g) ? r : g;
if (b > maxRGB) {
maxRGB = b;
}
int minRGB = (r < g) ? r : g;
if (b < minRGB) {
minRGB = b;
}
int brightness = (maxRGB + minRGB) / 2;
r = brightness;
g = brightness;
b = brightness;
return (a << 24) | (r << 16) | (g << 8) | b;
};
return rgbOpToFilterAction(rgbOp, "Desaturate");
}
public static FilterAction getSaturationChannelFA() {
RGBPixelOp rgbOp = (a, r, g, b) -> {
int rgbMax = (r > g) ? r : g;
if (b > rgbMax) {
rgbMax = b;
}
int rgbMin = (r < g) ? r : g;
if (b < rgbMin) {
rgbMin = b;
}
int saturation = 0;
if (rgbMax != 0) {
saturation = (int) (((float) (rgbMax - rgbMin)) / ((float) rgbMax) * 255);
}
r = saturation;
g = saturation;
b = saturation;
return (a << 24) | (r << 16) | (g << 8) | b;
};
return rgbOpToFilterAction(rgbOp, "Saturation");
}
public static FilterAction getHueChannelFA() {
RGBPixelOp rgbOp = new RGBPixelOp() {
private float[] tmpHSBArray = {0.0f, 0.0f, 0.0f};
@Override
public int changeRGB(int a, int r, int g, int b) {
tmpHSBArray = Color.RGBtoHSB(r, g, b, tmpHSBArray);
// Color.RGBtoHSB return all values in the 0..1 interval
int hue = (int) (tmpHSBArray[0] * 255);
r = hue;
g = hue;
b = hue;
return (a << 24) | (r << 16) | (g << 8) | b;
}
};
return rgbOpToFilterAction(rgbOp, "Hue");
}
public static FilterAction getHueInColorsChannelFA() {
RGBPixelOp rgbOp = new RGBPixelOp() {
private static final float DEFAULT_SATURATION = 0.9f;
private static final float DEFAULT_BRIGHTNESS = 0.75f;
private float[] tmpHSBArray = {0.0f, 0.0f, 0.0f};
@Override
public int changeRGB(int a, int r, int g, int b) {
if (a == 0) {
return 0; // for premultiplied images
}
tmpHSBArray = Color.RGBtoHSB(r, g, b, tmpHSBArray);
int newRGB = Color.HSBtoRGB(tmpHSBArray[0], DEFAULT_SATURATION, DEFAULT_BRIGHTNESS); // alpha is 255 here
newRGB &= 0x00FFFFFF; // set alpha to 0
return (a << 24) | newRGB; // add the real alpha
}
};
return rgbOpToFilterAction(rgbOp, "Hue (with colors)");
}
private static FilterAction rgbOpToFilterAction(RGBPixelOp rgbOp, String name) {
return new FilterAction(name,
() -> new ExtractChannelFilter(rgbOp))
.withoutGUI()
.withExtractChannelListName();
}
}