【问题标题】:Java Graphics - Remove part of rounded rectangle under text?Java Graphics - 删除文本下的部分圆角矩形?
【发布时间】:2021-08-09 00:20:01
【问题描述】:

我正在尝试在圆角矩形顶部呈现文本,但我希望剪切掉文本下方的圆角矩形部分。这是我想要的样子:

问题是我找不到任何简单的方法来做到这一点。我尝试使用 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();
}

有没有更简单的方法来清除文本下方的圆角矩形部分?完成后,我想将整个内容覆盖在图像之上,所以我需要背景是透明的。

【问题讨论】:

  • 使用drawRect 可能会为您做到这一点?
  • 是的,正如@g00se 提到的,尝试在文本下方绘制一个没有边框的填充矩形
  • 是的,但是我想让文字下面的部分是透明的,这样你就可以看到下面的图像了。

标签: java graphics


【解决方案1】:

您可以使用Area 类的subtract 方法从stroked RoundRectangle2D 中删除一个矩形部分。

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

【讨论】:

    【解决方案2】:

    试试这个。

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

    【讨论】:

      【解决方案3】:

      您可以只使用 TitledBorder。由于曲线与线的大小成正比,我使用 API 中 paintBorder() 方法的大部分代码创建了一个 RoundedBorder 类,以允许指定圆弧角的大小。现在,对于 widthheightarc radius,它都是一个简单的 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);
              }
          }
      }
      

      上面的代码在运行时会生成以下图像。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-19
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多