Embedding TTF and using with g2d - java

I'm trying to embed a TTF font and then use draw it with Grapics2D. I've been able to create the font, but I'm not exactly sure how to pass the font to setFont. I make a new font here, which throws no exceptions:
private Font pixel = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("font/amora.ttf"));
But I can't figure out how to draw it with setFont();
Here's my code:
private static final long serialVersionUID = 1L;
private Timer timer;
private Char Char;
private Font pixel = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("font/amora.ttf")); <<<--------
public Board() throws FontFormatException, IOException {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
Char = new Char();
timer = new Timer(5, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(Char.getImage(), Char.getX(), Char.getY(), this);
g.setColor(Color.white);
g.setFont( What goes here? ); // <------------
g.drawString("Amora Engine rev25 (acetech09)", 10, 20);
g.drawString(Char.getDebugStats(0), 10, 40);
g.drawString(Char.getDebugStats(1), 10, 60);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e) {
Char.move();
repaint();
}
}
Any help would be greatly appreciated. Thanks.

You could just do...
g.setFont(pixel);
But you might have better sucess with
g.setFont(pixel.deriveFont(Font.BOLD, 36f));
Are variations of....
Also, don't dispose of a Graphics context you did not create...
Graphics2D g2d = (Graphics2D)g;
/*...*/
// g.dispose();
Or
Graphics2D g2d = (Graphics2D)g.create();
/*...*/
g.dispose();
I'd also be loathed to override the paint method. Assuming you're using something like JComponent or JPanel, you should use paintComponent. If you're rendering directly yo a top level container (like JFrame), then I wouldn't. There are issues with double buffering and frame borders that won't make your life fun...
I'm also concerned about new Timer(5, this) - 5 milliseconds is close enough to 0 to make little difference. You'd be better of with something like 40, which should give you something like 25fps or 17 which will give you roughly 60fps...

It should be
g.setFont( this.pixel );
If this is not working, try:
Commenting out the setFont instruction.
Replacing Font.createFont with a reference to a Java standard font.
to rule out possible issues.

Related

JFrame not displaying Canvas

I've recently been working with BufferStrategy and JFrame for preliminary graphics. However, when attempting to draw a simple rectangle to the frame, nothing appears. Here is the code:
import java.awt.*;
import java.awt.image.BufferStrategy;
import javax.swing.*;
public class GTestingMain {
public static void main(String[] args) {
JFrame myFrame = new JFrame();
Canvas myCanvas = new Canvas();
Graphics2D g;
BufferStrategy strategy;
myFrame.setSize(500, 500);
myFrame.setResizable(false);
myFrame.setLocationRelativeTo(null);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myCanvas.setPreferredSize(new Dimension(500, 500));
myFrame.add(myCanvas);
myFrame.pack();
strategy = myCanvas.getBufferStrategy();
if(strategy == null) {
myCanvas.createBufferStrategy(3);
}
strategy = myCanvas.getBufferStrategy();//Throwing in again so strategy != null
do {
do {
g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.red);
g.fillRect(10, 40, 50, 70);
g.dispose();
}while(strategy.contentsRestored());
strategy.show();
}while(strategy.contentsLost());
}
}
Now the problem is a little more unique. When I go into the debugger and step through the code, it works just fine. If I run normally, blank. If I click on the Frame before it is drawn to while in the debugger - blank.
I know I can 'solve' this issue with a thread, but i'd like to know why it works* in debug mode but not in a regular run. Thanks!
Before you start off with bufferStrategies, go through java doc
It says that,
A buffer strategy gives you two all-purpose methods for drawing: getDrawGraphics and show. When you want to start drawing, get a draw graphics and use it. When you are finished drawing and want to present your information to the screen, call show. These two methods are designed to fit rather gracefully into a rendering loop:
What you are missing is a rendering loop basically. Also since it uses volatile images for its buffer, we never know when our video memory is lost. That explains why you were getting the rectangle in debug mode. Its like a callback system with contentLost and contentsRestored methods.
Just wrap your do while loops as below.
while(isHappy()){ // your logic goes here.
do {
do {
g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.red);
g.fillRect(10, 40, 50, 70);
g.dispose();
}while(strategy.contentsRestored());
strategy.show();
}while(strategy.contentsLost());
}

Java 2D Graphics BufferedImage FillRect issue

