Java - 使用Graphics.drawImage()和双屏缓冲策略绘制许多图像,扭曲和剪切图像

时间:2010-01-19 21:28:21

标签: image swing graphics java-2d

我正在使用循环来调用双缓冲绘画。这与覆盖我唯一的Panel重绘方法一起,旨在将重绘的完全控制传递给我的循环,并且仅在必要时进行渲染(即在GUI中进行了一些更改)。

这是我的渲染例程:

    Log.write("renderer painting");

    setNeedsRendering(false);

    Graphics g = frame.getBufferStrategy().getDrawGraphics();

    g.setFont(font);
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, window.getWidth(),window.getHeight());

    if(frame != null)
        window.paint(g);

    g.dispose();

    frame.getBufferStrategy().show();

正如您所看到的,它非常标准。我从缓冲区策略中获取了grpahics对象(初始化为2),将其全部变为黑色并将其传递给我的“window”对象的paint方法。

使用图形对象完成窗口后,我将其处理并在缓冲区策略上调用show以显示虚拟缓冲区的内容。

重要的是要注意窗口将图形对象传递给填充窗口的许多其他子组件,然后每个组件使用相同的图形对象实例在屏幕上绘制内容:文本,形状或图像。

我的问题开始显示系统何时运行并呈现大图像。图像看起来被切割成半成品并一次又一次地(3-4次)绘制,在图像应该被渲染的地方内部具有不同的偏移。请参阅我附带的图片:

这是原始图片: alt text http://img109.imageshack.us/img109/8308/controller.png

这就是我得到的: alt text http://img258.imageshack.us/img258/3248/probv.png

请注意,在第二张图片中,我在图片上渲染形状 - 这些形状总是在正确的位置。

知道为什么会这样吗? 如果我将图像保存到文件中,就像它在内存中一样,就在调用g.drawImage(...)之前,它与原始图像相同。

1 个答案:

答案 0 :(得分:2)

呃,你在使用Swing?
通常,Swing 会自动渲染图像,您无法将其关闭。重画() 方法超出范围,因为Swing有一个非常复杂的渲染例程 AWT小部件的方法兼容性和几个优化,仅包含绘图 必要时 ! 如果要使用高速绘图API,则使用具有BufferStrategy的组件 像JFrame和Window一样,使用

setIgnoreRepaint(假);

关闭Swing渲染,设置绘图循环并绘制内容本身。 或者您可以使用JOGL进行OpenGL渲染。您正在使用的方法似乎完全正确 与正确的Java2D使用不一致。

这里正确使用:

public final class FastDraw extends JFrame {
  private static final transient double NANO = 1.0e-9;


 private BufferStrategy bs;

 private BufferedImage frontImg;

 private BufferedImage backImg;

 private int PIC_WIDTH,
             PIC_HEIGHT;

  private Timer timer;

  public FastDraw() {
    timer = new Timer(true);
    JMenu menu = new JMenu("Dummy");
    menu.add(new JMenuItem("Display me !"));
    menu.add(new JMenuItem("Display me, too !"));
    JMenuBar menuBar = new JMenuBar();
    menuBar.add(menu);
    setJMenuBar(menuBar);

    setIgnoreRepaint(true);
    setVisible(true);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) {
        super.windowClosing(evt);
        timer.cancel();
        dispose();
        System.exit(0);
      }
    });
    try {
      backImg = javax.imageio.ImageIO.read(new File("MyView"));
      frontImg = javax.imageio.ImageIO.read(new File("MyView"));
    }
    catch (IOException e) {
      System.out.println(e.getMessage());
    }
    PIC_WIDTH = backImg.getWidth();
    PIC_HEIGHT = backImg.getHeight();
    setSize(PIC_WIDTH, PIC_HEIGHT);


    createBufferStrategy(1); // Double buffering
    bs = getBufferStrategy();
    timer.schedule(new Drawer(),0,20);
  }
  public static void main(String[] args) {
    new FastDraw();
  }

  private class Drawer extends TimerTask {

    private VolatileImage img;

    private int count = 0;

    private double time = 0;

    public void run() {
      long begin = System.nanoTime();
      Graphics2D  g  = (Graphics2D) bs.getDrawGraphics();
      GraphicsConfiguration gc = g.getDeviceConfiguration();
      if (img == null)
        img = gc.createCompatibleVolatileImage(PIC_WIDTH, PIC_HEIGHT);
      Graphics2D g2 = img.createGraphics();
      // Zeichenschleife
      do {
        int valStatus = img.validate(gc);
        if (valStatus == VolatileImage.IMAGE_OK)
          g2.drawImage(backImg,0,0,null);
        else {
          g.drawImage(frontImg, 0, 0, null);
        }
        // volatile image is ready
        g.drawImage(img,0,50,null);
        bs.show();
      } while (img.contentsLost());
      time = NANO*(System.nanoTime()-begin);
      count++;
      if (count % 100 == 0)
        System.out.println(1.0/time);
    }
  }