Reputation: 6970
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:
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?
Upvotes: 2
Views: 557
Reputation: 168845
The answer is to be found by drawing a circle around the center at the same radius
as the letters.
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).
Upvotes: 1