У меня есть некоторый Java-код, который должен программно отображать текст на изображении. Поэтому я использую BufferedImage и пишу текст на объекте Graphics.
Однако при настройке экземпляра шрифта размер шрифта указывается в пунктах. Когда фрагмент текста отображается на изображении, AWT преобразует точки в пиксели в зависимости от разрешения объекта Graphics. Я не хочу вовлекаться в вычисление отношения пиксель / точка, так как это действительно задача для AWT. Изображение, которое создается для устройства с высоким разрешением (выше, чем у любых настольных мониторов).
Но, похоже, я не могу найти способ указать разрешение графики. Он наследует его от локальной графической среды, которая находится вне моего контроля. Я не хочу, чтобы этот код зависел от чего-то локального, и я даже не уверен, что это «нормально» - использовать локальную графическую среду для определения разрешения внеэкранных растров, которые знают, для чего они нужны людям.
Итак, каким-либо образом я могу указать разрешение для изображения вне экрана любого типа (предпочтительно того, которое может создавать графический объект, чтобы я мог использовать стандартный API рендеринга AWT)?
(обновление)
Вот примерная (довольно длинная) проблема, которая визуализирует фрагмент текста на изображении с предопределенным размером шрифта в пикселей (фактически, DPI целевого устройства равно 72). Что меня беспокоит, так это то, что мне приходится использовать DPI локального экрана для расчета размера шрифта в точках, хотя я не использую экран в любом случае, так что это не актуально, и обычные сбои на безголовых системах все вместе. Вместо этого мне бы хотелось, чтобы в этом случае можно было создавать внеэкранное изображение (графика, растр) с разрешением DPI 72, что позволило бы сделать точки по значению равными пикселям.
Пример способа запуска кода:
$ java FontDisplay Monospace 150 "Cat in a bag" 1.png
Это приведет к отображению сообщения «Кошка в сумке» с размером шрифта 150 пикселей на изображении высотой 150 пикселей и сохранит результат в 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();
}
}