Making text width flexible with ttf font - java

I am inquiring about two things. First I am having an ttf file and it is located in my macair drive. I do not want to add that file into my project structure. How can i import the True_type font from it. I have tried various ways to import it my Java program. e.g. public class TextFixer {
private static String[] names = { "iksswgrg.ttf" }; //this exists on my macair drive and i want to create font from it.
private static Map<String, Font> cache = new ConcurrentHashMap<String, Font>(names.length);
static {
for (String name : names) {
cache.put(name, getFont(name));
}
}
public static Font getFont(String name) {
Font font = null;
if (cache != null) {
if ((font = cache.get(name)) != null) {
return font;
}
}
String fName = "/fonts/" + name;
try {
InputStream is = TextFixer.class.getResourceAsStream(fName);
font = new Font("ttf", 0, 16);
//font = Font.createFont(Font.TRUETYPE_FONT, is);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(fName + " not loaded. Using serif font.");
font = new Font("serif", Font.PLAIN, 24);
}
return font;
}
2nd part is I want to create a String by using Graphics. First I need to have width that is of 130mm. The height of the displayed box will be the tallest character in the provided string. The font size is between 8 and 16. I have an enterprise project which take care of the height and size of the ttf. The problem i face is: I do not want to use swing/javafx libraries. I want to use Graphics library of Java, use Graphics2D to have a rectangle. How can i set its width to be precisely 130mm? Then I want to make that width flexible with according to the Font. I want to draw a string and the string should get adjusted/being flexible in the provided width. I am able to draw a string through g.drawString() but I am unable to see it on console. As I do not want to use Jframe or any Swing/javaFX libraries.
I know this seems a bit long but I hope I have explained it well enough. I desperately need help. Please let me know if you guys can help me out here.
Thanks in advance

First I am having an ttf file and it is located in my macair drive. I do not want to add that file into my project structure. How can i import the True_type font from it
This is more of a problem to do with "How do you reference a file on the file system" then "How do I load a font", because if you can solve the first, you can solve the second.
File fontFile = new File("some/relative/path/to/your/Font.tff");
or
File fontFile = new File("/some/absolute/path/to/your/Font.tff");
Personally, I like neither, as it it causes too much trouble (working directories, other systems, etc), I prefer to use embedded resources where possible or put the files in a common location.
For example {user.home}/AppData/Local/{application name} on Windows or on Mac you could use {user.home}/Library/Application Support/{application name}, then it doesn't matter where the program is executed from
Loading the font is relatively simple. For my example, I placed the font file in the working directory of the program
System.out.println(new File("Pacifico.ttf").exists());
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("Pacifico.ttf"));
2nd part is I want to create a String by using Graphics. First I need to have width that is of 130mm. The height of the displayed box will be the tallest character in the provided string
This is much more complicated, as images are measured in pixels. In order to know how many pixels make up a given distance, we need to know the DPI of the image.
its 72DPI
Okay then, from that, we can calculate the number of pixels we need
public static double cmToPixel(double cm, double dpi) {
return (dpi / 2.54) * cm;
}
130mm (13 cm) comes out to be 368.503937007874 # 72dpi.
From this, we need to find the font point size for a given piece of text to fit within this range.
Now, there are a number of was you can do this, you could simply start at point 1 and perform a linear progression till you pass the range you're after. It's not exactly fast and, as you increase the size, it can become a little error prone.
I've opted for more of a divide and conquer approach
protected static int widthOfText(String text, Font font, float fontSize, Graphics2D g2d) {
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
return textWidth;
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d, float min, float max) {
float fontSize = min + ((max - min) / 2f);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
if (fontSize == min || fontSize == max) {
return fontSize;
}
if (textWidth < width) {
return pointToFit(width, text, font, g2d, fontSize, max);
} else if (textWidth > width) {
return pointToFit(width, text, font, g2d, min, fontSize);
}
return fontSize;
}
Important to note, it's not perfect, but it betters a linear progression :P
With this in hand, we can start calculating the required properties we need...
String text = "Happy, Happy, Joy, Joy";
double width = cmToPixel(13.0, 72.0);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
float fontSize = pointToFit(width, text, font, g2d, 0, (float)width);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
Okay, so this creates a small (1x1) temporary image. We need Graphics context in order to calculate all the other properties. It then calculates the font point size, from it can then calculate the text height
With all that information in hand, we can get around to actually rendering the text...
img = new BufferedImage((int) Math.round(width), height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
Which will eventually output something like this...
I added the red border before I rendered the text so I could see how well it fitted.
Now, this is a really basic example, what this doesn't do is tell you when the text won't fit (ie, the point size is 1 or 0), you'll have to put traps in to catch that yourself
And, because I know you'll probably have lots of fun putting it together, my test code...
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class Test {
public static void main(String[] args) {
try {
System.out.println(new File("Pacifico.ttf").exists());
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("Pacifico.ttf"));
String text = "Happy, Happy, Joy, Joy";
double width = cmToPixel(13.0, 72.0);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
float fontSize = pointToFit(width, text, font, g2d, 0, (float) width);
System.out.println(width);
System.out.println(fontSize);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage((int) Math.round(width), height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
JOptionPane.showConfirmDialog(null, new ImageIcon(img));
} catch (IOException | FontFormatException e) {
//Handle exception
}
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d) {
return pointToFit(width, text, font, g2d, 0f, Float.MAX_VALUE);
}
protected static int widthOfText(String text, Font font, float fontSize, Graphics2D g2d) {
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
return textWidth;
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d, float min, float max) {
float fontSize = min + ((max - min) / 2f);
NumberFormat nf = NumberFormat.getInstance();
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
if (fontSize == min || fontSize == max) {
return fontSize;
}
if (textWidth < width) {
return pointToFit(width, text, font, g2d, fontSize, max);
} else if (textWidth > width) {
return pointToFit(width, text, font, g2d, min, fontSize);
}
return fontSize;
}
public static double cmToPixel(double cm, double dpi) {
return (dpi / 2.54) * cm;
}
}

Related

Rotate BufferedImage with transparent background

I have an image with transparent background. I'd like to rotate this image to a specific angle and keep the transparent background for the resulting image. For this purpose I use the following method:
public static BufferedImage rotateImage(BufferedImage image, double angle, Color backgroundColor) {
System.out.println(image.getType());
double theta = Math.toRadians(angle);
double sin = Math.abs(Math.sin(theta));
double cos = Math.abs(Math.cos(theta));
int w = image.getWidth();
int h = image.getHeight();
int newW = (int) Math.floor(w * cos + h * sin);
int newH = (int) Math.floor(h * cos + w * sin);
BufferedImage tmp = new BufferedImage(newW, newH, image.getType());
Graphics2D g2d = tmp.createGraphics();
if (backgroundColor != null) {
g2d.setColor(backgroundColor);
g2d.fillRect(0, 0, newW, newH);
}
g2d.fillRect(0, 0, newW, newH);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.translate((newW - w) / 2, (newH - h) / 2);
g2d.rotate(theta, w / 2, h / 2);
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return tmp;
}
I invoke it with background=null:
BufferedImage image = ImageIO.read(file);
rotateImage(image, 4, null);
ImageIO.write(bi, "PNG", new File("image.png"));
but the background of the resulting image.png is WHITE. What am I doing wrong and how to properly keep the transparent background for image.png?
I'm a bit puzzled about the behavior of Graphics.drawImage(). Maybe somebody else can comment about it.
However, Graphics2D.drawRenderedImage() works a treat. It takes an AffineTransform to control the rotation. The below example nicely works. You probably have additional requirement about the final image size and the location of the rotated image.
import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
public class ImageRotation {
public static void main(String[] args) {
ImageRotation rotation = new ImageRotation();
rotation.rotate("input.png", 45, "output.png");
}
public void rotate(String inputImageFilename, double angle, String outputImageFilename) {
try {
BufferedImage inputImage = ImageIO.read(new File(inputImageFilename));
BufferedImage outputImage = rotateImage(inputImage, angle);
ImageIO.write(outputImage, "PNG", new File(outputImageFilename));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private BufferedImage rotateImage(BufferedImage sourceImage, double angle) {
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
BufferedImage destImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = destImage.createGraphics();
AffineTransform transform = new AffineTransform();
transform.rotate(angle / 180 * Math.PI, width / 2 , height / 2);
g2d.drawRenderedImage(sourceImage, transform);
g2d.dispose();
return destImage;
}
}
Update
While the above code works for most PNGs, it does not work for the image that alexanoid is using. I've analyzed the image:
It's a grayscale image without a color palette (PNG color type 0) .
It uses simple transparency with a 2 byte long tRNS chunk.
As far as I can tell that's perfectly legal. However, ImageIO does not implement this combination. If the image has no palette, it simply ignores the tRNS chunk and therefore ignores the transparency information. That's most likely a bug.
You basically have two options now:
Look for an alternative library to read PNG files.
Fix the transparency after you have read the PNG file. This only works if know that the image used the particular problematic format.
Input and output for working PNG files
Input image:
Ouptput Image:

Java Graphics2D scale font to fill in background

I'm having troubles scaling font to fit in background width. I have a 1000 height and 350 width background, and I'm trying to scale font when it's bigger than background.
I've done several test with different font and results are the same, some letters missed or blank spaces at the end of text.
This is the code:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class PruebaStackoverflow {
public static void main(String[] args) {
String titleText = null;
Graphics2D g2D = null;
Font testFont = null;
File imageGrayBackgroundFile = new File(
"resources/pruebaAltaResolucionGris.png");
File destinationImageGray = new File("resources/outputTextGray.png");
BufferedImage background = readImage(imageGrayBackgroundFile);
titleText = "Lorem ipsum dolor sit amet asdkf sdm";
testFont = new Font("Lucida Console", Font.PLAIN, 50);
g2D = background.createGraphics();
g2D.setColor(Color.BLACK);
g2D.setFont(testFont);
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2D = scaleFontFromFontMetrics(g2D, background, titleText);
g2D.drawString(titleText, 0, 150);
g2D.dispose();
writeImage(destinationImageGray, background);
}
private static Graphics2D scaleFontFromFontMetrics(Graphics2D g2D,
BufferedImage backgroundImage, String text) {
double xScale;
double yScale;
double scale;
Integer backgroundWidth = null;
Integer backgroundHeight = null;
Integer textWidth = null;
Integer textHeigth = null;
backgroundWidth = backgroundImage.getWidth();
backgroundHeight = backgroundImage.getHeight();
Font f = g2D.getFont();
FontMetrics fm = g2D.getFontMetrics(f);
textWidth = fm.stringWidth(text);
textHeigth = fm.getHeight();
xScale = backgroundWidth / (double) textWidth;
yScale = backgroundHeight / (double) textHeigth;
if (xScale > yScale) {
scale = yScale;
} else {
scale = xScale;
}
g2D.setFont(f.deriveFont(AffineTransform.getScaleInstance(scale, scale)));
return g2D;
}
private static BufferedImage readImage(File sourceImage) {
BufferedImage bufferedImage = null;
try {
bufferedImage = ImageIO.read(sourceImage);
} catch (IOException e1) {
e1.printStackTrace();
}
return bufferedImage;
}
private static void writeImage(File destinationImage,
BufferedImage bufferedImage) {
try {
ImageIO.write(bufferedImage, "png", destinationImage);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Image Saved");
}
}
this is the text to scale "Lorem ipsum dolor sit amet asdkf sdm"
and this is text scaled with affine transformation.
output image with font scaled and 'm' letter missed
I hope that you may help me, thanks
you can measure the length of a string and verify if it fits in your content.
int lengthInPixel = graphics.getFontMetrics().stringWidth("Lorem ipsum dolor sit amet asdkf sdm")
Following on from my comment earlier, here's a solution where the closest font size to the image width is used. The text is drawn to a separate image, resized, then drawn to the final image. This is all done in the createTextImage() method. Note, I have created a background image rather than using a file.
The outcome may not be as crisp as desired, but you could experiment with different algorithms for resizing. Hopefully it'll give you a starting point.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Main {
public static void main(String[] args) {
String titleText = "Lorem ipsum dolor sit amet asdkf sdm";
Font initialFont = new Font("Lucida Console", Font.PLAIN, 50);
BufferedImage textImg = createTextImage(titleText, 350, 1000, 150,
initialFont, Color.BLACK, Color.GRAY);
writeImage(new File("outputTextGray.png"), textImg);
}
private static BufferedImage createTextImage(String text, int targetWidth,
int targetHeight, int textYOffset, Font font, Color textColor, Color bgColor) {
// The final image
BufferedImage finalImg = createBackgroundImg(targetWidth, targetHeight, bgColor);
Graphics2D finalImgG = finalImg.createGraphics();
Font closestFont = scaleFont(finalImg, font, text);
finalImgG.setFont(closestFont);
// Create new image to fit text
int textWidth = finalImgG.getFontMetrics().stringWidth(text);
int textHeight = finalImgG.getFontMetrics().getHeight();
BufferedImage textImg = createBackgroundImg(textWidth, textHeight * 2, bgColor);
// Draw text
Graphics2D textImgG = textImg.createGraphics();
textImgG.setFont(closestFont);
textImgG.setColor(textColor);
textImgG.drawString(text, 0, textHeight);
// Scale text image
double scale = getScale(textImg.getWidth(), textImg.getHeight(),
targetWidth, targetHeight);
Image resized = textImg.getScaledInstance((int) (textImg.getWidth() * scale),
(int) (textImg.getHeight() * scale), Image.SCALE_SMOOTH);
// Draw text image onto final image
finalImgG.drawImage(resized, 0, textYOffset, null);
return finalImg;
}
private static Font scaleFont(BufferedImage img, Font font, String text) {
Graphics2D g2D = img.createGraphics();
g2D.setFont(font);
double scale = getScale(g2D.getFontMetrics().stringWidth(text),
g2D.getFontMetrics().getHeight(), img.getWidth(),
img.getHeight());
return g2D.getFont().deriveFont(AffineTransform.getScaleInstance(scale, scale));
}
private static double getScale(int width, int height, int targetWidth, int targetHeight) {
assert width > 0 && height > 0 : "width and height must be > 0";
double scaleX = (double) targetWidth / width;
double scaleY = (double) targetHeight / height;
return scaleX > scaleY ? scaleY : scaleX;
}
private static BufferedImage createBackgroundImg(int width, int height, Color color) {
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < bufferedImage.getWidth(); x++) {
for (int y = 0; y < bufferedImage.getHeight(); y++) {
bufferedImage.setRGB(x, y, color.getRGB());
}
}
return bufferedImage;
}
private static void writeImage(File destinationImage,
BufferedImage bufferedImage) {
try {
ImageIO.write(bufferedImage, "png", destinationImage);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Image Saved");
}
}
Something I do to fit a game-screen to a certain resolution, is to pre-calculate the ratio, after testing its maximum bound. Something like this (I changed my actual code to your case):
double calculateScaling( BufferedImage image, String text, Font font ){
//These are final to avoid accidental mending, since they are
//the base for our calculations.
//Belive me, it took me a while to debug the
//scale calculation when I made this for my games :P
/**
* imageWidth and imageHeight are the bounds
*/
final int imageWidth = image.getWidth();
final int imageHeight = image.getHeight();
Graphics2D g2 = image.createGraphics();
FontMetrics fm = g2.getFontMetrics( font );
/**
* requestedStringWidthSize e requestedStringHeightSize are the measures needed
* to draw the text WITHOUT resizing.
*/
final int requestedStringWidthSize = fm.stringWidth( text );
final int requestedStringHeightSize = fm.getHeight();
double stringHeightSizeToUse = imageHeight;
double stringWidthSizeToUse;
double scale = stringHeightSizeToUse/requestedStringHeightSize;
stringWidthSizeToUse = scale*requestedStringWidthSize;
/**
* Checking if fill in height makes the text go out of bound in width,
* if it does, it rescalates it to size it to maximum width.
*/
if( imageWidth < ((int)(Math.rint(stringWidthSizeToUse))) ) {
stringWidthSizeToUse = imageWidth;
scale = stringWidthSizeToUse/requestedStringWidthSize;
//stringHeightSizeToUse = scale*requestedStringHeightSize;
}
g2.dispose(); //we created this to use fontmetrics, now we don't need it.
return scale;
}
In my game, I would store the scale as float instead of double to avoid heavy calculations on the run, but for you it's just a simple scaling, right?
All you have to do now is to study the code and implement it to yours.
I hope I have helped.
Have a nice day. :)

Setting the background using a JLabel and an image inserted into it

I've been working on a small project for fun, i'm currently working on the background however it is really small, to change this i'm setting the dimensions to the max screen size (the project is full screen)
public void setBackground(JLabel bg) {
bg = new JLabel(new ImageIcon(this.getClass().getResource("/Background.gif")));
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) d.getWidth();
int height = (int) d.getHeight();
bg.setSize(width, height);
add(bg);
}
However, it does increase the JLabel size but not the actual image size, why is this?
EDIT:
i've found a way to do this, but it doesn't seem to find the specified path! i had made a resources folder where it is stored (a source folder in eclipse) i put it in there but it can't read the input file.
public void setBackground(JLabel bg) {
try {
img = ImageIO.read(new File("/Background.gif"));
} catch(Exception e) {
e.printStackTrace();
}
ImageIcon imgi = new ImageIcon(fitimage(img, bg.getWidth(), bg.getHeight()));
bg.setIcon(imgi);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) d.getWidth();
int height = (int) d.getHeight();
bg.setSize(width, height);
add(bg);
}
private Image fitimage(Image img , int w , int h) {
BufferedImage resizedimage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedimage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, 0, 0,w,h,null);
g2.dispose();
return resizedimage;
}
You may need to resize your image first before using it in your application. It must be the same size as your label. Whatever the actual size of your image is, that's the size Java will display it as and will not auto-resize it respectively to your label

