JavaFX ImageView没有任何平滑

是否可以在JavaFX 2.2的ImageView中渲染缩放的图像而不应用任何平滑处理? 我正在使用setSmooth(false)将50×50图像渲染到200×200 ImageView中,因此源图像中的每个像素都应该映射到屏幕上的4×4正方形。

然而,所得到的渲染仍然平滑了所有16个目标像素的源像素。 有没有人知道的方法来做到这一点,而不是手动将每个像素复制到一个新的图像?

在JavaFX 2.2中ImageView总是要做一些平滑处理,而不pipe你提供给ImageView提示是否平滑 。

(基于使用Java 7u15和Windows 7以及ATI HD4600graphics卡进行的testing)。

也许这是一个错误, ImageView将永远平滑Image ,但文档并没有真正指定平滑做什么或不做什么,所以很难说真正的意图是什么。 您可能想要将此问题的参考信息发布到openjfx-dev邮件列表或在JavaFX问题跟踪器中logging问题,以获得开发人员的更多专家意见。


我尝试了一些缩放图像的不同方法:

  1. 在Image构造函数中缩放。
  2. 使用fitWidth / fitHeight在ImageView 缩放 。
  3. 通过在ImageView上使用scaleX / scaleY属性进行缩放。
  4. 通过使用PixelReader对Image进行采样并使用PixelWriter创build新图像进行缩放 。

我发现方法1和4导致了一个锐利的像素化图像,如您所愿,2&3导致模糊的别名图像。

机器人采样

示例代码来生成上面的输出。


更新有关实现自己的图像filter的想法

JavaFX效果与用于图像加载例程的滤镜不同,但可以创build用于过滤图像的效果。 在JavaFX 2.2公开logging的API中,支持自定义效果的创build,因此创build自定义效果可能很困难。

图像支持的本地代码最近作为openjfx项目的一部分开源,所以你可以看看如何实现过滤。

您可能还希望针对JavaFX运行时项目提交function请求,以“允许我们制作自己的2D滤镜”。

我知道这是有点老,但我最近有需要这样的ImageView,下面的小黑客正是我想在我的(Windows)机器上。 没有保证,它在任何地方工作。

 import com.sun.javafx.sg.prism.NGImageView; import com.sun.javafx.sg.prism.NGNode; import com.sun.prism.Graphics; import com.sun.prism.Texture; import com.sun.prism.impl.BaseResourceFactory; import com.sun.prism.Image; import javafx.scene.image.ImageView; @SuppressWarnings("restriction") public class PixelatedImageView extends ImageView { @Override protected NGNode impl_createPeer() { return new NGImageView() { private Image image; @Override public void setImage(Object img) { super.setImage(img); image = (Image) img; } @Override protected void renderContent(Graphics g) { BaseResourceFactory factory = (BaseResourceFactory) g.getResourceFactory(); Texture tex = factory.getCachedTexture(image, Texture.WrapMode.CLAMP_TO_EDGE); tex.setLinearFiltering(false); tex.unlock(); super.renderContent(g); } }; } } 

这里的技巧是纹理被重新使用,所以线性过滤设置保持“粘性”。 为什么NGImageView无法简单地将“平滑”标志传递给纹理的线性过滤设置,这是我的NGImageView

当您将以下构造函数添加到Martin Sojka的答案时,您可以简单地将javafx图像传递给构造函数。 同样,尽pipe有关已弃用函数的警告,他的答案仍然正常(JDK 1.8_121)。

 public PixelatedImageView (javafx.scene.image.Image image) { super(image); }