Java图像缩放质量在JAR文件中丢失

时间:2015-01-22 02:19:02

标签: java swing jar bufferedimage graphics2d

我正在编写一个程序,其中整个JPanel放大了JScrollPane作为地图,但我也希望为用户提供缩放和放大最小化JScrollPane角落中整个地图的视图。我正在使用BlueJ,& (至少在BlueJ)我基本上得到了我想要的东西。为了缩小地图,我创建了一个BufferedImagebi,这是迷你地图的大小,然后使用其Graphics对象,g,将其转换为到Graphics2D对象g2,然后通过以下内容g2 RenderingHints,{/ 1>}

g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON));

从那里开始,我使用Graphics.scale(double sx, double sy)上的g2方法来设置比例,以便在调用paint(Graphics g)方法的大g2作为参数时,它将在bi上绘制大型地图的缩放版本,这是迷你地图的确切大小。这种情况每秒发生20次(有些随意,在这个速度下,我认为它看起来最好。迷你地图反映了用户实时做的事情&我认为如果每秒少于20次,它看起来很迟钝。)

在我的Macbook Pro上,此代码的外观如下:

enter image description here
当我运行程序时,这段代码没有明显的延迟,这导致我每秒重复采样20次,因为这似乎有足够的CPU。但是,在将项目导出到JAR文件时,生成的外观如下:

enter image description here
程序运行时仍然几乎没有滞后,但到底发生了什么?只要我在BlueJ中运行代码,它就可以运行 - 但在JAR文件中,迷你地图看起来很糟糕。

为了澄清,这是要缩放的地图(具有讽刺意味的是,当我将它放在这篇文章中时,它正在缩放): enter image description here 以下是两个BlueJ& JAR文件迷你地图,并排:

enter image description here enter image description here

这可能是什么原因? 当我运行" java -version"时,这是输出:

java版本" 1.8.0_31"
Java(TM)SE运行时环境(版本1.8.0_31-b13)
Java HotSpot(TM)64位服务器VM(版本25.31-b07,混合模式)

铊; DR:
当我在BlueJ中运行我的代码时,小图片看起来很好。导出到JAR文件后,它看起来很糟糕。可能导致这种情况的原因是什么?


编辑:我现在正在加入一个SSCCE,以便更好地了解我的意思。

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import javax.swing.border.*;

public class ScaleTest
{
    int scrollSpeed = 16, imageSize = 200;
    int rows = 40, columns = 40;
    JFrame f1 = new JFrame("ScaleTest: Full Size");
        JScrollPane scrollPane = new JScrollPane();
            JPanel f1Panel = new JPanel(new GridLayout(rows,columns,1,1));
    JFrame f2 = new JFrame("ScaleTest: Scaled");
        JPanel f2Panel = new JPanel()
        {
            public void paintComponent(Graphics g)
            {
                Graphics2D g2 = (Graphics2D)g;
                g2.drawImage(bi,0,0,null);
            }
        };
            BufferedImage bi = new BufferedImage(imageSize,imageSize,BufferedImage.TYPE_INT_ARGB);

    public ScaleTest()
    {
        f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f1.add(scrollPane);
            scrollPane.setPreferredSize(new Dimension(600,600));
            scrollPane.getHorizontalScrollBar().setUnitIncrement(scrollSpeed);
            scrollPane.getVerticalScrollBar().setUnitIncrement(scrollSpeed);
            scrollPane.setViewportView(f1Panel);
                for (int i = 0; i < rows*columns; i++)
                {
                    JPanel p = new JPanel();
                    p.setBackground(Color.WHITE);
                    p.setBorder(BorderFactory.createLineBorder(Color.BLACK,1));
                    p.setPreferredSize(new Dimension(100,100));
                    f1Panel.add(p);
                }
        f1.pack();

        f2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f2.setResizable(false);
        f2.add(f2Panel);
            f2Panel.setPreferredSize(new Dimension(imageSize,imageSize));
        f2.pack();

        Graphics2D g2 = (Graphics2D)bi.getGraphics();
        g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON));
        g2.scale(((double)imageSize)/f1Panel.getWidth(),((double)imageSize)/f1Panel.getHeight());
        f1Panel.paint(g2);
    }
    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI()
    {
        ScaleTest s = new ScaleTest();
        s.f1.setVisible(true);
        s.f2.setVisible(true);
    }
}

在BlueJ中,生成的缩放图像是这样的:
enter image description here
然而,在从BlueJ生成的JAR文件中,运行JAR会生成以下图像:
enter image description here
发生了什么事?

2 个答案:

答案 0 :(得分:2)

我猜你的BlueJ使用的是JDK1.6.0。

  • java版本&#34; 1.6.0_45&#34;

enter image description here

  • java版本&#34; 1.8.0_31&#34;

enter image description here

答案 1 :(得分:1)

我在SE上找到了这个答案:https://stackoverflow.com/a/24746194/1695856。 它的结果是提高缩小图像质量的一种方法是模糊它并分阶段缩小。在下面的示例中,我将图像缩小了50%三次,然后缩小了80%,最终缩放了原始图像的10%。

引用的文件(map.png)是您之前发布的大图片。在绘制缩放图像时设置抗锯齿渲染提示是没有用的,因为它只对线条,椭圆,矩形等有影响,但对图像没有影响。插值渲染提示有点帮助,但依赖于任何渲染提示并不总是有效,因为它们可能无法在不同平台上实现相同(或根本不是!)。

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Rescale {

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			private ConvolveOp	cop;

			@Override
			public void run() {
				JFrame frame = new JFrame("Map");
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				try {
					BufferedImage im = ImageIO.read(new File("map.png"));
					cop = new ConvolveOp(new Kernel(3, 3, new float[] { 0f, 1f / 5f, 0f, 1f / 5f, 1f / 5f, 1f / 5f, 0f, 1f / 5f, 0f }),
							ConvolveOp.EDGE_NO_OP, null);

					for (int i = 0; i < 3; i++) {
						im = getScaled(im, 0.5);
					}

					im = getScaled(im, 0.8f);

					JLabel lab = new JLabel(new ImageIcon(im));
					frame.setContentPane(lab);
					frame.pack();
					frame.setLocationRelativeTo(null);
					frame.setVisible(true);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			private BufferedImage getScaled(BufferedImage im, double scale) {
				BufferedImage nim;
				Dimension dim = new Dimension((int) (im.getWidth() * scale), (int) (im.getHeight() * scale));
				nim = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB);
				Graphics2D g = (Graphics2D) nim.getGraphics();
				g.scale(scale, scale);
				g.drawImage(im, cop, 0, 0);
				g.dispose();
				return nim;
			}

		});
	}

}

我希望这会有所帮助。