3

Be patient I'm still a beginner, no rude comments please.

So the goal of this question is so I learn how to set the background of my already transparent JFrame to be blurred. This is what I have now.

Current JFrame

So as you can see it's transparent, but not blurry. I was thinking maybe Java has some process that can blur an image from JAR and use it as a background without changing the original image. So I looked and looked, but nothing I found helped me.

The background of the JFrame, as seen above, is a label with no text but rather the 'background image' as the label's icon.

Organization of JAR :

META-INF(folder) > MANIFEST.MF

SystemInfo(folder) > classes and background image

This is the code I have so far, but its not working.

        setOpacity(); // sets opacity of the background
        Color c = Color.WHITE; // default color
            setColor(c);

        //background = (new JLabel((Icon) new ImageIcon(a)));
        BufferedImage mshi = null;    
        try{mshi = ImageIO.read(new File("SystemInfo/black.png"));}catch(Exception e){e.printStackTrace();}

        BufferedImage databuf = new BufferedImage(mshi.getWidth(null),
                mshi.getHeight(null),
                BufferedImage.TYPE_INT_BGR);

        Graphics g = databuf.getGraphics();
        g.drawImage(mshi, 455, 255, null);

        float[] blurKernel = {
            1 / 9f, 1 / 9f, 1 / 9f,
            1 / 9f, 1 / 9f, 1 / 9f,
            1 / 9f, 1 / 9f, 1 / 9f
        };

        BufferedImageOp blur = new ConvolveOp(new Kernel(3, 3, blurKernel));
        mshi = blur.filter(mshi, new BufferedImage(mshi.getWidth(),
                mshi.getHeight(), mshi.getType()));
        g.dispose();
        //background = (new JLabel((Icon) new ImageIcon(mshi)));
        background.setIcon((Icon)new JLabel(new ImageIcon(mshi)));

Errors the above code produces :

javax.imageio.IIOException: Can't read input file!
    at javax.imageio.ImageIO.read(ImageIO.java:1301)
    at SystemInfo.GuiMain.cinitComponents(GuiMain.java:150)
    at SystemInfo.GuiMain.<init>(GuiMain.java:30)
    at SystemInfo.GuiMain$8.run(GuiMain.java:256)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at SystemInfo.GuiMain.cinitComponents(GuiMain.java:152)
    at SystemInfo.GuiMain.<init>(GuiMain.java:30)
    at SystemInfo.GuiMain$8.run(GuiMain.java:256)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

In-case its needed, the setOpacity(); funciton :

        float fOpacity = (float)opacity/10;
        String sOpacity = Float.toString(fOpacity)+"f";
        this.setOpacity(Float.parseFloat(sOpacity));

My main goal is to have the JFrame produce somthing like this :

What I would like to see

As you can see, the frame blurs out the computer background slightly and is transparent.

Thank you all in advance.

