为什么Windows和Linux(java)上的字体呈现不同

为什么Windows和Linux(java)上的字体呈现不同,java,graphics,fonts,centos,Java,Graphics,Fonts,Centos,我有一段java代码,它在缓冲区上绘制文本并将其保存为单色BMP。我在Windows7和CentOS6.3上执行了这个程序 使用的字体为arial。在Windows中生成的图像清晰,字符均匀渲染。为什么在Cent操作系统上,字符很薄,看起来像是平台没有渲染某些像素 import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontM

我有一段java代码,它在缓冲区上绘制文本并将其保存为单色BMP。我在Windows7和CentOS6.3上执行了这个程序

使用的字体为arial。在Windows中生成的图像清晰,字符均匀渲染。为什么在Cent操作系统上,字符很薄,看起来像是平台没有渲染某些像素

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class TimesB extends Canvas {
    private Image img;

    public TimesB() {
    setBackground(Color.white);
    }

      public static void main(String s[]) throws IOException {
        WindowListener l = new WindowAdapter() {
            public void windowClosing(WindowEvent e) {System.exit(0);}
            public void windowClosed(WindowEvent e) {System.exit(0);}
        };


        int width = 400, height = 300;

        // TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
        // into integer pixels
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);

        Graphics2D ig2 = bi.createGraphics();
        ig2.setBackground(Color.WHITE);




        Font font = new Font("Arial", Font.PLAIN, 18);
        ig2.setFont(font);


        FontRenderContext frc = ig2.getFontRenderContext();



        System.out.println("Transform Type: " + frc.getTransformType());

        System.out.println("Transform: " + frc.getTransform());

        System.out.println("Anti- Aliasing: " + frc.getAntiAliasingHint());

        String message = "Cantaloupemelone weissfleischig hell, mit Kernen!";

        FontMetrics fontMetrics = ig2.getFontMetrics();
        int stringWidth = fontMetrics.stringWidth(message);
        int stringHeight = fontMetrics.getAscent();
     //   ig2.setPaint(Color.black);

        ig2.drawString(message, 10,30);

        message = "Imazalil, Theiabendazol und orthophenylphenol";
        ig2.drawString(message, 10,60);

        message = "gleichmabig feucht halten, Staunsse vermiden";
        ig2.drawString(message, 10,90);


        WritableRaster raster = bi.getRaster();
             // Put the pixels on the raster. Note that only values 0 and 1 are used for the pixels.
             // You could even use other values: in this type of image, even values are black and odd
             // values are white.
             for(int h=0;h<height;h++)
               for(int w=0;w<width;w++){
                  int iVal =  raster.getSample(w, h, 0);

                  if(iVal == 0) raster.setSample(w,h,0,1);
                  else
                      raster.setSample(w,h,0,0);

               }




       ImageIO.write(bi, "BMP", new File("D:\\project\\Java\\yourImageName_w.BMP"));



    }
}
导入java.awt.Canvas;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Font;
导入java.awt.FontMetrics;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.Image;
导入java.awt.RenderingHints;
导入java.awt.event.WindowAdapter;
导入java.awt.event.WindowEvent;
导入java.awt.event.WindowListener;
导入java.awt.font.FontRenderContext;
导入java.awt.font.TextLayout;
导入java.awt.geom.AffineTransform;
导入java.awt.image.buffereImage;
导入java.awt.image.WritableRaster;
导入java.io.File;
导入java.io.IOException;
导入javax.imageio.imageio;
公共类TimesB扩展画布{
私有图像img;
公共时间b(){
挫折地面(颜色:白色);
}
公共静态void main(字符串s[])引发IOException{
WindowListener l=新的WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowClosed(WindowEvent e){System.exit(0);}
};
内部宽度=400,高度=300;
//TYPE_INT_ARGB指定图像格式:8位RGBA压缩
//转换为整数像素
BuffereImage bi=新的BuffereImage(宽度、高度、BuffereImage.TYPE_BYTE_BINARY);
Graphics2D ig2=bi.createGraphics();
ig2.立根背景(颜色:白色);
Font=新字体(“Arial”,Font.PLAIN,18);
ig2.setFont(字体);
FontRenderContext frc=ig2.getFontRenderContext();
System.out.println(“转换类型:+frc.getTransformType());
System.out.println(“Transform:+frc.getTransform());
System.out.println(“反走样:+frc.getAntialasinghint());
String message=“哈密瓜梅隆-维斯弗莱希地狱,麻省理工学院-科宁!”;
FontMetrics FontMetrics=ig2.getFontMetrics();
int stringWidth=fontMetrics.stringWidth(消息);
int stringHeight=fontMetrics.getAscent();
//ig2.setPaint(颜色:黑色);
ig2.抽绳(信息,10,30);
message=“伊马扎利、噻吩达唑和邻苯苯酚”;
ig2.抽绳(信息,10,60);
message=“gleichmabig feucht halten,Staunsse vermiden”;
ig2.抽绳(信息,10,90);
WritableRaster raster=bi.getRaster();
//将像素放在光栅上。请注意,像素仅使用值0和1。
//您甚至可以使用其他值:在这种类型的图像中,偶数值是黑色和奇数
//值为白色。

对于(inth=0;h我使用fontconfig infinality在Linux中具有更好的字体呈现。 此配置还改进了浏览器字体呈现

sudo添加apt存储库ppa:no1wantdthisname/ppa 更新源 升级 sudo apt get install fontconfig infinality

您在此处有更多信息:


传统96dpi屏幕的像素密度太低,无法准确绘制复杂的小图形,如字母(CJK字形更糟糕)

因此,在此类屏幕上绘制文本是一种折衷:

  • 你想要以glypĥ失真和失真为代价的高对比度文本吗 雕文设计的屠宰

  • 您是否接受一些有助于平滑形状(亚像素定位)的彩色条纹

  • 对于一种字体大小,您是否希望您的文本运行完全平衡 更改字体大小时非线性重新调整大小的成本

  • 你想要一个可以处理任何字体的文本引擎,还是一个文本引擎 发动机严重依赖仅在某些情况下存在的特殊规则 字体

  • 您是否积极地针对特定像素密度进行优化,但代价是在任何密度不同的屏幕上进行降级渲染,并且无法过渡到其他硬件

  • 您是否优化每个字形的对比度(将笔杆移向像素线)或尝试保留笔杆的位置(有利于流动文本和任何形成连字的字形组合)

这些问题都没有“好”的答案(还有许多其他问题),只有妥协,不同的系统会做出不同的妥协

为了“随处运行”,SUN过去常常在JVM中包含自己专有的字体渲染器,尽管最近的Java运行时倾向于使用system one

Arial是一个特例,因为它在Microsoft的妥协历史很长。它被设计用来解决Windows文本呈现问题,而Windows文本呈现被设计用来隐藏Arial设计问题

Windows历来严重偏向于“高对比度、高失真、非线性调整大小、特殊规则、仅96dpi”选项。因此,Windows用户倾向于发现任何非Windows字体呈现模糊。而非Windows用户倾向于发现Windows文本呈现扭曲和丑陋

OSX做出了不同的选择。苹果在设计界占有很高的市场份额,因此使计算机文本形状更接近纸上的形状(高密度介质,无形状失真)比更高的对比度(但形状保真度较低)更重要而且设计社区使用了很多不同的字体,苹果不能像微软那样对少数字体进行特殊处理。这也是highdpi对苹果来说比较容易的原因之一(相对而言)

Linux还制造了其他字体。主要是为了充分利用任何字体,因为它不能委托像苹果或微软这样的特别调整的字体集。(而且Linux有大量的可调参数,使它像Windows、OSX或其他东西一样)。而且因为它有大量的可调参数,文本堆栈希望应用程序设置它们(通常是继承的)