Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java setting background from JAR and making it transparent

Tags:

java

swing

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.

like image 625
11 revs, 2 users 93% Avatar asked Dec 17 '25 13:12

11 revs, 2 users 93%


2 Answers

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.

like image 163
prunge Avatar answered Dec 20 '25 14:12

prunge


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.

like image 26
MadProgrammer Avatar answered Dec 20 '25 14:12

MadProgrammer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!