旋转球失去锋利和颜色

时间:2014-08-30 00:26:23

标签: java image swing java-2d

 package testIDE;

import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import Utils.MyJFrame;

public class ExampleClass {

    public static void main(String[] args) {
        JFrame ballRotate = new BallRotate();
    }
}

class BallRotate extends MyJFrame {

    ArrayList<Integer> degree = new ArrayList<Integer>();
    BufferedImage backGroundImage = getBufferedImage("testIDE/buttonDefaultImage.jpg");
    JLabel backGroundLabel = new JLabel(new ImageIcon(backGroundImage));
    BufferedImage footballImage = getBufferedImage("testIDE/Tennis_Ball.png");
    int x = 0;

    public BallRotate() {

        footballImage=getScaledImage(250, 250, footballImage);
        BufferedImage rotatedImage = footballImage;

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridBagLayout());

        setLabel();
        add(backGroundLabel);

        pack();
        centeringWindow();
        setVisible(true);

        setArray();

        while (true) {
            setDelay(60);
            rotatedImage = rotateImage(rotatedImage, x);

            setMyFuckingLabel(rotatedImage);
            x += 10;
            if (x == 10000) {
                break;
            }
        }
    }

    private void setArray() {
        for (int i = 0; i <= 360; i += 40) {
            degree.add(i);
        }
    }

    private void setLabel() {
        JPanel footBallPanel = new JPanel(new BorderLayout());
        JLabel footBallLabel = new JLabel(new ImageIcon(footballImage));

        footBallPanel.add(footBallLabel);

        borderingJPanel(footBallPanel, null, null); 

        backGroundLabel.setLayout(new GridBagLayout());
        backGroundLabel.add(footBallPanel);
    }

    private BufferedImage rotateImage(BufferedImage buffImage, int degree) {
        BufferedImage rotatedImage = null;

        AffineTransform affineTransform = AffineTransform.getRotateInstance(
                Math.toRadians(15*Math.PI), buffImage.getWidth() / 2,
                buffImage.getHeight() / 2);
        System.out.println(degree*Math.toRadians(1));       
        rotatedImage = new BufferedImage(buffImage.getWidth(),
                buffImage.getHeight(), buffImage.getType());
        Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
        g.setTransform(affineTransform);
        g.drawImage(buffImage, 0, 0, null);
        return rotatedImage;
    }

    public void setMyLabel(BufferedImage rotatedBuffImage) {
        JLabel backgroundlabel = (JLabel) getContentPane().getComponent(0);
        JPanel footBallPanel = (JPanel) backgroundlabel.getComponent(0);
        JLabel footBallLabel = (JLabel) footBallPanel.getComponent(0);

        footBallLabel.setIcon(new ImageIcon(rotatedBuffImage));
    }
}

enter image description here  enter image description here enter image description here

正如你所看到的,我的旋转网球失去了他的形状和着色。似乎颜色也在旋转。 为什么?有没有办法防止这种情况?我发布了生成上述对话框的代码。

感谢您的帮助。

1 个答案:

答案 0 :(得分:5)

所以一大堆问题......

  • 一步缩放图像绝不是一个好主意(除非你只缩放50%)。 Java也不是特别擅长。您可以使用一些技巧,例如使用多步骤缩放(在示例中演示)或使用像imgscalr这样的外部库。有关详细信息,请参阅The Perils of Image.getScaledInstance()
  • 您应避免将效果多次应用于同一图像,这只会使更改复杂化并降低图像质量。相反,尽可能保持主图像尽可能接近原始图像并使用它,因此您始终从相同的起点开始。
  • Swing不是线程安全的。这意味着三件事。首先,你不应该在可能阻塞它的事件调度线程的上下文中做任何事情,比如无限循环。其次,您应该只在EDT的上下文中更改UI组件的状态,第三,您应该确保从EDT的上下文中创建UI。有关详细信息,请参阅Concurrency in SwingInitial Threads ...
  • 除了直线水平或垂直线之外的任何其他东西看起来都很漂亮......在默认渲染设置下是普通的。您需要提供一些RenderingHints来增强结果

