/* * 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.colors.palette; import com.jhlabs.image.ImageMath; import pixelitor.colors.ColorUtils; import pixelitor.colors.FgBgColors; import java.awt.Color; public class HSBColorMixPalette extends Palette { private static int lastRows = 7; private static int lastCols = 10; private final boolean fg; private float hue, otherHue; private final float sat, bri, otherSat, otherBri; private final float averageSat; private float extraSat; private static final float MAX_BRI_DEVIATION = 0.5f; public HSBColorMixPalette(boolean fg) { super(lastRows, lastCols); this.fg = fg; Color color, otherColor; if (fg) { color = FgBgColors.getFG(); otherColor = FgBgColors.getBG(); } else { color = FgBgColors.getBG(); otherColor = FgBgColors.getFG(); } float[] hsb = ColorUtils.colorToHSB(color); float[] hsb2 = ColorUtils.colorToHSB(otherColor); hue = hsb[0]; sat = hsb[1]; bri = hsb[2]; otherHue = hsb2[0]; otherSat = hsb2[1]; otherBri = hsb2[2]; // if the saturation is 0, then the hue does not mean anything, // but can lead to unexpected hue variations in the mix if (sat == 0) { hue = otherHue; } else if (otherSat == 0) { otherHue = hue; } // set the average saturation as the slider default averageSat = (sat + otherSat) / 2; config = new HueSatPaletteConfig(0.0f, averageSat); } @Override public void onConfigChange() { HueSatPaletteConfig hs = (HueSatPaletteConfig) config; extraSat = hs.getSaturation() - averageSat; } @Override public void addButtons(VariationsPanel panel) { for (int y = 0; y < numRows; y++) { float briStep = calcBriStep(); for (int x = 0; x < numCols; x++) { Color c; if (numRows == 1) { float mixFactor = calcMixFactor(x); float h = calcHue(mixFactor); float s = calcSat(mixFactor); float b = ImageMath.lerp(mixFactor, bri, otherBri); c = new Color(Color.HSBtoRGB(h, s, b)); } else { float mixFactor = calcMixFactor(x); float h = calcHue(mixFactor); float s = calcSat(mixFactor); float b = ImageMath.lerp(mixFactor, bri, otherBri); float startBri = b - MAX_BRI_DEVIATION; b = startBri + y * briStep; if (b > 1.0f) { b = 1.0f; } else if (b < 0.0f) { b = 0.0f; } c = new Color(Color.HSBtoRGB(h, s, b)); } panel.addButton(x, y, c); } } } private float calcBriStep() { // the total bri range (2 * MAX_BRI_DEVIATION) is // divided into numRows - 1 equal parts return 2 * MAX_BRI_DEVIATION / (numRows - 1); } private float calcMixFactor(int x) { return (x * (numCols + 1) / (float) numCols) / (float) numCols; } private float calcSat(float mixFactor) { float s = ImageMath.lerp(mixFactor, sat, otherSat) + extraSat; if (s > 1.0f) { s = 1.0f; } else if (s < 0.0f) { s = 0.0f; } return s; } private float calcHue(float mixFactor) { HueSatPaletteConfig hs = (HueSatPaletteConfig) config; float hueShift = hs.getHueShift(); float h = hueShift + ColorUtils.lerpHue(mixFactor, hue, otherHue); if (h > 1.0f) { h = h - 1.0f; } return h; } @Override public void setSize(int numRows, int numCols) { super.setSize(numRows, numCols); lastCols = numCols; lastRows = numRows; } @Override public String getDialogTitle() { return fg ? "HSB Mix with Background" : "HSB Mix with Foreground"; } }