Blur an Image
/* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.awt.AlphaComposite; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Composite; import java.awt.Cursor; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.LinearGradientPaint; import java.awt.Paint; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ColorModel; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.List; import java.util.ResourceBundle; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.TransferHandler; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.jdesktop.animation.timing.Cycle; import org.jdesktop.animation.timing.Envelope; import org.jdesktop.animation.timing.TimingController; import org.jdesktop.animation.timing.interpolation.ObjectModifier; import org.jdesktop.animation.timing.interpolation.PropertyRange; public class Blur { private static MainFrame mainFrame; private static ResourceBundle bundle; private Blur() { } public static MainFrame getMainFrame() { return mainFrame; } public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } SwingUtilities.invokeLater(new Runnable() { public void run() { mainFrame = new MainFrame(); mainFrame.setVisible(true); } }); } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class MainFrame extends JFrame { private StepLabel stepLabel; private BufferedImage image; private ProgressGlassPane waitPanel; private TimingController timer; private SizeStepPanel sizeStep; private DragAndDropStepPanel dragAndDropStep; private DoneStepPanel doneStep; private String fileName; public MainFrame() { super(""); setContentPane(new GradientPanel()); setGlassPane(waitPanel = new ProgressGlassPane()); buildContentPane(); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(640, 480); setResizable(false); setLocationRelativeTo(null); } private void buildContentPane() { buildStepLabel(); add(stepLabel, BorderLayout.SOUTH); showDragAndDropStep(); } private void buildStepLabel() { stepLabel = new StepLabel(); stepLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 36, 0)); } public void showDragAndDropStep() { if (image != null) { image.flush(); image = null; } if (sizeStep != null) { remove(sizeStep); sizeStep = null; } else if (doneStep != null) { remove(doneStep); doneStep = null; } dragAndDropStep = new DragAndDropStepPanel(); dragAndDropStep.setTransferHandler(new ImageTransferHandler()); add(dragAndDropStep); setStepInfo(1, "Drop an image in this window"); hideWaitGlassPane(); } private void setStepInfo(int step, String message) { stepLabel.setStep(step); stepLabel.setText(message); } public void setImage(BufferedImage image, String fileName) { this.fileName = fileName; this.image = image; showSizeStep(); } public BufferedImage getImage() { return image; } private void showSizeStep() { sizeStep = new SizeStepPanel(); remove(dragAndDropStep); dragAndDropStep = null; add(sizeStep); setStepInfo(2, "Choose Title"); } public void showWaitGlassPane() { Cycle cycle = new Cycle(2500, 33); Envelope envelope = new Envelope(TimingController.INFINITE, 0, Envelope.RepeatBehavior.REVERSE, Envelope.EndBehavior.HOLD); PropertyRange fadeRange = PropertyRange.createPropertyRangeInt("progress", 0, 100); // NON-NLS timer = new TimingController(cycle, envelope, new ObjectModifier(waitPanel, fadeRange)); waitPanel.setProgress(0); waitPanel.setVisible(true); timer.start(); } public void hideWaitGlassPane() { if (timer != null && timer.isRunning()) { timer.stop(); } waitPanel.setVisible(false); } public void showDoneStep() { doneStep = new DoneStepPanel(); remove(sizeStep); sizeStep = null; add(doneStep); setStepInfo(3, "Picture saved"); hideWaitGlassPane(); } public String getFileName() { return fileName; } } /* * $Id: AbstractFilter.java,v 1.1 2007/01/15 16:12:02 gfx Exp $ * * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). * * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * <p>Provides an abstract implementation of the <code>BufferedImageOp</code> * interface. This class can be used to created new image filters based * on <code>BufferedImageOp</code>.</p> * * @author Romain Guy <romain.guy@mac.com> */ abstract class AbstractFilter implements BufferedImageOp { public abstract BufferedImage filter(BufferedImage src, BufferedImage dest); /** * {@inheritDoc} */ public Rectangle2D getBounds2D(BufferedImage src) { return new Rectangle(0, 0, src.getWidth(), src.getHeight()); } /** * {@inheritDoc} */ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { if (destCM == null) { destCM = src.getColorModel(); } return new BufferedImage(destCM, destCM.createCompatibleWritableRaster( src.getWidth(), src.getHeight()), destCM.isAlphaPremultiplied(), null); } /** * {@inheritDoc} */ public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { return (Point2D) srcPt.clone(); } /** * {@inheritDoc} */ public RenderingHints getRenderingHints() { return null; } } /* * $Id: ColorTintFilter.java,v 1.1 2007/01/15 16:12:02 gfx Exp $ * * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). * * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * <p>A color mixer filter can be used to mix a solid color to an image. The * result is an image tinted by the specified color. The force of the effect * can be controlled with the <code>mixValue</code>, a number between 0.0 and * 1.0 that can be seen as the percentage of the mix (0.0 does not affect the * source image and 1.0 replaces all the pixels by the solid color).</p> * <p>The color of the pixels in the resulting image is computed as follows:</p> * <pre> * cR = cS * (1 - mixValue) + cM * mixValue * </pre> * <p>Definition of the parameters:</p> * <ul> * <li><code>cR</code>: color of the resulting pixel</li> * <li><code>cS</code>: color of the source pixel</li> * <li><code>cM</code>: the solid color to mix with the source image</li> * <li><code>mixValue</code>: strength of the mix, a value between 0.0 and 1.0</li> * </ul> * * @author Romain Guy <romain.guy@mac.com> */ class ColorTintFilter extends AbstractFilter { private final Color mixColor; private final float mixValue; /** * <p>Creates a new color mixer filter. The specified color will be used * to tint the source image, with a mixing strength defined by * <code>mixValue</code>.</p> * * @param mixColor the solid color to mix with the source image * @param mixValue the strength of the mix, between 0.0 and 1.0; if the * specified value lies outside this range, it is clamped * @throws IllegalArgumentException if <code>mixColor</code> is null */ public ColorTintFilter(Color mixColor, float mixValue) { if (mixColor == null) { throw new IllegalArgumentException("mixColor cannot be null"); } this.mixColor = mixColor; if (mixValue < 0.0f) { mixValue = 0.0f; } else if (mixValue > 1.0f) { mixValue = 1.0f; } this.mixValue = mixValue; } /** * <p>Returns the mix value of this filter.</p> * * @return the mix value, between 0.0 and 1.0 */ public float getMixValue() { return mixValue; } /** * <p>Returns the solid mix color of this filter.</p> * * @return the solid color used for mixing */ public Color getMixColor() { return mixColor; } /** * {@inheritDoc} */ @Override public BufferedImage filter(BufferedImage src, BufferedImage dst) { if (dst == null) { dst = createCompatibleDestImage(src, null); } int width = src.getWidth(); int height = src.getHeight(); int[] pixels = new int[width * height]; GraphicsUtilities.getPixels(src, 0, 0, width, height, pixels); mixColor(pixels); GraphicsUtilities.setPixels(dst, 0, 0, width, height, pixels); return dst; } private void mixColor(int[] pixels) { int mix_a = mixColor.getAlpha(); int mix_r = mixColor.getRed(); int mix_g = mixColor.getBlue(); int mix_b = mixColor.getGreen(); for (int i = 0; i < pixels.length; i++) { int argb = pixels[i]; int a = (argb >> 24) & 0xFF; int r = (argb >> 16) & 0xFF; int g = (argb >> 8) & 0xFF; int b = (argb ) & 0xFF; a = (int) (a * (1.0f - mixValue) + mix_a * mixValue); r = (int) (r * (1.0f - mixValue) + mix_r * mixValue); g = (int) (g * (1.0f - mixValue) + mix_g * mixValue); b = (int) (b * (1.0f - mixValue) + mix_b * mixValue); pixels[i] = a << 24 | r << 16 | g << 8 | b; } } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class DoneStepPanel extends JPanel { public DoneStepPanel() { setLayout(new GridBagLayout()); setBackground(Color.BLACK); setOpaque(false); JLabel label = new JLabel("Done"); label.setFont(new Font("Helvetica", Font.BOLD, 64)); // NON-NLS label.setForeground(Color.WHITE); add(label, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class DragAndDropStepPanel extends JComponent { private BufferedImage dropHere; public DragAndDropStepPanel() { setBackground(Color.BLACK); setOpaque(false); loadSupportImage(); } private void loadSupportImage() { try { dropHere = GraphicsUtilities.loadCompatibleImage( getClass().getResource("drop-here.png")); // NON-NLS //dropHere = Reflection.createReflection(dropHere); } catch (IOException e) { e.printStackTrace(); } } @Override protected void paintComponent(Graphics g) { //Rectangle clip = g.getClipBounds(); //g.setColor(getBackground()); //g.fillRect(clip.x, clip.y, clip.width, clip.height); int x = (getWidth() - dropHere.getWidth()) / 2; int y = (getHeight() - dropHere.getHeight()) / 2; g.drawImage(dropHere, x, y, null); } } /* * $Id: FastBlurFilter.java,v 1.1 2007/01/15 16:12:02 gfx Exp $ * * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). * * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * * @author Romain Guy <romain.guy@mac.com> */ class FastBlurFilter extends AbstractFilter { private final int radius; public FastBlurFilter() { this(3); } public FastBlurFilter(int radius) { if (radius < 1) { radius = 1; } this.radius = radius; } public int getRadius() { return radius; } /** * {@inheritDoc} */ @Override public BufferedImage filter(BufferedImage src, BufferedImage dst) { int width = src.getWidth(); int height = src.getHeight(); if (dst == null) { dst = createCompatibleDestImage(src, null); } int[] srcPixels = new int[width * height]; int[] dstPixels = new int[width * height]; GraphicsUtilities.getPixels(src, 0, 0, width, height, srcPixels); // horizontal pass blur(srcPixels, dstPixels, width, height, radius); // vertical pass blur(dstPixels, srcPixels, height, width, radius); // the result is now stored in srcPixels due to the 2nd pass GraphicsUtilities.setPixels(dst, 0, 0, width, height, srcPixels); return dst; } private static void blur(int[] srcPixels, int[] dstPixels, int width, int height, int radius) { int windowSize = radius * 2 + 1; int sumAlpha; int sumRed; int sumGreen; int sumBlue; int srcIndex = 0; int dstIndex; int pixel; for (int y = 0; y < height; y++) { sumAlpha = sumRed = sumGreen = sumBlue = 0; dstIndex = y; pixel = srcPixels[srcIndex]; sumAlpha += (radius + 1) * ((pixel >> 24) & 0xFF); sumRed += (radius + 1) * ((pixel >> 16) & 0xFF); sumGreen += (radius + 1) * ((pixel >> 8) & 0xFF); sumBlue += (radius + 1) * ( pixel & 0xFF); for (int i = 1; i <= radius; i++) { pixel = srcPixels[srcIndex + (i <= width - 1 ? i : width - 1)]; sumAlpha += (pixel >> 24) & 0xFF; sumRed += (pixel >> 16) & 0xFF; sumGreen += (pixel >> 8) & 0xFF; sumBlue += pixel & 0xFF; } for (int x = 0; x < width; x++) { dstPixels[dstIndex] = sumAlpha / windowSize << 24 | sumRed / windowSize << 16 | sumGreen / windowSize << 8 | sumBlue / windowSize; dstIndex += height; int nextPixelIndex = x + radius + 1; if (nextPixelIndex >= width) { nextPixelIndex = width - 1; } int previousPixelIndex = x - radius; if (previousPixelIndex < 0) { previousPixelIndex = 0; } int nextPixel = srcPixels[srcIndex + nextPixelIndex]; int previousPixel = srcPixels[srcIndex + previousPixelIndex]; sumAlpha += (nextPixel >> 24) & 0xFF; sumAlpha -= (previousPixel >> 24) & 0xFF; sumRed += (nextPixel >> 16) & 0xFF; sumRed -= (previousPixel >> 16) & 0xFF; sumGreen += (nextPixel >> 8) & 0xFF; sumGreen -= (previousPixel >> 8) & 0xFF; sumBlue += nextPixel & 0xFF; sumBlue -= previousPixel & 0xFF; } srcIndex += width; } } } class GaussianBlurFilter extends AbstractFilter { private final int radius; /** * <p>Creates a new blur filter with a default radius of 3.</p> */ public GaussianBlurFilter() { this(3); } /** * <p>Creates a new blur filter with the specified radius. If the radius * is lower than 0, a radius of 0.1 will be used automatically.</p> * * @param radius the radius, in pixels, of the blur */ public GaussianBlurFilter(int radius) { if (radius < 1) { radius = 1; } this.radius = radius; } /** * <p>Returns the radius used by this filter, in pixels.</p> * * @return the radius of the blur */ public int getRadius() { return radius; } /** * {@inheritDoc} */ @Override public BufferedImage filter(BufferedImage src, BufferedImage dst) { int width = src.getWidth(); int height = src.getHeight(); if (dst == null) { dst = createCompatibleDestImage(src, null); } int[] srcPixels = new int[width * height]; int[] dstPixels = new int[width * height]; float[] kernel = createGaussianKernel(radius); GraphicsUtilities.getPixels(src, 0, 0, width, height, srcPixels); // horizontal pass blur(srcPixels, dstPixels, width, height, kernel, radius); // vertical pass //noinspection SuspiciousNameCombination blur(dstPixels, srcPixels, height, width, kernel, radius); // the result is now stored in srcPixels due to the 2nd pass GraphicsUtilities.setPixels(dst, 0, 0, width, height, srcPixels); return dst; } /** * <p>Blurs the source pixels into the destination pixels. The force of * the blur is specified by the radius which must be greater than 0.</p> * <p>The source and destination pixels arrays are expected to be in the * INT_ARGB format.</p> * <p>After this method is executed, dstPixels contains a transposed and * filtered copy of srcPixels.</p> * * @param srcPixels the source pixels * @param dstPixels the destination pixels * @param width the width of the source picture * @param height the height of the source picture * @param kernel the kernel of the blur effect * @param radius the radius of the blur effect */ static void blur(int[] srcPixels, int[] dstPixels, int width, int height, float[] kernel, int radius) { float a; float r; float g; float b; int ca; int cr; int cg; int cb; for (int y = 0; y < height; y++) { int index = y; int offset = y * width; for (int x = 0; x < width; x++) { a = r = g = b = 0.0f; for (int i = -radius; i <= radius; i++) { int subOffset = x + i; if (subOffset < 0 || subOffset >= width) { subOffset = (x + width) % width; } int pixel = srcPixels[offset + subOffset]; float blurFactor = kernel[radius + i]; a += blurFactor * ((pixel >> 24) & 0xFF); r += blurFactor * ((pixel >> 16) & 0xFF); g += blurFactor * ((pixel >> 8) & 0xFF); b += blurFactor * ((pixel ) & 0xFF); } ca = (int) (a + 0.5f); cr = (int) (r + 0.5f); cg = (int) (g + 0.5f); cb = (int) (b + 0.5f); dstPixels[index] = ((ca > 255 ? 255 : ca) << 24) | ((cr > 255 ? 255 : cr) << 16) | ((cg > 255 ? 255 : cg) << 8) | (cb > 255 ? 255 : cb); index += height; } } } static float[] createGaussianKernel(int radius) { if (radius < 1) { throw new IllegalArgumentException("Radius must be >= 1"); } float[] data = new float[radius * 2 + 1]; float sigma = radius / 3.0f; float twoSigmaSquare = 2.0f * sigma * sigma; float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI); float total = 0.0f; for (int i = -radius; i <= radius; i++) { float distance = i * i; int index = i + radius; data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot; total += data[index]; } for (int i = 0; i < data.length; i++) { data[i] /= total; } return data; } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class ImageTransferHandler extends TransferHandler { @Override public boolean canImport(TransferSupport support) { if (!support.isDrop()) { return false; } if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { return false; } boolean copySupported = (COPY & support.getSourceDropActions()) == COPY; if (copySupported) { support.setDropAction(COPY); return true; } return false; } @Override public boolean importData(TransferSupport support) { if (!support.isDrop()) { return false; } if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { return false; } Transferable t = support.getTransferable(); try { Object data = t.getTransferData(DataFlavor.javaFileListFlavor); final File file = ((List<File>) data).get(0); Thread loader = new Thread(new Runnable() { public void run() { //Application.getMainFrame().showWaitGlassPane(); try { BufferedImage image = GraphicsUtilities .loadCompatibleImage(file.toURI().toURL()); Application.getMainFrame().setImage(image, file.getName()); } catch (IOException e) { e.printStackTrace(); Application.getMainFrame().hideWaitGlassPane(); } } }); loader.start(); } catch (UnsupportedFlavorException e) { return false; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return true; } } final class Reflection { private Reflection() { } public static BufferedImage createReflection(BufferedImage image) { BufferedImage mask = createGradientMask(image.getWidth(), image.getHeight()); return createReflectedPicture(image, mask); } public static BufferedImage createReflectedPicture(BufferedImage avatar, BufferedImage alphaMask) { int avatarWidth = avatar.getWidth() + 6; int avatarHeight = avatar.getHeight(); BufferedImage buffer = createReflection(avatar, avatarWidth, avatarHeight); applyAlphaMask(buffer, alphaMask, avatarHeight); return buffer;/*.getSubimage(0, 0, avatarWidth, avatarHeight * 3 / 2)*/ } private static void applyAlphaMask(BufferedImage buffer, BufferedImage alphaMask, int avatarHeight) { Graphics2D g2 = buffer.createGraphics(); g2.setComposite(AlphaComposite.DstOut); g2.drawImage(alphaMask, null, 0, avatarHeight); g2.dispose(); } private static BufferedImage createReflection(BufferedImage avatar, int avatarWidth, int avatarHeight) { BufferedImage buffer = new BufferedImage(avatarWidth, avatarHeight * 5 / 3, BufferedImage.TYPE_INT_ARGB); Graphics2D g = buffer.createGraphics(); g.drawImage(avatar, null, null); g.translate(0, avatarHeight * 2); g.scale(1.0, -1.0); FastBlurFilter filter = new FastBlurFilter(3); g.drawImage(avatar, filter, 0, 0); g.dispose(); return buffer; } public static BufferedImage createGradientMask(int avatarWidth, int avatarHeight) { return createGradientMask(avatarWidth, avatarHeight, 0.7f, 1.0f); } public static BufferedImage createGradientMask(int avatarWidth, int avatarHeight, float opacityStart, float opacityEnd) { BufferedImage gradient = new BufferedImage(avatarWidth, avatarHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D g = gradient.createGraphics(); GradientPaint painter = new GradientPaint(0.0f, 0.0f, new Color(1.0f, 1.0f, 1.0f, opacityStart), 0.0f, avatarHeight / 2.0f, new Color(1.0f, 1.0f, 1.0f, opacityEnd)); g.setPaint(painter); g.fill(new Rectangle2D.Double(0, 0, avatarWidth, avatarHeight)); g.dispose(); return gradient; } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class GradientPanel extends JPanel { GradientPanel() { super(new BorderLayout()); } @Override protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; Rectangle clip = g2.getClipBounds(); Paint paint = g2.getPaint(); g2.setPaint(new GradientPaint(0.0f, getHeight() * 0.22f, new Color(0x202737), 0.0f, getHeight() * 0.9f, Color.BLACK)); g2.fillRect(clip.x, clip.y, clip.width, clip.height); g2.setPaint(paint); } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class ProgressGlassPane extends JComponent { private static final int BAR_WIDTH = 200; private static final int BAR_HEIGHT = 10; private static final Color TEXT_COLOR = new Color(0xFFFFFF); private static final float[] GRADIENT_FRACTIONS = new float[] { 0.0f, 0.499f, 0.5f, 1.0f }; private static final Color[] GRADIENT_COLORS = new Color[] { Color.GRAY, Color.DARK_GRAY, Color.BLACK, Color.GRAY }; private static final Color GRADIENT_COLOR2 = Color.WHITE; private static final Color GRADIENT_COLOR1 = Color.GRAY; private String message = "Please wait..."; private int progress = 0; private BufferedImage backDrop = null; public ProgressGlassPane() { setBackground(Color.WHITE); setFont(new Font("Helvetica", Font.BOLD, 16)); // NON-NLS setOpaque(true); } public int getProgress() { return progress; } @Override public void setVisible(boolean visible) { if (visible) { MainFrame mainFrame = Application.getMainFrame(); backDrop = GraphicsUtilities.createCompatibleImage(mainFrame.getRootPane().getWidth(), mainFrame.getRootPane().getHeight()); Graphics2D g2 = backDrop.createGraphics(); mainFrame.getRootPane().paint(g2); g2.dispose(); backDrop = GraphicsUtilities.createThumbnail(backDrop, mainFrame.getRootPane().getWidth() / 2); backDrop = new ColorTintFilter(Color.BLACK, 0.10f).filter(backDrop, null); backDrop = new GaussianBlurFilter(12).filter(backDrop, null); } else { if (backDrop != null) { backDrop.flush(); } backDrop = null; } super.setVisible(visible); } public void setProgress(int progress) { int oldProgress = this.progress; this.progress = progress; if (progress > oldProgress) { // computes the damaged area FontMetrics metrics = getGraphics().getFontMetrics(getFont()); int w = (int) (BAR_WIDTH * ((float) oldProgress / 100.0f)); int x = w + (getWidth() - BAR_WIDTH) / 2; int y = (getHeight() - BAR_HEIGHT) / 2; y += metrics.getDescent() / 2 + 2; w = (int) (BAR_WIDTH * ((float) progress / 100.0f)) - w; int h = BAR_HEIGHT; repaint(x, y, w, h); } else { FontMetrics metrics = getGraphics().getFontMetrics(getFont()); int w = (int) (BAR_WIDTH * ((float) oldProgress / 100.0f)); int x = w + (getWidth() - BAR_WIDTH) / 2; int y = (getHeight() - BAR_HEIGHT) / 2; y += metrics.getDescent() / 2 + 2; w = (int) (BAR_WIDTH * ((float) progress / 100.0f)) + w; int h = BAR_HEIGHT; repaint(x, y, w, h); } } @Override protected void paintComponent(Graphics g) { // enables anti-aliasing Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); MainFrame mainFrame = Application.getMainFrame(); int width = mainFrame.getRootPane().getWidth(); int height = mainFrame.getRootPane().getHeight(); g2.drawImage(backDrop, 0, 0, width, height, null); // sets a 65% translucent composite AlphaComposite alpha = AlphaComposite.SrcOver.derive(0.75f); Composite composite = g2.getComposite(); // centers the progress bar on screen FontMetrics metrics = g.getFontMetrics(); int x = (getWidth() - BAR_WIDTH) / 2; int y = (getHeight() - BAR_HEIGHT - metrics.getDescent()) / 2; g2.setComposite(alpha); g2.setColor(Color.BLACK); g2.fillRoundRect(x - 15, y - metrics.getAscent() - 7, BAR_WIDTH + 30, BAR_HEIGHT + 22 + metrics.getAscent(), 20, 20); g2.setComposite(composite); // draws the text g2.setColor(TEXT_COLOR); g2.drawString(message, x, y); // goes to the position of the progress bar y += metrics.getDescent() + 2; // computes the size of the progress indicator int w = (int) (BAR_WIDTH * ((float) progress / 100.0f)); int h = BAR_HEIGHT; // draws the content of the progress bar Paint paint = g2.getPaint(); g2.setComposite(alpha); // bar's background Paint gradient = new GradientPaint(x, y, GRADIENT_COLOR1, x, y + h, GRADIENT_COLOR2); g2.setPaint(gradient); g2.fillRect(x, y, BAR_WIDTH, BAR_HEIGHT); // actual progress gradient = new LinearGradientPaint(x, y, x, y + h, GRADIENT_FRACTIONS, GRADIENT_COLORS); g2.setPaint(gradient); g2.fillRect(x, y, w, h); g2.setPaint(paint); // draws the progress bar border g2.setColor(Color.DARK_GRAY); g2.drawRect(x, y, BAR_WIDTH, BAR_HEIGHT); g2.setComposite(composite); } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class StepLabel extends JLabel { private int step; private boolean rebuildIcon; public StepLabel() { setBackground(Color.BLACK); setForeground(Color.WHITE); setHorizontalAlignment(CENTER); setIconTextGap(12); //setOpaque(true); setFont(new Font("Helvetica", Font.PLAIN, 24)); setStep(1); setText(" "); } public void setStep(int step) { this.step = step; this.rebuildIcon = true; repaint(); } public int getStep() { return step; } @Override protected void paintComponent(Graphics g) { if (rebuildIcon) { FontMetrics fontMetrics = g.getFontMetrics(); int height = (int) (fontMetrics.getHeight() / 1.5 + 2); BufferedImage image = GraphicsUtilities.createTranslucentCompatibleImage(height, height); Graphics2D g2 = image.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); g2.setFont(getFont().deriveFont(Font.BOLD, 20)); fontMetrics = g2.getFontMetrics(); String s = String.valueOf(step); int x = (height - fontMetrics.stringWidth(s)) / 2; int y = height - fontMetrics.getAscent() / 8; //g2.setColor(Color.WHITE); Paint paint = g2.getPaint(); g2.setPaint(new GradientPaint(0.0f, 0.0f, Color.WHITE, 0.0f, height, Color.GRAY)); g2.fillOval(0, 0, height, height); g2.setPaint(paint); //g2.setColor(Color.BLACK); g2.setComposite(AlphaComposite.Clear); g2.drawString(s, x, y); g2.dispose(); setIcon(new ImageIcon(image)); rebuildIcon = false; } super.paintComponent(g); } } /* * $Id: GraphicsUtilities.java,v 1.1 2007/01/15 16:12:03 gfx Exp $ * * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). * * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * <p><code>GraphicsUtilities</code> contains a set of tools to perform * common graphics operations easily. These operations are divided into * several themes, listed below.</p> * <h2>Compatible Images</h2> * <p>Compatible images can, and should, be used to increase drawing * performance. This class provides a number of methods to load compatible * images directly from files or to convert existing images to compatibles * images.</p> * <h2>Creating Thumbnails</h2> * <p>This class provides a number of methods to easily scale down images. * Some of these methods offer a trade-off between speed and result quality and * shouuld be used all the time. They also offer the advantage of producing * compatible images, thus automatically resulting into better runtime * performance.</p> * <p>All these methodes are both faster than * {@link java.awt.Image#getScaledInstance(int, int, int)} and produce * better-looking results than the various <code>drawImage()</code> methods * in {@link java.awt.Graphics}, which can be used for image scaling.</p> * <h2>Image Manipulation</h2> * <p>This class provides two methods to get and set pixels in a buffered image. * These methods try to avoid unmanaging the image in order to keep good * performance.</p> * * @author Romain Guy <romain.guy@mac.com> */ class GraphicsUtilities { private static final GraphicsConfiguration CONFIGURATION = GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().getDefaultConfiguration(); private GraphicsUtilities() { } /** * <p>Returns a new <code>BufferedImage</code> using the same color model * as the image passed as a parameter. The returned image is only compatible * with the image passed as a parameter. This does not mean the returned * image is compatible with the hardware.</p> * * @param image the reference image from which the color model of the new * image is obtained * @return a new <code>BufferedImage</code>, compatible with the color model * of <code>image</code> */ public static BufferedImage createColorModelCompatibleImage(BufferedImage image) { ColorModel cm = image.getColorModel(); return new BufferedImage(cm, cm.createCompatibleWritableRaster(image.getWidth(), image.getHeight()), cm.isAlphaPremultiplied(), null); } /** * <p>Returns a new compatible image with the same width, height and * transparency as the image specified as a parameter.</p> * * @see java.awt.Transparency * @see #createCompatibleImage(int, int) * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) * @see #createTranslucentCompatibleImage(int, int) * @see #loadCompatibleImage(java.net.URL) * @see #toCompatibleImage(java.awt.image.BufferedImage) * @param image the reference image from which the dimension and the * transparency of the new image are obtained * @return a new compatible <code>BufferedImage</code> with the same * dimension and transparency as <code>image</code> */ public static BufferedImage createCompatibleImage(BufferedImage image) { return createCompatibleImage(image, image.getWidth(), image.getHeight()); } /** * <p>Returns a new compatible image of the specified width and height, and * the same transparency setting as the image specified as a parameter.</p> * * @see java.awt.Transparency * @see #createCompatibleImage(java.awt.image.BufferedImage) * @see #createCompatibleImage(int, int) * @see #createTranslucentCompatibleImage(int, int) * @see #loadCompatibleImage(java.net.URL) * @see #toCompatibleImage(java.awt.image.BufferedImage) * @param width the width of the new image * @param height the height of the new image * @param image the reference image from which the transparency of the new * image is obtained * @return a new compatible <code>BufferedImage</code> with the same * transparency as <code>image</code> and the specified dimension */ public static BufferedImage createCompatibleImage(BufferedImage image, int width, int height) { return CONFIGURATION.createCompatibleImage(width, height, image.getTransparency()); } /** * <p>Returns a new opaque compatible image of the specified width and * height.</p> * * @see #createCompatibleImage(java.awt.image.BufferedImage) * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) * @see #createTranslucentCompatibleImage(int, int) * @see #loadCompatibleImage(java.net.URL) * @see #toCompatibleImage(java.awt.image.BufferedImage) * @param width the width of the new image * @param height the height of the new image * @return a new opaque compatible <code>BufferedImage</code> of the * specified width and height */ public static BufferedImage createCompatibleImage(int width, int height) { return CONFIGURATION.createCompatibleImage(width, height); } /** * <p>Returns a new translucent compatible image of the specified width * and height.</p> * * @see #createCompatibleImage(java.awt.image.BufferedImage) * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) * @see #createCompatibleImage(int, int) * @see #loadCompatibleImage(java.net.URL) * @see #toCompatibleImage(java.awt.image.BufferedImage) * @param width the width of the new image * @param height the height of the new image * @return a new translucent compatible <code>BufferedImage</code> of the * specified width and height */ public static BufferedImage createTranslucentCompatibleImage(int width, int height) { return CONFIGURATION.createCompatibleImage(width, height, Transparency.TRANSLUCENT); } /** * <p>Returns a new compatible image from a URL. The image is loaded from the * specified location and then turned, if necessary into a compatible * image.</p> * * @see #createCompatibleImage(java.awt.image.BufferedImage) * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) * @see #createCompatibleImage(int, int) * @see #createTranslucentCompatibleImage(int, int) * @see #toCompatibleImage(java.awt.image.BufferedImage) * @param resource the URL of the picture to load as a compatible image * @return a new translucent compatible <code>BufferedImage</code> of the * specified width and height * @throws java.io.IOException if the image cannot be read or loaded */ public static BufferedImage loadCompatibleImage(URL resource) throws IOException { BufferedImage image = ImageIO.read(resource); return toCompatibleImage(image); } /** * <p>Return a new compatible image that contains a copy of the specified * image. This method ensures an image is compatible with the hardware, * and therefore optimized for fast blitting operations.</p> * * @see #createCompatibleImage(java.awt.image.BufferedImage) * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int) * @see #createCompatibleImage(int, int) * @see #createTranslucentCompatibleImage(int, int) * @see #loadCompatibleImage(java.net.URL) * @param image the image to copy into a new compatible image * @return a new compatible copy, with the * same width and height and transparency and content, of <code>image</code> */ public static BufferedImage toCompatibleImage(BufferedImage image) { if (image.getColorModel().equals(CONFIGURATION.getColorModel())) { return image; } BufferedImage compatibleImage = CONFIGURATION.createCompatibleImage( image.getWidth(), image.getHeight(), image.getTransparency()); Graphics g = compatibleImage.getGraphics(); g.drawImage(image, 0, 0, null); g.dispose(); return compatibleImage; } /** * <p>Returns a thumbnail of a source image. <code>newSize</code> defines * the length of the longest dimension of the thumbnail. The other * dimension is then computed according to the dimensions ratio of the * original picture.</p> * <p>This method favors speed over quality. When the new size is less than * half the longest dimension of the source image, * {@link #createThumbnail(BufferedImage, int)} or * {@link #createThumbnail(BufferedImage, int, int)} should be used instead * to ensure the quality of the result without sacrificing too much * performance.</p> * * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int) * @see #createThumbnail(java.awt.image.BufferedImage, int) * @see #createThumbnail(java.awt.image.BufferedImage, int, int) * @param image the source image * @param newSize the length of the largest dimension of the thumbnail * @return a new compatible <code>BufferedImage</code> containing a * thumbnail of <code>image</code> * @throws IllegalArgumentException if <code>newSize</code> is larger than * the largest dimension of <code>image</code> or <= 0 */ public static BufferedImage createThumbnailFast(BufferedImage image, int newSize) { float ratio; int width = image.getWidth(); int height = image.getHeight(); if (width > height) { if (newSize >= width) { throw new IllegalArgumentException("newSize must be lower than" + " the image width"); } else if (newSize <= 0) { throw new IllegalArgumentException("newSize must" + " be greater than 0"); } ratio = (float) width / (float) height; width = newSize; height = (int) (newSize / ratio); } else { if (newSize >= height) { throw new IllegalArgumentException("newSize must be lower than" + " the image height"); } else if (newSize <= 0) { throw new IllegalArgumentException("newSize must" + " be greater than 0"); } ratio = (float) height / (float) width; height = newSize; width = (int) (newSize / ratio); } BufferedImage temp = createCompatibleImage(image, width, height); Graphics2D g2 = temp.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(image, 0, 0, temp.getWidth(), temp.getHeight(), null); g2.dispose(); return temp; } /** * <p>Returns a thumbnail of a source image.</p> * <p>This method favors speed over quality. When the new size is less than * half the longest dimension of the source image, * {@link #createThumbnail(BufferedImage, int)} or * {@link #createThumbnail(BufferedImage, int, int)} should be used instead * to ensure the quality of the result without sacrificing too much * performance.</p> * * @see #createThumbnailFast(java.awt.image.BufferedImage, int) * @see #createThumbnail(java.awt.image.BufferedImage, int) * @see #createThumbnail(java.awt.image.BufferedImage, int, int) * @param image the source image * @param newWidth the width of the thumbnail * @param newHeight the height of the thumbnail * @return a new compatible <code>BufferedImage</code> containing a * thumbnail of <code>image</code> * @throws IllegalArgumentException if <code>newWidth</code> is larger than * the width of <code>image</code> or if code>newHeight</code> is larger * than the height of <code>image</code> or if one of the dimensions * is <= 0 */ public static BufferedImage createThumbnailFast(BufferedImage image, int newWidth, int newHeight) { if (newWidth >= image.getWidth() || newHeight >= image.getHeight()) { throw new IllegalArgumentException("newWidth and newHeight cannot" + " be greater than the image" + " dimensions"); } else if (newWidth <= 0 || newHeight <= 0) { throw new IllegalArgumentException("newWidth and newHeight must" + " be greater than 0"); } BufferedImage temp = createCompatibleImage(image, newWidth, newHeight); Graphics2D g2 = temp.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(image, 0, 0, temp.getWidth(), temp.getHeight(), null); g2.dispose(); return temp; } /** * <p>Returns a thumbnail of a source image. <code>newSize</code> defines * the length of the longest dimension of the thumbnail. The other * dimension is then computed according to the dimensions ratio of the * original picture.</p> * <p>This method offers a good trade-off between speed and quality. * The result looks better than * {@link #createThumbnailFast(java.awt.image.BufferedImage, int)} when * the new size is less than half the longest dimension of the source * image, yet the rendering speed is almost similar.</p> * * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int) * @see #createThumbnailFast(java.awt.image.BufferedImage, int) * @see #createThumbnail(java.awt.image.BufferedImage, int, int) * @param image the source image * @param newSize the length of the largest dimension of the thumbnail * @return a new compatible <code>BufferedImage</code> containing a * thumbnail of <code>image</code> * @throws IllegalArgumentException if <code>newSize</code> is larger than * the largest dimension of <code>image</code> or <= 0 */ public static BufferedImage createThumbnail(BufferedImage image, int newSize) { int width = image.getWidth(); int height = image.getHeight(); boolean isWidthGreater = width > height; if (isWidthGreater) { if (newSize >= width) { throw new IllegalArgumentException("newSize must be lower than" + " the image width"); } } else if (newSize >= height) { throw new IllegalArgumentException("newSize must be lower than" + " the image height"); } if (newSize <= 0) { throw new IllegalArgumentException("newSize must" + " be greater than 0"); } float ratioWH = (float) width / (float) height; float ratioHW = (float) height / (float) width; BufferedImage thumb = image; do { if (isWidthGreater) { width /= 2; if (width < newSize) { width = newSize; } height = (int) (width / ratioWH); } else { height /= 2; if (height < newSize) { height = newSize; } width = (int) (height / ratioHW); } BufferedImage temp = createCompatibleImage(image, width, height); Graphics2D g2 = temp.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null); g2.dispose(); thumb = temp; } while (newSize != (isWidthGreater ? width : height)); return thumb; } /** * <p>Returns a thumbnail of a source image.</p> * <p>This method offers a good trade-off between speed and quality. * The result looks better than * {@link #createThumbnailFast(java.awt.image.BufferedImage, int)} when * the new size is less than half the longest dimension of the source * image, yet the rendering speed is almost similar.</p> * * @see #createThumbnailFast(java.awt.image.BufferedImage, int) * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int) * @see #createThumbnail(java.awt.image.BufferedImage, int) * @param image the source image * @param newWidth the width of the thumbnail * @param newHeight the height of the thumbnail * @return a new compatible <code>BufferedImage</code> containing a * thumbnail of <code>image</code> * @throws IllegalArgumentException if <code>newWidth</code> is larger than * the width of <code>image</code> or if code>newHeight</code> is larger * than the height of <code>image or if one the dimensions is not > 0</code> */ public static BufferedImage createThumbnail(BufferedImage image, int newWidth, int newHeight) { int width = image.getWidth(); int height = image.getHeight(); if (newWidth >= width || newHeight >= height) { throw new IllegalArgumentException("newWidth and newHeight cannot" + " be greater than the image" + " dimensions"); } else if (newWidth <= 0 || newHeight <= 0) { throw new IllegalArgumentException("newWidth and newHeight must" + " be greater than 0"); } BufferedImage thumb = image; do { if (width > newWidth) { width /= 2; if (width < newWidth) { width = newWidth; } } if (height > newHeight) { height /= 2; if (height < newHeight) { height = newHeight; } } BufferedImage temp = createCompatibleImage(image, width, height); Graphics2D g2 = temp.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null); g2.dispose(); thumb = temp; } while (width != newWidth || height != newHeight); return thumb; } /** * <p>Returns an array of pixels, stored as integers, from a * <code>BufferedImage</code>. The pixels are grabbed from a rectangular * area defined by a location and two dimensions. Calling this method on * an image of type different from <code>BufferedImage.TYPE_INT_ARGB</code> * and <code>BufferedImage.TYPE_INT_RGB</code> will unmanage the image.</p> * * @param img the source image * @param x the x location at which to start grabbing pixels * @param y the y location at which to start grabbing pixels * @param w the width of the rectangle of pixels to grab * @param h the height of the rectangle of pixels to grab * @param pixels a pre-allocated array of pixels of size w*h; can be null * @return <code>pixels</code> if non-null, a new array of integers * otherwise * @throws IllegalArgumentException is <code>pixels</code> is non-null and * of length < w*h */ public static int[] getPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) { if (w == 0 || h == 0) { return new int[0]; } if (pixels == null) { pixels = new int[w * h]; } else if (pixels.length < w * h) { throw new IllegalArgumentException("pixels array must have a length" + " >= w*h"); } int imageType = img.getType(); if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_RGB) { Raster raster = img.getRaster(); return (int[]) raster.getDataElements(x, y, w, h, pixels); } // Unmanages the image return img.getRGB(x, y, w, h, pixels, 0, w); } /** * <p>Writes a rectangular area of pixels in the destination * <code>BufferedImage</code>. Calling this method on * an image of type different from <code>BufferedImage.TYPE_INT_ARGB</code> * and <code>BufferedImage.TYPE_INT_RGB</code> will unmanage the image.</p> * * @param img the destination image * @param x the x location at which to start storing pixels * @param y the y location at which to start storing pixels * @param w the width of the rectangle of pixels to store * @param h the height of the rectangle of pixels to store * @param pixels an array of pixels, stored as integers * @throws IllegalArgumentException is <code>pixels</code> is non-null and * of length < w*h */ public static void setPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) { if (pixels == null || w == 0 || h == 0) { return; } else if (pixels.length < w * h) { throw new IllegalArgumentException("pixels array must have a length" + " >= w*h"); } int imageType = img.getType(); if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_RGB) { WritableRaster raster = img.getRaster(); raster.setDataElements(x, y, w, h, pixels); } else { // Unmanages the image img.setRGB(x, y, w, h, pixels, 0, w); } } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class SizeStepPanel extends JPanel { private BufferedImage small; private BufferedImage medium; private BufferedImage large; private boolean isLoaded; private int smallHeight; private int mediumHeight; private int largeHeight; private Rectangle largeImageBounds; private Rectangle mediumImageBounds; private Rectangle smallImageBounds; public SizeStepPanel() { setBackground(Color.BLACK); setOpaque(false); createThumbnails(); addMouseMotionListener(new CursorChanger()); addMouseListener(new SizeSelector()); } private void createThumbnails() { Thread loader = new Thread(new Runnable() { public void run() { final MainFrame mainFrame = Application.getMainFrame(); BufferedImage image = mainFrame.getImage(); small = GraphicsUtilities.createThumbnail(image, 90); smallHeight = small.getHeight(); small = Reflection.createReflection(small); medium = GraphicsUtilities.createThumbnail(image, 160); mediumHeight = medium.getHeight(); medium = Reflection.createReflection(medium); large = GraphicsUtilities.createThumbnail(image, 240); largeHeight = large.getHeight(); large = Reflection.createReflection(large); SwingUtilities.invokeLater(new Runnable() { public void run() { mainFrame.hideWaitGlassPane(); } }); isLoaded = true; repaint(); } }); loader.start(); } public void dispose() { if (large != null) { large.flush(); large = null; } if (medium != null) { medium.flush(); medium = null; } if (small != null) { small.flush(); small = null; } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (!isLoaded) { return; } int totalWidth = 24 * 2; totalWidth += large.getWidth() + medium.getWidth() + small.getWidth(); int x = (getWidth() - totalWidth) / 2; int y = (getHeight() - large.getHeight()) / 2; y += 42; g.drawImage(large, x, y, null); if (largeImageBounds == null) { largeImageBounds = new Rectangle(x, y, large.getWidth(), largeHeight); } x += large.getWidth() + 24; y += largeHeight - mediumHeight; g.drawImage(medium, x, y, null); if (mediumImageBounds == null) { mediumImageBounds = new Rectangle(x, y, medium.getWidth(), mediumHeight); } x += medium.getWidth() + 24; y += mediumHeight - smallHeight; g.drawImage(small, x, y, null); if (smallImageBounds == null) { smallImageBounds = new Rectangle(x, y, small.getWidth(), smallHeight); } } private static void saveImage(final BufferedImage image, final File file) { Thread writer = new Thread(new Runnable() { public void run() { try { ImageIO.write(image, "JPEG", file); // NON-NLS } catch (IOException e) { e.printStackTrace(); } SwingUtilities.invokeLater(new Runnable() { public void run() { Application.getMainFrame().showDoneStep(); } }); } }); writer.start(); } private class SizeSelector extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { Point point = e.getPoint(); for (final Rectangle r : new Rectangle[] { largeImageBounds, mediumImageBounds, smallImageBounds }) { if (r != null && r.contains(point)) { Application.getMainFrame().showWaitGlassPane(); Thread sizer = new Thread(new Runnable() { public void run() { int width; if (r == largeImageBounds) { width = 1024; } else if (r == mediumImageBounds) { width = 800; } else { width = 640; } final BufferedImage toSave = GraphicsUtilities.createThumbnail( Application.getMainFrame().getImage(), width); SwingUtilities.invokeLater(new Runnable() { public void run() { JFileChooser chooser = new JFileChooser(); chooser.setSelectedFile(new File( "x",Application .getMainFrame().getFileName() ) ); dispose(); if (chooser.showSaveDialog(Application.getMainFrame()) == JFileChooser.APPROVE_OPTION) { File selectedFile = chooser.getSelectedFile(); if (!selectedFile.getPath().toLowerCase().endsWith(".jpg")) { // NON-NLS selectedFile = new File(selectedFile.getPath() + ".jpg"); // NON-NLS } saveImage(toSave, selectedFile); } else { Application.getMainFrame().showDragAndDropStep(); } } }); } }); sizer.start(); } } } } private class CursorChanger extends MouseAdapter { @Override public void mouseMoved(MouseEvent e) { Point point = e.getPoint(); if ((largeImageBounds != null && largeImageBounds.contains(point)) || (mediumImageBounds != null && mediumImageBounds.contains(point)) || (smallImageBounds != null && smallImageBounds.contains(point))) { setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else if (!getCursor().equals(Cursor.getDefaultCursor())) { setCursor(Cursor.getDefaultCursor()); } } } } /* * Copyright (c) 2007, Romain Guy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //package org.progx.artemis; //import java.util.ResourceBundle; //import javax.swing.SwingUtilities; //import javax.swing.UIManager; //import javax.swing.UnsupportedLookAndFeelException; //import org.progx.artemis.ui.MainFrame; class Application { private static MainFrame mainFrame = new MainFrame(); private static ResourceBundle bundle; private Application() { } public static MainFrame getMainFrame() { mainFrame.setVisible(true); return mainFrame; } public static void main(String[] args) { } public static synchronized ResourceBundle getResourceBundle() { if (bundle == null) { bundle = ResourceBundle.getBundle("org.progx.artemis.messages"); // NON-NLS } return bundle; } }