/* * Copyright 2020 Laszlo Balazs-Csiki and Contributors * * 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 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 = Math.max(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 rgbOp.toFilterAction(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 = Math.max(r, g); if (b > maxRGB) { maxRGB = b; } int minRGB = Math.min(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 rgbOp.toFilterAction("Desaturate"); } public static FilterAction getSaturationChannelFA() { RGBPixelOp rgbOp = (a, r, g, b) -> { int rgbMax = Math.max(r, g); if (b > rgbMax) { rgbMax = b; } int rgbMin = Math.min(r, g); if (b < rgbMin) { rgbMin = b; } int saturation = 0; if (rgbMax != 0) { saturation = (int) ((rgbMax - rgbMin) / (float) rgbMax * 255); } r = saturation; g = saturation; b = saturation; return a << 24 | r << 16 | g << 8 | b; }; return rgbOp.toFilterAction("Saturation"); } public static FilterAction getHueChannelFA() { var 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 rgbOp.toFilterAction("Hue"); } public static FilterAction getHueInColorsChannelFA() { var 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 newRGB &= 0x00FFFFFF; // set alpha to 0 return a << 24 | newRGB; // add the real alpha } }; return rgbOp.toFilterAction("Hue (with colors)"); } }