Java 2D - Frequently Asked Questions

Open all Close all
  • Programming, Debugging and Performance questions

  • Q. Is there a list of the various runtime flags that Java2D uses?
  • Q. What kinds of graphics hardware acceleration does Java2D use?

    Java 2D uses Xrender or OpenGL on Linux, Metal or OpenGL on macOS and Direct3D on Windows.

  • Q. How can I get better performance for my Java2D application?

    This is a difficult question to answer without knowing what exact performance problems you face. You could start by using normal Java profiling tools to see how much CPU and memory and GC overhead you have and by using Java 2D tracing (see the question about tracing) to see what code paths are being taken by rendering.

  • Q: Are there any tracing facilities in Java2D to help me track down performance issues in my application?

    -Dsun.java2d.trace=[log[,timestamp]],[count],[out:<filename>],[help],[verbose]

    See the trace property in System Properties for Java 2D Technology.

  • Image questions

  • Q: How do I create a resized copy of an image?
    BufferedImage createResizedCopy(Image originalImage,
    
                                    int scaledWidth, int scaledHeight, 
                                    boolean preserveAlpha) {
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha) {
           g.setComposite(AlphaComposite.Src);
        }
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null); 
        g.dispose();
        return scaledBI;
    }
  • Q: Can I use Java2D to generate dynamic images from my servlet (or other server-side Java application)?
    import java.awt.*;
    
    import java.awt.image.*;
    import javax.imageio.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class ImageServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {
            
                response.setContentType("image/jpeg");
    
                // Create image
                int width=200, height=200;
                BufferedImage image =
                    new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    
                // Get drawing context
                Graphics2D g2d = image.createGraphics();
    
                // Fill background with white
                g2d.setColor(Color.WHITE);
                g2d.fillRect(0, 0, width, height);
    
                // Draw a smiley face
                g2d.setColor(Color.YELLOW);
                g2d.fillOval(10, 10, 180, 180);
                g2d.setColor(Color.BLACK);
                g2d.fillOval(40, 40, 40, 40);
                g2d.fillOval(120, 40, 40, 40);
                g2d.fillRect(50, 150, 100, 10);
    
                // Dispose context
                g2d.dispose();
    
                // Write image to the output stream
                ServletOutputStream os = response.getOutputStream();        
    
                ImageIO.write(bi, "jpeg", os);
        }
    }
  • Font and Text questions

  • Q: What are the capabilities of the Java 2D text rendering system?
    • Antialiased and sub-pixel (also known as LCD) text display
    • Transformed text
    • Text as shapes that can be filled with colors, gradient paints etc.
    • Rendering complex text scripts (for example, Indic) and bidirectional text
    • APIs to locate and use platform fonts
    • APIs to directly load and register fonts from files and network resources.
  • Q: What are the different ways that text can be rendered using Java 2D?
    • java.awt.Graphics2D.drawString() draws a String of text using the current font and other rendering attributes. This is the most direct way to render text. See Rendering Graphics Primitives.
    • java.awt.font.TextLayout object allows you to implement text editing yourself: it includes mixed styles, BIDI text layout, carets, highlighting, hit testing and many other features. See Managing Text Layout.
    • java.awt.font.GlyphVector enables you to have total control over how text is shaped and positioned. See Implementing a Custom Text Layout Mechanism.
    • Using Swing text components: Because Swing is based upon Java 2D JTextField, JTextArea, and JEditorPane, which supports editing and multiple fonts and styles, all utilize the previously mentioned Java 2D APIs. Consequently, instead of not directly using the 2D text APIs, you can use the UI-oriented Swing interfaces. See Using Text Components in The Java Tutorials.
  • Q. What font types does Java 2D support?

    OpenType and Type1

  • Q: Are any fonts bundled with Java 2D?

    No

  • Q: How can I list all available fonts?
    • java.awt.GraphicsEnvironment.getAvailableFontFamilyNames()
    • java.awt.GraphicsEnvironment.getAllFonts()
    • java.awt.GraphicsEnvironment.getAvailableFontFamilyNames()
  • Q: How can I make my custom font available to my Java application?

    You can load custom fonts dynamically by using the following methods:

    • java.awt.Font.createFont() to create a Font object from a file or stream
    • java.awt.Font.deriveFont() to derive new Font objects with varying sizes, styles, transforms, and font features
    • java.awt.Font.registerFont() to register the created font with the graphics environment; once you have done so, the font is available in calls to getAvailableFontFamilyNames() and can be used in font constructors

    See Bundling Physical Fonts with Your Application in The Java Tutorials.

  • Q: Why does, for instance, a 10 pt font in Java applications appear to have a different size from the same font at 10 pt in a native application?
    • The DPI reported by platform APIs likely has no correspondence to the true DPI
    • It's unlikely that Java 2D's default matches the platform default.

    Call the method java.awt.Toolkit.getScreenResolution() to obtain the screen resolution in dots-per-inch.

  • Q: How do I find out if I can use a font to display Cyrillic, Hindi, or another writing system?

    Font.canDisplay()

  • Q. How can I specify the text antialiasing/font smoothing settings to be used by Swing?

    Use the system property awt.useSystemAAFontSettings:

    java -Dawt.useSystemAAFontSettings=lcd

    See awt.useSystemAAFontSettings in System Properties for Java 2D Technology.

    See JDK-6274842 : RFE: Provide a means for a custom look and feel to use desktop font antialiasing settings.

  • Q: How do I obtain font metrics?

    Call the method java.awt.Graphics.getFontMetrics(), which returns the font metrics of the graphics content's current font or java.awt.Graphics.getFontMetrics(Font), which returns the font metrics of the specified font. Both of these methods return an instance of FontMetrics.

  • Q. What is the difference between logical, visual and pixel bounds?

    Logical bounds are the most commonly used and include the ascent, descent, leading and advance of the text. They are useful to position the text correctly, particularly when appending one string after another or for multiple lines of text but they very likely will not enclose the rendered image. Particular examples of this may be glyphs which extend a pixel to the left of the "origin" at which it is drawn. "W" is a particular example – the leftmost long diagonal may extend to the left of the rendering origin. Glyphs in italic fonts may commonly extend further to the right than the overall "advance" of the text may indicate. These two issues may lead to text being clipped on the left or the right if placed in a tight area measured using the advance of the string. Adding a couple of pixels of padding at each end is probably the simplest workaround for this. Similarly, large descenders, or diacritics that are used in European languages, may extend beyond the reported descent or ascent. If they are used to create a tight bounding box for a label, for example, they may clip at the bottom or top. Extra padding is again the simplest solution. To get the logical bounds of a String, use any of following methods as appropriate:

    • Font.getStringBounds(...)
    • TextLayout.getAscent()
    • TextLayout.getDescent()
    • TextLayout.getLeading()
    • TextLayout.getAdvance()
    • GlyphVector.getLogicalBounds(...)
    • GlyphVector.getVisualBounds(...)
    • GlyphVector.getPixelBounds(...)
    • TextLayout.getPixelBounds(...)
    • TextLayout.getPixelBounds(...)
  • Printing questions

  • Q:What are the differences between the various printing APIs I see in the JDK?
    • 1.1 (also known as AWT) printing: java.awt.PrintJob
      • A UI component-oriented printing API
      • Can print only the 1.1 "Graphics" API, not "Graphics2D" extensions
    • 2D printing: java.awt.print.PrinterJob
      • A more flexible API for printing documents
      • Can print all of Java 2D.
      • Callback printing model
      • Integrates with javax.print
    • Java Printing Service: javax.print packages
      • Adds discovery of printers and capabilities
      • Adds ability to specify job behavior through attributes
      • Adds ability to install custom print services
  • Q Why is it so hard to print from Swing?

    See the print methods in the javax.swing.JTable class and Printing Support in Swing Components in The Java Tutorials.

  • Q: What are the causes of large spool files from java.awt.print.PrinterJob and how can I avoid them?
    • Printing using non-opaque colors, gradient paints, and custom paints
      • the application printing code could avoid using these.
      • the application could render a selected area which uses these to an offscreen opaque BufferedImage and then draw that BufferedImage to the printer graphics.
      • the application could lower the device resolution of the print job which may be higher than needed, using the javax.print.attribute.standard.PrinterResolution class.
    • Printing text on Solaris with non-Postscript standard fonts
  • Q How do I keep the information from getting cut off from the top and left sides of the page when I print using the Java 2D printing API?
    public int print(Graphics g, PageFormat pf, int pageIndex)
    
            throws PrinterException {
        Graphics2D g2 = (Graphics2D)g;
        g2.translate(pf.getImageableX(), 
        pf.getImageableY() + 72);
        // ...
    }
  • Q: How do I troubleshoot printing problems in Windows?
  • Q: How do I scale an image to fit a page?
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
    
    
        if (pageIndex > 0) return Printable.NO_SUCH_PAGE;
        Graphics2D g2d = (Graphics2D) graphics;
    
        // Set us to the upper left corner
      
        g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
        AffineTransform at = new AffineTransform();
        at.translate(0,0);
    
        // We need to scale the image properly so that it fits on one page.
      
        double xScale = pageFormat.getImageableWidth() / m_image.getWidth();
        double yScale = pageFormat.getImageableHeight() / m_image.getHeight();
      
        // Maintain the aspect ratio by taking the min of those 2 factors and
        // using it to scale both dimensions.
      
        double aspectScale = Math.min(xScale, yScale);
    
        g2d.drawRenderedImage(m_image, at);
        return Printable.PAGE_EXISTS;
    }
  • Q: When I print using PDF or HTML using the corresponding DocFlavor, how come it is printed as garbage or plain text?

    See Specifying Document Types for information about how to accurately describe print data to the print service with a DocFlavor.

  • Q: Why is Java unable to print to my CUPS 1.2 printers?

    This might happen if CUPS is listening to a local domain socket as well as localhost.

    1. Edit the CUPS configuration file, which is usually /etc/cups/cupsd.conf and uncomment the following line:
      # Listen /var/run/cups/cups.sock
    2. In the CUPS configuration file, ensure that the line that specifies the port number to which CUPS listens for connections is correct:
      Port 631
    3. Save the CUPS configuration file and restart the CUPS server:
      sh /etc/init.d/cups restart cd /usr/lib ln -s libcups.so.2 libcups.so

    See JDK-6500903 : PrintServices are incorrectly listed as "not accepting jobs" for more information.

  • Rendering questions

  • Q: What is the Rendering Process?

    See Java 2D Rendering in The Java Tutorials.

    The following are terms related to Java 2D rendering:

    • Paint: Represents the color or pattern rendered to the destination for the text and shape draw and fill methods.
    • Stroke: Describes the line style of the outline of shapes which are rendered using the shape draw (but not fill) methods.
    • Font: The font of the text to be rendered in the text draw methods.
    • Rendering hint: Suggests optional algorithms for how a primitive should be rendered, such as whether a faster or more accurate algorithm should be used.
    • Transform: Represents the mapping from user space to device space and additional coordinate transforms, such as rotate and scale, to be applied to all primitives.
    • Composite: Defines how the paint colors should replace or be mixed or blended with the colors already in the destination for all primitives.
    • Clip: Identifies a subset of the pixels in the destination which are allowed to be changed. Pixels which fall outside the clip should never be modified by any primitive.
  • Q: What kinds of shapes can I draw using Java 2D?
    Arc2D Represents an arc defined by a bounding rectangle, start angle, angular extent, and a closure type.
    CubicCurve2D Represents a cubic parametric curve segment.
    Ellipse2D Represents an ellipse defined by a bounding rectangle.
    Line2D Represents a line segment in (x, y) coordinate space.
    Point2D A point representing a location in (x,y) coordinate space. Points render nothing when drawn or filled, but the Point2D class is used in many of the APIs that manipulate or construct shapes.
    QuadCurve2D Represents a quadratic parametric curve segment.
    Rectangle2D Represents a rectangle defined by a location (x, y) and dimension (w x h).
    RoundRectangle2D Represents a rectangle with rounded corners defined by a location (x, y), a dimension (w x h), and the width and height of the corner arcs.

    In addition to these classes that enable you to create common shapes, the Java 2D API provides two other classes that allow you to define odd shapes: GeneralPath and Area. Shapes created with GeneralPath must be created segment by segment, but this means that you can combine straight lines and curved lines into a single shape. The Area class supports constructive area geometry, which enables you to combine two shapes to create another shape, either by adding or intersecting the shapes, subtracting one shape from another, or by subtracting the intersection of the shapes.

    You can also create a Shape object from a String by calling getOutline on a TextLayout object. After creating the Shape, you can perform operations such as filling and transforming on the Shape.

    For more information on working with shapes in Java 2D, see the 2D Graphics tutorial.

  • Q: How do I draw on an image?
    BufferedImage bi = null;
    
    try {
        bi = ImageIO.read(new File("images/bld.jpg"));
    } catch (IOException ioe) {
        // ...
    }
    Graphics2D g2d = bi.createGraphics();
    g2d.drawLine(10, 10, 20, 20);  // draw a line on the image
    // ...
    g2d.dispose();
  • Q: I have a shape whose outline intersects itself. How do I control the filling of the shape?

    Use one of the winding rules, Path2D.WIND_EVEN_ODD or Path2D.WIND_NON_ZERO, when creating a geometric path with Path2D.

  • Q: How do I draw a quadratic arrow-headed curves?
    GeneralPath path = new GeneralPath();
    
    float p1x = 10, p1y = 10;   // P1
    float p2x = 100, p2y = 10;  // P2
    float cx = 55, cy = 50;     // Control point of the curve
    float arrSize = 5;          // Size of the arrow segments
    
    float adjSize = (float)(arrSize/Math.sqrt(2));
    float ex = p2x - cx;
    float ey = p2y - cy;
    float abs_e = (float)Math.sqrt(ex*ex + ey*ey);
    ex /= abs_e;
    ey /= abs_e;
    
    // Creating quad arrow
    path.moveTo(p1x, p1y);
    path.quadTo(cx, cy, p2x, p2y);
    path.lineTo(p2x + (ey-ex)*adjSize, p2y - (ex + ey)*adjSize);
    path.moveTo(p2x, p2y);
    path.lineTo(p2x - (ey + ex)*adjSize, p2y + (ex - ey)*adjSize);
  • Q: Why do I get unexpected results when I use the setTransform method of Graphics2D to perform transformations?

    To perform transformations, use these steps:

    1. Use getTransform to get the current transform:

      AffineTransform aT = g2.getTransform();

    2. Use the transform, translate, scale, shear, or rotate methods to concatenate a transform:

      g2.transform(...);

    3. Perform the rendering:

      g2.draw(...);

    4. Restore the original transform using setTransform:

      g2.setTransform(aT);