Java 图形 - 删除文本下方的部分圆角矩形?
Java Graphics - Remove part of rounded rectangle under text?
我正在尝试在圆角矩形的顶部呈现文本,但我想要剪切掉文本下方的圆角矩形部分。这是我想要的样子:
问题是我找不到任何简单的方法来做到这一点。我尝试使用 clearRect,但这只会创建一个黑色矩形,我想在下方放置一个图像(目前它只是白色)。
然后我想到也许我可以只用白色填充我想要删除的矩形区域,然后过滤掉所有白色像素。这并没有像我希望的那样有效,因为仍然有白色像素遗留下来:
这是我目前拥有的代码:
public static void createRoundedRectImg(int width, int height)
{
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
int padding = 50;
g.setColor(Color.BLUE);
g.drawRoundRect(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
float textSize = 84f;
Font font = g.getFont().deriveFont(textSize).deriveFont(Font.BOLD);
g.setFont(font);
String text = "TEXT";
Rectangle2D stringBounds = g.getFontMetrics(font).getStringBounds(text, g);
int textWidth = (int) stringBounds.getWidth();
int textHeight = (int) (stringBounds.getHeight() + g.getFontMetrics(font).getDescent());
int textX = (width / 2) - (textWidth / 2);
int textY = g.getFontMetrics(font).getDescent() * 2 + padding;
//g.clearRect(textX, textY - textHeight, textWidth, textHeight);
g.setColor(Color.WHITE);
g.fillRect(textX, textY - textHeight, textWidth, textHeight);
g.setColor(Color.GREEN);
g.drawString(text, textX, textY);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Color c = new Color(img.getRGB(x, y));
if (c.getRGB() == Color.WHITE.getRGB())
img.setRGB(x, y, new Color(0, 0, 0, 255).getRGB());
}
}
g.dispose();
}
有没有更简单的方法只清除文本下方的圆角矩形部分?完成后我想把整个东西叠加在一张图片上,所以我需要背景是透明的。
试试这个。
public static void createRoundedRectImg(int width, int height)
{
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D)img.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
int padding = 50;
g.setComposite(AlphaComposite.Clear);
g.fillRoundRect(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
g.setComposite(AlphaComposite.SrcOver);
g.setColor(Color.BLUE);
g.drawRoundRect(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
float textSize = 84f;
Font font = g.getFont().deriveFont(textSize).deriveFont(Font.BOLD);
g.setFont(font);
String text = "TEXT";
Rectangle2D stringBounds = g.getFontMetrics(font).getStringBounds(text, g);
int textWidth = (int) stringBounds.getWidth();
int textHeight = (int) (stringBounds.getHeight() + g.getFontMetrics(font).getDescent());
int textX = (width / 2) - (textWidth / 2);
int textY = g.getFontMetrics(font).getDescent() * 2 + padding;
g.setColor(Color.WHITE);
g.fillRect(textX, textY - textHeight, textWidth, textHeight);
g.setColor(Color.GREEN);
g.drawString(text, textX, textY);
g.dispose();
}
您可以只使用 TitledBorder。由于曲线与线的大小成比例,我创建了一个 RoundedBorder
class,其中大部分代码来自 API 中的 paintBorder()
方法,以允许弧角的大小待指定。 arc radius
.
的 width
和 height
现在是一个简单的 pixel amount
- 首先,创建一个 RoundedBorder 实例。尝试
30
作为圆弧半径。
- 然后,使用 BorderFactor,创建一个 TitledBorder 实例并将圆形实例作为第一个参数传递。
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
public class TitledBorderDemo extends JPanel {
JFrame frame = new JFrame();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new TitledBorderDemo().start());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
public void start() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Border b = new RoundedBorder(Color.black, 2, 30);
Border titled = BorderFactory.createTitledBorder(b, "Text",
TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION,
new Font("Arial", Font.BOLD, 48));
setBorder(titled);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class RoundedBorder extends LineBorder {
private int arc;
public RoundedBorder(Color color, int lineThickness, int arc) {
super(color, lineThickness);
this.arc = arc;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
if ((this.thickness > 0) && (g instanceof Graphics2D)) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color oldColor = g2d.getColor();
g2d.setColor(this.lineColor);
Shape outer;
Shape inner;
int offs = this.thickness;
int size = offs + offs;
outer = new RoundRectangle2D.Float(x, y, width, height,
arc, arc);
inner = new RoundRectangle2D.Float(x + offs, y + offs,
width - size, height - size, arc, arc);
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(outer, false);
path.append(inner, false);
g2d.fill(path);
g2d.setColor(oldColor);
}
}
}
以上,当运行时,产生如下图像。
您可以使用 Area class to remove a rectangular section from a stroked RoundRectangle2D 的 subtract
方法。
float strokeWidth = 1.5f;
RoundRectangle2D roundedRect = new RoundRectangle2D.Double(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
Rectangle2D rectMask = new Rectangle2D.Double(textX, padding-strokeWidth, textWidth, 2*strokeWidth);
Stroke stroke = new BasicStroke(strokeWidth);
Area roundedRectArea = new Area(stroke.createStrokedShape(roundedRect));
roundedRectArea.subtract(new Area(rectMask));
g.setColor(Color.BLACK);
g.fill(roundedRectArea);
g.drawString(text, textX, textY);
产生:
完整代码:
public static void createRoundedRectImg(int width, int height)
{
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
float textSize = 84f;
Font font = g.getFont().deriveFont(textSize).deriveFont(Font.BOLD);
g.setFont(font);
int padding = 50;
String text = "TEXT";
Rectangle2D stringBounds = g.getFontMetrics(font).getStringBounds(text, g);
int textWidth = (int) stringBounds.getWidth();
int textX = (width / 2) - (textWidth / 2);
int textY = g.getFontMetrics(font).getDescent() * 2 + padding;
float strokeWidth = 1.5f;
RoundRectangle2D roundedRect = new RoundRectangle2D.Double(padding, padding, width - (padding * 2),
height - (padding * 2), 50, 50);
Rectangle2D rectMask = new Rectangle2D.Double(textX, padding - strokeWidth, textWidth, 2 * strokeWidth);
Stroke stroke = new BasicStroke(strokeWidth);
Area roundedRectArea = new Area(stroke.createStrokedShape(roundedRect));
roundedRectArea.subtract(new Area(rectMask));
g.setColor(Color.BLACK);
g.fill(roundedRectArea);
g.drawString(text, textX, textY);
g.dispose();
try
{
ImageIO.write(img, "png", new File("round.png"));
} catch (IOException e)
{
e.printStackTrace();
}
}
我正在尝试在圆角矩形的顶部呈现文本,但我想要剪切掉文本下方的圆角矩形部分。这是我想要的样子:
问题是我找不到任何简单的方法来做到这一点。我尝试使用 clearRect,但这只会创建一个黑色矩形,我想在下方放置一个图像(目前它只是白色)。
然后我想到也许我可以只用白色填充我想要删除的矩形区域,然后过滤掉所有白色像素。这并没有像我希望的那样有效,因为仍然有白色像素遗留下来:
这是我目前拥有的代码:
public static void createRoundedRectImg(int width, int height)
{
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
int padding = 50;
g.setColor(Color.BLUE);
g.drawRoundRect(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
float textSize = 84f;
Font font = g.getFont().deriveFont(textSize).deriveFont(Font.BOLD);
g.setFont(font);
String text = "TEXT";
Rectangle2D stringBounds = g.getFontMetrics(font).getStringBounds(text, g);
int textWidth = (int) stringBounds.getWidth();
int textHeight = (int) (stringBounds.getHeight() + g.getFontMetrics(font).getDescent());
int textX = (width / 2) - (textWidth / 2);
int textY = g.getFontMetrics(font).getDescent() * 2 + padding;
//g.clearRect(textX, textY - textHeight, textWidth, textHeight);
g.setColor(Color.WHITE);
g.fillRect(textX, textY - textHeight, textWidth, textHeight);
g.setColor(Color.GREEN);
g.drawString(text, textX, textY);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Color c = new Color(img.getRGB(x, y));
if (c.getRGB() == Color.WHITE.getRGB())
img.setRGB(x, y, new Color(0, 0, 0, 255).getRGB());
}
}
g.dispose();
}
有没有更简单的方法只清除文本下方的圆角矩形部分?完成后我想把整个东西叠加在一张图片上,所以我需要背景是透明的。
试试这个。
public static void createRoundedRectImg(int width, int height)
{
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D)img.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
int padding = 50;
g.setComposite(AlphaComposite.Clear);
g.fillRoundRect(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
g.setComposite(AlphaComposite.SrcOver);
g.setColor(Color.BLUE);
g.drawRoundRect(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
float textSize = 84f;
Font font = g.getFont().deriveFont(textSize).deriveFont(Font.BOLD);
g.setFont(font);
String text = "TEXT";
Rectangle2D stringBounds = g.getFontMetrics(font).getStringBounds(text, g);
int textWidth = (int) stringBounds.getWidth();
int textHeight = (int) (stringBounds.getHeight() + g.getFontMetrics(font).getDescent());
int textX = (width / 2) - (textWidth / 2);
int textY = g.getFontMetrics(font).getDescent() * 2 + padding;
g.setColor(Color.WHITE);
g.fillRect(textX, textY - textHeight, textWidth, textHeight);
g.setColor(Color.GREEN);
g.drawString(text, textX, textY);
g.dispose();
}
您可以只使用 TitledBorder。由于曲线与线的大小成比例,我创建了一个 RoundedBorder
class,其中大部分代码来自 API 中的 paintBorder()
方法,以允许弧角的大小待指定。 arc radius
.
width
和 height
现在是一个简单的 pixel amount
- 首先,创建一个 RoundedBorder 实例。尝试
30
作为圆弧半径。 - 然后,使用 BorderFactor,创建一个 TitledBorder 实例并将圆形实例作为第一个参数传递。
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
public class TitledBorderDemo extends JPanel {
JFrame frame = new JFrame();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new TitledBorderDemo().start());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
public void start() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Border b = new RoundedBorder(Color.black, 2, 30);
Border titled = BorderFactory.createTitledBorder(b, "Text",
TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION,
new Font("Arial", Font.BOLD, 48));
setBorder(titled);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class RoundedBorder extends LineBorder {
private int arc;
public RoundedBorder(Color color, int lineThickness, int arc) {
super(color, lineThickness);
this.arc = arc;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
if ((this.thickness > 0) && (g instanceof Graphics2D)) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color oldColor = g2d.getColor();
g2d.setColor(this.lineColor);
Shape outer;
Shape inner;
int offs = this.thickness;
int size = offs + offs;
outer = new RoundRectangle2D.Float(x, y, width, height,
arc, arc);
inner = new RoundRectangle2D.Float(x + offs, y + offs,
width - size, height - size, arc, arc);
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(outer, false);
path.append(inner, false);
g2d.fill(path);
g2d.setColor(oldColor);
}
}
}
以上,当运行时,产生如下图像。
您可以使用 Area class to remove a rectangular section from a stroked RoundRectangle2D 的 subtract
方法。
float strokeWidth = 1.5f;
RoundRectangle2D roundedRect = new RoundRectangle2D.Double(padding, padding, width - (padding * 2), height - (padding * 2), 50, 50);
Rectangle2D rectMask = new Rectangle2D.Double(textX, padding-strokeWidth, textWidth, 2*strokeWidth);
Stroke stroke = new BasicStroke(strokeWidth);
Area roundedRectArea = new Area(stroke.createStrokedShape(roundedRect));
roundedRectArea.subtract(new Area(rectMask));
g.setColor(Color.BLACK);
g.fill(roundedRectArea);
g.drawString(text, textX, textY);
产生:
完整代码:
public static void createRoundedRectImg(int width, int height)
{
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
float textSize = 84f;
Font font = g.getFont().deriveFont(textSize).deriveFont(Font.BOLD);
g.setFont(font);
int padding = 50;
String text = "TEXT";
Rectangle2D stringBounds = g.getFontMetrics(font).getStringBounds(text, g);
int textWidth = (int) stringBounds.getWidth();
int textX = (width / 2) - (textWidth / 2);
int textY = g.getFontMetrics(font).getDescent() * 2 + padding;
float strokeWidth = 1.5f;
RoundRectangle2D roundedRect = new RoundRectangle2D.Double(padding, padding, width - (padding * 2),
height - (padding * 2), 50, 50);
Rectangle2D rectMask = new Rectangle2D.Double(textX, padding - strokeWidth, textWidth, 2 * strokeWidth);
Stroke stroke = new BasicStroke(strokeWidth);
Area roundedRectArea = new Area(stroke.createStrokedShape(roundedRect));
roundedRectArea.subtract(new Area(rectMask));
g.setColor(Color.BLACK);
g.fill(roundedRectArea);
g.drawString(text, textX, textY);
g.dispose();
try
{
ImageIO.write(img, "png", new File("round.png"));
} catch (IOException e)
{
e.printStackTrace();
}
}