0

I currently have a method which generates an image based on a template, two separate avatars and a text to then return it as a byte array.
The text displayed has a different colour based on the size of the chance integer provided.

Since the font can have a colour that the template image has, is there a chance (no pun intended) that the text would not be visible on the resulting image, which is why I would like to apply a black outline to the font shown.

I already found this answer here and while it actually gives two examples, does it confuse me more than actually helping me.

The first example has a lot of steps I myself don't need and I'm not sure which one I can discard and which are mandatory to keep.
I'm also not sure how I would apply my logic with centring the text here, as the example seems to apply the font's outline and fill to each letter individually which in my case would be extremely annoying and also not guaranteed to be the same each time, as the text could be #%, ##% or ###%.

The second example seems to be more about usage within a JPanel? Or in other words am I not sure if this code could also be applied to an image alone, or if it needs tinkering to work with only images.

I basically need to know what methods are needed to create the font with the fontColor, add a black outline for it and then place it in the centre of the image itself before returning it as a byte array.

Here is the code I currently use for context.

    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;
        }
    }
Andre_601
  • 87
  • 8

1 Answers1

0

Found a solution.

The second example seems to be the one to use and I managed to get this setup to work for me:

    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;
        }
    }
Andre_601
  • 87
  • 8