/* * Copyright 2017 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 net.jafama.FastMath; import pixelitor.ThreadPool; import pixelitor.filters.gui.AngleParam; import pixelitor.filters.gui.ImagePositionParam; import pixelitor.filters.gui.ParamSet; import pixelitor.filters.gui.RangeParam; import pixelitor.filters.gui.ShowOriginal; import pixelitor.utils.BasicProgressTracker; import pixelitor.utils.ImageUtils; import pixelitor.utils.ProgressTracker; import java.awt.Color; import java.awt.image.BufferedImage; import java.util.concurrent.Future; /** * Renders a color wheel */ public class ColorWheel extends FilterWithParametrizedGUI { public static final String NAME = "Color Wheel"; private final ImagePositionParam center = new ImagePositionParam("Center"); private final AngleParam hueShiftParam = new AngleParam("Rotate (Degrees)", 0); private final RangeParam brightnessParam = new RangeParam("Brightness (%)", 0, 75, 100); private final RangeParam satParam = new RangeParam("Saturation (%)", 0, 90, 100); public ColorWheel() { super(ShowOriginal.NO); setParamSet(new ParamSet(center, hueShiftParam, brightnessParam, satParam)); } @Override public BufferedImage doTransform(BufferedImage src, BufferedImage dest) { int[] destData = ImageUtils.getPixelsAsArray(dest); int width = dest.getWidth(); int height = dest.getHeight(); int cx = (int) (width * center.getRelativeX()); int cy = (int) (height * center.getRelativeY()); float hueShift = (float) hueShiftParam.getValueInRadians(); float saturation = satParam.getValueAsPercentage(); float brightness = brightnessParam.getValueAsPercentage(); ProgressTracker pt = new BasicProgressTracker(NAME, height); Future<?>[] futures = new Future[height]; for (int y = 0; y < height; y++) { int finalY = y; Runnable lineTask = () -> calculateLine(destData, width, cx, cy, hueShift, saturation, brightness, finalY); futures[y] = ThreadPool.submit(lineTask); } ThreadPool.waitForFutures(futures, pt); pt.finish(); return dest; } private static void calculateLine(int[] destData, int width, int cx, int cy, float hueShift, float saturation, float brightness, int y) { for (int x = 0; x < width; x++) { double yDiff = (double) (cy - y); double xDiff = (double) x - cx; float angle = (float) (FastMath.atan2(yDiff, xDiff)) + hueShift; float hue = (float) (angle / (2 * Math.PI)); destData[x + y * width] = Color.HSBtoRGB(hue, saturation, brightness); } } @Override public boolean supportsGray() { return false; } }