What causes poor image quality in Java JLabel icons?

后端 未结 3 1473
渐次进展
渐次进展 2021-01-17 22:06

Java JLabel icons are displaying with distorted pixels in JFrame. This is happening consistently with different png images (all 32x32). I am not sc

相关标签:
3条回答
  • 2021-01-17 22:26

    Answer is from this link to generate high quality image : https://componenthouse.com/2008/02/08/high-quality-image-resize-with-java/

    The appropriate class from the link :

    public class ImageResize {
    
        public static void main(String[] args) {
            try {
                URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
                BufferedImage image = ImageIO.read(url);
                ImageIO.write(resizeImage(image, 32, 32), "png", new File("D:/picture3.png"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private static BufferedImage resize(BufferedImage image, int width, int height) {
            int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
            BufferedImage resizedImage = new BufferedImage(width, height, type);
            Graphics2D g = resizedImage.createGraphics();
            g.setComposite(AlphaComposite.Src);
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.drawImage(image, 0, 0, width, height, null);
            g.dispose();
            return resizedImage;
        }
    
        private static BufferedImage resizeImage(BufferedImage image, int width, int height) {
            image = createCompatibleImage(image);
            image = resize(image, 100, 100);
            image = blurImage(image);
            return resize(image, width, height);
        }
    
        public static BufferedImage blurImage(BufferedImage image) {
            float ninth = 1.0f/9.0f;
            float[] blurKernel = {
                    ninth, ninth, ninth,
                    ninth, ninth, ninth,
                    ninth, ninth, ninth
            };
    
            Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
            map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
            map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            RenderingHints hints = new RenderingHints(map);
            BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
            return op.filter(image, null);
        }
    
        private static BufferedImage createCompatibleImage(BufferedImage image) {
            GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
            int w = image.getWidth();
            int h = image.getHeight();
            BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
            Graphics2D g2 = result.createGraphics();
            g2.drawRenderedImage(image, null);
            g2.dispose();
            return result;
        }
    
    }
    
    0 讨论(0)
  • 2021-01-17 22:35

    First option: Instead of using ImageIcon, you can try to create your own icon class drawing the Image using graphics.drawImage(x,y,width,height,null) controlling rendering quality (https://docs.oracle.com/javase/tutorial/2d/advanced/quality.html)

    an example would be something like this:

    public class Icon32 extends ImageIcon {
        public Icon32(String f) {
          super(f);
    
          BufferedImage i= new BufferedImage(32, 32, 
               BufferedImage.TYPE_INT_RGB);
    
    
          Graphics2D g2d = (Graphics2D) i.getGraphics();
                    g2d.setRenderingHint(
                        RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    
                    g2d.setRenderingHint(
                        RenderingHints.KEY_INTERPOLATION,
                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    
          g2d.drawImage(getImage(), 0, 0, 32, 32, null);
          setImage(i);
        }
    
        public int getIconHeight() {
          return 32;
        }
    
        public int getIconWidth() {
          return 32;
        }
    
        public void paintIcon(Component c, Graphics g, int x, int y) {
          g.drawImage(getImage(), x, y, c);
        }
      }
    

    where the method:

    getImage()
    

    is loading your image/icon...

    Second option: if you are not happy with the result you can try to use this library: https://github.com/mortennobel/java-image-scaling it claims to provides better image scaling options than the Java runtime provides.

    0 讨论(0)
  • 2021-01-17 22:38

    You may think you're displaying the images at 32x32 size, but your example of the tiled images says that's not so. You have a 9x2 grid of icons, which should be 288x64 pixels, but in your sample image the grid is 302x66.

    If you carefully examine your tiled image, you can see that the individual tiles are being displayed 34px wide - see the magenta border that extends from 32px to 66px. (Note, some of the tiles are displayed 33px wide; it appears to be 33, 34, 34, 33, 34...)

    In order to stretch the tiles to the wider width, certain columns are being doubled (red borders) and this creates the visual glitches you are seeing.

    Have you tried fixing the size of the JLabel instead of allowing it to size based on its contents?

    0 讨论(0)
提交回复
热议问题