-1

I'm trying to do a simulation program using java swing gui. I have 2 images that are same but one is blurred all the way and other one is normal. And a 3rd image that is just a transparent rectangular frame in .png format. What I want to achieve is that, I will drag the transparent rectangular box over the blurred image and it will reveal the non-blurred image below. How can I achieve this?

P.S: Images are loaded into the program using JLabel onto JLayeredPane and JFrame. Also transparent rectangular box has a mouse listener.

ezpzzzz
  • 13
  • 5
  • 1
    There are probably multiple ways you approach this problem, for [example](https://stackoverflow.com/questions/23709070/how-to-disable-java-awt-graphics-fillrectint-x-int-y-int-width-int-heights/23709320#23709320). I think what I might do is use `BufferedImage#subImage` and based on the current x/y position, grab a sub image snapshot of the unblurred image and render it over the top of the blurred image. The point is, focus on the illusion you're trying to create, not how you might make it physically work. – MadProgrammer Aug 08 '22 at 21:45
  • Alternatively, you could create a masked version of the blurred image with the "view area" cut out and render that, but this can be quite expensive – MadProgrammer Aug 08 '22 at 21:46
  • @MadProgrammer Hi thanks for your help. I've been trying to achieve this with the overlay illusion but couldn't make it work. How can I do it with the way you said in your first comment. I'm not very experienced with java GUI so couldn't figure out, especially x/y coordinates. – ezpzzzz Aug 11 '22 at 14:17
  • Will the example I posted does exactly that – MadProgrammer Aug 11 '22 at 22:17

1 Answers1

1

A "overlay" illusion...

Basically this is going to generate a subImage of the un-blurred image based on the current mouse position and view port size, this is then blended with the "overlay effect" and rendered on top of the blurred image, creating the "illusion" of a cutout effect.

The following example will follow the mouse around, exposing a 200x200 pixel area of the image around the mouse cursor.

enter image description here

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage blurredImage;
        private BufferedImage normalImage;
        private BufferedImage spyScopeImage;

        private int viewPortSize = 200;

        private Point currentLocation;

        public TestPane() throws IOException {
            blurredImage = ImageIO.read(getClass().getResource("/images/PosterBlurred.png"));
            normalImage = ImageIO.read(getClass().getResource("/images/Poster.png"));

            spyScopeImage = new BufferedImage(viewPortSize, viewPortSize, BufferedImage.TYPE_INT_ARGB);
            Graphics2D masked = spyScopeImage.createGraphics();
            Color transparent = new Color(255, 0, 0, 0);
            Color fill = Color.RED;
            RadialGradientPaint rgp = new RadialGradientPaint(
                    new Point2D.Double(viewPortSize / 2d, viewPortSize / 2d),
                    viewPortSize,
                    new float[]{0f, 0.5f, 1f},
                    new Color[]{fill, transparent, transparent});
//            masked.setComposite(AlphaComposite.DstAtop);
            masked.setPaint(rgp);
            masked.fill(new Rectangle(0, 0, viewPortSize, viewPortSize));
            masked.dispose();

            MouseAdapter mouseAdapter = new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    currentLocation = e.getPoint();
                    repaint();
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    currentLocation = e.getPoint();
                    repaint();
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    currentLocation = null;
                    repaint();
                }
            };

            addMouseMotionListener(mouseAdapter);
        }

        @Override
        public Dimension getPreferredSize() {
            if (blurredImage != null) {
                return new Dimension(blurredImage.getWidth(), blurredImage.getHeight());
            }
            return new Dimension(800, 600);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (blurredImage != null) {
                int x = (getWidth() - blurredImage.getWidth()) / 2;
                int y = (getHeight() - blurredImage.getHeight()) / 2;
                g2d.drawImage(blurredImage, x, y, this);
                if (currentLocation != null && normalImage != null) {
                    int mouseX = currentLocation.x - x;
                    int mouseY = currentLocation.y - y;

                    int viewPortOffset = viewPortSize / 2;

                    int minX = Math.max(0, mouseX - viewPortOffset);
                    int minY = Math.max(0, mouseY - viewPortOffset);

                    int maxX = Math.min(normalImage.getWidth(), mouseX + viewPortSize);
                    int maxY = Math.min(normalImage.getHeight(), mouseY + viewPortSize);

                    int viewX = minX - viewPortOffset;
                    int viewY = minY - viewPortOffset;

                    BufferedImage subimage = normalImage.getSubimage(minX, minY, maxX - minX, maxY - minY);

                    // Here we're going to "mask" the sub image and the "spy scope" effect together
                    BufferedImage masked = new BufferedImage(viewPortSize, viewPortSize, BufferedImage.TYPE_INT_ARGB);
                    Graphics2D mg = masked.createGraphics();
                    mg.drawImage(subimage, 0, 0, this);
                    mg.setComposite(AlphaComposite.DstAtop);
                    mg.drawImage(spyScopeImage, 0, 0, this);
                    mg.dispose();
                    g2d.drawImage(masked, x + minX, y + minY, this);
                }
            }
            g2d.dispose();
        }

    }
}

Alternatively...

You could create a "masked" version of the blurred image with the "scope effect" which exposes the image rendered below it, but agin, this will be expensive, as each time you're creating a new image the size of the original blurred image.

This concept is demonstrated in How to create a transparent shape in the image

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366