简体   繁体   中英

off screen graphics resolution in java.awt

I have some java code that needs to programmatically render text onto an image. So I use BufferedImage, and write text on the Graphics object.

However, when configuring the font instance, one would specify the font size in points. When a piece of text is rendered onto an image, AWT will translate the points into pixels, based on the resolution of the Graphics object. I don't want to get myself involved in computing the pixel/point ratio, since it's really the task for the AWT. The image that is being produced is for a high resolution device (higher than any desktop monitors).

But, I don't seem to find a way to specify what the resolution of the Graphics is. It inherits it from the local graphics environment, which is beyond my control. I don't really want this code to be dependent on anything local, and I'm not even sure it's "sane", to use local graphics environment for determining the resolution of off screen rasters, who knows what people would want them for.

So, any way I can specify the resolution for an off screen image of any kind (preferably the one that can create Graphics object so I can use standard AWT rendering API)?

(update) Here is a (rather long) sample problem that renders a piece of text on an image, with predefined font size in pixels (effectively, the target device DPI is 72). What bugs me, is that I have to use local screen DPI to make the calculation of the font size in points, though I'm not using the screen in any way, so it's not relevant, and plain fails on headless systems all together. What I would loved in this case instead, is being able to create an off screen image (graphics, raster), with DPI of 72, which would make points, by value, be equal to pixels.

Sample way to run the code:

$ java FontDisplay Monospace 150 "Cat in a bag" 1.png

This would render "Cat in a bag message", with font size of 150 pixels, on a 150 pixel tall image, and save the result in 1.png.

import java.awt.*;
import java.awt.image.*;
import java.awt.font.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import java.io.*;
import java.util.*;

public class FontDisplay {

    public static void main(String a[]) throws Exception {

        // args: <font_name> <pixel_height> <text> <image_file>
        // image file must have supported extension.

        int height = Integer.parseInt(a[1]);
        String text = a[2];

        BufferedImage bi = new BufferedImage(1, 1,
                BufferedImage.TYPE_INT_ARGB);

        int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
        System.out.println("dpi : "+dpi);
        float points = (float)height * 72.0F / (float)dpi;
        System.out.println("points : "+points);

        Map m = new HashMap();
        m.put(TextAttribute.FAMILY, a[0]);
        m.put(TextAttribute.SIZE, points);

        Font f = Font.getFont(m);

        if (f == null) {
            throw new Exception("Font "+a[0]+" not found on your system");
        }

        Graphics2D g = bi.createGraphics();

        FontMetrics fm = g.getFontMetrics(f);

        int w = fm.charsWidth(text.toCharArray(), 0, text.length());

        bi = new BufferedImage(w, height, BufferedImage.TYPE_INT_ARGB);

        g = bi.createGraphics();
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, w, height);
        g.setColor(Color.WHITE);
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
        g.setFont(f);
        g.drawString(text, 0, fm.getMaxAscent());

        String fName = a[3];
        String ext = fName.substring(fName.lastIndexOf('.')+1).toLowerCase();

        File file = new File(fName);
        ImageWriter iw = ImageIO.getImageWritersBySuffix(ext).next();

        ImageOutputStream ios = ImageIO.createImageOutputStream(file);
        iw.setOutput(ios);
        iw.write(bi);
        ios.flush();
        ios.close();

    }

}

Comparing points to pixels is like kg to Newton where the acceleration may give varying conversions. AWT lets you elect a device (screen, printer), but in your case you definitely have to determine your ratio.

You may of course use Photoshop or Gimp and create a normative image for java.


After elaborated question:

Ah, I think I see the misunderstanding. An image does only concern pixels, never points, mm, DPI, or whatever. (Sometimes only as metainfo added separately to the image.)

So if you know the DPI of your device, the inches you want to use, then the dots/pixels are clear. points/dpi may shed more light.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM