JavaFX ImageView без сглаживания
Можно ли отображать масштабированное изображение в ImageView в JavaFX 2.2 без какого-либо сглаживания? Я представляю изображение 50x50 в ImageView с разрешением 200x200 с помощью setSmooth (false), поэтому каждый пиксель исходного изображения должен отображаться на квадрат 4x4 на экране.
Однако результирующий рендеринг все еще сглаживает исходный пиксель по всем 16 целевым пикселям. Кто-нибудь знает способ сделать это без ручного копирования каждого пикселя в новое изображение?
Ответы
Ответ 1
В JavaFX 2.2 ImageView
всегда будет выполняться сглаживание независимо от smooth, который вы указываете на ImageView
.
(На основе тестирования с использованием Java 7u15 и Windows 7 с видеокартой ATI HD4600).
Возможно, это ошибка, что ImageView
всегда будет сглаживать Image
, но в документации не указано точно, что сглаживание делает или не делает, поэтому трудно сказать, каково ее реальное намерение. Вы можете отправить ссылку на этот вопрос в список рассылки openjfx-dev или зарегистрировать проблему в JavaFX вопрос трекера, чтобы получить более экспертное мнение от разработчика.
Я попробовал несколько разных способов масштабирования изображения:
Я обнаружил, что методы 1 и 4 приводили к резкому пикселированному изображению по вашему желанию, а 2 и 3 приводили к размытому псевдониму.
![robot-sampling]()
Пример кода для создания указанного выше результата.
Обновление с идеями по внедрению собственного фильтра изображений
Эффект JavaFX не совпадает с фильтром, используемым для подпрограмм загрузки изображений, хотя может быть создан Эффект для фильтрации изображения. В JavaFX 2.2 публично документированный API для поддержки создания пользовательских эффектов, поэтому создание настраиваемого эффекта может оказаться затруднительным.
собственный код для поддержки изображений недавно был открыт в составе openjfx, чтобы вы могли посмотреть, как это происходит в настоящее время.
Вы также можете запросить запрос функции против проекта среды JavaFX, чтобы "позволить нам создавать собственные 2D-фильтры".
Ответ 2
Я знаю, что это немного старше, но мне недавно понадобился такой 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
не мог просто передать флаг "гладкий", чтобы настройка линейной фильтрации текстуры была вне меня.
Ответ 3
Когда вы добавляете следующий конструктор в ответ Martin Sojka, вы можете просто передать javafx Image в конструктор. Кроме того, несмотря на предупреждения об устаревших функциях, его ответ все еще работает нормально (на JDK 1.8_121).
public PixelatedImageView (javafx.scene.image.Image image) {
super(image);
}
Ответ 4
В случае, если у кого-то возникла та же проблема в Java 9 или выше, вот отредактированная версия решения Мартина Сойки, которая использует отражение для получения доступа к некоторым теперь закрытым членам ImageView
:
import java.lang.reflect.InvocationTargetException;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import com.sun.javafx.geom.BaseBounds;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.javafx.scene.ImageViewHelper;
import com.sun.javafx.sg.prism.NGImageView;
import com.sun.javafx.sg.prism.NGNode;
import com.sun.prism.Graphics;
import com.sun.prism.Image;
import com.sun.prism.Texture;
import com.sun.prism.impl.BaseResourceFactory;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
public class PixelatedImageView extends ImageView {
public PixelatedImageView(javafx.scene.image.Image image) {
super(image);
try {
initialize();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private void initialize() throws IllegalAccessException {
Object nodeHelper = FieldUtils.readField(this, "nodeHelper", true);
FieldUtils.writeField(nodeHelper, "imageViewAccessor", null, true);
ImageViewHelper.setImageViewAccessor(new ImageViewHelper.ImageViewAccessor() {
@Override
public NGNode doCreatePeer(Node node) {
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);
}
};
}
@Override
public void doUpdatePeer(Node node) {
try {
MethodUtils.invokeMethod(node, "doUpdatePeer");
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public BaseBounds doComputeGeomBounds(Node node, BaseBounds bounds, BaseTransform tx) {
try {
return (BaseBounds) MethodUtils.invokeMethod(node, "doComputeGeomBounds", bounds, tx);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean doComputeContains(Node node, double localX, double localY) {
try {
return (boolean) MethodUtils.invokeMethod(node, "doComputeContains", localX, localY);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
}
});
}
}