Java Graphics drawline性能问题

时间:2015-07-22 14:24:39

标签: java graphics2d

我遇到了Graphics类的drawline方法的速度问题。我用它从链表中绘制线条图到屏幕。一旦列表足够大(大约150000个值),循环整个列表并重绘所有行需要更长的时间。我想知道如何通过优化drawline方法或放弃它来改善程序的性能。

@Override
protected void paintComponent(Graphics g) {
    ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
    ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);          
        Graphics2D scaledG = (Graphics2D) g.create();
        g.dispose();
        super.paintComponent(scaledG);
        AffineTransform scaleTransform = new AffineTransform();
        scaleTransform.scale(graphScale, 1);
        scaledG.setTransform(scaleTransform);
        scaledG.setColor(new Color(242,100,66));
            for (Line line : lines) {
                   scaledG.drawLine((int)line.x1, (int)line.y1, (int)line.x2, (int)line.y2);      
                   }
           scaledG.dispose();
  }

2 个答案:

答案 0 :(得分:4)

由于你的问题非常广泛,很难给出明确的答案,所以我只会给你一些我会检查以提高渲染性能的一般方法。

  1. 缓存渲染的静态部分:绘制大量形状时,一个非常有用的技巧是通过将形状渲染到{{1}来缓存形状的“静态”部分然后将该图像与“动态”形状一起渲染到BufferedImage对象上。

    要应用它,关键问题在于您是否可以知道哪些线路是静态的,哪些线路需要动态渲染。如果你不能在线上假设任何东西,这种方法不适用 - 你需要渲染一切。但是,如果您知道,例如,大多数渲染中前N行不会改变,则可能值得一试。

    这种方法的一个小缺点是动态部件总是呈现在静态部件之上。在许多应用程序中,例如编辑形状,这无关紧要,在其他应用程序中,它确实如此。

  2. “细节级别”/平滑方法:如果您的线条(线段)形成折线或多边形,请考虑是否可以插入或完全忽略某些线段。粗略的方法是检查后续段的变换(像素)端点是否与当前段的变换(像素)端点不同;如果没有,该段将对结果图像没有影响,您可以跳过它。

    然而,不要使用这个仅用于证明一般想法的算法;有更多更好的算法可用于“缩小”或“平滑”折线和多边形,例如,请参阅SimpliPolyDavid Eberly's polyline reduction作为首发。

    当然,这一切都取决于你的线条是否“平滑”,以及它们是否连接。对于地理数据(海岸线,河流等),此优化可以将您的数据压缩到原始大小的分数;对于完全随机和未连接的线路,这无济于事。

  3. 使用异步增量优化提供快速预览:如果上述两种方法都不适用,或者仍然不够,可能没有有效的方法来大幅加快应用程序的速度(见下文)。在这种情况下,我会尝试即时提供某种快速预览,然后异步提升(Graphics或另一个计算线程)。只要更改其中一行,就会停止细化渲染,提供下一个预览,然后重新开始细化。虽然这并没有真正加速渲染(相反:),但它确实使您的应用程序在主观上更具响应性,而且这通常比纯时钟周期更重要。

    在您的示例中,您可以通过渲染前N 000行来简单地开始。然后你开始你的“渲染剩余”线程,只要线条不变,就会逐渐绘制更多的线条;但是,用户可以在渲染所有线条之前更改线条的参数,如果他意识到这不是他想要的那样。

    这种方法的主要缺点是增加了复杂性。多线程需要仔细同步以防止竞争问题,并且总是容易出现令人讨厌的错误。然而,这种方法的效果往往令人惊讶。

  4. 低级优化和分析:最后但并非最不重要的是,您始终可以尝试去除所有不必要的计算。不要设置任何SwingWorker。不要使用RenderingHints对象的变换,自己动手 - 在你的例子中,简单地乘以线坐标,如果缩放在大多数时间保持不变,可以缓存缩放的坐标(#1的变体) 。甚至可能将线条自己光栅化为一些像素缓冲区,从中创建图像并渲染它。剖析渲染,看看你可以在几个时钟上削减。

    然而,虽然这可能会改善表现,但是A)难以维持而且B)无法解决一般问题,只需将边界推得更远。

  5. 当然,您可以将这些方法结合起来。

    如果所有这些都不适用或帮助,您唯一的选择是切换到允许比Java更直接的硬件(图形卡)通信的编程语言。

答案 1 :(得分:0)

不要处置()传递给绘制方法的Graphics对象。只处理您创建的Graphics()Graphics对象。

尝试以正常比例创建BufferedImage,因此绘画只执行一次,而不是调用paintComponent()方法。然后在paintComponent()方法中,可以在绘制图像时缩放图像。