然后提出了如何在Swing中进行动画的问题?好吧,你有两个基本选项,你可以使用某种Thread,这需要你手动将更新同步到EDT,或者你可以使用Swing javax.swing.Timer,它允许你安排通话在EDT的背景下以规则的间隔后退。请查看How to use Swing Timers了解更多详情......

RotateBall

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class BallRotate {

    public static void main(String[] args) {
        new BallRotate();
    }

    public BallRotate() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage master;
        private JLabel ball;

        private BufferedImage rotatedImage;
        private float angle = 0;
        private float delta = 5;

        public TestPane() {
            setLayout(new GridBagLayout());
            try {
                master = ImageIO.read(getClass().getResource("/Ball.png"));
                master = getScaledInstanceToFit(master, new Dimension(250, 250));
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            ImageIcon icon = new ImageIcon(getRotatedImage(0));
            ball = new JLabel(icon);
            add(ball);

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle += delta;
//                    ball.setIcon(new ImageIcon(getRotatedImage(delta)));
                    getRotatedImage(angle);
                    ball.repaint();
                    System.out.println(angle);
                }
            });

            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    timer.start();
                }

            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        protected BufferedImage getRotatedImage(float degree) {

            if (rotatedImage == null) {
                rotatedImage = new BufferedImage(master.getWidth(),
                                master.getHeight(), BufferedImage.TYPE_INT_ARGB);
            }

            AffineTransform affineTransform = AffineTransform.getRotateInstance(
                            Math.toRadians(degree), rotatedImage.getWidth() / 2,
                            rotatedImage.getHeight() / 2);

            Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
            g.setBackground(new Color(255, 255, 255, 0));
            g.clearRect(0, 0, rotatedImage.getWidth(), rotatedImage.getHeight());
            g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            g.setTransform(affineTransform);
            g.drawImage(master, 0, 0, null);
            g.dispose();

            return rotatedImage;
        }
    }

    public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {

        return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);

    }

    protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {

        BufferedImage imgScale = img;

        int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
        int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);

//        System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
        if (dScaleFactor < 1.0d) {

            imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);

        }

        return imgScale;

    }

    protected static BufferedImage getScaledDownInstance(BufferedImage img,
                    int targetWidth,
                    int targetHeight,
                    Object hint,
                    boolean higherQuality) {

        int type = (img.getTransparency() == Transparency.OPAQUE)
                        ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;

        if (targetHeight > 0 || targetWidth > 0) {

            int w, h;
            if (higherQuality) {
                // Use multi-step technique: start with original size, then
                // scale down in multiple passes with drawImage()
                // until the target size is reached
                w = img.getWidth();
                h = img.getHeight();
            } else {
                // Use one-step technique: scale directly from original
                // size to target size with a single drawImage() call
                w = targetWidth;
                h = targetHeight;
            }

            do {
                if (higherQuality && w > targetWidth) {
                    w /= 2;
                    if (w < targetWidth) {
                        w = targetWidth;
                    }
                }

                if (higherQuality && h > targetHeight) {
                    h /= 2;
                    if (h < targetHeight) {
                        h = targetHeight;
                    }
                }

                //            if (w <= 0) w = 1;
                //            if (h <= 0) h = 1;
                BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();

                ret = tmp;

            } while (w != targetWidth || h != targetHeight);

        } else {

            ret = new BufferedImage(1, 1, type);

        }

        return ret;

    }

    public static double getScaleFactor(int iMasterSize, int iTargetSize) {

        return (double) iTargetSize / (double) iMasterSize;

    }

    public static double getScaleFactorToFit(Dimension original, Dimension toFit) {

        double dScale = 1d;

        if (original != null && toFit != null) {

            double dScaleWidth = getScaleFactor(original.width, toFit.width);
            double dScaleHeight = getScaleFactor(original.height, toFit.height);

            dScale = Math.min(dScaleHeight, dScaleWidth);

        }

        return dScale;

    }

    public static double getScaleFactorToFit(BufferedImage img, Dimension size) {

        double dScale = 1;

        if (img != null) {

            int imageWidth = img.getWidth();
            int imageHeight = img.getHeight();

            dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);

        }

        return dScale;

    }

    public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {

        double scaleFactor = getScaleFactorToFit(img, size);

        return getScaledInstance(img, scaleFactor);

    }

}