为什么Windows和Linux(java)上的字体渲染有所不同

Gur*_*uru 4 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"));



    }
}
Run Code Online (Sandbox Code Playgroud)

这不仅适用于Java,甚至与C ++一起使用的freetype库也会产生相同的输出。

是因为底层的图形层吗?如何解决?如何使Linux字体渲染效果与Windows一样好?

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

nim*_*nim 5

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

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

  • 您是否希望以glyp为代价的高对比度文本?字形设计的失真和分割?

  • 您接受一些颜色边缘化,这将有助于平滑形状(子像素定位)吗?

  • 您是否希望一种字体大小的文本运行完全平衡,以改变字体大小时非线性调整大小为代价?

  • 您要使用可处理任何字体的文本引擎,还是要严重依赖仅在某些字体中存在的特殊规则的文本引擎?

  • 您是否会针对特定的像素密度进行积极的优化,以降低任何密度不同的屏幕上的渲染质量,并且无法过渡到其他硬件为代价?

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

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

为了“在任何地方运行”,SUN过去在JVM中包括自己的专有字体渲染器,尽管最近的Java运行时倾向于使用系统。

Arial由于其长期的Microsoft折衷方案而成为特殊情况。它旨在解决Windows文本呈现问题,而Windows文本呈现旨在隐藏Arial设计问题。

Windows历史上一直偏重于“高对比度,高失真,非线性调整大小,特殊规则,仅96dpi”选择。因此,Windows用户倾向于发现任何非Windows字体渲染模糊的问题。非Windows用户往往会发现Windows文本渲染失真且难看。

OSX做出了不同的选择。苹果在设计社区中占有较高的市场份额,因此使计算机文本形状更接近纸上的形状(高密度介质,无形状失真)比获得较高的对比度(但降低形状保真度)更为重要。设计社区使用了许多不同的字体,Apple不能像Microsoft这样的特殊字体。这是高dpi对苹果而言比较容易的原因之一。

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

Android是从Linux继承而来的,这就是为什么它可以在不同版本之间更改系统字体而没有特殊问题的原因。智能手机屏幕的高像素密度会有所帮助。

但是民意调查一再表明,任何计算机用户都将最习惯于其惯用系统的文本呈现,会偏爱其惯用系统的字体,并且讨厌其他字体和其他类型的文本呈现(并迫使他反复使用另一种折衷方案几个月后,偏好设置会发生变化)。当前没有一种字体渲染比其他字体更好或更差。对于舒适而言,重要的是大脑解码形状的速度。大脑会日复一日地看到自己的文字进行自我训练。

因此,在Windows上使用Apple文本呈现的Apple软件遭到了强烈的拒绝,就像Windows在Linux上模拟软件一样。

呈现文本的“好方法”是让您的用户的系统以习惯的方式呈现文本。“坏”的方法是尝试重现您的习惯。

它应该随着高dpi的屏幕而改变,因为它们保证使像素网格拟合成为文本失真和折衷的根源。但是,人们仍然会讨厌暴露于他们不习惯使用的字体(除非是小剂量,否则会出现标题或其他有限效果)。最有可能的长期影响是屏幕衬线字体的复兴。衬线字体在低密度屏幕上非常糟糕,但是人们似乎更喜欢在高密度媒体(例如印刷书籍)上使用它们。

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