本文介绍了Java / Swing离线渲染(Cobra HTMLPanel - > BufferedImage)问题:组件不能完成第一次重绘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将Java / Swing 的内容渲染为屏幕外的BufferedImage,用于我的应用程序中的其他地方:

  slideViewPanel.setDocument(document,rendererContext); 
BufferedImage test = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
Graphics g = test.getGraphics();
slideViewPanel.paint(g);

g中的结果图像显示了部分呈现的页面 - 有时是新的HTMLFrame的内容文件已设定;有时候是新文档的半渲染版本。我收集这是因为Cobra的setDocument方法只是为了重新渲染而安排文档,但我正在调试器中加入,而且我没有看到第二个线程进行重新渲染。任何人都可以看到这里可能发生的事情吗?

当解析页面时,您需要等到所有图像在铺设组件之前加载。

拦截所有图像加载以确保在布置组件之前全部加载所有图像。我通过过滤HtmlDocumentImpl.loadImage来完成此操作。 (必须继承DocumentBuilderImpl的子类并重写createDocument才能使其工作)。我使用了一个信号灯来等待image.getWItdh的结果可用。



必须设置因为有些脚本可能会循环并永远不会返回,所以请在解析时使用计时器。我不知道是否有更好的方法来解决这个问题。



关于布局,有一系列的货物崇拜和实验导致在下面被剪断,所以也许你可以尝试删除一些东西。

  htmlPanel.setVisible(true); 
htmlPanel.setPreferredWidth(DEFAULT_PAGE_WIDTH);
logger.info(计算首选大小);

//获取当前宽度的首选高度。
Dimension psvz = htmlPanel.getPreferredSize();
Dimension min = htmlPanel.getMinimumSize();

logger.info(prf:+ psvz);
logger.info(min:+ min);

//放大到最小宽度(有限制)
int width = Math.min(MAX_PAGE_WIDTH,Math.max(DEFAULT_PAGE_WIDTH,
psvz.width));
int height = psvz.height;

logger.info(width:+ width);
logger.info(heigth:+ height);

htmlPanel.setSize(width,height);

//实际上,htmlPanel是一个子类,并且此方法公开validateTree。它可能没有它。
htmlPanel.forceValidateTree();

htmlPanel.doLayout();

setImageSize(width);
logger.info(actual size:+ htmlPanel.getSize());

我无法弄清楚JFrame如何处理HtmlPanel,以便它能正确地绘制子元素。
我必须使用子组件绘制;即可以使用htmlPanel.getBlockRenderable()或frameset。



图像被绘制为异步(并且绘画可能会中止),所以在使用BufferedImage之前,所有必须完成图像涂料。



我使用委托的graphics2d对象覆盖所有的图像绘画方法,直到绘画完成。



之后,我发现html可能从重新布局中受益,因为所有图像大小都是已知的,所以我使组件无效并再次进行布局和绘画(或者实际上,我只是将代码调用两次...)

之后,可以使用BufferedImage。也许有一个更简单的方法。


I'm trying to render the contents of a the Java/Swing Cobra HTML renderer to an offscreen BufferedImage, for use elsewhere in my app:

 slideViewPanel.setDocument(document, rendererContext);
 BufferedImage test = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
 Graphics g = test.getGraphics();
 slideViewPanel.paint(g);

The resulting image in g shows a partially rendered page -- sometimes the contents of the HTMLFrame before the new document was set; sometimes a half-rendered version of the new document. I gather this is because Cobra's setDocument method just schedules the document for re-rendering, but I'm stepping through in the debugger and I don't see a second thread to do re-rendering. Anyone have any insight into what might be happening here?

解决方案

When the page has been parsed, you need to wait until all images are loaded before laying out the component.

Intercept all image loading to make sure all images are completely loaded before laying out the component. I did this by overiding HtmlDocumentImpl.loadImage. (Had to subclass DocumentBuilderImpl and overriding createDocument to make it work.) I used a semaphore to wait until the result of a image.getWItdh is available.

I had to set up a timer around the parsing, as some scripts may loop and never return. I have no idea if there is a better way of solving this.

Regarding the layout, there is a a deal of cargo cult and experimentation that lead to the snipped below , so maybe you can try to remove some things.

            htmlPanel.setVisible(true); 
    htmlPanel.setPreferredWidth(DEFAULT_PAGE_WIDTH);
    logger.info("Calculating preferred size");

    // Get the preferred heigth for the current width.
    Dimension psvz = htmlPanel.getPreferredSize();
    Dimension min = htmlPanel.getMinimumSize();

    logger.info("prf :" + psvz);
    logger.info("min :" + min);

    // Enlarge to the minimum width (with a limit)
    int width = Math.min(MAX_PAGE_WIDTH, Math.max(DEFAULT_PAGE_WIDTH,
            psvz.width));
    int height = psvz.height;

    logger.info("width :" + width);
    logger.info("heigth :" + height);

    htmlPanel.setSize(width, height);

            // actually, htmlPanel is a subclass, and this method exposes validateTree. It may work without it.
    htmlPanel.forceValidateTree(); 

    htmlPanel.doLayout();

    setImageSize(width);
    logger.info("actual size:" + htmlPanel.getSize());

I couldn't figure out what a JFrame does with the HtmlPanel so that it paints its children properly. I had to paint using the children component; Ie either the htmlPanel.getBlockRenderable() or the frameset.

Images are painted asychronous, (and the paints might abort), so before the BufferedImage can be used, all the image paints must be completed.

I used a delegating graphics2d object overriding all the image paint methods to wait until the painting is completed.

After that, i found that the html might benefit from a re-layout as all images sizes are known, so i invalidate the component and do the layout and painting again (or actually, I just call the code twice...)

After that, the BufferedImage can be used. Maybe there is a simpler way.

这篇关于Java / Swing离线渲染(Cobra HTMLPanel - > BufferedImage)问题:组件不能完成第一次重绘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 17:57