Mesh swings and bitmaps

I have a Java desktop application that works in particular on OS X.

Now the new MacBook Pro has a mesh display, and I'm worried: how will it work in relation to Swing?

How about when a Java application uses both Swing components and some bitmap graphics (like custom icons / ImageIcon)?

All automatic changes to all applications on the Java desktop (for example, four times every pixel), or I will need to create two versions of my icon sets (for example, one with 24x24 icons and the other with 96x96 icons) and somehow determine what Does the app work on the retina screen?

+6
source share
5 answers

Use the IconLoader library. It supports HiDPI images http://bulenkov.com/iconloader/ It also provides the ability to work with HiDPI images (drawing, etc.)

+7
source

In Apple Java 6, you can provide multiple versions of the same image. Depending on the screen (retina or not), one or another image is selected and drawn.

However, these images must be loaded in a special way:

Toolkit.getDefaultToolkit().getImage("NSImage://your_image_name_without_extension"); 

For example, if your image (regular resolution) is called "scissor.png", you need to create a high-resolution version of " scissor@2x.png " (after the Apple Naming Agreement ) and place both images in the Resources directory of your application package (yes, you need to combine your application ). Then call:

 Image img = Toolkit.getDefaultToolkit().getImage("NSImage://scissor"); 

You can use the resulting image in your buttons, and it will be drawn with the correct resolution in a magical way.

There are two other tricks you can use:

  • Using AffineTransform (0.5, 0.5) on your Graphics2D object before drawing the image. Also see this java-dev post
  • Creating a high-precision version of your image programmatically using this hack

The first trick (0.5 scaling) now also works on Oracle Java 7/8. That is, if you draw an image with a scale of 0.5 directly on the Graphics Graphics object, it will be displayed in high resolution on Retina displays (as well as half its original size).

+4
source

I can confirm that scaling your images works on Oracle Java 1.8. I cannot hack NSImage to work with java 1.7 or 1.8. I think this only works with Java 6 with Mac ...

If anyone else has a better solution, I do the following:

Create two sets of icons. If you have a 48pixel wide 48pixel , create one 48px @normal DPI and the other at 96px using 2x DPI . Rename the 2xDPI image as @2x.png to meet Apple's naming standards.

Subclass ImageIcon and name it RetinaIcon or whatever. You can check the Retina display as follows:

 public static boolean isRetina() { boolean isRetina = false; GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); try { Field field = graphicsDevice.getClass().getDeclaredField("scale"); if (field != null) { field.setAccessible(true); Object scale = field.get(graphicsDevice); if(scale instanceof Integer && ((Integer) scale).intValue() == 2) { isRetina = true; } } } catch (Exception e) { e.printStackTrace(); } return isRetina; } 

Make sure @Override width and height of the new ImageIcon class:

 @Override public int getIconWidth() { if(isRetina()) { return super.getIconWidth()/2; } return super.getIconWidth(); } @Override public int getIconHeight() { if(isRetina()) { return super.getIconHeight()/2; } return super.getIconHeight(); } 

Once you have a test for the retina screen and your custom width / height methods are overridden, you can set up the painIcon method as follows:

 @Override public synchronized void paintIcon(Component c, Graphics g, int x, int y) { ImageObserver observer = getImageObserver(); if (observer == null) { observer = c; } Image image = getImage(); int width = image.getWidth(observer); int height = image.getHeight(observer); final Graphics2D g2d = (Graphics2D)g.create(x, y, width, height); if(isRetina()) { g2d.scale(0.5, 0.5); } else { } g2d.drawImage(image, 0, 0, observer); g2d.scale(1, 1); g2d.dispose(); } 

I do not know how this will work with multiple screens, although is there anyone who can help with this?

Hope this code helps anyway!

Jason Barracklow.

Here is an example of using scaling as described above: RetinaIcon is on the left. ImageIcon is on the right

+1
source

Here's what the icons look like on my macbook '12 retina:

enter image description here

The icons are on the left side in IntelliJ IDEA 11 (the rotation app) and on the right side of IDEA 12, which is said to be reinstalled. As you can see, the automatically changing icon sizes (on the left) look pretty ugly.

As far as I know, they, like the guys from the Chrome team , did this by providing double-sized badges.

0
source

Here is a solution that also works when the icons are used on the Apple menu. There, the icon will automatically be grayed out. So, I implemented the DenseIcon class, which draws tightly:

 public synchronized void paintIcon(Component c, Graphics g, int x, int y) { if(getImageObserver() == null) { g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), c); } else { g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), getImageObserver()); } } 

How to connect to graying, I still do not understand. So, as kludge, we return a low resolution image so that the menu can make its changes:

 public Image getImage() { Image image = getImage0().getScaledInstance( getIconWidth(), getIconHeight(), Image.SCALE_SMOOTH); ImageIcon icon = new ImageIcon(image, getDescription()); return icon.getImage(); } 

Here you will find the code for the full gist class. You need to create an instance of the icon class with a URL for the image, which is twice as large. Works for 2K displays.

0
source

Source: https://habr.com/ru/post/925441/


All Articles