JavaFx vs Swing визуализация изображений


Я исследую, имеет ли смысл передавать приложение из Swing в JavaFx 8, и мне нужна помощь. Приложение визуализирует изображения в реальном времени, в основном я обновляю изображение с определенной частотой, например 1 секунда. Размер изображений-28k x 4k; когда я использую JavaFx imageView, производительность плохая по сравнению с Swing.(Fps низкий, около 1-2, приложение отстает). Я делаю это следующим образом:

    animation = new Timeline();
    animation.getKeyFrames().add(new KeyFrame(Duration.millis(1000), new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            for (int count = 0; count < 1; count++) {
                if (indicator)
                    imageView.setImage(writableImage);
                else
                    imageView.setImage(image1);
                indicator = !indicator;
            }
        }
    }));
    animation.setCycleCount(Animation.INDEFINITE);

Поэтому я попытался использовать холст JavaFx :

    imageCanvas.setHeight(image1.getHeight());
    imageCanvas.setWidth(image1.getWidth());
    imageCanvas.getGraphicsContext2D().drawImage(image1, 0, 0);

Когда я пытаюсь это сделать, я получаю следующую ошибку.

java.lang.NullPointerException
    at com.sun.prism.impl.BaseGraphics.drawTexture(BaseGraphics.java:400)
    at com.sun.prism.impl.ps.BaseShaderGraphics.drawTexture(BaseShaderGraphics.java:139)
    at com.sun.javafx.sg.prism.NGCanvas.handleRenderOp(NGCanvas.java:1336)
    at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:1086)
    at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:595)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2308)
    at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2202)
    at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2228)
    at com.sun.javafx.sg.prism.CacheFilter.impl_renderNodeToCache(CacheFilter.java:663)
    at com.sun.javafx.sg.prism.CacheFilter.render(CacheFilter.java:567)
    at com.sun.javafx.sg.prism.NGNode.renderCached(NGNode.java:2372)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2058)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2308)
    at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2202)
    at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2228)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2061)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
    at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
    at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:474)
    at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:320)
    at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91)
    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:125)
    at java.lang.Thread.run(Thread.java:745)

Проблема вызвана размером изображения, потому что оно работает с меньшими. Во-первых, я не понимаю, почему производительность с imageView намного хуже, чем с Swing? (В swing я использую панель, которая расширяет JPanel и метод paintComponent.)

Во-вторых, существует ли какое-то ограничение на размер холста в JavaFx ?

Заранее благодарю вас.

1 2

1 ответ:

Почему ваше приложение JavaFX не работает

28k x 4k-это абсолютно массивное изображение, и JavaFX 8 не поддерживает его непосредственно против аппаратного конвейера. Я не знаю, является ли это ограничение официально задокументированным где-либо.

Смотрите: максимальные размеры холста в JavaFX .

Конвейер рендеринга JavaFX по умолчанию будет пытаться рисовать изображения (и холсты) в текстурах на видеокарте (для поддержки аппаратного ускорения композитинга). Видеокарты ограничены в размерах текстур, которые они поддерживают, обычно это какая-то мощность двух, например, 8192 x 8192. JavaFX (по крайней мере, в предыдущих версиях, которые я использовал), просто выдаст исключение, если вы попытаетесь сделать изображение больше, чем максимальный размер текстуры, поддерживаемый базовым видеооборудованием.

Потенциальные Обходные Пути

Чтобы обойти ограничение размера текстуры в JavaFX, обработайте входящие данные для изображения и загрузите его в 7 изображений 4k x 4k (использование записываемых изображений с помощью пиксельной записи). При этом убедитесь, что входные данные закодированы в соответствующем пиксельном формате, например:ByteBgraPreInstance, в противном случае потребуется преобразование данных, что может существенно повлиять на производительность вашего приложения.

Существуют недокументированные коммутаторы для JavaFX, чтобы отключить аппаратную визуализацию и использовать вместо этого программный конвейер визуализации. Эти переключатели могут позволить или не позволить вашему приложению работать с большими размерами изображений без однако при реализации описанного выше алгоритма разбиения на листы, вероятно, будет лучше для вашего приложения в целом сохранить включенным конвейер аппаратного ускорения графики и закодировать приложение для работы в рамках ограничений этого конвейера (путем реализации пользовательского алгоритма разбиения на листы для поддержки больших изображений).

Аспекты Производительности

Что касается различий в производительности в программе JavaFX по сравнению с программой Swing, то это невозможно проанализировать без исходного кода для обоих программы (и, возможно, трудно сделать, даже если исходные тексты были предоставлены). Поэтому я не буду больше комментировать этот аспект вашего вопроса.

Canvas-более сложный элемент управления, чем ImageView, и использование Canvas для этой задачи вряд ли даст вам какую-либо улучшенную производительность по сравнению с использованием ImageView.