Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fonts are blurry when using offscreen image and zoom with windows display settings to 150% #313

Closed
belkacsa opened this issue Mar 20, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@belkacsa
Copy link

belkacsa commented Mar 20, 2023

Description

with amazon corretto java 11 when text is drawn in JPanel using offscreen image (see code below) then use windows display setting to zoom to 150 % the fonts become blurry.

if not using offscreen image, this problem does not happen
if using java 8 this problem does not happen with or without offscreen image

To Reproduce

//Steps and (source) code to reproduce the behavior.
//execute the program below using java 11, then use windows 10  display settings  to change the zoom to 150%, 1755 ..
// note that the fonts  are blurry
// change the variable useDoubleBuffer  to false and execute again, note that the fonts are not blurry
//execute again using java  8 , note that fonts are not  blurry at 150% or any zoom level 


import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

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


public class BlurryFont extends JPanel
{
    
    private Image bufferImage;

    private Graphics2D bufferImageGraphics;

    boolean useDoubleBuffer = true;

    public void setBufferGraphics(Graphics2D graphics)
    {
        bufferImageGraphics = graphics;
    }
      
    private void createBufferImage(int width, int height)
    {
        bufferImage = this.createImage(width, height);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        
        int w = this.getWidth();
        int h = this.getHeight();
        
        System.out.println("(w, h)=" + w + " " + h );

        createBufferImage(w, h);
 
        setBufferGraphics((useDoubleBuffer) ? (Graphics2D) bufferImage.getGraphics() : (Graphics2D)g);
        
        bufferImageGraphics.setColor(java.awt.Color.blue);
        bufferImageGraphics.fillRect(0, 0, getSize().width, getSize().height);
              
        Font font = new Font("Lucida Console", 0, 16);
        
        bufferImageGraphics.setFont(font);       
        bufferImageGraphics.setColor(java.awt.Color.white);     
        bufferImageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
        
        bufferImageGraphics.drawString("Delete All Alarms", 75, 50);      
        bufferImageGraphics.drawString("A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z", 75, 110);

        if (useDoubleBuffer)
        {
            g.drawImage(bufferImage, 0, 0, null);
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame();
        frame.setTitle("Drawing a String");
        frame.setSize(1200, 800);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e)
            {
                System.exit(0);
            }
        });

        Container contentPane = frame.getContentPane();
        
        BlurryFont p =new BlurryFont();
        
        contentPane.add(p);

        frame.setVisible(true);
    }
}

Expected behavior

we expect the fonts to be not blurry at 150% windows display setting the same how it was behaving in java 8

Screenshots

image

here with java 11 fonts are blurry at 150 % windows display settings zoom

image

here without using offscreen image with java 11 fonts are not blurry at 150% zoom
image

with java 8 fonts are not blurry at 150% with or without using offscreen image
image

Platform information

Version: java 11  jdk11.0.18_10
OS: Windows 10
@belkacsa belkacsa added the bug Something isn't working label Mar 20, 2023
@earthling-amzn
Copy link
Contributor

Thank you for the detailed bug report and reproducer! We will look into it!

@mrserb
Copy link
Contributor

mrserb commented Mar 20, 2023

This is the result of how the HiDPI support was implemented on Windows in JDK9. On macOS, this can be reproduced since JDK8.

The JEP 263 changed the way the AWT/Swing components/frames are rendered on HiDPI monitors, but still maintains some compatibility with the old versions of JDK:

  • When the application starts the size of any components/frames are still reported the same for low and hidpi screen, in your test the size of the frame is always reported as "1200x800".
  • Under the hood all native resources are scaled based on the screen dpi, like the native structures for windows, the volatile images/etc. Unfortunately, the raster-based images cannot be scaled in the same way, because that will affect the size reported to the application(like for Bufferredimage).

The problem you faced is caused by the JPanel.createImage(w,h) which creates the raster of the exact size in pixels, and that raster just cannot handle smooth rendering as it has a low dpi.

To solve the problem you can:

  • replace createImage(w,h) by the createVolatileImage(w,h), or
  • disable double buffering completely since you render to the SwingDoubleBuffer anyway, or
  • manually scale the requested "w and h" before passing to the createImage() based on the scalefactor of the monitor, or
  • disable hidpi "-Dsun.java2d.uiScale.enabled=false"

@earthling-amzn
Copy link
Contributor

I'm closing this because we've provided several suggestions for moving forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants