【问题标题】:What causes poor image quality in Java JLabel icons?是什么导致 Java JLabel 图标中的图像质量不佳?
【发布时间】:2019-10-23 08:40:28
【问题描述】:

Java JLabel 图标在JFrame 中显示失真像素。这与不同的 png 图像(所有 32x32)一致地发生。我没有缩放图像,它们显示在程序 32x32 中,我在 JLabel 上使用 getWidthgetHeight 进行了验证。每次运行程序时,失真都会出现在同一个地方,而不是随机出现。

使用下面提供的示例代码的屏幕截图。

在此屏幕截图中,您可以看到一组 JLabel 图标,每个图标的影响不同。

从侧面调整窗口大小时,随着图标随窗口移动,变形像一条垂直线一样在图标上移动。

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

public class FrameApp extends JFrame
{
    public static void main(String[] args) throws IOException
    {
        FrameApp frameApp = new FrameApp();
    }

    private FrameApp() throws IOException
    {
        BufferedImage image;

        URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
        image = ImageIO.read(url);

        JLabel label = new JLabel(new ImageIcon(image));

        add(label);

        pack();
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

编辑:
我在 Windows 8.1 64 位上使用 JDK 11.0.3,Java SE 运行时环境 build 1.8.0_202。

【问题讨论】:

  • 我猜这与图像缩放有关,您需要打开某种抗锯齿功能。虽然只是猜测,但可以为 Google 提供一些信息。
  • 1) 为了尽快获得更好的帮助,edit 添加minimal reproducible exampleShort, Self Contained, Correct Example。 2) 例如,获取图像的一种方法是热链接到this Q&A 中看到的图像。例如。 This answer 指向嵌入在 this question 中的图像的热链接。
  • @AndrewThompson 我想我按照你的建议正确地编辑了我的问题,但仍然没有答案,而且它已经被否决了。这个问题是否不正确,您认为我应该放弃答案吗?谢谢
  • 您使用的是哪个版本的 java?我尝试使用您的示例进行复制,但图像看起来非常好(openjdk 11.0.1)。
  • Java(TM) SE Runtime Environment (build 1.8.0_77-b03) 在 Windows 7 上也没有问题。

标签: java image swing jlabel imageicon


【解决方案1】:

您可能认为您正在以 32x32 尺寸显示图像,但您的平铺图像示例表明并非如此。您有一个 9x2 的图标网格,应该是 288x64 像素,但在您的示例图像中,网格是 302x66。

如果您仔细检查您的平铺图像,您会发现各个平铺显示的宽度为 34 像素 - 请查看从 32 像素延伸到 66 像素的洋红色边框。 (请注意,某些图块显示为 33 像素宽;它似乎是 33、34、34、33、34...)

为了将图块拉伸到更宽的宽度,某些列被加倍(红色边框),这会产生您所看到的视觉故障。

您是否尝试过修复 JLabel 的大小,而不是允许它根据其内容调整大小?

【讨论】:

  • 很好地注意到了这一点。我尝试将 JLabels 显式调整为所需的 32x32 以及更大或更小,但无济于事。即使尺寸缩小到像 28x28 这样的更小尺寸,也会存在相同的视觉故障,这似乎反驳了您认为它是由图标扩展引起的想法。但是,我像您一样在 28x28 处目视检查了它,但它仍然大于应有的大小(请参阅此处i.imgur.com/xyrGpUJ.png)。调用 label.getWidth() 返回 28,调用 label.getIcon().getIconWidth() 返回 32。很有趣,但我仍然不知道该怎么做。
  • 因此,即使在您的新示例中,看起来加倍的列也是定期发生的; 20 或 21 像素开始开始。在前面带有“32x32”图标的示例中,它们是 22 或 23。我不确定这告诉我们什么......设备像素和逻辑像素之间是否存在差异? (我正在抓住稻草。)
  • 感谢大卫回复。在提示 OP 随着时间的推移调整和扩展问题后,我很失望它已经从主页上掉下来了,一旦它变成了一个很好的问题,就没有收到任何回复。添加赏金(我觉得我的代表远远超过我需要的应得的)然后是不费吹灰之力。
  • @AndrewThompson 这一个有趣的问题;很抱歉我没有看到它解决。不幸的是我自己无法重现它,所以我只能指出我能看到的东西......
  • 并非每个问题都有可行的答案。 (耸耸肩)也许是因为“小鬼”。
【解决方案2】:

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

链接中的相应类

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;
    }

}

【讨论】:

  • 为什么你觉得这个问题与调整大小有关?他们说图像是 32x32,它显示为 32x32。图像有失真。当他们调整大小时,他们只是调整 JFrame 的大小,图像仍然是 32x32,但它会导致变形移动。
【解决方案3】:

第一个选项: 除了使用 ImageIcon,您可以尝试创建自己的图标类,使用 graphics.drawImage(x,y,width,height,null) 控制渲染质量 (https://docs.oracle.com/javase/tutorial/2d/advanced/quality.html)

一个例子是这样的:

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);
    }
  }

方法所在:

getImage()

正在加载您的图片/图标...

第二个选项:如果你对结果不满意,你可以尝试使用这个库: https://github.com/mortennobel/java-image-scaling 它声称提供了比 Java 运行时提供的更好的图像缩放选项。

【讨论】:

    猜你喜欢
    • 2021-05-11
    • 1970-01-01
    • 2012-04-14
    • 2020-02-14
    • 1970-01-01
    • 2013-06-06
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多