I am still getting used to painting graphics on java and am trying to write a simple graphics program that paints a background using a buffered image. However, strangely enough, even though my jpanel size is set to 1200x400 and so are the buffered image and fillrect method, there is a small "gap" as you can see in the picture I have attached so the panel is clearly larger than 1200x400 but I don't understand why? What does the setPreferredSize method actually do? Also when I change my fillrect method and bufferedimage to 1300x500 there is no longer a gap so this is clearly the issue. If anyone has any advice as to where I am going wrong I would greatly appreciate it, thanks
Here is my code:
public class Q2 extends JPanel {
private BufferedImage image;
public static void main(String[] args) {
Q2 test = new Q2();
}
public Q2() {
this.init();
}
private void init() {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setContentPane(this);
this.setPreferredSize(new Dimension(1200,400));
refreshCanvas();
window.pack();
window.setVisible(true);
window.setResizable(false);
}
public void paintComponent(Graphics g) {
Graphics2D twoD = (Graphics2D) g;
twoD.drawImage(image,0,0,null);
}
private void refreshCanvas() {
image = new BufferedImage(1200,400,BufferedImage.TYPE_INT_ARGB);
Graphics2D twoD = image.createGraphics();
twoD.setColor(Color.BLACK);
twoD.fillRect(0, 0, 1200,400);
repaint();
}
}
Have a look at this answer here.
You have to put window.setResizeable(false); before window.pack();. This should fix it.

Drawing a circle and line onto a JFrame using JPanels without GridLayout

Currently I am trying to draw a line and a circle (which will become animated, like a wheel) onto my canvas.
I have a constructor called WheelAnimation().
Within this constructor, I have these two implementation classes, the first one is the circle:
class CircleComponent extends JComponent
{
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
for(int i = 0; i < 200; i++)
{
// repaint();
g2.fillOval(i, 50, 50, 50);
}
}
}
final CircleComponent component2 = new CircleComponent();
panel.add(component2);
And this draws the line under the circle:
class LineComponent extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.drawLine(120, 120, 380, 120);
}
}
final LineComponent component = new LineComponent();
panel.add(component);
If I use a setLayout method such as: panel.setLayout(new GridLayout(1, 1));
I can make the two items show up (though their formatting is not good).
http://puu.sh/8fm9B/4f1dc1d0e5.png
But if I remove the setLayout method, nothing shows up onto my frame, despite the coordinates staying the same.
Could someone tell me why this is happening and give me a recommendation on how to set those layouts and make them show up?
I can make the two items show up (though their formatting is not good).
When you use a layout manager it is responsible for setting the size and location of the component added to the panel.
If you don't use a layout manager then your application code is responsible for setting the size and location of each component.

How to resize text in java

