JavaFX ImageView 没有任何平滑

Posted

技术标签:

【中文标题】JavaFX ImageView 没有任何平滑【英文标题】:JavaFX ImageView without any smoothing 【发布时间】:2013-04-11 22:37:38 【问题描述】:

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

但是,生成的渲染仍然会在所有 16 个目标像素上平滑源像素。有谁知道无需手动将每个像素复制到新图像中的方法?

【问题讨论】:

您可以尝试 Canvas 以获得最大的控制权。 不幸的是,我认为也没有办法在画布中做到这一点。他们真正需要做的是让我们制作自己的 2D 过滤器(我猜它们在 JavaFX 中被称为“效果”)。 用实现自己的图像过滤器的想法更新了我的答案。 【参考方案1】:

ImageView 没有修复,但它对我帮助很大。 找了好久,偶然发现了这个帖子:How can I disable antialiasing on a JavaFX Canvas?

为了在画布上绘制图像,从 JavaFX 12 开始可以禁用平滑

canvas.getGraphicsContext2D().setImageSmoothing(false);

【讨论】:

【参考方案2】:

当您将以下构造函数添加到 Martin Sojka 的答案时,您可以简单地将 javafx Image 传递给构造函数。此外,尽管有关于已弃用功能的警告,但他的回答仍然可以正常工作(在 JDK 1.8_121 上)。

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

【讨论】:

【参考方案3】:

我知道这有点老了,但我最近需要这样的 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 不能简单地将“平滑”标志传递给纹理的线性过滤设置是我无法理解的。

【讨论】:

看起来他们不想让你这样做。 这适用于 Java 8,但看起来这里提到的函数已被重命名并设置为 Java 9 中的私有函数。看起来它不能以相同的方式被覆盖而不进行重大更改ImageViewImageViewHelper。有人知道如何解决 Java 9 中的新限制吗? 这个答案为我节省了几个小时的工作量......如果 JavaFX 根本不关心它,为什么还有 smooth=false 选项。【参考方案4】:

在 JavaFX 2.2 中,ImageView 总是会进行一些平滑处理,无论您提供给ImageView 的smooth 提示如何。

(基于使用 Java 7u15 和带有 ATI HD4600 显卡的 Windows 7 进行的测试)。

也许ImageView 总是会平滑Image 是一个错误,但文档并没有真正具体说明平滑做什么或不做什么,所以很难说它的真正意图是什么。您可能想在openjfx-dev mailing list 上发布对此问题的引用或在JavaFX issue tracker 中记录问题,以获得开发人员更专业的意见。


我尝试了几种不同的方法来缩放图像:

    在Image constructor 中缩放。 用fitWidth/fitHeight缩小ImageView。 使用ImageView 上的scaleX/scaleY 属性进行扩展。 通过使用PixelReader 对Image 进行采样并使用PixelWriter 创建一个新图像来进行扩展。

我发现方法 1 和 4 会产生您希望的清晰像素化图像,而方法 2 和 3 会产生模糊的混叠图像。

Sample code 生成上述输出。


更新实现您自己的图像过滤器的想法

JavaFX 效果与用于图像加载例程的过滤器不同,尽管可以创建过滤图像的效果。在 JavaFX 2.2 中公开记录的 API 支持创建自定义效果,因此创建自定义效果可能会很困难。

native code for image support 最近作为openjfx project 的一部分开源,因此您可以查看它以了解当前如何实现过滤。

您可能还想提交feature request against the JavaFX runtime project 以“允许我们制作自己的 2D 滤镜”。

【讨论】:

你总是给出如此令人印象深刻的答案jewelsea:D 是的,感谢您的详细回答。我得出了同样的结论,并最终实施了#4。实现本身是微不足道的,但我担心它比 #2 或 #3 慢得多(尽管我还没有验证这一点)。 这个答案已经两年了。有谁知道这是否已在 JavaFX 中修复? 我不确定您所说的固定教育是什么意思。我的猜测是系统的行为符合开发人员的意图。如果您想了解有关在 JavaFX 中过滤和平滑图像的更多信息,您可以按照答案中的说明发布到 open-jfx 开发人员邮件列表。 很奇怪,N° 1. 解决方案对我的 BMP 文件不起作用,它不加载图像,它适用于其他 3 个解决方案,我将使用 N° 4. 解决方案,谢谢。

以上是关于JavaFX ImageView 没有任何平滑的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX 对背景的影响

JavaFX ImageView旋转更改拖放

加载视频缩略图 - JavaFx

在ImageView中缩放图像(javafx)

JavaFX 将 ImageView 裁剪为 AnchorPane 中的椭圆

JavaFX ImageView