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



我有一段java代码,它在缓冲区上绘制文本并将其保存为单色BMP。我在Windows7和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个信誉!!

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

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

  • 你想要以glypĥ失真为代价的高对比度文本吗屠杀字形设计?

  • 你接受一些有助于平滑形状(亚像素定位)的彩色流苏吗?

  • 对于一种字体大小,您是否希望文本运行完全平衡当字体大小发生变化时,非线性重新调整大小的成本是多少?

  • 你想要一个可以处理任何字体的文本引擎,还是一个文本严重依赖特殊规则的引擎字体?

  • 你是否会针对特定的像素密度进行积极的优化,而代价是在任何密度不同的屏幕上渲染性能下降,并且无法过渡到其他硬件?

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

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

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

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

Windows在历史上一直严重偏向于"高对比度、高失真、非线性调整大小、特殊规则、仅96dpi"的选择。因此,Windows用户倾向于发现任何非Windows字体呈现都是模糊的。而非Windows用户往往会发现Windows文本呈现失真和丑陋。

OSX做出了不同的选择。苹果在设计界拥有很高的市场份额,因此使计算机文本形状更接近纸上的形状(高密度介质,没有形状失真)比更高的对比度(但形状保真度较低)更重要。设计社区使用了很多不同的字体,苹果公司不能像微软这样为数不多的字体做特例。这就是为什么高dpi对苹果来说很容易(相对而言)。

Linux制造了另外一些。主要是为了充分利用任何字体,因为它无法委托像苹果或微软这样经过特殊调整的字体。(Linux有大量的可调程序,可以让它像Windows、OSX或其他东西一样)。由于它有大量可调内容,文本堆栈希望应用程序设置它们(通常从GUI环境继承)。当您在无头模式下使用freetype时(需要在代码中设置可调值),或者当您使用Java时(除非我错了,否则JVM仍然没有设置这些可调值,这取决于DE为其设置这些值,或者取决于显式JVM标志),这都是一个问题。

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

但民意调查一再显示,任何计算机用户都会对其常用系统的文本呈现感到最舒服,更喜欢其常用系统中的字体,并讨厌其他字体和其他类型的文本呈现(并迫使他在几个月内反复使用另一种折衷方案,偏好会发生变化)。当前没有一种字体渲染比其他字体渲染更好或更差。对于舒适来说,重要的是大脑解码形状的速度。大脑通过日复一日看到的文本进行自我训练。

因此,在Windows上使用苹果文本渲染的苹果软件遭到了强烈的拒绝,在Linux等上使用Windows模拟软件也是如此

呈现文本的"好"方法是让用户的系统按照他们习惯的方式呈现文本。"坏"方法是尝试重现你的习惯。

它应该随着高dpi屏幕而改变,因为它们承诺让像素网格适应文本失真和妥协的根源。但人们仍然会讨厌接触他们不习惯的字体(除了小剂量、页眉或其他有限效果)。最可能的长期影响将是屏幕上衬线字体的复兴。Serif字体在低密度屏幕上很糟糕,但人们似乎更喜欢在印刷书籍等高密度介质上使用。

在位图上预渲染文本时,还可以通过增大位图大小,然后缩小位图来避免大多数系统渲染瑕疵。许多系统文本渲染魔法都被调整到本地屏幕上,无论如何都不会像原来那样转换到另一个屏幕上。

我使用fontconfig infinality在Linux中实现更好的字体渲染。此配置还改进了浏览器的字体渲染。

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

您在这里有更多信息:

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

相关内容

  • 没有找到相关文章

最新更新