Rendering multi-line multi-page formatted text to a BufferedImage (not in Android)

I've just had to implement the creation of a PNG Image, rendering out the contents of a text file. Searching online I found a few implementations using Android but no complete example for multi-line text using standard Java only so thought it would be worth posting my solution here.
The requirements were:
Take a String of potentially any size and render it out with properly formatted paragraphs to fit into PNG images, splitting the String into lines and paragraphs properly. If the rendered document does not fit into one page then generate multiple BufferedImages, one for each page.
I found some sample code in the Java documentation for rendering out a paragraph, building on that I made the following:
private static final Font FONT = new Font("Serif", Font.PLAIN, 14);
private static final float PARAGRAPH_BREAK = 10;
private static final float MARGIN = 20;
private Graphics2D setupGraphics(BufferedImage img) {
Graphics2D g2d = img.createGraphics();
g2d.setFont(FONT);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
return g2d;
}
private List<BufferedImage> renderText(String str, int width, int height) {
String[] paragraphs = str.split("\n");
List<BufferedImage> images = new ArrayList<>();
BufferedImage img = new BufferedImage(width,
height,
BufferedImage.TYPE_3BYTE_BGR);
images.add(img);
Graphics2D g2d = setupGraphics(img);
float drawPosY = 0;
for (int paragraph=0;paragraph<paragraphs.length;paragraph++) {
drawPosY += PARAGRAPH_BREAK;
AttributedString attStr = new AttributedString(paragraphs[paragraph]);
AttributedCharacterIterator it = attStr.getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(it, g2d.getFontRenderContext());
measurer.setPosition(it.getBeginIndex());
while (measurer.getPosition() < it.getEndIndex()) {
TextLayout layout = measurer.nextLayout(img.getWidth()-MARGIN*2);
if (drawPosY > img.getHeight() - layout.getAscent() - layout.getDescent() - layout.getLeading()) {
drawPosY = 0;
img = new BufferedImage((int)(
width,
height,
BufferedImage.TYPE_3BYTE_BGR);
images.add(img);
g2d.dispose();
g2d = setupGraphics(img);
}
drawPosY += layout.getAscent();
layout.draw(g2d, MARGIN, drawPosY);
drawPosY += layout.getDescent()+layout.getLeading();
}
}
g2d.dispose();
return images;
}
In my case I needed the generated PNG in memory so I created it as follows:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(output, "png", baos);
ret.setImageData(baos.toByteArray());
} catch (IOException ex) {
Logger.getLogger(ImageGenerationService.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
Almost identical code in this section would cause ImageIO to write out the file different formats (for example "jpg" instead of "png") or write the image to a file (using FileOutputStream instead of ByteArrayOutputStream).
I hope this helps anyone else with the same problem.

Java Write Text Image with Specific Fonts

I'm writing some text on top of an existing image and the font isn't very sharp. Is there some settings either with the Graphics2D or Font classes that help make fonts look nicer when writing text on top of images? The Dante font doesn't come out as Dante when I write it. I've tried to use antialiasing but it had no effect (see setRenderingHint). The images came out the same with or without the RenderingHint set. Any suggestions?
public class ImageCreator{
public void createImage(String text){
Graphics2D g = img.createGraphics(); //img is a BufferedImage read in from file system
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font fnt=new Font("Dante",1,20);
Color fntC = new Color(4, 4, 109);
g.setColor(fntC);
g.setFont(fnt);
Dimension d = new Dimension(200, 113);
drawCenteredString(text, d.width, d.height, g);
}
public static void drawCenteredString(String s, int w, int h, Graphics g) {
FontMetrics fm = g.getFontMetrics();
int x = (w - fm.stringWidth(s)) / 2;
int y = (fm.getAscent() + (h - (fm.getAscent() + fm.getDescent())) / 2);
g.drawString(s, x, y);
}
}
Use TextLayout, as shown here.
Addendum: The advantage of TextLayout is that RenderingHints may be applied to the FontRenderContext.

Categories