Search code examples
javastringimageborderbufferedimage

String to BufferedImage with set borders and new line


I am new to StackOverflow and need help with following problem.

background:

I have to do a project for school where we get a lego mindstorm robot that prints stuff (coordinate based). My idea was to implement program in Java that translates (Google translation API) a given input, uses that String to create a BufferedImage and then reads out the coordinates of that image, so the robot can draw/print the translated input. I got everything to work except the writing of the text on to the BufferedImage.

problem:

I'm looking for a way to create a BufferedImage using a input String. The image should have fixed borders (160x200 px since that is the size of the robots coordinate system). I managed to create a BufferedImage with said borders, but when I insert the String on the image, it just leaves the image, so the back part of the String gets lost. Is it possible to create a new line in the BufferedImage automatically, when it reaches the border?

I am only worrying about the width right now, so its not a problem, if it gets cut off at the bottom (although if you know how to change that you can tell me also). Font should be:

Font font = new Font("Arial", Font.PLAIN, 25);

because it supports the languages I use.

Thank you for your help!

TL;DR: BufferedImage with fixed size and String as content. String shouldn't get cut off: new line, if string reaches the border, without words getting cut off.


Solution

  • Well since I was told to post my answer (even though that keeps future people from doing their assignments on their own), here it is. This class creates a BufferedImage (160x200 px) from a given input String (also saves the image as a file in the source folder). I'm sure it still can be improved, but I wouldn't know how, since thats all that I managed to make from the help that I got on here.

    example output of an image

    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.font.FontRenderContext;
    import java.awt.geom.Rectangle2D;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    
    import javax.imageio.ImageIO;
    
    public class TextToImage {
        
        public static BufferedImage createImage(String inputString) throws IOException{
            
            BufferedImage image = createGraphics(inputString);
            saveImage(image);
            
            return image;
        }
        
        public static BufferedImage createGraphics(String inputString) {
            
            BufferedImage bufferedImage = new BufferedImage(160, 195, BufferedImage.TYPE_INT_RGB);
            Font font = new Font("Arial", Font.PLAIN, 25);
            Graphics2D graphics2D = prepareGraphics(bufferedImage);
            double baseY = getY(getBounds(font, inputString, graphics2D));
            
            if(isLatin(inputString)) {
                drawLinesAsWords(graphics2D, inputString, font, baseY);
            } else {
                drawLinesAsCharacters(graphics2D, inputString, font, baseY);
            }
            
            graphics2D.dispose();
    
            return bufferedImage;
        }
        
        public static double getY(Rectangle2D bounds) {
            
            double ascent = - bounds.getY();
            double baseY = 0 + ascent;
            return baseY;
        }
        
        public static Rectangle2D getBounds(Font font, String content, Graphics2D graphics2D) {
            FontRenderContext context = graphics2D.getFontRenderContext();
            Rectangle2D bounds = font.getStringBounds(content, context);
            
            return bounds;
        }
        
        public static Graphics2D prepareGraphics(BufferedImage bufferedImage) {
            Graphics2D graphics2D = (Graphics2D)bufferedImage.getGraphics();
            graphics2D.setBackground(Color.GRAY);
            graphics2D.clearRect(0, 0, 160, 195);
            graphics2D.setPaint(Color.BLACK);
            
            return graphics2D;
        }
        
        public static boolean isLatin(String inputString) {
            String regex = "^.*\\p{IsLatin}.*";
            boolean result = inputString.matches(regex);
            if(result) {
                return true;
            } else {
                return false;
            }
        }
        
        public static void saveImage(BufferedImage bufferedImage) throws IOException {
            
            ImageIO.write(bufferedImage, "png", new File("./Image.jpeg"));
        }
        
        public static int getHeight(Font font, Graphics2D g) {
            
            int lineHeight = g.getFontMetrics(font).getHeight();
            return lineHeight;
        }
    
        public static void drawLinesAsWords(Graphics2D graphics2D, String content, Font font, double baseY) {
            
            int lineHeight = getHeight(font, graphics2D);
            int leftBorder = 5;
            String[] wordArray = content.split(" ");
            FontMetrics fontMetrics = graphics2D.getFontMetrics(font);
            String currentContent = "";
            double leftTopCornerLine = baseY;
            
            for(int i = 0; i < wordArray.length; i++) {
                
                if(leftTopCornerLine < 195) {
    
                    if(fontMetrics.stringWidth(currentContent)>=240) {
                        if(fontMetrics.stringWidth(wordArray[i])<=240-fontMetrics.stringWidth(currentContent)) {
                            currentContent += " " + wordArray[i];
                            graphics2D.drawString(currentContent, leftBorder, (int)leftTopCornerLine);
                            currentContent ="";
                            leftTopCornerLine += lineHeight;
                        } else {
                            graphics2D.drawString(currentContent, leftBorder, (int)leftTopCornerLine);
                            currentContent ="";
                            leftTopCornerLine += lineHeight;
                        }
                    } else {
                        int contentWidth = fontMetrics.stringWidth(currentContent);
                        if(contentWidth<=260) {
                            currentContent += " " + wordArray[i];
                        }
                    }
                } else {
                    System.out.println("Input was cut, because it was too long.");
                    break;
                }
            }
        }
        
        public static void drawLinesAsCharacters(Graphics2D graphics2D, String content, Font font, double baseY) {
            int lineHeight = getHeight(font, graphics2D);
            int leftBorder = 5;
            String[] characterArray = content.split("");
            FontMetrics fontMetrics = graphics2D.getFontMetrics(font);
            String currentContent = "";
            double leftTopCornerLine = baseY;
            
            for(int i = 0; i < characterArray.length; i++) {
                
                if(leftTopCornerLine < 195) {
    
                    if(fontMetrics.stringWidth(currentContent)>=210) {
                        if(fontMetrics.stringWidth(characterArray[i])<=210-fontMetrics.stringWidth(currentContent)) {
                            currentContent += characterArray[i];
                            graphics2D.drawString(currentContent, leftBorder, (int)leftTopCornerLine);
                            currentContent ="";
                            leftTopCornerLine += lineHeight;
                        } else {
                            graphics2D.drawString(currentContent, leftBorder, (int)leftTopCornerLine);
                            currentContent ="";
                            leftTopCornerLine += lineHeight;
                        }
                    } else {
                        int contentWidth = fontMetrics.stringWidth(currentContent);
                        if(contentWidth<=230) {
                            currentContent += characterArray[i];
                        }
                    }
                } else {
                    System.out.println("Input was cut, because it was too long.");
                    break;
                }
            }
        }
        
    }