import javax.swing.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.*;
import java.io.*;
import java.util.*;
class ImageGlow
{
    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    new ImageGlow();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    public ImageGlow() throws Exception
    {
        JFrame f = new JFrame();
        f.getContentPane().setLayout(new GridLayout(1,0));
        BufferedImage input = ImageIO.read(new File("image03.png"));
        JLabel label = new JLabel(new ImageIcon(input));
        label.setBackground(Color.WHITE);
        label.setOpaque(true);
        f.getContentPane().add(label);
        BufferedImage output = crateGlow(input);
        label = new JLabel(new ImageIcon(output));
        label.setBackground(Color.WHITE);
        label.setOpaque(true);
        f.getContentPane().add(label);
        label = new JLabel(new ImageIcon(output));
        label.setBackground(Color.GRAY);
        label.setOpaque(true);
        f.getContentPane().add(label);
        label = new JLabel(new ImageIcon(output));
        label.setBackground(Color.BLACK);
        label.setOpaque(true);
        f.getContentPane().add(label);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
    private static BufferedImage crateGlow(BufferedImage in)
    {
        int glowSize = 30;
        // Eingabebild in die Mitte von einem ARGB-Bild malen, das
        // einen Rand für das Glühen hat
        int iw = in.getWidth();
        int ih = in.getHeight();
        int ow = iw+glowSize*2;
        int oh = iw+glowSize*2;
        BufferedImage input = new BufferedImage(ow, oh, BufferedImage.TYPE_INT_ARGB);
        Graphics g = input.createGraphics();
        g.setColor(new Color(0,0,0,0));
        g.fillRect(0,0,input.getWidth(), input.getHeight());
        g.drawImage(in, glowSize, glowSize, null);
        g.dispose();
        // Kernel erstellen, der das bild weichzeichnet
        int gg = glowSize * glowSize;
        float matrix[] = new float[gg];
        Arrays.fill(matrix, 1.0f/gg);
        //Kernel kernel = new Kernel(glowSize, glowSize, matrix);
        Kernel kernel = createKernel(glowSize); //new Kernel(glowSize, glowSize, matrix);
        BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_ZERO_FILL, null );
        // Weichzeichnen
        BufferedImage output = new BufferedImage(ow, oh, BufferedImage.TYPE_INT_ARGB);
        output = op.filter(input, output);
        // Das Glühen heller machen
        RescaleOp rescale = new RescaleOp(
            new float[]{2.0f,2.0f,2.0f,2.0f},
            new float[]{0,0,0,0}, null);
        output = rescale.filter(output, output);
        // Originalbild drübermalen
        g = output.createGraphics();
        g.drawImage(input, 0, 0, null);
        g.dispose();
        return output;
    }
    private static Kernel createKernel(int arrayRadius)
    {
        float kernelRadius = 3;
        float sigma = 1;
        int size = arrayRadius*2+1;
        float sum = 0;
        float result[] = new float[size*size];
        for (int x=-arrayRadius; x<=arrayRadius; x++)
        {
            for (int y=-arrayRadius; y<=arrayRadius; y++)
            {
                float fx = kernelRadius * (float)x/arrayRadius;
                float fy = kernelRadius * (float)y/arrayRadius;
                int ix = x+arrayRadius;
                int iy = y+arrayRadius;
                float value = gaussian(fx, fy, sigma);
                result[ix+iy*size] = value;
                sum += value;
            }
        }
        float invSum = 1.0f / sum;
        for (int x=0; x<size*size; x++)
        {
            result[x] *= invSum;
        }
        return new Kernel(size, size, result);
    }
    private static float gaussian(float x, float y, float sigma)
    {
        float nominator = x*x + y*y;
        float sigmaSquared = sigma * sigma;
        float denominator = 2 * sigmaSquared;
        float exponent = -nominator / denominator;
        float power = (float)Math.exp(exponent);
        float factor = 1.0f / (2 * (float)Math.PI * sigmaSquared);
        float result = factor * power;
        return result;
    }
}