/** * @file ImageEffects.java * @brief Class implementing the generic pluggable image effects. * * @section License * * Copyright (C) 2014 Robert B. Colton * This file is a part of the LateralGM IDE. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. **/ package org.lateralgm.components; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Toolkit; import java.awt.color.ColorSpace; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ColorConvertOp; import java.awt.image.ConvolveOp; import java.awt.image.FilteredImageSource; import java.awt.image.ImageFilter; import java.awt.image.ImageProducer; import java.awt.image.Kernel; import java.awt.image.RGBImageFilter; import java.util.ArrayList; import java.util.List; import javax.swing.GroupLayout; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.GroupLayout.Alignment; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.lateralgm.components.NumberField.ValueChangeEvent; import org.lateralgm.components.NumberField.ValueChangeListener; import org.lateralgm.main.Util; import org.lateralgm.messages.Messages; import static javax.swing.GroupLayout.PREFERRED_SIZE; public class ImageEffects { public abstract interface EffectOptionListener { public abstract void optionsUpdated(); } public static abstract class ImageEffect { private List<EffectOptionListener> listeners = new ArrayList<EffectOptionListener>(); public abstract BufferedImage getAppliedImage(BufferedImage img); public abstract JPanel getOptionsPanel(); public String getName() { return Messages.getString("ImageEffects." + getKey()); } public abstract String getKey(); protected void optionsUpdated() { for (EffectOptionListener listener : listeners) { listener.optionsUpdated(); } } public void addOptionUpdateListener(EffectOptionListener listener) { listeners.add(listener); } public void removeOptionUpdateListener(EffectOptionListener listener) { listeners.remove(listener); } } public static class BlackAndWhiteEffect extends ImageEffect { private final String key = "BlackAndWhiteEffect"; @Override public BufferedImage getAppliedImage(BufferedImage img) { BufferedImage ret = new BufferedImage(img.getColorModel(), img.copyData(null), img.isAlphaPremultiplied(), null); ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null); op.filter(img, ret); return ret; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); return pane; } @Override public String getKey() { return key; } } public static class OpacityEffect extends ImageEffect { private final String key = "OpacityEffect"; private JSlider alphaSlider = null; @Override public BufferedImage getAppliedImage(BufferedImage img) { BufferedImage target = new BufferedImage(img.getWidth(), img.getHeight(), java.awt.Transparency.TRANSLUCENT); // Get the images graphics Graphics2D g = target.createGraphics(); // Set the Graphics composite to Alpha g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alphaSlider.getValue()/255)); // Draw the image into the prepared reciver image g.drawImage(img, null, 0, 0); // let go of all system resources in this Graphics g.dispose(); // Return the image return target; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel alphaLabel = new JLabel(Messages.getString("ImageEffects.TRANSPARENCY")); alphaSlider = new JSlider(0,255,155); alphaSlider.setPaintTicks(true); alphaSlider.setMajorTickSpacing(15); alphaSlider.setMinorTickSpacing(3); final NumberField alphaField = new NumberField(0,255,155); alphaSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { alphaField.setValue(alphaSlider.getValue()); optionsUpdated(); } }); alphaField.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent evt) { alphaSlider.setValue((int) evt.getNewValue()); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createParallelGroup() /**/.addGroup(gl.createSequentialGroup() /* */.addComponent(alphaLabel) /* */.addComponent(alphaSlider) /* */.addComponent(alphaField,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(alphaLabel) /* */.addComponent(alphaSlider) /* */.addComponent(alphaField,PREFERRED_SIZE,PREFERRED_SIZE,PREFERRED_SIZE))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static class InvertEffect extends ImageEffect { private final String key = "InvertEffect"; @Override public BufferedImage getAppliedImage(BufferedImage img) { int width = img.getWidth(); int height = img.getHeight(); BufferedImage dst = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); for (int i = 0; i < width; i++) { for (int ii = 0; ii < height; ii++) { int rgba = img.getRGB(i,ii); Color col = new Color(rgba, true); /* Monochrome col = new Color(Math.abs(255 - col.getRed()), Math.abs(255 - col.getRed()), Math.abs(255 - col.getRed()), col.getAlpha()); */ col = new Color(255 - col.getRed(), 255 - col.getGreen(), 255 - col.getBlue(), col.getAlpha()); dst.setRGB(i,ii,col.getRGB()); } } return dst; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); return pane; } @Override public String getKey() { return key; } } public static class EdgeDetectEffect extends ImageEffect { private final String key = "EdgeDetectEffect"; @Override public BufferedImage getAppliedImage(BufferedImage img) { img = Util.convertImage(img,BufferedImage.TYPE_INT_ARGB); BufferedImage dst = new BufferedImage(img.getWidth(),img.getHeight(), img.getType()); Kernel kernel = new Kernel(3, 3, new float[]{ -1, -1, -1, -1, 8, -1, -1, -1, -1}); BufferedImageOp op = new ConvolveOp(kernel,ConvolveOp.EDGE_ZERO_FILL,null); return op.filter(img, dst); } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); return pane; } @Override public String getKey() { return key; } } public static class EmbossEffect extends ImageEffect { private final String key = "EmbossColorEffect"; @Override public BufferedImage getAppliedImage(BufferedImage img) { int width = img.getWidth(); int height = img.getHeight(); BufferedImage dst = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { int upperLeft = 0; int lowerRight = 0; if (i > 0 && j > 0) upperLeft = img.getRGB(j - 1, i - 1); if (i < height - 1 && j < width - 1) lowerRight = img.getRGB(j + 1, i + 1); int redDiff = ((lowerRight >> 16) & 255) - ((upperLeft >> 16) & 255); int greenDiff = ((lowerRight >> 8) & 255) - ((upperLeft >> 8) & 255); int blueDiff = (lowerRight & 255) - (upperLeft & 255); int diff = redDiff; if (Math.abs(greenDiff) > Math.abs(diff)) diff = greenDiff; if (Math.abs(blueDiff) > Math.abs(diff)) diff = blueDiff; int grayColor = 128 + diff; if (grayColor > 255) grayColor = 255; else if (grayColor < 0) grayColor = 0; int newColor = (grayColor << 16) + (grayColor << 8) + grayColor; dst.setRGB(j, i, newColor); } return dst; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); return pane; } @Override public String getKey() { return key; } } public static class BlurEffect extends ImageEffect { private final String key = "BlurEffect"; private JSlider repeatSlider; @Override public BufferedImage getAppliedImage(BufferedImage img) { img = Util.convertImage(img,BufferedImage.TYPE_INT_ARGB); BufferedImage dst = new BufferedImage(img.getWidth(),img.getHeight(), img.getType()); Kernel kernel = new Kernel(3, 3, new float[]{ 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f}); BufferedImageOp op = new ConvolveOp(kernel,ConvolveOp.EDGE_ZERO_FILL,null); dst = op.filter(img, dst); for (int i = 0; i < repeatSlider.getValue() - 1; i++) { dst = op.filter(dst,null); } return dst; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel alphaLabel = new JLabel(Messages.getString("ImageEffects.REPETITIONS")); repeatSlider = new JSlider(1,20,2); repeatSlider.setPaintTicks(true); repeatSlider.setSnapToTicks(true); repeatSlider.setMajorTickSpacing(5); repeatSlider.setMinorTickSpacing(1); repeatSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createParallelGroup() /**/.addGroup(gl.createSequentialGroup() /* */.addComponent(alphaLabel) /* */.addComponent(repeatSlider))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(alphaLabel) /* */.addComponent(repeatSlider))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static class SharpenEffect extends ImageEffect { private final String key = "SharpenEffect"; private JSlider repeatSlider; @Override public BufferedImage getAppliedImage(BufferedImage img) { img = Util.convertImage(img,BufferedImage.TYPE_INT_ARGB); BufferedImage dst = new BufferedImage(img.getWidth(),img.getHeight(), img.getType()); Kernel kernel = new Kernel(3, 3, new float[]{ -1, -1, -1, -1, 9, -1, -1, -1, -1}); BufferedImageOp op = new ConvolveOp(kernel,ConvolveOp.EDGE_ZERO_FILL,null); dst = op.filter(img, dst); for (int i = 0; i < repeatSlider.getValue() - 1; i++) { dst = op.filter(dst,null); } return dst; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel alphaLabel = new JLabel(Messages.getString("ImageEffects.REPETITIONS")); repeatSlider = new JSlider(1,20,2); repeatSlider.setPaintTicks(true); repeatSlider.setSnapToTicks(true); repeatSlider.setMajorTickSpacing(5); repeatSlider.setMinorTickSpacing(1); repeatSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createParallelGroup() /**/.addGroup(gl.createSequentialGroup() /* */.addComponent(alphaLabel) /* */.addComponent(repeatSlider))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(alphaLabel) /* */.addComponent(repeatSlider))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static class RemoveTransparencyEffect extends ImageEffect { private final String key = "RemoveTransparencyEffect"; private ColorSelect colorSelect; @Override public BufferedImage getAppliedImage(BufferedImage img) { BufferedImage dst = Util.clearBackground(img,colorSelect.getSelectedColor()); return dst; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel colorLabel = new JLabel(Messages.getString("ImageEffects.COLOR")); colorSelect = new ColorSelect(Color.WHITE,true); colorSelect.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent ie) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createParallelGroup() /**/.addGroup(gl.createSequentialGroup() /* */.addComponent(colorLabel) /* */.addComponent(colorSelect))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.BASELINE) /* */.addComponent(colorLabel) /* */.addComponent(colorSelect))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static double ColourDistance(Color c1, Color c2) { double rmean = ( c1.getRed() + c2.getRed() )/2; int r = c1.getRed() - c2.getRed(); int g = c1.getGreen() - c2.getGreen(); int b = c1.getBlue() - c2.getBlue(); double weightR = 2 + rmean/256; double weightG = 4.0; double weightB = 2 + (255-rmean)/256; return Math.sqrt(weightR*r*r + weightG*g*g + weightB*b*b); } public static class RemoveColorEffect extends ImageEffect { private final String key = "RemoveColorEffect"; private ColorSelect colorSelect; private JSlider toleranceSlider; @Override public BufferedImage getAppliedImage(BufferedImage img) { final int col = colorSelect.getSelectedColor().getRGB(); ImageFilter filter = new RGBImageFilter() { @Override public int filterRGB(int x, int y, int rgb) { if (ColourDistance(new Color(rgb), new Color(col)) < toleranceSlider.getValue()) return col & 0x00FFFFFF; return rgb; } }; ImageProducer ip = new FilteredImageSource(img.getSource(),filter); return Util.toBufferedImage(Toolkit.getDefaultToolkit().createImage(ip)); } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel colorLabel = new JLabel(Messages.getString("ImageEffects.COLOR")); colorSelect = new ColorSelect(Color.WHITE,true); colorSelect.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent ie) { optionsUpdated(); } }); JLabel toleranceLabel = new JLabel(Messages.getString("ImageEffects.TOLERANCE")); toleranceSlider = new JSlider(0,255,15); toleranceSlider.setPaintTicks(true); toleranceSlider.setSnapToTicks(true); toleranceSlider.setMajorTickSpacing(15); toleranceSlider.setMinorTickSpacing(3); toleranceSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.TRAILING) /* */.addComponent(colorLabel) /* */.addComponent(toleranceLabel)) /**/.addGroup(gl.createParallelGroup() /* */.addComponent(colorSelect) /* */.addComponent(toleranceSlider))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.BASELINE) /* */.addComponent(colorLabel) /* */.addComponent(colorSelect)) /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(toleranceLabel) /* */.addComponent(toleranceSlider))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static class FadeColorEffect extends ImageEffect { private final String key = "FadeColorEffect"; private ColorSelect colorSelect; private JSlider intensitySlider; @Override public BufferedImage getAppliedImage(BufferedImage img) { BufferedImage target = new BufferedImage(img.getWidth(), img.getHeight(), java.awt.Transparency.TRANSLUCENT); // Get the images graphics Graphics2D g = target.createGraphics(); // Draw the image into the prepared reciver image g.drawImage(img, null, 0, 0); // Set the Graphics composite to Alpha g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, (float) intensitySlider.getValue()/255)); g.setColor(colorSelect.getSelectedColor()); g.fillRect(0,0,img.getWidth(),img.getHeight()); // let go of all system resources in this Graphics g.dispose(); // Return the image return target; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel colorLabel = new JLabel(Messages.getString("ImageEffects.COLOR")); colorSelect = new ColorSelect(Color.YELLOW,false); colorSelect.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent ie) { optionsUpdated(); } }); JLabel toleranceLabel = new JLabel(Messages.getString("ImageEffects.INTENSITY")); intensitySlider = new JSlider(0,255,155); intensitySlider.setPaintTicks(true); intensitySlider.setSnapToTicks(true); intensitySlider.setMajorTickSpacing(15); intensitySlider.setMinorTickSpacing(3); intensitySlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.TRAILING) /* */.addComponent(colorLabel) /* */.addComponent(toleranceLabel)) /**/.addGroup(gl.createParallelGroup() /* */.addComponent(colorSelect) /* */.addComponent(intensitySlider))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.BASELINE) /* */.addComponent(colorLabel) /* */.addComponent(colorSelect)) /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(toleranceLabel) /* */.addComponent(intensitySlider))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static float clamp(float val, float min, float max) { return Math.max(min, Math.min(max, val)); } public static float wrap(float val, float min, float max) { float dif = max - min; while (val < min) val += dif; while (val > max) val -= dif; return val; } public static class ColorizeEffect extends ImageEffect { private final String key = "ColorizeEffect"; private JSlider hueSlider; private JCheckBox hueShift; private JSlider satSlider; private JCheckBox satShift; private JSlider valSlider; private JCheckBox valShift; @Override public BufferedImage getAppliedImage(BufferedImage img) { int width = img.getWidth(); int height = img.getHeight(); BufferedImage dst = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); for (int i = 0; i < width; i++) { for (int ii = 0; ii < height; ii++) { int rgba = img.getRGB(i,ii); Color col = new Color(rgba, true); float[] hslVals = new float[3]; int alpha = col.getAlpha(); Color.RGBtoHSB(col.getRed(), col.getGreen(), col.getBlue(), hslVals); // Pass .5 (= 180 degrees) as HUE col = new Color(Color.HSBtoRGB( wrap((hueShift.isSelected() ? hslVals[0] : 0) + hueSlider.getValue() / 360.0f,0,1), satShift.isSelected() ? clamp(hslVals[1] + satSlider.getValue() / 100.0f, 0.0f, 1.0f) : (100.0f + satSlider.getValue()) / 200.0f, valShift.isSelected() ? clamp(hslVals[2] + valSlider.getValue() / 100.0f, 0.0f, 1.0f) : (100.0f + valSlider.getValue()) / 200.0f)); col = new Color(col.getRed(), col.getGreen(), col.getBlue(), alpha); dst.setRGB(i,ii,col.getRGB()); } } return dst; } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel hueLabel = new JLabel(Messages.getString("ImageEffects.HUE")); hueSlider = new JSlider(-180,180,0); hueSlider.setPaintTicks(true); hueSlider.setSnapToTicks(false); hueSlider.setMajorTickSpacing(45); hueSlider.setMinorTickSpacing(5); hueSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); hueShift = new JCheckBox(Messages.getString("ImageEffects.RELATIVE"), true); hueShift.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent arg0) { optionsUpdated(); } }); JLabel satLabel = new JLabel(Messages.getString("ImageEffects.SATURATION")); satSlider = new JSlider(-100,100,0); satSlider.setPaintTicks(true); satSlider.setSnapToTicks(false); satSlider.setMajorTickSpacing(20); satSlider.setMinorTickSpacing(5); satSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); satShift = new JCheckBox(Messages.getString("ImageEffects.RELATIVE"), true); satShift.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent arg0) { optionsUpdated(); } }); JLabel valLabel = new JLabel(Messages.getString("ImageEffects.VALUE")); valSlider = new JSlider(-100,100,0); valSlider.setPaintTicks(true); valSlider.setSnapToTicks(false); valSlider.setMajorTickSpacing(20); valSlider.setMinorTickSpacing(5); valSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); valShift = new JCheckBox(Messages.getString("ImageEffects.RELATIVE"), true); valShift.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent arg0) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.TRAILING) /* */.addComponent(hueLabel) /* */.addComponent(satLabel) /* */.addComponent(valLabel)) /**/.addGroup(gl.createParallelGroup(Alignment.TRAILING) /* */.addGroup(gl.createSequentialGroup() /* */.addComponent(hueSlider) /* */.addComponent(hueShift)) /* */.addGroup(gl.createSequentialGroup() /* */.addComponent(satSlider) /* */.addComponent(satShift)) /* */.addGroup(gl.createSequentialGroup() /* */.addComponent(valSlider) /* */.addComponent(valShift)))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(hueLabel) /* */.addComponent(hueSlider) /* */.addComponent(hueShift)) /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(satLabel) /* */.addComponent(satSlider) /* */.addComponent(satShift)) /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(valLabel) /* */.addComponent(valSlider) /* */.addComponent(valShift))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } public static class IntensityEffect extends ImageEffect { private final String key = "IntensityEffect"; private JSlider brightnessSlider; private JSlider contrastSlider; //from David Fichtm�ller public BufferedImage applyBrightnessAndContrast(BufferedImage bi, double brightness, double contrast) { final double gamma = 0.25; if (contrast > 0) { contrast = (100 * Math.pow(contrast - 1, 1 / gamma) / Math.pow(100, 1 / gamma)) + 1; } else if (contrast == 0) { contrast = 1; } else { contrast = 1 / ((100 * Math.pow(-contrast + 1, 1 / gamma) / Math.pow(100, 1 / gamma)) + 1); } if (brightness > 0) { brightness = (100 * Math.pow(brightness, 1 / gamma) / Math.pow(100, 1 / gamma)) + 1; } else if (brightness == 0) { brightness = 1; } else { brightness = 1 / ((100 * Math.pow(-brightness, 1 / gamma) / Math.pow(100, 1 / gamma)) + 1); } final int w = bi.getWidth(); final int h = bi.getHeight(); final BufferedImage out = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { int rgb = bi.getRGB(x, y); // get the rgb-values int alpha = (int) ((rgb & 0xff000000l) >> 24); int r = ((rgb & 0x00ff0000) >> 16); int g = ((rgb & 0x0000ff00) >> 8); int b = ((rgb & 0x000000ff)); // apply brightness filter r = (int) (r * brightness); g = (int) (g * brightness); b = (int) (b * brightness); // convert to YCbCr double Y = r * 0.299 + g * 0.587 + b * 0.114; double Cb = r * -0.168736 + g * -0.331264 + b * 0.5; double Cr = r * 0.5 + g * -0.418688 + b * -0.081312; // apply contrast filter Y = (Y + brightness - 127) * contrast + 127; Cb = Cb * contrast; Cr = Cr * contrast; // convert back to RGB r = (int) (Y + (Cr * 1.402)); g = (int) (Y + (Cb * -0.344136) + (Cr * -0.714136)); b = (int) (Y + (Cb * 1.772)); // check sizes of return values if (alpha > 255) { alpha = 255; } else if (alpha < 0) { alpha = 0; } if (g > 255) { g = 255; } else if (g < 0) { g = 0; } if (r > 255) { r = 255; } else if (r < 0) { r = 0; } if (b > 255) { b = 255; } else if (b < 0) { b = 0; } rgb = ((alpha & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); out.setRGB(x, y, rgb); } } return out; } @Override public BufferedImage getAppliedImage(BufferedImage img) { return this.applyBrightnessAndContrast(img,brightnessSlider.getValue(), contrastSlider.getValue()); } @Override public JPanel getOptionsPanel() { JPanel pane = new JPanel(); JLabel hueLabel = new JLabel(Messages.getString("ImageEffects.BRIGHTNESS")); brightnessSlider = new JSlider(-100,100,0); brightnessSlider.setPaintTicks(true); brightnessSlider.setSnapToTicks(false); brightnessSlider.setMajorTickSpacing(20); brightnessSlider.setMinorTickSpacing(5); brightnessSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); JLabel satLabel = new JLabel(Messages.getString("ImageEffects.CONTRAST")); contrastSlider = new JSlider(-100,100,0); contrastSlider.setPaintTicks(true); contrastSlider.setSnapToTicks(false); contrastSlider.setMajorTickSpacing(20); contrastSlider.setMinorTickSpacing(5); contrastSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { optionsUpdated(); } }); GroupLayout gl = new GroupLayout(pane); gl.setAutoCreateContainerGaps(true); gl.setAutoCreateGaps(true); gl.setHorizontalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.TRAILING) /* */.addComponent(hueLabel) /* */.addComponent(satLabel)) /**/.addGroup(gl.createParallelGroup(Alignment.TRAILING) /* */.addComponent(brightnessSlider) /* */.addComponent(contrastSlider))); gl.setVerticalGroup(gl.createSequentialGroup() /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(hueLabel) /* */.addComponent(brightnessSlider)) /**/.addGroup(gl.createParallelGroup(Alignment.CENTER) /* */.addComponent(satLabel) /* */.addComponent(contrastSlider))); pane.setLayout(gl); return pane; } @Override public String getKey() { return key; } } }