2

I was trying to achieve dynamic text on top and bottom of the image. Below is the output right now I am able to produce, but the characters in the bottom line getting overlapped each other. Please tell me where I went wrong in my code:

enter image description here

code snippet running to generate image as in the image:

package com.logogenerator.util;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.imageio.ImageIO;

public class CurvedText {

    public static void main(String[] args) throws NoninvertibleTransformException {
        try {

            final BufferedImage image = ImageIO.read(new File("E://xxx.png"));
            Graphics2D g;
            g = (Graphics2D) image.getGraphics();
            Font font = new Font("Serif", Font.PLAIN, 16);
            g.setFont(font);
            g.setColor(Color.GREEN);

            drawCircleTextTop("ABCDEFGH", image, g);
            drawCircleTextBottom("ABCDEFGH", image, g);

            g.dispose();
            ImageIO.write(image, "png", new File("E://Boathouse-WorkSpace//testboth.png"));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Flip Down and writing the text 
     * @param s String to be written on the image
     * @param image Buffered image on which string to be written
     * @param g Graphics 2D object to access the Buffered Image
     * @throws IOException
     * @throws NoninvertibleTransformException
     */
    private static void drawCircleTextTop(String s, BufferedImage image, Graphics2D g) throws IOException, NoninvertibleTransformException {  

        if(image != null){

            Dimension cd = new Dimension(256,256);
            Point pt = new Point(cd.width / 2, cd.height / 2);
            int radius = 100;


            String st = s;
            Point center = pt;
            double r = radius;
            double charDegree = 5;
            double a1 = Math.toRadians(360 - (s.length()/2 * charDegree ));//-Math.PI/4;
            double af = 1.0;


            double curangle = a1;
            Point2D c = new Point2D.Double(center.x, center.y);
            char ch[] = st.toCharArray();
            FontMetrics fm = g.getFontMetrics();
            AffineTransform xform1, cxform;
            xform1 = AffineTransform.getTranslateInstance(c.getX(),c.getY());
            for(int i = 0; i < ch.length; i++) {
                double cwid = (double)(getWidth(ch[i],fm));
                if (!(ch[i] == ' ' || Character.isSpaceChar(ch[i]))) {
                    cwid = (double)(fm.charWidth(ch[i]));
                    cxform = new AffineTransform(xform1);
                    cxform.rotate(curangle, 0.0, 0.0);
                    String chstr = new String(ch, i, 1);
                    g.setTransform(cxform);
                    g.drawString(chstr, (float)(-cwid/2), (float)(-r));
                }

                // compute advance of angle assuming cwid<
                if (i < (ch.length - 1)) {
                    double adv = cwid/2.0 + fm.getLeading() + getWidth(ch[i + 1],fm)/2.0;
                    curangle += Math.sin(adv / r);
                }
            }

        }
    }

    /**
     * Flip Down and writing the text 
     * @param s String to be written on the image
     * @param image Buffered image on which string to be written
     * @param g Graphics 2D object to access the Buffered Image
     * @throws IOException 
     * @throws NoninvertibleTransformException
     */
    private static void drawCircleTextBottom(String s, BufferedImage image, Graphics2D g) throws IOException, NoninvertibleTransformException {  

        if(image != null){

            Dimension cd = new Dimension(256,256);
            Point pt = new Point(cd.width / 2, cd.height / 2);
            int radius = 100;

            String st = s;
            Point center = pt;
            double r = radius;
            double charDegree = 4;
            double a1 = Math.toRadians(360 - (s.length()/2 * charDegree ));//-Math.PI/4;
            double af = 1.0;



            double curangle = a1;
            Point2D c = new Point2D.Double(center.x, center.y);
            char ch[] = st.toCharArray();
            FontMetrics fm = g.getFontMetrics();
            AffineTransform xform1, cxform;
            xform1 = AffineTransform.getTranslateInstance(c.getX(),c.getY());
//            for(int i = ch.length-1; i > -1; i--) {
            for(int i = ch.length-1; i >-1; i--) {
                double cwid = (double)(getWidth(ch[i],fm));
                if (!(ch[i] == ' ' || Character.isSpaceChar(ch[i]))) {
                    cwid = (double)(fm.charWidth(ch[i]));
                    cxform = new AffineTransform(xform1); 
                    cxform.rotate(curangle, 0.0, 0.0);
                    String chstr = new String(ch, i, 1);
                    g.setTransform(cxform);
                    g.drawString(chstr, (float)(cwid/2), (float)(r));
//                    System.out.println("Curve Angle :"+curangle);
//                    System.out.println("Cwid : "+cwid);
                }

                // compute advance of angle assuming cwid<
                if (i < (ch.length - 1)) {
                    double adv = cwid/2.0 + fm.getLeading() + getWidth(ch[i + 1],fm)/2.0;
                    curangle += Math.sin((adv / r));
                }
            }

        }
    }

    static int getWidth(char c, FontMetrics fm) {
        if (c == ' ' || Character.isSpaceChar(c)) {
            return fm.charWidth('n');
        }
            else {
            return fm.charWidth(c);
        }
    }
}

Is there anything wrong in my approach?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Dipak
  • 6,532
  • 8
  • 63
  • 87
  • I am resolving this issue by adding some extra " " - spaces at last of the string, then its working fine. But it's not seems to be the solution, some issue is there in the approach. – Dipak Jul 13 '15 at 09:50
  • `final BufferedImage image = ImageIO.read(new File("E://xxx.png"));` 1) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). 2) One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson Jul 14 '15 at 08:04

1 Answers1

1

The answer is to be found by drawing a circle around the center at the same radius as the letters.

enter image description here

The angle is chosen in order to separate the letters at the given radius. But while they are drawn outside the circle at the top (adding extra space at the top of the letter), they're drawn inside the circle at the bottom (removing space at the top of the letter - crowding them together).

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433