我试图在JavaFX画布上显示非常大的图像。单个图像的分辨率为11980x8365。每个图像有一个相应的世界文件,我可以使用它来正确定位图像。我的帆布尺寸是800x600。有时我需要在画布上写完整的图像,有时只是画布的一部分。
以下是我迄今所做的工作:
基本上,我想使用GraphicsContext.drawImage(.) --将给定图像的当前源矩形绘制到画布的给定目标矩形。
对于这种方法,我正确地计算了所有参数。问题是,有时候Image大于2048x2048,出于某种原因,JavaFX试图使用GPU将此图像直接绘制到画布上(如果我正确理解的话)。当我遇到异常的时候:
java.lang.NullPointerException
at com.sun.prism.sw.SWGraphics.drawTexture(SWGraphics.java:686) at com.sun.prism.sw.SWGraphics.drawTexture(SWGraphics.java:686)
at com.sun.prism.sw.SWGraphics.drawTexture(SWGraphics.java:665)
at com.sun.prism.sw.SWGraphics.drawTexture(SWGraphics.java:648)
at com.sun.javafx.sg.prism.NGCanvas.handleRenderOp(NGCanvas.java:1228)
at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:997)
at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:578)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
at com.sun.javafx.sg.prism.CacheFilter.impl_renderNodeToCache(CacheFilter.java:655)
at com.sun.javafx.sg.prism.CacheFilter.render(CacheFilter.java:561)
at com.sun.javafx.sg.prism.NGNode.renderCached(NGNode.java:2346)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2034)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2037)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2037)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:469)
at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:317)
at com.sun.javafx.tk.quantum.UploadingPainter.run(UploadingPainter.java:132)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:129)
at java.lang.Thread.run(Thread.java:744)所以接下来我想尝试的是,在将图像发送到画布之前,在某个临时对象中裁剪和缩放图像。我找不到怎么做的例子。我发现的唯一例子是如何使用基于WritableImage的作物图像,但我不知道如何在裁剪后将其缩放,并将其转换为Image。
发布于 2014-10-16 15:08:53
有很多种方法可以做到这一点,这取决于您在流程中的各个点有哪些可用的信息。
如果您在加载之前知道文件中图像的大小,并因此可以计算缩放因子,则可以在加载它时对其进行缩放:
double requiredWidth = ... ;
double requiredHeight = ... ;
String imageURL = ... ;
Image image = new Image(imageURL, requiredWidth, requiredHeight, false, true);最后两个参数是preserveRatio和smooth。后者将强制执行一种速度较慢但质量较好的重标度算法。
现在您只需将其裁剪到一个新的WritableImage中,就像在张贴你的链接中一样。
double x = ... ;
double y = ... ;
double width = ...;
double height = ... ;
WritableImage croppedImage = new WritableImage(image.getPixelReader(), x, y, width, height);其中x、y、width和height定义了裁剪区域(在缩放坐标中)。
然后你就可以把裁剪好的图像画到画布上:
graphicsContent.drawImage(croppedImage, canvasX, canvasY);另一种方法是加载整个图像,然后使用ImageView创建一个裁剪的缩放视图:
Image fullImage = new Image(imageURL);
// define crop in image coordinates:
Rectangle2D croppedPortion = new Rectangle2D(x, y, width, height);
// target width and height:
double scaledWidth = ... ;
double scaledHeight = ... ;
ImageView imageView = new ImageView(fullImage);
imageView.setViewport(croppedPortion);
imageView.setFitWidth(scaledWidth);
imageView.setFitHeight(scaledHeight);
imageView.setSmooth(true);现在,您可以通过拍摄ImageView的快照,使用裁剪后的原始图像创建一个新的映像。要做到这一点,您需要将ImageView放到屏幕外场景中:
Pane pane = new Pane(imageView);
Scene offScreenScene = new Scene(pane);
WritableImage croppedImage = imageView.snapshot(null, null);然后你可以像以前一样把裁剪好的图像画到画布上。
https://stackoverflow.com/questions/26398888
复制相似问题