Arc
  • 441
  • 1
  • 9
  • 26
  • possible duplicate of [JFrame with blurred transparent background](http://stackoverflow.com/questions/14167814/jframe-with-blurred-transparent-background) – MirroredFate Feb 26 '14 at 02:26
  • @MirroredFate There doesn't seem to be an answer on that question so I don't feel okay marking this one as a duplicate. – Nick Rippe Feb 26 '14 at 18:22
  • @NickRippe Also http://stackoverflow.com/questions/14840763/how-to-make-a-jframe-blurred-in-java – MirroredFate Feb 26 '14 at 20:51
  • @MirroredFate also close, but the question is only talking about blurring a `JFrame` in the background of the focused `JFrame` (not the background behind the `JFrame`). The answer provided wouldn't work in this case. – Nick Rippe Feb 26 '14 at 21:33

2 Answers2

5

Java can blur an image using the code you have - the problem is that Java does not see the image 'underneath' your window so it will be blurring a blank image.

Window translucency is achieved through the native operating system. To get a blur effect, I don't see an easy way. And by that I mean it's going to be pretty darn difficult. A couple of things you might try:

  • Use java.awt.Robot to capture what's underneath the Window, then use blur on that. Pitfalls: you need to hide your window for a few milliseconds while taking the capture which might be noticeable by the user, and you need to do this every time the background changes which will probably involve polling.
  • Use native code or at least some calls to native libraries through JNA. You'll need to do this for each operating system you want to support. For Mac, this might start you off. For Windows, maybe start looking at the DWM API, maybe something with DwmEnableBlurBehindWindow can work.

But ultimately, given that these techniques are pretty advanced and you said you are a beginner (though you managed with the blurring using Image I/O OK) you might just want to settle with translucent windows.


(Edit: add example for Windows)

For Windows, you can use JNA to call DwmEnableBlurBehindWindow and it works great. You must have Java 7 or later for this to work.

Example:

package dwmtest;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public class DwmWindow extends JFrame
{
    public static void main(String... args)
    throws Exception
    {
        JFrame.setDefaultLookAndFeelDecorated(true);

        DwmWindow f = new DwmWindow();
        f.setSize(600, 500);
        f.setBackground(new Color(0,0,0,0));
        f.setTitle("Hello");
        TranslucentPanel panel = new TranslucentPanel();
        panel.setLayout(new BorderLayout());
        JLabel label = new JLabel("My background is blurry!");
        label.setFont(new Font("Dialog", Font.BOLD, 48));
        panel.add(label, BorderLayout.CENTER);
        f.add(panel);
        f.setDefaultCloseOperation(EXIT_ON_CLOSE);
        f.setVisible(true);

        HWND hwnd = new HWND(Native.getWindowPointer(f));
        Dwmapi.DWM_BLURBEHIND pBlurBehind = new Dwmapi.DWM_BLURBEHIND();
        pBlurBehind.dwFlags = Dwmapi.DWM_BB_ENABLE;
        pBlurBehind.fEnable = true;
        pBlurBehind.fTransitionOnMaximized = false;
        Dwmapi.INSTANCE.DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
    }

    private static class TranslucentPanel extends JPanel
    {
        @Override
        protected void paintComponent(Graphics g) 
        {
            if (g instanceof Graphics2D) {
                final int R = 240;
                final int G = 240;
                final int B = 240;

                Paint p = new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0), 0.0f, getHeight(), new Color(R, G, B, 255), true);
                Graphics2D g2d = (Graphics2D)g;
                g2d.setPaint(p);
                g2d.fillRect(0, 0, getWidth(), getHeight());
            }
        }
    }

    public static interface Dwmapi extends StdCallLibrary
    {
        Dwmapi INSTANCE = (Dwmapi)Native.loadLibrary("Dwmapi", Dwmapi.class, W32APIOptions.UNICODE_OPTIONS);

        int DWM_BB_ENABLE = 0x00000001;

        boolean DwmEnableBlurBehindWindow(HWND hWnd, DWM_BLURBEHIND pBlurBehind);

        public static class DWM_BLURBEHIND extends Structure 
        {
            public int dwFlags;
            public boolean fEnable;
            public IntByReference hRgnBlur;
            public boolean fTransitionOnMaximized;

            @Override
            protected List getFieldOrder() 
            {
                return Arrays.asList("dwFlags", "fEnable", "hRgnBlur", "fTransitionOnMaximized");
            }
        }
    }
}

If you have an Aero-capable Windows machine you will get a blurry background:

Blurry Java window

If you don't have Aero capability it will fall back to just being translucent without the blurriness.

The alpha values of the panel's background control which areas are see through and which not. A more sophisticated background painted in the panel could create effects like holes or other patterns. If you need a uniformly translucent background instead of the gradient effect, use a simple background color with an appropriate alpha value instead.

prunge
  • 22,460
  • 3
  • 73
  • 80
  • Using JNI like this (which is a cool idea) would preclude you adding any Java based components to the window ... – MadProgrammer Feb 26 '14 at 02:33
  • @MadProgrammer It's definitely possible for JNI code to interact with Java `Frame`s and `JFrame`s. Example for [JNA](https://jna.java.net/javadoc/com/sun/jna/Native.html#getWindowID%28java.awt.Window%29), example for [JNI](https://stackoverflow.com/questions/386792/in-java-swing-how-do-you-get-a-win32-window-handle-hwnd-reference-to-a-window). – prunge Feb 26 '14 at 03:19
  • @MadProgrammer you would start out creating a JFrame in Java, make it displayable, grab the hWnd and tweak it in native code, then back in Java treat it like normal, add/remove components, etc. – prunge Feb 26 '14 at 03:37
3

My first guess in "SystemInfo/black.png" can't be referenced as File because it's an embedded/internal resource, residing within your application Jar.

In order to read it (via ImageIO) you will need to use something more like...

ImageIO.read(getClass().getResource("SystemInfo/black.png"))

Instead.

Secondly, blurring the image probably won't result in the effect you are looking for, as it won't have any effect of the how the content behind your window is actually painted.

Instead, you will need to capture the section of the screen below your window and blur that.

You can achieve this by using Robot, but will need to make the window invisible when you grab the screen shot.

It will also not be a "live" update.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Well looks like that a bit complicated, do you think i'de be better off creating a blurred background in photoshop? – Arc Feb 25 '14 at 23:33
  • 1
    Any "static" image you blur will have no effect on how the desktop behind the image is rendered... – MadProgrammer Feb 25 '14 at 23:39