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

时间:2015-02-20 11:29:33

标签: java graphics fonts centos

我有一段java代码,它在缓冲区上绘制文本并将其保存为单色BMP。我在Windows 7和CentOS 6.3上执行了该程序。

使用的字体是arial。 Windows中生成的图像清晰,字符均匀呈现。为什么在Cent OS上,角色很薄,看起来像平台未命中渲染一些像素。

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,即使与C ++一起使用的freetype库也会产生相同的输出。

是否因为底层图形层?怎么修这个? 如何使Linux字体渲染与Windows一样好?

**我无法附加输出,因为我需要10个声望!!

2 个答案:

答案 0 :(得分:4)

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

因此,在这些屏幕上绘制文字是一种妥协:

  • 你想要高对比度的文字,代价是glypĥ失真和 屠杀字形设计?

  • 你接受一些彩色边纹,这有助于平滑形状(亚像素定位)吗?

  • 你更喜欢你的文本运行是完全平衡的,对于一个字体大小,at 更改字体大小时非线性重新调整大小的成本?

  • 您想要一个能处理任何字体或文本的文本引擎吗? 引擎严重依赖于某些特殊规则 字体?

  • 您是否积极优化特定像素密度,代价是密度不同且无法转换到其他硬件的任何屏幕上的渲染性能下降?

  • 你是否优化了每个字形的对比度(将茎移向像素线)或尝试保留茎的定位(适用于流动的文本和任何形成连字的字形组合)?

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

要“到处运行”,SUN过去常常在JVM中包含自己的专有字体渲染器,尽管最近的Java运行时倾向于使用系统。

Arial是一个特例,因为它有很长的微软妥协历史。它旨在解决Windows文本呈现问题,Windows文本呈现旨在隐藏Arial设计问题。

Windows在历史上一直偏向于“高对比度,高失真,非线性调整大小,特殊规则,仅96dpi”的选择。因此Windows用户倾向于发现任何非Windows字体渲染模糊。虽然非Windows用户倾向于发现Windows文本呈现失真和丑陋。

OSX做出了不同的选择。 Apple在设计社区中占有很高的市场份额,因此使计算机文本形状更接近纸张上的形状(高密度介质,没有形状失真),更重要的是更高的对比度(但更低的形状保真度)。设计社区使用了大量不同的字体,Apple无法像微软这样的少数几种字体。这就是为什么highdpi很容易为Apple(相对而言)。

Linux还有其他人。主要是为了充分利用任何字体,因为它无法调试像Apple或Microsoft这样经过特殊调整的设置。 (并且Linux有大量的可调参数,可以像Windows一样使用OSX,或者像其他东西一样)。并且因为它有大量的可调参数,所以文本堆栈需要应用程序设置它们(通常从GUI环境继承)。当您在无头模式下使用freetype(需要在代码中设置可调参数)时,或者当您使用Java时,这是一个问题(除非我错了,JVM仍然没有设置这些可调参数,它取决于DE为它设置它们,或者在显式的jvm标志上。)

Android继承自Linux,这就是为什么它可以在没有特殊问题的情况下将系统字体从版本更改为版本。智能手机屏幕的高像素密度也有帮助。

但民意调查反复表明,任何计算机用户都会对其常用系统的文本渲染感到最舒服,会更喜欢他常用系统的字体,并会讨厌其他字体和其他类型的文字渲染(并强迫他重复在几个月内使用另一种妥协,并且偏好将改变)。目前没有字体渲染比其他字体渲染更好或更差。舒适的关键在于大脑解码形状的速度。大脑会自动训练它日复一日的文本。

因此,在Windows上使用Apple文本呈现的Apple软件遭到强烈反对,Linux上的Windows模拟软件也遭到强烈反对。

呈现文本的“好方法”是让用户的系统以他们习惯的方式呈现它。 “糟糕”的方式是尝试重现你的习惯。

它应该随着高dpi屏幕而改变,因为它们承诺使像素网格适合文本扭​​曲和妥协的根源消失。但是人们仍然会讨厌他们不习惯的字体(小剂量,标题或其他有限效果除外)。最可能的长期效果将是屏幕衬线字体的复兴。 Serif字体在低密度屏幕上很糟糕,但人们似乎更喜欢它们在高密度媒体上,如印刷书籍。

在位图上预渲染文本时,您还可以通过增加大小,然后缩小位图来避免大多数系统渲染工件。许多系统文本渲染魔法都调到了本地屏幕,并且无论如何都不会按原样转换到另一个屏幕。

答案 1 :(得分:0)

我使用fontconfig-infinality来更好地使用Linux进行字体渲染。 此配置还改进了浏览器字体呈现。

sudo add-apt-repository ppa:no1wantdthisname / ppa sudo apt-get update sudo apt-get升级 sudo apt-get install fontconfig-infinality

您在这里有更多信息:

http://www.webupd8.org/2013/06/better-font-rendering-in-linux-with.html