1

I am trying to zoom out a text using the code below, but scaling does not scale the font of the text properly. I believe it does not keep the result the same.

My goal is to zoom html strings, but the issue still remains there, too. For example, if I paint the html text (different foreground and background in a JTextPane), it will be as if the string is dancing. :(

In other words, it does not scale smoothly.

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JPanel;

public class scaledText extends javax.swing.JDialog {

    public scaledText(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        setSize(800, 450);
        setLocationRelativeTo(null);
        setContentPane(new JPanel() {

            private float timer = 0.001f;

            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2 = (Graphics2D) g;
                super.paintComponent(g2);

                timer += 0.01f;
                if (timer > 2.7) {
                    timer = 0.001f;
                }
                float t = Math.min(timer, 2.5f);
                g2.setFont(new Font("Arial", 0, 60));

                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
                g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);

                String text = "This is a text";
                FontMetrics fm = new FontMetrics(g2.getFont()) {
                };
                g2.translate((600 - g2.getFontMetrics(g2.getFont()).stringWidth(text)) / 2, (450 - fm.getHeight()) / 2);
                g2.scale(t, t);
                g2.drawString(text, 0f, 0f);
                g2.draw(new Ellipse2D.Double(0, 0, 100, 100));
                try {
                    Thread.sleep(20);
                } catch (InterruptedException ex) {
                }
                this.repaint();
            }
        });
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                scaledText dialog = new scaledText(new javax.swing.JFrame(), true);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {

                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
Soley
  • 1,716
  • 1
  • 19
  • 33
  • 1
    Don't call Thread.sleep within your paintCompnent method, you're blocking the event dispatching thread. Don't call repaint from within your paint method, directly or indirectly, this will set up a condition by which it could start consuming your CPU cycles – MadProgrammer Mar 04 '15 at 20:29
  • Yeah thank, that is just a quick code to slow down the painting process. :) This code is apart from the main codes. – Soley Mar 04 '15 at 20:30
  • 1
    And while I think of it, don't modify the translation/scale/rotation of the Graphics context passed to your paintComponent, use Graphics#create to create a copy, which won't affect anything else that might be painted after you – MadProgrammer Mar 04 '15 at 20:31

1 Answers1

1

Here is another way which enables me to draw strings. However, It does not allow me to preserve font style, and colors :( That gives me just the shape of the text. But it scales perfectly.

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedString;

import javax.swing.JPanel;

public class scaledText extends javax.swing.JDialog {

    public static Shape getTextShape(Graphics2D g2d, String text, Font font, boolean ltr) {
        AttributedString attstring = new AttributedString(text);
        attstring.addAttribute(TextAttribute.FONT, font);
        attstring.addAttribute(TextAttribute.RUN_DIRECTION, ltr ? TextAttribute.RUN_DIRECTION_LTR : TextAttribute.RUN_DIRECTION_RTL);
        FontRenderContext frc = g2d.getFontRenderContext();
        TextLayout t = new TextLayout(attstring.getIterator(), frc);
        return t.getOutline(null);
    }

    public scaledText(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        setSize(800, 450);
        setLocationRelativeTo(null);
        setContentPane(new JPanel() {

            private float timer = 1.001f;

            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2 = (Graphics2D) g;
                super.paintComponent(g2);

                timer += 0.005f;
                if (timer > 2.7) {
                    timer = 1.001f;
                }
                float t = Math.min(timer, 2.5f);
                GraphicsEnvironment ge =
                        GraphicsEnvironment.getLocalGraphicsEnvironment();

                g2.setFont(new Font("Arial", 0, 100));

                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

                String text = "This is a text مرحبا";

                Shape shape = getTextShape(g2, text, g2.getFont(), true);

                FontMetrics fm = new FontMetrics(g2.getFont()) {
                };
                g2.translate(10, (450 - fm.getHeight()) / 2);
                g2.scale(t / 2.5, t / 2.5);

                g2.fill(shape);

                try {
                    Thread.sleep(20);
                } catch (InterruptedException ex) {
                }
                this.repaint();
            }
        });
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                scaledText dialog = new scaledText(new javax.swing.JFrame(), true);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {

                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }
}
Soley
  • 1,716
  • 1
  • 19
  • 33
  • 1
    *"does not allow me to preserve font style, and colors"* - Why not? The shape is based on the Font you pass it and is filled with the Color you specify ... In fact the AttributedString allows you to adjust the individual characters properties... – MadProgrammer Mar 04 '15 at 20:33
  • How am I supposed to use the color stored within a shape object? Foregrounds, backgrounds? And yes, font style will be there (Thanks, my bad :D ). Also is there a way to get the glyph of a JTextPane? That is the goal of this question so I can render the html text myself. I am reading custom glyph painter right now, perhaps it help me. – Soley Mar 04 '15 at 20:37
  • Edit: The font properties such as Italic and bold applies for the whole text which it is not being wanted. For html strings, this won't work. – Soley Mar 04 '15 at 21:36
  • Yes, the color won't be maintained, but the styling should be. No, you can get the "text" from a `JTextPane` as the rendering is handled WAY deep inside the core API. You might consider using something like `JXLayer` (AKA `JLayer` in Java 7), [for example](http://stackoverflow.com/questions/21174997/how-to-add-mouselistener-to-item-on-java-swing-canvas/21175125#21175125)... – MadProgrammer Mar 05 '15 at 00:06
  • Unfortunately JLayer gives me the same result. I think I should use two types of texts, one for html with limited operations and one with shape and vector properties and no limitation on number of effects I can apply. bwt, thanks for your help. – Soley Mar 05 '15 at 07:35