I have seen that in photoshop text can be easily resized just by dragging them. How can we do the same thing in Java? Any idea on how to resize text in java?
Added a snapshot of letter "A" resized in photoshop
Please let me know what is wrong with this code?
public class ResizeImage extends JFrame {
public ResizeImage(){
JPanel panel = new JPanel(){
public void paintComponent(Graphics g) {
// In your paint(Graphics g) method
// Create a buffered image for use as text layer
BufferedImage textLayer = new BufferedImage(240, 240,
BufferedImage.TYPE_INT_RGB);
// Get the graphics instance of the buffered image
Graphics2D gBuffImg = textLayer.createGraphics();
// Draw the string
gBuffImg.drawString("Hello World", 10, 10);
// Rescale the string the way you want it
gBuffImg.scale(200, 50);
// Draw the buffered image on the output's graphics object
g.drawImage(textLayer, 0, 0, null);
gBuffImg.dispose();
}
};
add(panel);
}
public static void main(String [] args){
ResizeImage frame = new ResizeImage();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
One way is to use an AffineTransform (this variant also fades the color).
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.io.File;
import javax.imageio.ImageIO;
public class StretchText {
public static void main(String[] args) throws Exception {
// used to stretch the graphics instance sideways
AffineTransform stretch = new AffineTransform();
int w = 640; // image width
int h = 200; // image height
int f = 21; // Font size in px
String s = "The quick brown fox jumps over the lazy dog.";
final BufferedImage bi = new BufferedImage(
w,h,BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.setFont(new Font("Serif",Font.PLAIN,f));
g.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// paint BG
g.setColor(Color.WHITE);
g.fillRect(0, 0, w, h);
g.setColor(Color.BLACK);
for (int i=0; (i*f)+f<=h; i++) {
g.drawString(s, 0, (i*f)+f);
// stretch
stretch.concatenate(
AffineTransform.getScaleInstance(1.18, 1d));
g.setTransform(stretch);
// fade
Color c = g.getColor();
g.setColor(new Color (
c.getRed(),
c.getGreen(),
c.getBlue(),
(int)(c.getAlpha()*.75)));
}
g.dispose();
ImageIO.write(bi, "png", new File(
new File(System.getProperty("user.home")),
"StretchText.png"));
Runnable r = new Runnable() {
#Override
public void run() {
JLabel gui = new JLabel(new ImageIcon(bi));
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}
You can use TextLayout to get the geometry, as shown here. The example scales the image to fill the frame. JInternalFrame might be a good choice to leverage the frame's resizing feature. Alternative, the example cited here shows how to click and drag multiple selections.
u can define type of font
e.g.
Font f = new Font("SansSerif", Font.BOLD, 40)
Unfortunately the java api doesn't have a native free-form scaling/transform method fonts.
You can however rescale a BufferedImage or Graphics object with the scale(x, y) method. So you can try an approach with "layers" instead. I.e. draw objects, such as text, in their own layer (i.e. a BufferedImage) first and then on the actual graphics output.
So draw the text as usual on a BufferedImage and rescale it the way you want. Here is some simple sample code to get you starting.
// In your paint(Graphics g) method
// Create a buffered image for use as text layer
BufferedImage textLayer = new BufferedImage(240, 240,
BufferedImage.TYPE_INT_ARGB);
// Get the graphics instance of the buffered image
Graphics2D gBuffImg = buffImg.createGraphics();
// Draw the string
gBuffImg.drawString("Hello World", 0, 0);
// Rescale the string the way you want it
gBuffImg.scale(240, 120);
// Draw the buffered image on the output's graphics object
g.drawImage(gBuffImg, 0, 0, null);
The actual size of the text layer could be determined with the help of the FontMetrics object but I'll leave that as an exercise for the OP.
This can be done at the Graphics level using Graphics.setTransform(). However I believe it is more obvious to do this at the Font level using the lesser known Font.deriveFont(transform). For example
// create transform
AffineTransform affineTransform = new AffineTransform();
affineTransform.scale(1d, 3d);
// create font using that transform
Font stretchedFont = g.getFont().deriveFont(affineTransform);
// set font as normal
g.setFont(stretchedFont);
// render as normal
g.drawString("Stretched", 23, 45);

draw buffered image ontop of another buffered image

my goal is to draw some bufferedimage onto another. then all this stuff draw onto some other bufferedimage and so on. And finally draw this on top of a panel.
For now i'm trying to draw bufferedimage onto panel and nothing works. My bufferedimage looks completely white:
public class Main2 {
public static void main(String[] args) {
JFrame frame = new JFrame("asdf");
final JPanel panel = (JPanel) frame.getContentPane();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
somepaint(panel);
}
});
}
private static void somepaint(JPanel panel) {
BufferedImage image = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
image.getGraphics().setColor(Color.red);
image.getGraphics().fillRect(0, 0, 200, 200);
Graphics2D graphics = (Graphics2D) panel.getGraphics();
graphics.setColor(Color.magenta);
graphics.fillRect(0, 0, 500, 500);
graphics.drawImage(image, null, 0, 0); // draws white square instead of red one
}
}
thanks
Re:
private static void somepaint(JPanel panel) {
BufferedImage image = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
image.getGraphics().setColor(Color.red);
image.getGraphics().fillRect(0, 0, 200, 200);
Graphics2D graphics = (Graphics2D) panel.getGraphics();
This is not how you draw inside of a JPanel or JComponent.
Don't call getGraphics() on a component as the Graphics object returned will be short-lived, and anything drawn with it will not persist. Instead do your JPanel's drawing inside of its paintComponent(Graphics G) method override. You will need to create a class that extends JPanel in order to override paintComponent(...).
Most importantly, to see how to do Swing graphics correctly, don't guess. You'll want to read the Swing Graphics Tutorials first as it will require you to toss out some incorrect assumptions (I know that this is what I had to do to get it right).
You need to rectify your parameters in the drawImage() call. Change this:
graphics.drawImage(image, null, 0, 0);
to
graphics.drawImage(image, 0, 0,null);
Check the Java docs for more details.

Categories