Кажется, что поглаживание по подпиксельным координатам стало нарушено в Java 8.
У меня есть три набора случаев, показанных на скриншотах (столбцы представляют случаи, строки представляют разные ширины штрихов):
Java 7u51 (масштаб 400%)
Java 8u60 (шкала 400%)
- Заполните и обведите по тем же координатам. Работает по назначению, поглаженная область больше, чем площадь заполнения.
- Покрытие сокращается (по ширине штриха) и центрируется (на половину ширины) внутри границ области заполнения. Эта часть разбита на Java 8 для 1px-инсульта, где происходит рисование по субпиксельной координате (первая строка); 3px-ход не имеет этой проблемы (третья строка). Кажется, что 0,5 округляется до 1px-хода.
- Фиксирующий прямоугольник сжимается по центру так же, как и в случае 2. Мне нужно это на графиках, которые поддерживают субпиксельный чертеж, чтобы сделать неперекрывающуюся заливку, когда ячейки перекрываются. Здесь вы можете видеть, что операция заполнения округляется от 0,5 до 0, поэтому проблема только поглаживания.
Код ниже:
import static java.awt.BasicStroke.*;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class TestCase
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Test case");
frame.setSize(115, 115);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new TestPanel());
frame.setVisible(true);
}
private static class TestPanel extends JPanel
{
TestPanel()
{
setOpaque(true);
}
@Override
protected void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
g2.fill(getBounds());
Rectangle2D rect = new Rectangle2D.Double();
Color background = new Color(0, 255, 255);
Color border = new Color(255, 0, 0, 128);
Stroke STROKE_1PX = new BasicStroke(1, CAP_SQUARE, JOIN_MITER);
Stroke STROKE_2PX = new BasicStroke(2, CAP_SQUARE, JOIN_MITER);
Stroke STROKE_3PX = new BasicStroke(3, CAP_SQUARE, JOIN_MITER);
g2.translate(10, 10);
/**
* Filling and stroking by original coordinates
*/
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_1PX);
g2.draw(rect);
g2.translate(0, 35);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_2PX);
g2.draw(rect);
g2.translate(0, 35);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_3PX);
g2.draw(rect);
/**
* Stroking is shrunk to be inside the filling rect
*/
g2.translate(35, -70);
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
rect.setRect(0.5, 0.5, 24, 24);
g2.setColor(border);
g2.setStroke(STROKE_1PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
rect.setRect(1, 1, 23, 23);
g2.setColor(border);
g2.setStroke(STROKE_2PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
rect.setRect(1.5, 1.5, 22, 22);
g2.setColor(border);
g2.setStroke(STROKE_3PX);
g2.draw(rect);
/**
* Filling rect is additionally shrunk and centered
*/
g2.translate(35, -70);
rect.setRect(0.5, 0.5, 24, 24);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_1PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(1, 1, 23, 23);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_2PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(1.5, 1.5, 22, 22);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_3PX);
g2.draw(rect);
}
}
}
Как я тестировал, Java 7 не имеет этой проблемы (пробовал на 7u51), Windows (8u77) и Mac (8u60) тоже. Пробовал Ubuntu (8u60 и 8u77) и Linux Mint (8u60) на разных машинах, и ошибка была здесь.
Кто-нибудь столкнулся с такой проблемой? Есть ли общее обходное решение?
Я не могу просто обрабатывать случай 1px в местах, где используется поглаживание. Это потому, что есть много мест, и я работаю с различными реализациями Graphics2D
, и кажется, что из того, что я использовал, проблема воспроизводится только на SunGraphics2D
. Это означает, что мне нужно использовать instanceOf
в этих местах, чтобы не нарушать общую логику.