Как я могу создать аппаратно-ускоренный образ с Java2D?

Я пытаюсь создать быстрый генератор изображений, который выполняет множество двумерных преобразований и рендеринг фигур, поэтому я пытаюсь использовать BufferedImage, а затем получить объект Graphics2D для выполнения всего моего рисования. Сейчас моя главная задача - сделать это очень быстро, поэтому я создаю BufferedImage, например:

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage bImage = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
Graphics2D graphics = bImage.createGraphics();

Однако если я сделаю:

System.out.println(bImage.getCapabilities(gc).isAccelerated());

Вывод всегда ложен, даже если я запускаю JVM с -Dsun.java2d.opengl=True, который печатает строку:

OpenGL pipeline enabled for default config on screen 0

Я делаю BufferedImage, потому что в конце я хочу сохранить его в файл PNG с ImageIO.write(bImage, "PNG", file);

Я могу создать VolatileImage, которое скажет, что оно ускорено, но ImageIO не нравится, когда он пытается сохранить, говоря, что это изображение не может быть приведено к RenderedImage. Любые идеи о том, как получить ускоренное изображение, которое может быть сохранено на диск? Также я не хочу создавать VolatileImage и копировать в BufferedImage для сохранения, так как мои изображения действительно большие, и у меня возникнут проблемы с памятью...

3 ответа

Решение

Из моего исследования и чтения учебника по Sun/Oracle 2D я нашел следующее:

Для создания ускоренного изображения можно использовать изменчивое изображение, которое создается как pbuffer. Есть преимущества и недостатки, VolatileImages быстр, пока вы не попытаетесь получить растровые данные пикселей. В этот момент они становятся обычным bufferedImage. Также они нестабильны, и нет никаких гарантий, что они будут доступны в конце вашего рендеринга. Для этого вы выполняете:

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
VolatileImage vImage = gc.createCompatibleVolatileImage(width, height, Transparency.TRANSLUCENT);

Это даст вам ускоренное изображение, однако невозможно использовать ImageIO, чтобы написать его напрямую, например, в формате PNG.

Чтобы использовать обычный BufferedImage, вам нужно сделать что-то вроде:

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
img.setAccelerationPriority(1);

Это создает BufferedImage, которое не ускоряется, но вы даете подсказку JVM, которая должна, передавая 1 в setAccelerationPriority. Это вы можете прочитать в 2D-следе Учебника Java.

Попробуйте добавить это в вашу командную строку:

-Dsun.java2d.accthreshold=0

РЕДАКТИРОВАТЬ

Я прочитал об этом после того, как вы сказали, что вышесказанное не сработало. Попробуйте изменить значение True для параметра OpenGL на строчные.

-Dsun.java2d.opengl=true

Вот как это работает:

То, как вы создаете образ, является правильным. Но Java не ускоряет изображение сразу. Существует порог вызовов рендеринга, который должен быть направлен на ваше изображение, после чего изображение будет ускорено. Но если вы установите следующее,

-Dsun.java2d.accthreshold=0

Ваше изображение должно быть ускорено, как только вы его создадите.

Возможно, вам все равно придется как-то использовать изображение, чтобы оно ускорилось. Например, у меня есть следующий фрагмент кода, который используется для копирования загруженного изображения (загрузка через ImageIO даст вам изображение, которое не может быть ускорено) в мой новый BufferedImage.

Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image,0,0,null);
g2d.dispose();

До этого сегмента кода BufferedImage не ускоряется, а потом это происходит.

Но будьте осторожны, если вы манипулируете данными изображения напрямую (т.е. не через Java-2d), ваше изображение больше не будет кэшироваться в VRAM, и вам придется скопировать его в новый управляемый образ, чтобы восстановить свое ускорение.

Другие вопросы по тегам