Подтвердить что ты не робот

Как вы можете получить резкие результаты краски при вращении BufferedImage?

Один из попыток - использовать TexturePaint и g.fillRect() для рисования изображения. Однако это требует создания нового объекта TexturePaint и Rectangle2D каждый раз, когда вы рисуете изображение, что не идеально - и никоим образом не помогает.

Когда я использую g.drawImage(BufferedImage,...), повернутые изображения кажутся размытыми/мягкими.

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

Код для использования TexturePaint выглядит примерно так.

Grahics2D g2d = (Graphics2D)g; 
g2d.setPaint(new TexturePaint(bufferedImage, new Rectangle2D.Float(0,0,50,50)));
g2d.fillRect(0,0,50,50);

Я использую AffineTransform для поворота руки карт в вентилятор. Каким будет лучший подход к быстрому рисованию хороших изображений?

Вот скриншот:
Example of blurred rotations
9 - хрустящий, но остальные карты определенно не такие острые.

Возможно, проблема заключается в том, что я создаю каждое изображение карты и сохраняю ее в массиве.
Как я это делаю сейчас:

// i from 0 to 52, card codes.
...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(86, 126, Transparency.TRANSLUCENT);

    Graphics2D g = img.createGraphics();
    setRenderingHints(g);
    g.drawImage(shadow, 0, 0, 86, 126, null);
    g.drawImage(white, 3, 3, 80, 120, null);
    g.drawImage(suit, 3, 3, 80, 120, null);
    g.drawImage(value, 3, 3, 80, 120, null);
    g.dispose();

    cardImages[i] = img;
}

private void setRenderingHints(Graphics2D g){
    g.setRenderingHint(KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g.setRenderingHint(KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
}

Как мне подойти к этому по-другому? Спасибо.

Edit:
Example of hand without RenderingHints
Без RenderingHints

Настройка подсказок AA не имела никакого значения. Кроме того, установка RenderingHints при создании изображений также не имеет значения. Это происходит только тогда, когда они поворачиваются с помощью AffineTransform и окрашиваются с помощью g.drawImage(...), которые, по-видимому, размываются.
Изображение выше показывает разницу между стандартным (ближайшим соседом) и билинейной интерполяцией.

Вот как я сейчас рисую их (намного быстрее, чем TexturePaint):

// GamePanel.java
private void paintCard(Graphics2D g, int code, int x, int y){
    g.drawImage(imageLoader.getCard(code), x, y, 86, 126, null);
  }

// ImageLoader.java
public BufferedImage getCard(int code){
    return cardImages[code];
  }

Все мои карты 80x120, а тень .png - 86x126, чтобы оставить полупрозрачную тень размером 3px вокруг карты. Это не реальная тень, которую я знаю, но все выглядит нормально.

И вот вопрос... Как вы можете получить резкие результаты краски при вращении BufferedImage?

Ссылка на предыдущий вопрос также относительно руки раздутой карты:
Как вы можете обнаружить событие мыши в объекте Image в Java?

Баунти-Edit: Хорошо, поэтому после долгих обсуждений я сделал несколько тестовых карт .svg, чтобы посмотреть, как SVG Salamander будет заниматься их рендерингом. К сожалению, производительность ужасная. Моя реализация достаточно чистая, так как с буферизацией BufferedImage с двойной буферизацией картина была невероятно быстрой. Это означает, что я пришел в полный круг, и я вернулся к своей первоначальной проблеме.

Я дам 50 бонусов тому, кто может дать мне решение, чтобы получить резкие вращения BufferedImage. Предложения заключались в том, чтобы сделать изображения более крупными, чем они должны быть и уменьшены до рисования, и использовать бикубическую интерполяцию. Если это единственные возможные решения, то я действительно не знаю, куда идти отсюда, и мне просто нужно иметь дело с размытыми вращениями - потому что оба из них налагают неудачи производительности.

Я могу закончить игру, если найду способ сделать это хорошо. Спасибо всем.:)

4b9b3361

Ответ 1

Когда вы вращаете растрированное изображение (например, BufferedImage), вы теряете данные. Лучшее решение - сохранить ваши изображения больше, чем вам понадобятся, и уменьшать масштаб на лету, когда вы их нарисуете. Я обнаружил, что размер в 1,5 раза является хорошей отправной точкой.

Затем, когда вы рисуете изображение, измените его размер на лету:

g.drawImage(bufferedImage, x, y, desiredWidth, desiredHeight, observer);

Рекомендуется использовать вращения с использованием билинейной интерполяции.

Кредит за предложение идет на guido.

Ответ 2

Этот совет, вероятно, немного задерживается в вашем дизайне, но, возможно, стоит упомянуть.

Растрированные изображения, вероятно, являются неправильной технологией, если много поводов и анимаций являются частью вашего пользовательского интерфейса; особенно со сложными изображениями с большим количеством кривых. Подождите, пока вы попытаетесь масштабировать свой холст. Я мог бы предложить посмотреть векторную графическую библиотеку. Они будут оказывать виды эффектов, которые вы хотите, с меньшим потенциалом для артефактов.

http://xmlgraphics.apache.org/batik/using/swing.htm

Ответ 3

Установка типа интерполяции, а также значения сглаживания в AffineTransformOp может дать некоторое улучшение. Тип TYPE_BICUBIC, хотя и медленнее, обычно является лучшим качеством; приведен пример здесь. Обратите внимание, что вы можете предоставить несколько RenderingHints. Другая ошибка возникает из-за невозможности применить подсказки каждый раз, когда изображение отображается. Вам также может потребоваться настроить прозрачность фона, как предложено здесь. Наконец, рассмотрите возможность создания sscce, который включает одно из ваших реальных изображений.