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.

widthheight 现在是一个简单的 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 RoundRectangle2Dsubtract 方法。

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();
    }
}