如何为文本添加轮廓,然后将其添加到图像的中心?

How to add an outline to a text and then add it to the image's center?

我目前有一种方法可以根据模板、两个单独的头像和文本生成图像,然后 return 将其作为字节数组。
根据提供的 chance 整数的大小,显示的文本具有不同的颜色。

由于字体可以具有模板图像所具有的颜色,是否有可能(没有双关语意)文本在生成的图像上不可见,这就是我想应用黑色轮廓的原因显示的字体。

我已经找到 this answer here 虽然它实际上给出了两个示例,但它是否比实际帮助我更让我困惑。

first example有很多我自己不需要的步骤,我不确定哪些可以放弃,哪些是必须保留的。
我也不确定我将如何在此处将文本居中应用我的逻辑,因为该示例似乎应用了字体的轮廓并分别填充每个字母,这在我的情况下会非常烦人,而且不能保证每个字母都相同时间,因为文本可以是 #%##%###%.

second example 似乎更多的是关于在 JPanel 中的使用?或者换句话说,我不确定这段代码是否也可以单独应用于图像,或者是否需要修改才能仅处理图像。

我基本上需要知道使用 fontColor 创建字体需要什么方法,为其添加黑色轮廓,然后在 returning 之前将其放置在图像本身的中心它作为一个字节数组。

这是我目前用于上下文的代码。

    private final OkHttpClient CLIENT = new OkHttpClient();

    private BufferedImage getAvatar(String url) throws IOException{
        URL url = new URL(url);
        URLConnection connection = url.openConnection();
        connection.setRequestProperty("User-Agent", "ImageRenderer");
        connection.connect();

        return ImageIO.read(connection.getInputStream());
    }

    public byte[] getChance(String url1, String url2, int chance){
        try{
            BufferedImage template = ImageIO.read(new File("img/chance.png"));
            BufferedImage avatar1 = getAvatar(url1);
            BufferedImage avatar2 = getAvatar(url2);

            // Create new BufferedImage with the template's sizes.
            BufferedImage background = new BufferedImage(template.getWidth(), template.getHeight(), template.getType());

            Graphics2D img = background.createGraphics();

            Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 80);
            img.setFont(font);

            Color fontColor;

            if(chance <= 100 && chance > 74){
                fontColor = Color.GREEN;
            }else
            if(chance <= 74 && chance > 49){
                fontColor = Color.ORANGE;
            }else
            if(chance <= 49 && chance > 24){
                fontColor = Color.RED;
            }else{
                fontColor = Color.BLACK;
            }
    
            String text = chance + "%";
            
            img.setColor(fontColor);

            // Set the avatars followed by the template.
            img.drawImage(avatar1, 0, 0, 320, 320, null);
            img.drawImage(avatar2, 640, 0, 320, 320, null);
            img.drawImage(template, 0, 0, null);

            // Get the image's width and height
            int imgWidth = template.getWidth();
            int imgHeight = template.getHeight();

            // Set X and Y position for the text to be centered.
            int textX = (imgWidth / 2) - (img.getFontMetrics().stringWidth(text) / 2);
            int textY = (imgHeight / 2) - 40;

            // Draw the actual String
            img.drawString(text, textX, textY);

            img.dispose();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.setUseCache(false);
            ImageIO.write(background, "png", baos);

            return baos.toByteArray();
        }catch(IOException ex){
            return null;
        }
    }

找到解决方案。

第二个示例似乎是可以使用的,我设法让这个设置为我工作:

    private final OkHttpClient CLIENT = new OkHttpClient();

    private BufferedImage getAvatar(String url) throws IOException{
        URL url = new URL(url);
        URLConnection connection = url.openConnection();
        connection.setRequestProperty("User-Agent", "ImageRenderer");
        connection.connect();

        return ImageIO.read(connection.getInputStream());
    }

    public byte[] getChance(String url1, String url2, int chance){
        try{
            BufferedImage template = ImageIO.read(new File("img/chance.png"));
            BufferedImage avatar1 = getAvatar(url1);
            BufferedImage avatar2 = getAvatar(url2);

            // Create new BufferedImage with the template's sizes.
            BufferedImage background = new BufferedImage(template.getWidth(), template.getHeight(), template.getType());

            Graphics2D img = background.createGraphics();

            Color outlineColor = Color.BLACK;
            Color fontColor;

            if(chance <= 100 && chance > 74){
                fontColor = Color.GREEN;
            }else
            if(chance <= 74 && chance > 49){
                fontColor = Color.ORANGE;
            }else
            if(chance <= 49 && chance > 24){
                fontColor = Color.RED;
            }else{
                fontColor = Color.BLACK;
            }

            // Set the avatars followed by the template.
            img.drawImage(avatar1, 0, 0, 320, 320, null);
            img.drawImage(avatar2, 640, 0, 320, 320, null);
            img.drawImage(template, 0, 0, null);

            Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 80);
            
            img.setColor(fontColor);
            img.setFont(font);

            String text = chance + "%";
            
            img.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            img.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

            FontRenderContext context = img.getFontRenderContext();

            // Set X and Y position for the text to be centred.
            int textX = (imgWidth / 2) - (img.getFontMetrics(font).stringWidth(text) / 2);
            int textY = (imgHeight / 2) + 40;

            // Draw the actual String
            img.drawString(text, textX, textY);

            // Get TextLayout and AffineTransform
            TextLayout layout = new TextLayout(text, font, context);
            AffineTransform transform = img.getTransform();
            
            // Create the Shape of the outline
            Shape outline = layout.getOutline(null);
            
            // Move position
            transform.translate(textX, textY);
            
            // Apply the shape
            img.transform(transform);
            img.setColor(outlineColor);
            img.draw(outline);
            
            img.setClip(outline);

            img.dispose();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.setUseCache(false);
            ImageIO.write(background, "png", baos);

            return baos.toByteArray();
        }catch(IOException ex){
            return null;
        }
    }