首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何裁剪和调整JavaFX图像的大小?

如何裁剪和调整JavaFX图像的大小?
EN

Stack Overflow用户
提问于 2014-10-16 07:45:04
回答 1查看 8.9K关注 0票数 3

我试图在JavaFX画布上显示非常大的图像。单个图像的分辨率为11980x8365。每个图像有一个相应的世界文件,我可以使用它来正确定位图像。我的帆布尺寸是800x600。有时我需要在画布上写完整的图像,有时只是画布的一部分。

以下是我迄今所做的工作:

  • 将完整大小的图像从文件加载到image对象中。
  • 计算要显示的图像的哪一部分,并计算缩放参数以正确地将其安装到800x600画布中。

基本上,我想使用GraphicsContext.drawImage(.) --将给定图像的当前源矩形绘制到画布的给定目标矩形。

对于这种方法,我正确地计算了所有参数。问题是,有时候Image大于2048x2048,出于某种原因,JavaFX试图使用GPU将此图像直接绘制到画布上(如果我正确理解的话)。当我遇到异常的时候:

代码语言:javascript
复制
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。

EN

回答 1

Stack Overflow用户

发布于 2014-10-16 15:08:53

有很多种方法可以做到这一点,这取决于您在流程中的各个点有哪些可用的信息。

如果您在加载之前知道文件中图像的大小,并因此可以计算缩放因子,则可以在加载它时对其进行缩放:

代码语言:javascript
复制
double requiredWidth = ... ;
double requiredHeight = ... ;
String imageURL = ... ;

Image image = new Image(imageURL, requiredWidth, requiredHeight, false, true);

最后两个参数是preserveRatiosmooth。后者将强制执行一种速度较慢但质量较好的重标度算法。

现在您只需将其裁剪到一个新的WritableImage中,就像在张贴你的链接中一样。

代码语言:javascript
复制
double x = ... ;
double y = ... ;
double width = ...;
double height = ... ;
WritableImage croppedImage = new WritableImage(image.getPixelReader(), x, y, width, height);

其中xywidthheight定义了裁剪区域(在缩放坐标中)。

然后你就可以把裁剪好的图像画到画布上:

代码语言:javascript
复制
graphicsContent.drawImage(croppedImage, canvasX, canvasY);

另一种方法是加载整个图像,然后使用ImageView创建一个裁剪的缩放视图:

代码语言:javascript
复制
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放到屏幕外场景中:

代码语言:javascript
复制
Pane pane = new Pane(imageView);
Scene offScreenScene = new Scene(pane);
WritableImage croppedImage = imageView.snapshot(null, null);

然后你可以像以前一样把裁剪好的图像画到画布上。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26398888

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档