zor*_*ran 3 canvas image javafx-2 javafx-8
我试图在JavaFX画布上显示非常大的图像.单张图像的分辨率为11980x8365.每个图像都有一个相应的世界文件,我可以使用它来正确定位图像.我的画布大小是800x600.有时候我需要在画布上写整个图像,有时只是它的一部分.
这是我到目前为止所做的:
所以基本上我想使用GraphicsContext.drawImage(...) - 将给定图像的当前源矩形绘制到Canvas的给定目标矩形.
对于这种方法,我正确计算了所有参数.问题是有时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)
Run Code Online (Sandbox Code Playgroud)
所以我接下来要尝试的是在将一些临时对象中的Image裁剪并缩放之前将其发送到画布.我找不到任何示例如何做到这一点.我发现的唯一例子是如何使用WritableImage裁剪图像,但我不知道如何在裁剪后缩放它并将其转换为Image.
您可以通过多种方式执行此操作,具体取决于您在流程中的各个阶段提供的信息.
如果您在加载前知道文件中的图像大小,并因此可以计算比例因子,您可以在加载时实际缩放它:
double requiredWidth = ... ;
double requiredHeight = ... ;
String imageURL = ... ;
Image image = new Image(imageURL, requiredWidth, requiredHeight, false, true);
Run Code Online (Sandbox Code Playgroud)
最后两个参数是preserveRatio和smooth.后者将强制更慢但更好的质量重新缩放算法.
现在,您可以将其裁剪为新链接,WritableImage如您链接的帖子中所示:
double x = ... ;
double y = ... ;
double width = ...;
double height = ... ;
WritableImage croppedImage = new WritableImage(image.getPixelReader(), x, y, width, height);
Run Code Online (Sandbox Code Playgroud)
其中x,y,width,和height(在缩放坐标)限定的裁剪区域.
然后你可以将裁剪后的图像绘制到画布中:
graphicsContent.drawImage(croppedImage, canvasX, canvasY);
Run Code Online (Sandbox Code Playgroud)
另一种方法是加载整个图像,然后使用a 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);
Run Code Online (Sandbox Code Playgroud)
现在,您可以通过拍摄快照来创建具有原始图像的裁剪版本的新图像ImageView.为此,您需要将其ImageView置于屏幕外场景中:
Pane pane = new Pane(imageView);
Scene offScreenScene = new Scene(pane);
WritableImage croppedImage = imageView.snapshot(null, null);
Run Code Online (Sandbox Code Playgroud)
然后你可以像以前一样将裁剪后的图像绘制到画布中.