Java Graphics.fillXxx() 结合 Graphics2D.scale()
Java Graphics.fillXxx() in combination with Graphics2D.scale()
我有这个程序:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class TestLine {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestLine().start();
}
});
}
private static void start() {
JFrame frame = new JFrame();
frame.setContentPane(new CarthPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static class CarthPanel extends JComponent {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
int w = gg.getClipBounds().width;
int h = gg.getClipBounds().height;
System.out.println("(w,h)=(" + w + "," + h + ")");
gg.translate(w - 1, 0); // <<< when uncommenting both lines, mirroring applies
gg.scale(-1.0, 1.0); //
paintTest(gg, w, h);
}
private static void paintTest(Graphics2D g, int w, int h) {
// black background
g.setColor(Color.black);
g.fillRect(0, 0, w, h);
// colored corners
g.setColor(Color.RED);
g.drawLine(0, 0, 10, 0);
g.drawLine(0, 0, 0, 10);
g.setColor(Color.RED);
g.drawLine(0, 199, 10, 199);
g.drawLine(0, 199, 0, 189);
g.setColor(Color.CYAN);
g.drawLine(189, 0, 199, 0);
g.drawLine(199, 0, 199, 10);
g.setColor(Color.CYAN);
g.drawLine(189, 199, 199, 199);
g.drawLine(199, 199, 199, 189);
// yellow squares
g.setColor(Color.yellow);
g.drawRect(3, 3, 10, 10);
g.fillRect(186, 3, 11, 11);
g.fillRect(3, 186, 11, 11);
g.drawRect(186, 186, 10, 10);
String chars = "ABC";
g.setFont(Font.decode("Arial 72"));
Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g);
g.drawString(chars, (int) (200 - rect.getWidth()) / 2, (int) (200 - rect.getHeight()));
}
}
}
如果你 运行 这个程序一次有两行被注释掉,然后又一次被相同的行注释掉(见代码),那么你会看到这个:
[
如果您没有发现问题,这里有一张放大的图片:
人们会期望图像是完美的镜像。这适用于所有笔划和空心形状(= drawXxx() 方法)。但是,所有填充的形状(= fillXxx() 方法)都在我期望的位置左侧绘制了一个像素;例如填充的黄色矩形,您还可以注意到黑色背景已经移动,如右边框的白线所示。
这是一个错误还是有意为之?我怀疑这与 "width" 和 "height" 在 drawXxx() 和 fillXxx() 方法中的处理方式不同有关:
- drawRect(x,y,w,h) 生成一个 X 轴边界为 x 和 x+w 的空心矩形,因此该矩形的宽度为 w+1 像素。
- fillRect(x,y,w,h) 生成一个 X 轴边界为 x 和 x+w-1 的填充矩形,因此矩形宽度为 w 像素。
我错过了什么?
这是一个错误,不是一个功能:)
肯定不是故意的,镜像应该是完美的,没有理由不完美。
有一种方法可以使用BufferedImage在其上正常渲染,然后翻转绘制此BufferedImage,唯一的缺点是性能影响小,使用LCD子像素绘制的文字不好看。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class TestLine {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestLine().start();
}
});
}
private static void start() {
JFrame frame = new JFrame();
frame.setContentPane(new CarthPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static class CarthPanel extends JComponent {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
// System.out.println("(w,h)=(" + w + "," + h + ")");
gg.translate(getWidth(), 0); // <<< when uncommenting both lines, mirroring applies
gg.scale(-1.0, 1.0); //
BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
try {
paintTest(img.createGraphics());
} catch (Exception e) {
e.printStackTrace();
}
g.drawImage(img, 0, 0, null);
}
private void paintTest(Graphics2D g) {
// black background
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// colored corners
g.setColor(Color.RED);
g.drawLine(0, 0, 10, 0);
g.drawLine(0, 0, 0, 10);
g.setColor(Color.RED);
g.drawLine(0, 199, 10, 199);
g.drawLine(0, 199, 0, 189);
g.setColor(Color.CYAN);
g.drawLine(189, 0, 199, 0);
g.drawLine(199, 0, 199, 10);
g.setColor(Color.CYAN);
g.drawLine(189, 199, 199, 199);
g.drawLine(199, 199, 199, 189);
// yellow squares
g.setColor(Color.yellow);
g.drawRect(3, 3, 10, 10);
g.fillRect(186, 3, 11, 11);
g.fillRect(3, 186, 11, 11);
g.drawRect(186, 186, 10, 10);
String chars = "ABC";
g.setFont(Font.decode("Arial 72"));
Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g);
g.drawString(chars, (int) (200 - rect.getWidth()) / 2, (int) (200 - rect.getHeight()));
}
}
}
不是答案,而是假设 - 矩形的 "contains(x,y)" 将 true
用于形成矩形的 (x,y) 角的边和 false
对于制作 (maxx, maxy) 角的边。演示:
Rectangle r=new Rectangle(0, 0, 10, 10);
System.out.println(r.contains(0, 5)); // true
System.out.println(r.contains(5, 0)); // true
System.out.println(r.contains(10, 5)); // false
System.out.println(r.contains(5, 10)); // false
假设 fillRect
不会将 "max sides" 视为要填充的内部点。
为了评估这个假设,我建议您尝试使用定义相同矩形的 GeneralPath
,看看它在填充时有什么不同。 GeneralPath 应该禁止对 "the right-top borders are out of the shape's interior"
做任何假设
我有这个程序:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class TestLine {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestLine().start();
}
});
}
private static void start() {
JFrame frame = new JFrame();
frame.setContentPane(new CarthPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static class CarthPanel extends JComponent {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
int w = gg.getClipBounds().width;
int h = gg.getClipBounds().height;
System.out.println("(w,h)=(" + w + "," + h + ")");
gg.translate(w - 1, 0); // <<< when uncommenting both lines, mirroring applies
gg.scale(-1.0, 1.0); //
paintTest(gg, w, h);
}
private static void paintTest(Graphics2D g, int w, int h) {
// black background
g.setColor(Color.black);
g.fillRect(0, 0, w, h);
// colored corners
g.setColor(Color.RED);
g.drawLine(0, 0, 10, 0);
g.drawLine(0, 0, 0, 10);
g.setColor(Color.RED);
g.drawLine(0, 199, 10, 199);
g.drawLine(0, 199, 0, 189);
g.setColor(Color.CYAN);
g.drawLine(189, 0, 199, 0);
g.drawLine(199, 0, 199, 10);
g.setColor(Color.CYAN);
g.drawLine(189, 199, 199, 199);
g.drawLine(199, 199, 199, 189);
// yellow squares
g.setColor(Color.yellow);
g.drawRect(3, 3, 10, 10);
g.fillRect(186, 3, 11, 11);
g.fillRect(3, 186, 11, 11);
g.drawRect(186, 186, 10, 10);
String chars = "ABC";
g.setFont(Font.decode("Arial 72"));
Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g);
g.drawString(chars, (int) (200 - rect.getWidth()) / 2, (int) (200 - rect.getHeight()));
}
}
}
如果你 运行 这个程序一次有两行被注释掉,然后又一次被相同的行注释掉(见代码),那么你会看到这个:
[
如果您没有发现问题,这里有一张放大的图片:
人们会期望图像是完美的镜像。这适用于所有笔划和空心形状(= drawXxx() 方法)。但是,所有填充的形状(= fillXxx() 方法)都在我期望的位置左侧绘制了一个像素;例如填充的黄色矩形,您还可以注意到黑色背景已经移动,如右边框的白线所示。
这是一个错误还是有意为之?我怀疑这与 "width" 和 "height" 在 drawXxx() 和 fillXxx() 方法中的处理方式不同有关:
- drawRect(x,y,w,h) 生成一个 X 轴边界为 x 和 x+w 的空心矩形,因此该矩形的宽度为 w+1 像素。
- fillRect(x,y,w,h) 生成一个 X 轴边界为 x 和 x+w-1 的填充矩形,因此矩形宽度为 w 像素。
我错过了什么?
这是一个错误,不是一个功能:) 肯定不是故意的,镜像应该是完美的,没有理由不完美。
有一种方法可以使用BufferedImage在其上正常渲染,然后翻转绘制此BufferedImage,唯一的缺点是性能影响小,使用LCD子像素绘制的文字不好看。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class TestLine {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestLine().start();
}
});
}
private static void start() {
JFrame frame = new JFrame();
frame.setContentPane(new CarthPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static class CarthPanel extends JComponent {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
// System.out.println("(w,h)=(" + w + "," + h + ")");
gg.translate(getWidth(), 0); // <<< when uncommenting both lines, mirroring applies
gg.scale(-1.0, 1.0); //
BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
try {
paintTest(img.createGraphics());
} catch (Exception e) {
e.printStackTrace();
}
g.drawImage(img, 0, 0, null);
}
private void paintTest(Graphics2D g) {
// black background
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// colored corners
g.setColor(Color.RED);
g.drawLine(0, 0, 10, 0);
g.drawLine(0, 0, 0, 10);
g.setColor(Color.RED);
g.drawLine(0, 199, 10, 199);
g.drawLine(0, 199, 0, 189);
g.setColor(Color.CYAN);
g.drawLine(189, 0, 199, 0);
g.drawLine(199, 0, 199, 10);
g.setColor(Color.CYAN);
g.drawLine(189, 199, 199, 199);
g.drawLine(199, 199, 199, 189);
// yellow squares
g.setColor(Color.yellow);
g.drawRect(3, 3, 10, 10);
g.fillRect(186, 3, 11, 11);
g.fillRect(3, 186, 11, 11);
g.drawRect(186, 186, 10, 10);
String chars = "ABC";
g.setFont(Font.decode("Arial 72"));
Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g);
g.drawString(chars, (int) (200 - rect.getWidth()) / 2, (int) (200 - rect.getHeight()));
}
}
}
不是答案,而是假设 - 矩形的 "contains(x,y)" 将 true
用于形成矩形的 (x,y) 角的边和 false
对于制作 (maxx, maxy) 角的边。演示:
Rectangle r=new Rectangle(0, 0, 10, 10);
System.out.println(r.contains(0, 5)); // true
System.out.println(r.contains(5, 0)); // true
System.out.println(r.contains(10, 5)); // false
System.out.println(r.contains(5, 10)); // false
假设 fillRect
不会将 "max sides" 视为要填充的内部点。
为了评估这个假设,我建议您尝试使用定义相同矩形的 GeneralPath
,看看它在填充时有什么不同。 GeneralPath 应该禁止对 "the right-top borders are out of the shape's interior"