taohe, Author at Shajisoft中文版 https://shajisoft.com/shajisoft_wp/cn/author/taohe/ 一个关于简单、实用工具的网站 Sun, 08 Apr 2018 13:02:09 +0000 zh-Hans hourly 1 https://wordpress.org/?v=6.7 在基于ARM(armv5tel)的Linux编译安装rtorrent 0.9.6 https://shajisoft.com/shajisoft_wp/cn/build-rtorrent-v0-9-6-for-linux-on-arm-armv5tel-with-ssl-and-tlsv1-2/ https://shajisoft.com/shajisoft_wp/cn/build-rtorrent-v0-9-6-for-linux-on-arm-armv5tel-with-ssl-and-tlsv1-2/#respond Sun, 08 Apr 2018 12:41:09 +0000 http://shajisoft.com/shajisoft_wp/cn/?p=200 我平时使用的网络文件存储设备是个服役好几年的 Buffalo Linkstation Live。该系统上安装、 […]

The post 在基于ARM(armv5tel)的Linux编译安装rtorrent 0.9.6 appeared first on Shajisoft中文版.

]]>
在NAS(armv5tel)上运行rtorrent 0.9.6

我平时使用的网络文件存储设备是个服役好几年的 Buffalo Linkstation Live。该系统上安装、配置了 Optware。可惜Optware 软件仓库里只提供 rtorrent v0.8.1。这个版本并不支持TLSv1.2,所以无法连接强制使用 TLS v1.2 的HTTPS 服务器。这个帖子介绍如何在上述系统上编译、安装 rtorrent 0.9.6 的大概步骤。编译后的 rtorrent 0.9.6 将支持 TLS v1.2。

前言

这个帖子介绍了如何在NAS上编译、安装rtorrent 0.9.6的大致步骤。假设该系统已经有软件编译工具。

具体来说,我们需要编译如下一些软件包

rtorrent支持其它工具通过XML-RPC协议与之通讯。由于我用不到相应的功能,所以我在编译rtorrent的时候没有包含和XML-RPC相关的代码。

编译步骤

在下面的编译示例中,软件的安装路径都在/opt/local下面的各个子目录中。

automake

tar zxvf automake-1.16.tar.gz
cd automake-1.16
mkdir mybuild
cd mybuild
../configure --prefix=/opt/local
make
# as root
make install

libz

进入zlib-1.2.11.tar.gz所在的子目录

tar zxvf zlib-1.2.11.tar.gz
cd zlib-1.2.11
mkdir mybuild
cd mybuild
../configure  --prefix=/opt/local
make

# as root
make install

OpenSSL

进入openssl-1.1.0g.tar.gz所在的子目录

tar zxvf openssl-1.1.0h.tar.gz
cd openssl-1.1.0h
mkdir mybuild
cd mybuild
../config -Wl,--enable-new-dtags --prefix=/opt/local/ssl --openssldir=/opt/local/ssl enable-egd
make

# as root
make install

注意:安装路径的根目录是/opt/local/ssl。同时需要在配置时加上“enable-egd”,要不然,编译curl时会报错。

curl

进入curl-7.59.0.tar.gz所在的目录

tar zxvf curl-7.59.0.tar.gz
cd curl-7.59.0
mkdir mybuild
cd mybuild
PKG_CONFIG_PATH=/opt/local/ssl/lib/pkgconfig ../configure --prefix=/opt/local --with-ssl=/opt/local/ssl --with-libssl-prefix=/opt/local/ssl
make

# as root
make install

libtorrent

进入libtorrent-0.13.6.tar.gz所在的目录

tar zxvf libtorrent-0.13.6.tar.gz
cd libtorrent-0.13.6
mkdir mybuild
cd mybuild
PKG_CONFIG_PATH="/opt/local/ssl/lib/pkgconfig:/opt/local/lib/pkgconfig" ../configure --prefix=/opt/local
make

# as root
make install

这一步会遇到一些麻烦。编译安装时会出现类似于下面所示的错误

undefined reference to '__sync_sub_and_fetch_4'

主要原因是所用的编译器gcc 4.2.3版本太旧,而libtorrent代码中用到了一些和原子操作有关的gcc内部函数,只有在gcc 4.3及以后版本中才有。一般来说有两种解决办法:一是换用较新版本的gcc,这需要编译安装另一版本的gcc;再一个解决办法就是找到新版gcc中关于原子操作函数的代码,这需要找到一个文件(linux-atomic.c),编译后使用。在这里这里能获得更多详情。

另外,我们其实可以在编译libtorrent时通过使用“-disable-instrumentation”配置选项来避免编译使用到有问题函数的代码。根据我自己的测试,这样虽然能够编译安装libtorrent,但接下来在编译rtorrent仍然会出错。所以我还是采用了上面提到的第二种方案,也就是,使用linux-atomic.c。

接下来,我们切换到另外一个工作目录,比如~/downloads/linux-atomic

wget -O linux-atomic.c "http://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libgcc/config/arm/linux-atomic.c;hb=master"
libtool --tag=CC --mode=compile gcc -g -O2 -MT linux-atomic.lo -MD -MP -MF linux-atomic.Tpo -c -o linux-atomic.lo linux-atomic.c
libtool --tag=CC --mode=link gcc -g -O2 -o liblinux-atomic.la linux-atomic.lo

切换回libtorrent-0.13.6目录,在我们开始编译之前,我们需要再做一件事,那就是修改两个源文件,这也是我测试出错后才知道的。需要修改的文件分别是src/utils/instrumentation.h和src/utils/instrumentation.cc。具体需要修改的是:把所有的int64_t换成int32_t,再把所有的PRIi64换成PRIi32。做完这些改动之后,回到libtorrent-3.6/mybuild。如果之前运行过configure命令,记得首先运行“make distclean”,然后才执行如下命令

# Assume linux-atomic.c is in /home/taohe/downloads/linux-atomic
PKG_CONFIG_PATH="/opt/local/ssl/lib/pkgconfig:/opt/local/lib/pkgconfig" ../configure --prefix=/opt/local LDFLAGS="-L/home/taohe/downloads/linux-atomic" LIBS="-llinux-atomic"
make 

# as root 
make install

rtorrent

终于要编译rtorrent主程序了。不过在正式操作之前,首先确保系统上有ncurses的头文件。如果是用Optware,我们需要安装”ncurses-dev”以及”ncursesw-dev”两个包(使用ipkg install命令)

进入rtorrent-0.9.6.tar.gz所在的目录

# Assume linux-atomic.c is in /home/taohe/downloads/linux-atomic 
tar zxvf rtorrent-0.9.6.tar.gz
cd rtorrent-0.9.6
mkdir mybuild
cd mybuild
PKG_CONFIG_PATH="/opt/local/lib/pkgconfig:/opt/local/ssl/lib/pkgconfig" ../configure --prefix=/opt/local LDFLAGS="-L/home/taohe/downloads/linux-atomic" LIBS="-llinux-atomic"
make

# as root
make install

搞定! 执行/opt/local/bin/rtorrent,或者把/opt/local/bin加入$PATH,就能启动刚刚编译好的rtorrent 0.9.6。这样编译的rtorrent可以连接强制TLSv1.2的HTTPS服务器。请注意rtorrent 0.9.x的配置文件和旧版0.8.x的不兼容,关于rtorrent 0.9.6的配置以及命令等相关信息,请参考rtorrent wiki网页。

下载

在NAS上编译以上软件包非常耗时。所以我把我的NAS上的/opt/local打包后供有需要的朋友试用。打包后的文件可在本站下载。如果硬件兼容,这些编译好的可执行文件极有可能可以直接运行。

The post 在基于ARM(armv5tel)的Linux编译安装rtorrent 0.9.6 appeared first on Shajisoft中文版.

]]>
https://shajisoft.com/shajisoft_wp/cn/build-rtorrent-v0-9-6-for-linux-on-arm-armv5tel-with-ssl-and-tlsv1-2/feed/ 0
为什么同一个截屏图形会被不同的工具保存成不一样大小的PNG https://shajisoft.com/shajisoft_wp/cn/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%90%8c%e4%b8%80%e4%b8%aa%e6%88%aa%e5%b1%8f%e5%9b%be%e5%bd%a2%e4%bc%9a%e8%a2%ab%e4%b8%8d%e5%90%8c%e7%9a%84%e5%b7%a5%e5%85%b7%e4%bf%9d%e5%ad%98%e6%88%90%e4%b8%8d%e4%b8%80/ https://shajisoft.com/shajisoft_wp/cn/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%90%8c%e4%b8%80%e4%b8%aa%e6%88%aa%e5%b1%8f%e5%9b%be%e5%bd%a2%e4%bc%9a%e8%a2%ab%e4%b8%8d%e5%90%8c%e7%9a%84%e5%b7%a5%e5%85%b7%e4%bf%9d%e5%ad%98%e6%88%90%e4%b8%8d%e4%b8%80/#respond Sun, 11 Oct 2015 22:03:14 +0000 http://shajisoft.com/shajisoft_wp/cn/?p=165 使用不同的软件工具,比如Gimp或者Windows Paint,保存同样的屏幕截图的时候,产生的PNG文件的大 […]

The post 为什么同一个截屏图形会被不同的工具保存成不一样大小的PNG appeared first on Shajisoft中文版.

]]>
使用不同的软件工具,比如Gimp或者Windows Paint,保存同样的屏幕截图的时候,产生的PNG文件的大小会不同。在这个帖子里,我将用Python脚本尝试解析PNG文件,同时了解造成前面所说差异的原因。

简介

PNG是一种在Internet上常用的图形格式。我习惯于把屏幕截图保存为PNG格式。和普通的照片比起来,软件工具的屏幕截图用到的颜色数目会更少,所以我们可以通过数据压缩技术得到比较小的图形文件。另外,PNG是个开源的图形格式。基于这些原因,我更倾向于使用PNG格式来保存软件工具的屏幕截图。

说老实话,过去我很少注意软件产生的PNG文件的大小,直到最近,当我需要给个人网站准备图形文件的时候,为了更好的网页浏览效果,我才开始注意各种PNG文件的大小。一般来说,我主要使用Gimp和Windows Paint工具来创建软件工具的屏幕截图。前者Gimp是个强大的免费图形处理工具软件,用它来生成屏幕截图真的有点大材小用的感觉。WindowsPaint是Windows自带的图形工具。从Windows 7起,下Windows系统自带的Paint工具支持一些简单的图形编辑功能,勉强可以用来创建屏幕截图。在使用这些工具时,我假设这些工具可以生成最优的PNG图形文件。可是直到最近,我才发现,对于同样的屏幕截图,Gimp和Windows Paint生成的PNG文件大小并不一样。而且,尽管Paint并没有和PNG文件相关的选项,可是它仍然能生成比Gimp中选择最高压缩比的选项所产生的PNG还要小的文件。处于好奇,我尝试理解造成这种区别的原因。在这个帖子里,我将分享我从这个过程中学到的东东。

PNG 格式

这里,PNG指的是Portable Network Graphics。它是一个位图格式。最初,PNG是以作为GIF格式的替代品为设计、开发目标的。如想了解更多有关PNG格式,请移步相关Wikipedia网页。

简单来说,PNG文件的开始包含8字节的头信息,然后就是各种具有特别意义的数据块。每个数据块包含如下四个部分:

  1. 数据块的长度 – 4 字节
  2. 数据块的类型 – 4 字节
  3. 数据块数据 – 前面提到的数据块长度指定的大小
  4. CRC – 4 字节

也就是说,如果一个数据块的前四个字节是个数值为8192的整数,它表明数据块中的数据大小为8192字节。该数据块的大小即为 4+4+8192+4=8204 字节.

数据块的第二个部分(从第五到第八字节)指明了该数据块的类别。它通常是区分大小写的ASCII文本。一个PNG文件至少包含如下几个关键的数据块:

  1. IHDR: 必须是文件中的第一个数据块,它记录图形的包含宽、高等元信息。
  2. PLTE or sRGB: 图形所用到的所有颜色
  3. IDAT: 图形数据
  4. IEND: 图形结束的地方

一个PNG文件可以包含多个IDAT数据块。解析PNG文件的时候,所有的IDAT块需要按照它们在文件中存储的顺序依次连接起来,然后才解压缩。

下面的截图演示了一个PNG文件在TotalCommander的Lister工具中以十六进制选项查看的例子:

以十六进制方式查看一个PNG图形文件
十六进制显示的PNG文件

使用 Python 解析 PNG 文件

首先我们创建一个描述PNG文件中数据块的类:

class Chunk(object):

    '''Definition of a chunk contained in a PNG file '''

    def __init__(self, buf):
        '''TODO: to be defined1. '''
        self.__length = 0
        self.__type = 0
        self.__data = []
        self.__crc = 0
        self.__size = 0     # The total size of the chunk in bytes

        if buf:
            self.load(buf)

    def load(self, buf):
        '''Load the chunk from the given buffer.

        @param buf List of bytes read from the PNG file
        @return: None

        '''
        length_buf = binascii.hexlify(buf[:4])
        #self.__length = int(''.join(length_buf), 16)
        self.__length = int(length_buf, 16)

        fmt = '4c'
        #self.__type = ''.join(struct.unpack(fmt, ''.join(buf[4:8])))
        self.__type = buf[4:8].decode()

        end_data = 8+self.__length
        self.__data = buf[8:end_data]
        
        buf = buf[end_data:]
        crc_bytes = binascii.hexlify(buf[:4])
        #self.__crc = int(''.join(crc_bytes), 16)
        self.__crc = int(crc_bytes, 16)

        self.__size = 8 + self.__length + 4;

    def totalSize(self):
        '''TODO: Returns the total size of the chunk in bytes.
        @return: TODO

        '''
        return self.__size

    def type(self):
        '''TODO: Docstring for type.
        @return: TODO

        '''
        return self.__type

    def data(self):
        '''TODO: Docstring for data.
        @return: TODO

        '''
        return self.__data

    def length(self):
        '''TODO: Docstring for length.
        @return: TODO

        '''
        return self.__length

 

 

解析PNG文件的时候,首先打开该文件,读取所有内容到内存,然后解析文件的头信息以及数据块:

class PNG(object):

    '''class for a PNG file. '''

    def __init__(self, file_path):
        '''TODO: to be defined1. '''
        self.__fileName = file_path
        self.__file = None
        self.__fobj = None
        self.size = [0, 0]
        self.__chunks = []  # List of chunks
        self.__width = 0
        self.__height = 0
        self.__bitDepth = 0
        self.__colorType = 0
        self.__cmpMtd = 0
        self.__fltMtd = 0
        self.__itlMtd = 0
        self.__totalIDAT = 0

        if file_path:
            self.readFile(file_path)
            self.__file = file_path
    
    def loadHeader(self, buf):
        '''TODO: Docstring for loadHeader.

        @param buf Byte buffer read from the import file
        @return: TODO

        '''
        pass

    def readFile(self, file_path):
        '''TODO: Docstring for readFile.

        @param file_path Full path to the png file
        @return: True if successful, False otherwise

        '''
        
        if file_path is None and self.__file is None:
          logger.info("File name is empty. Nothing to load!")
          return
          
        if file_path is not None:
          self.__file = file_path
        
        # Open the file for reading
        self.__fobj = open( self.__file, 'rb')

        fsize = os.path.getsize( file_path )
        # map the file into memory
        fno = self.__fobj.fileno()
        data = mmap.mmap( fno, fsize, access=mmap.ACCESS_READ )

        fmt = '8c'
        header = struct.unpack( fmt, data[:8] )

        # Get the header information
        #self.loadHeader() 
        #logger.debug("Header: %s" %  header )
        
        #working buffer   
        buf = data[8:]
        ihdr = Chunk(buf)
        self.parseIHDR(ihdr.data() )

        chunk_size = ihdr.totalSize()
        self.__chunks = [] 
        self.__chunks.append(ihdr)
        while len(buf) > chunk_size:
            buf = buf[chunk_size:]
            ck = Chunk(buf)
            chunk_size = ck.totalSize()
            self.__chunks.append(ck)
       
        self.parseIDAT()


        ### close the file
        data.close()
        self.__fobj.close() 
...

一个PNG文件通常包含至少一个IDAT数据块。IDAT数据块包含了压缩后的图形数据。图形数据是个常见的矩形像素数组。数组的每个元素指明了相关的颜色。PNG图形文件中常见的颜色类型有三种:

  1. 灰度像素。最小像素大小:1 位
  2. 颜色索引像素。最小像素大小:1 位
  3. 真彩色像素:最小像素大小:24 位

另外,每个像素还可以包含关于透明颜色的信息。这个信息通常是8位,所以一个带有透明信息的真彩色像素大小为4字节。

PNG文件中的图形数据是从上到下依次排列的。每行的像素数据从左到右依次排列,形成一条扫描线。每条扫描线都包含两部分:第一个字节指明了所用的滤波方法,接下来就是从左到右依次排列的图形数据。所有的扫描线最后用和zlib兼容的DEFLATE算法压缩。因为PNG文件所用的数据压缩算法和zlib兼容,所以我们可以使用Python的zlib模块来解压缩PNG图形:

def testCompress(self):
        idat_data = b''
        self.__totalIDAT = 0
        for i in range(1, len(self.__chunks)):
            if self.__chunks[i].type() == 'IDAT':
                idat_data += self.__chunks[i].data() 
       img_data = zlib.decompress( idat_data ) 
       ...

 

如想了解更多关于zlib压缩文件的格式,请移步zlib RFC网页 简而言之,zlib压缩后的数据在开头的地方有两个字节代表了和压缩算法有关的参数信息。如果以十六进制方式查看zlib压缩后的数据的时候,首两个字节看起来会像”78 da”。从这两个字节,我们可以猜出数据压缩时所用到的某些参数。但对于一些关键参数比如压缩级别,我们无法得知具体的数值,因为不同的压缩级参数会对应于相同的zlib头信息。为了获得真正的压缩参数,我们可以采取暴力测试的方式,用常见的压缩参数逐一测试。这种测试可以通过一个Python脚本来实现。

其实Python已经有可以解析PNG文件的模块,但是因为我需要测试不同的压缩参数,所以我自己写了一个简单的Python脚本来方便测试。完整的脚本可从这里下载。下载的脚本名为sspng.py。它可以用在Python2.7和3.4
环境中。运行该脚本时需要给定一个PNG文件名。脚本运行后会显示该PNG图形的基本信息,以及压缩信息。

Exampels

下面我们以TotalCommander 8.52a在Windows 10 x64上的屏幕截图为例。屏幕截图如下图所示

TotalCommander 8.52a在Windows 10 x64上的屏幕截图
TotalCommander 8.52a在Windows 10 x64上的屏幕截图

为了产生如上的屏幕截图,首先使得TotalCommander显示在桌面的最前端,按下“Alt-PrtScrn”。TotalCommander的截图将会被拷贝到系统的剪贴板上,然后分别把它黏贴到Gimp或者Windows Paint中,然后保存为PNG文件。这里我用的Gimp是最新的开发版本,Paint是系统自带的。在保存PNG文件的时候,Paint并没有任何和PNG相关的选项,而Gimp有包含PNG压缩级别等一些选项。这里全部采用缺省选项。Gimp和Paint产生的PNG文件大小分别是:

  • Paint: 125,149 字节
  • Gimp: 162,688 字节

假设Gimp产生的PNG文件路径为
c:\users\wdong\Pictures\totalcmd-en-gimp.png,我们可以按如下所示运行sspng.py:
 

C:\Users\dongw\Pictures>c:\Python27\python.exe sspng.py totalcmd-en-gimp.png


Information about totalcmd-en-gimp.png
IHDR information:
        Width: 1010
        Height: 793
        Bit depth: 8
        Color type: 2
        Compression method: 0
        Filter method: 0
        Interlace method: 0

 Chunk pHYs: Data length: 9, total size: 21 bytes

 Chunk tIME: Data length: 7, total size: 19 bytes

 Chunk tEXt: Data length: 25, total size: 37 bytes

 Chunk IDAT: IDAT chunk size: 8192 bytes, total IDAT size: 162326 bytes

 Chunk IEND: Data length: 0, total size: 12 bytes
size of img_data = 2403583
zlib header in the PNG file = 78, da
With compression level 9, mem_level 8, strategy 1, zlib.compress gives 162326 bytes

 

数据块中有793条扫描线。图形的真彩色的,也就是说每个像素有三个字节。由于每条扫描线的第一个字节是关于滤波信息的,那么这个IDAT中所包含的图形数据就有(1+1010*3)*793=2403583字节。压缩后的数据总共有162326字节大小,以8192字节的大小分割为多个小块分别储存在多个IDAT数据块中。看起来Gimp 2.9仍然使用标准的zlib压缩算法,因为我们可以通过Python的zlib模块实现和该PNG一样的压缩比

用Windows Paint产生的PNG文件做实验的输出结果如下:

C:\Users\dongw\Pictures>c:\Python27\python.exe sspng.py totalcmd-cn-paint.png


Information about totalcmd-cn-paint.png
IHDR information:
        Width: 1010
        Height: 793
        Bit depth: 8
        Color type: 2
        Compression method: 0
        Filter method: 0
        Interlace method: 0

 Chunk sRGB: Data length: 1, total size: 13 bytes

 Chunk gAMA: Data length: 4, total size: 16 bytes

 Chunk pHYs: Data length: 9, total size: 21 bytes

 Chunk IDAT: IDAT chunk size: 65445 bytes, total IDAT size: 124688 bytes

 Chunk IEND: Data length: 0, total size: 12 bytes
size of img_data = 2403583
zlib header in the PNG file = 78, 5e
With compression level 0, mem_level 1, strategy 0, zlib.compress gives 2427294 bytes
With compression level 1, mem_level 1, strategy 0, zlib.compress gives 176182 bytes
With compression level 2, mem_level 1, strategy 0, zlib.compress gives 160285 bytes
With compression level 3, mem_level 1, strategy 0, zlib.compress gives 146284 bytes
With compression level 4, mem_level 1, strategy 0, zlib.compress gives 134058 bytes
With compression level 5, mem_level 1, strategy 0, zlib.compress gives 125760 bytes
With compression level 6, mem_level 1, strategy 0, zlib.compress gives 117158 bytes
With compression level 7, mem_level 1, strategy 0, zlib.compress gives 116340 bytes
With compression level 8, mem_level 1, strategy 0, zlib.compress gives 113287 bytes
With compression level 9, mem_level 1, strategy 0, zlib.compress gives 111966 bytes
With compression level 0, mem_level 2, strategy 0, zlib.compress gives 2415384 bytes
With compression level 1, mem_level 2, strategy 0, zlib.compress gives 170222 bytes
With compression level 2, mem_level 2, strategy 0, zlib.compress gives 155723 bytes
With compression level 3, mem_level 2, strategy 0, zlib.compress gives 143172 bytes
With compression level 4, mem_level 2, strategy 0, zlib.compress gives 129169 bytes
With compression level 5, mem_level 2, strategy 0, zlib.compress gives 122506 bytes
With compression level 6, mem_level 2, strategy 0, zlib.compress gives 114908 bytes
With compression level 7, mem_level 2, strategy 0, zlib.compress gives 114331 bytes
With compression level 8, mem_level 2, strategy 0, zlib.compress gives 111654 bytes
With compression level 9, mem_level 2, strategy 0, zlib.compress gives 110420 bytes
With compression level 0, mem_level 3, strategy 0, zlib.compress gives 2409474 bytes
With compression level 1, mem_level 3, strategy 0, zlib.compress gives 164668 bytes
With compression level 2, mem_level 3, strategy 0, zlib.compress gives 150928 bytes
With compression level 3, mem_level 3, strategy 0, zlib.compress gives 139918 bytes
With compression level 4, mem_level 3, strategy 0, zlib.compress gives 124791 bytes
With compression level 5, mem_level 3, strategy 0, zlib.compress gives 118426 bytes
With compression level 6, mem_level 3, strategy 0, zlib.compress gives 112056 bytes
With compression level 7, mem_level 3, strategy 0, zlib.compress gives 111606 bytes
With compression level 8, mem_level 3, strategy 0, zlib.compress gives 108879 bytes
With compression level 9, mem_level 3, strategy 0, zlib.compress gives 107891 bytes
With compression level 0, mem_level 4, strategy 0, zlib.compress gives 2406529 bytes
With compression level 1, mem_level 4, strategy 0, zlib.compress gives 161203 bytes
With compression level 2, mem_level 4, strategy 0, zlib.compress gives 148187 bytes
With compression level 3, mem_level 4, strategy 0, zlib.compress gives 137649 bytes
With compression level 4, mem_level 4, strategy 0, zlib.compress gives 121817 bytes
With compression level 5, mem_level 4, strategy 0, zlib.compress gives 115812 bytes
With compression level 6, mem_level 4, strategy 0, zlib.compress gives 110109 bytes
With compression level 7, mem_level 4, strategy 0, zlib.compress gives 109712 bytes
With compression level 8, mem_level 4, strategy 0, zlib.compress gives 107154 bytes
With compression level 9, mem_level 4, strategy 0, zlib.compress gives 106122 bytes
With compression level 0, mem_level 5, strategy 0, zlib.compress gives 2405059 bytes
With compression level 1, mem_level 5, strategy 0, zlib.compress gives 159511 bytes
With compression level 2, mem_level 5, strategy 0, zlib.compress gives 146528 bytes
With compression level 3, mem_level 5, strategy 0, zlib.compress gives 136218 bytes
With compression level 4, mem_level 5, strategy 0, zlib.compress gives 120177 bytes
With compression level 5, mem_level 5, strategy 0, zlib.compress gives 114230 bytes
With compression level 6, mem_level 5, strategy 0, zlib.compress gives 108545 bytes
With compression level 7, mem_level 5, strategy 0, zlib.compress gives 108230 bytes
With compression level 8, mem_level 5, strategy 0, zlib.compress gives 105560 bytes
With compression level 9, mem_level 5, strategy 0, zlib.compress gives 104583 bytes
With compression level 0, mem_level 6, strategy 0, zlib.compress gives 2404324 bytes
With compression level 1, mem_level 6, strategy 0, zlib.compress gives 158833 bytes
With compression level 2, mem_level 6, strategy 0, zlib.compress gives 146029 bytes
With compression level 3, mem_level 6, strategy 0, zlib.compress gives 135299 bytes
With compression level 4, mem_level 6, strategy 0, zlib.compress gives 120105 bytes
With compression level 5, mem_level 6, strategy 0, zlib.compress gives 114075 bytes
With compression level 6, mem_level 6, strategy 0, zlib.compress gives 108182 bytes
With compression level 7, mem_level 6, strategy 0, zlib.compress gives 107714 bytes
With compression level 8, mem_level 6, strategy 0, zlib.compress gives 104922 bytes
With compression level 9, mem_level 6, strategy 0, zlib.compress gives 103967 bytes
With compression level 0, mem_level 7, strategy 0, zlib.compress gives 2403959 bytes
With compression level 1, mem_level 7, strategy 0, zlib.compress gives 157836 bytes
With compression level 2, mem_level 7, strategy 0, zlib.compress gives 145142 bytes
With compression level 3, mem_level 7, strategy 0, zlib.compress gives 134822 bytes
With compression level 4, mem_level 7, strategy 0, zlib.compress gives 119127 bytes
With compression level 5, mem_level 7, strategy 0, zlib.compress gives 113359 bytes
With compression level 6, mem_level 7, strategy 0, zlib.compress gives 107632 bytes
With compression level 7, mem_level 7, strategy 0, zlib.compress gives 107275 bytes
With compression level 8, mem_level 7, strategy 0, zlib.compress gives 104603 bytes
With compression level 9, mem_level 7, strategy 0, zlib.compress gives 103742 bytes
With compression level 0, mem_level 8, strategy 0, zlib.compress gives 2403954 bytes
With compression level 1, mem_level 8, strategy 0, zlib.compress gives 157680 bytes
With compression level 2, mem_level 8, strategy 0, zlib.compress gives 145059 bytes
With compression level 3, mem_level 8, strategy 0, zlib.compress gives 134853 bytes
With compression level 4, mem_level 8, strategy 0, zlib.compress gives 118942 bytes
With compression level 5, mem_level 8, strategy 0, zlib.compress gives 113425 bytes
With compression level 6, mem_level 8, strategy 0, zlib.compress gives 107872 bytes
With compression level 7, mem_level 8, strategy 0, zlib.compress gives 107516 bytes
With compression level 8, mem_level 8, strategy 0, zlib.compress gives 104837 bytes
With compression level 9, mem_level 8, strategy 0, zlib.compress gives 103848 bytes
With compression level 0, mem_level 9, strategy 0, zlib.compress gives 2403954 bytes
With compression level 1, mem_level 9, strategy 0, zlib.compress gives 158120 bytes
With compression level 2, mem_level 9, strategy 0, zlib.compress gives 145273 bytes
With compression level 3, mem_level 9, strategy 0, zlib.compress gives 134947 bytes
With compression level 4, mem_level 9, strategy 0, zlib.compress gives 119473 bytes
With compression level 5, mem_level 9, strategy 0, zlib.compress gives 114064 bytes
With compression level 6, mem_level 9, strategy 0, zlib.compress gives 108411 bytes
With compression level 7, mem_level 9, strategy 0, zlib.compress gives 108041 bytes
With compression level 8, mem_level 9, strategy 0, zlib.compress gives 105321 bytes
With compression level 9, mem_level 9, strategy 0, zlib.compress gives 104264 bytes
With compression level 0, mem_level 1, strategy 1, zlib.compress gives 2427294 bytes
With compression level 1, mem_level 1, strategy 1, zlib.compress gives 176182 bytes
With compression level 2, mem_level 1, strategy 1, zlib.compress gives 160285 bytes
With compression level 3, mem_level 1, strategy 1, zlib.compress gives 146284 bytes
With compression level 4, mem_level 1, strategy 1, zlib.compress gives 138646 bytes
With compression level 5, mem_level 1, strategy 1, zlib.compress gives 129359 bytes
With compression level 6, mem_level 1, strategy 1, zlib.compress gives 120436 bytes
With compression level 7, mem_level 1, strategy 1, zlib.compress gives 119583 bytes
With compression level 8, mem_level 1, strategy 1, zlib.compress gives 116264 bytes
With compression level 9, mem_level 1, strategy 1, zlib.compress gives 115021 bytes
With compression level 0, mem_level 2, strategy 1, zlib.compress gives 2415384 bytes
With compression level 1, mem_level 2, strategy 1, zlib.compress gives 170222 bytes
With compression level 2, mem_level 2, strategy 1, zlib.compress gives 155723 bytes
With compression level 3, mem_level 2, strategy 1, zlib.compress gives 143172 bytes
With compression level 4, mem_level 2, strategy 1, zlib.compress gives 134176 bytes
With compression level 5, mem_level 2, strategy 1, zlib.compress gives 126207 bytes
With compression level 6, mem_level 2, strategy 1, zlib.compress gives 118319 bytes
With compression level 7, mem_level 2, strategy 1, zlib.compress gives 117738 bytes
With compression level 8, mem_level 2, strategy 1, zlib.compress gives 114529 bytes
With compression level 9, mem_level 2, strategy 1, zlib.compress gives 113488 bytes
With compression level 0, mem_level 3, strategy 1, zlib.compress gives 2409474 bytes
With compression level 1, mem_level 3, strategy 1, zlib.compress gives 164668 bytes
With compression level 2, mem_level 3, strategy 1, zlib.compress gives 150928 bytes
With compression level 3, mem_level 3, strategy 1, zlib.compress gives 139918 bytes
With compression level 4, mem_level 3, strategy 1, zlib.compress gives 128996 bytes
With compression level 5, mem_level 3, strategy 1, zlib.compress gives 121984 bytes
With compression level 6, mem_level 3, strategy 1, zlib.compress gives 115209 bytes
With compression level 7, mem_level 3, strategy 1, zlib.compress gives 114679 bytes
With compression level 8, mem_level 3, strategy 1, zlib.compress gives 111747 bytes
With compression level 9, mem_level 3, strategy 1, zlib.compress gives 110594 bytes
With compression level 0, mem_level 4, strategy 1, zlib.compress gives 2406529 bytes
With compression level 1, mem_level 4, strategy 1, zlib.compress gives 161203 bytes
With compression level 2, mem_level 4, strategy 1, zlib.compress gives 148187 bytes
With compression level 3, mem_level 4, strategy 1, zlib.compress gives 137649 bytes
With compression level 4, mem_level 4, strategy 1, zlib.compress gives 125905 bytes
With compression level 5, mem_level 4, strategy 1, zlib.compress gives 119155 bytes
With compression level 6, mem_level 4, strategy 1, zlib.compress gives 113051 bytes
With compression level 7, mem_level 4, strategy 1, zlib.compress gives 112575 bytes
With compression level 8, mem_level 4, strategy 1, zlib.compress gives 109749 bytes
With compression level 9, mem_level 4, strategy 1, zlib.compress gives 108727 bytes
With compression level 0, mem_level 5, strategy 1, zlib.compress gives 2405059 bytes
With compression level 1, mem_level 5, strategy 1, zlib.compress gives 159511 bytes
With compression level 2, mem_level 5, strategy 1, zlib.compress gives 146528 bytes
With compression level 3, mem_level 5, strategy 1, zlib.compress gives 136218 bytes
With compression level 4, mem_level 5, strategy 1, zlib.compress gives 124186 bytes
With compression level 5, mem_level 5, strategy 1, zlib.compress gives 117731 bytes
With compression level 6, mem_level 5, strategy 1, zlib.compress gives 111589 bytes
With compression level 7, mem_level 5, strategy 1, zlib.compress gives 111112 bytes
With compression level 8, mem_level 5, strategy 1, zlib.compress gives 108285 bytes
With compression level 9, mem_level 5, strategy 1, zlib.compress gives 107157 bytes
With compression level 0, mem_level 6, strategy 1, zlib.compress gives 2404324 bytes
With compression level 1, mem_level 6, strategy 1, zlib.compress gives 158833 bytes
With compression level 2, mem_level 6, strategy 1, zlib.compress gives 146029 bytes
With compression level 3, mem_level 6, strategy 1, zlib.compress gives 135299 bytes
With compression level 4, mem_level 6, strategy 1, zlib.compress gives 123926 bytes
With compression level 5, mem_level 6, strategy 1, zlib.compress gives 117330 bytes
With compression level 6, mem_level 6, strategy 1, zlib.compress gives 111161 bytes
With compression level 7, mem_level 6, strategy 1, zlib.compress gives 110609 bytes
With compression level 8, mem_level 6, strategy 1, zlib.compress gives 107642 bytes
With compression level 9, mem_level 6, strategy 1, zlib.compress gives 106434 bytes
With compression level 0, mem_level 7, strategy 1, zlib.compress gives 2403959 bytes
With compression level 1, mem_level 7, strategy 1, zlib.compress gives 157836 bytes
With compression level 2, mem_level 7, strategy 1, zlib.compress gives 145142 bytes
With compression level 3, mem_level 7, strategy 1, zlib.compress gives 134822 bytes
With compression level 4, mem_level 7, strategy 1, zlib.compress gives 122917 bytes
With compression level 5, mem_level 7, strategy 1, zlib.compress gives 116738 bytes
With compression level 6, mem_level 7, strategy 1, zlib.compress gives 110681 bytes
With compression level 7, mem_level 7, strategy 1, zlib.compress gives 110313 bytes
With compression level 8, mem_level 7, strategy 1, zlib.compress gives 107484 bytes
With compression level 9, mem_level 7, strategy 1, zlib.compress gives 106377 bytes
With compression level 0, mem_level 8, strategy 1, zlib.compress gives 2403954 bytes
With compression level 1, mem_level 8, strategy 1, zlib.compress gives 157680 bytes
With compression level 2, mem_level 8, strategy 1, zlib.compress gives 145059 bytes
With compression level 3, mem_level 8, strategy 1, zlib.compress gives 134853 bytes
With compression level 4, mem_level 8, strategy 1, zlib.compress gives 123086 bytes
With compression level 5, mem_level 8, strategy 1, zlib.compress gives 116643 bytes
With compression level 6, mem_level 8, strategy 1, zlib.compress gives 110820 bytes
With compression level 7, mem_level 8, strategy 1, zlib.compress gives 110508 bytes
With compression level 8, mem_level 8, strategy 1, zlib.compress gives 107777 bytes
With compression level 9, mem_level 8, strategy 1, zlib.compress gives 106770 bytes
With compression level 0, mem_level 9, strategy 1, zlib.compress gives 2403954 bytes
With compression level 1, mem_level 9, strategy 1, zlib.compress gives 158120 bytes
With compression level 2, mem_level 9, strategy 1, zlib.compress gives 145273 bytes
With compression level 3, mem_level 9, strategy 1, zlib.compress gives 134947 bytes
With compression level 4, mem_level 9, strategy 1, zlib.compress gives 123774 bytes
With compression level 5, mem_level 9, strategy 1, zlib.compress gives 117299 bytes
With compression level 6, mem_level 9, strategy 1, zlib.compress gives 111406 bytes
With compression level 7, mem_level 9, strategy 1, zlib.compress gives 111126 bytes
With compression level 8, mem_level 9, strategy 1, zlib.compress gives 108399 bytes
With compression level 9, mem_level 9, strategy 1, zlib.compress gives 107291 bytes

 

这说明我们无法用标准的zlib压缩算法重现该PNG文件中的压缩比。比较以上两次试验结果,我们可以看到如下所示几个关于在Windows 10 x64系统上,Windows Paint和Gimp所产生的PNG文件的不同之处:

  • Gimp以8192字节分割IDAT数据块,而Windows Paint以65445字节来分割
  • Windows 10系统的Paint应该是在压缩图形数据之前进行了某种滤波预处理以优化压缩
  • Windows 10系统的Paint并没有使用最优的压缩参数

使用Gimp 2.8以及Windows 7所带的Paint等做类似实验后发现,这些工具都是使用标准的zlib压缩算法在所产生的PNG中压缩数据的。

优化PNG文件

一般上有如下三种途径优化PNG图形文件:

  1. 使用颜色索引而不是真彩色,这样每个像素在图形数据中会更小
  2. 压缩之前对数据做预处理
  3. 使用压缩比更好的DEFLATE压缩算法实现,比如7-zip以及Google公布的Zopfli都是和zlib兼容的同时又有更高压缩比的DEFLATE算法实现

下面两个连接有更多关于优化PNG文件的信息:

  1. https://zoompf.com/blog/2010/01/top-png-optimizers-dont-use-zlib
  2. http://www.smashingmagazine.com/2009/07/clever-png-optimization-techniques/

The post 为什么同一个截屏图形会被不同的工具保存成不一样大小的PNG appeared first on Shajisoft中文版.

]]>
https://shajisoft.com/shajisoft_wp/cn/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%90%8c%e4%b8%80%e4%b8%aa%e6%88%aa%e5%b1%8f%e5%9b%be%e5%bd%a2%e4%bc%9a%e8%a2%ab%e4%b8%8d%e5%90%8c%e7%9a%84%e5%b7%a5%e5%85%b7%e4%bf%9d%e5%ad%98%e6%88%90%e4%b8%8d%e4%b8%80/feed/ 0
完美解决中文在英文Windows上显示高矮不一的问题 https://shajisoft.com/shajisoft_wp/cn/%e5%ae%8c%e7%be%8e%e8%a7%a3%e5%86%b3%e4%b8%ad%e6%96%87%e5%9c%a8%e8%8b%b1%e6%96%87windows%e4%b8%8a%e6%98%be%e7%a4%ba%e9%ab%98%e7%9f%ae%e4%b8%8d%e4%b8%80%e7%9a%84%e9%97%ae%e9%a2%98/ https://shajisoft.com/shajisoft_wp/cn/%e5%ae%8c%e7%be%8e%e8%a7%a3%e5%86%b3%e4%b8%ad%e6%96%87%e5%9c%a8%e8%8b%b1%e6%96%87windows%e4%b8%8a%e6%98%be%e7%a4%ba%e9%ab%98%e7%9f%ae%e4%b8%8d%e4%b8%80%e7%9a%84%e9%97%ae%e9%a2%98/#comments Sun, 06 Sep 2015 22:07:47 +0000 http://shajisoft.com/shajisoft_wp/cn/?p=140 问题简介 就像在旧的Windows7/8/8.1上也可能出现的问题一样,如果Windows的系统语言是英文,那 […]

The post 完美解决中文在英文Windows上显示高矮不一的问题 appeared first on Shajisoft中文版.

]]>
问题简介

就像在旧的Windows7/8/8.1上也可能出现的问题一样,如果Windows的系统语言是英文,那么在某些应用程序中中文的显示有可能很丑陋,可能出现中文字体高矮不一的情况。

 

最近我从Windows 7升级到Windows 10。激活Windows后我又重新安装了一次Windows,所以需要重新安装所有常用的软件,于是遇到了本文提到的问题。在网上也正好看到有人也遇到同样的问题,网上能找到的解决办法有些并不适用,而且解释也不清楚。于是有了写篇日志的想法,想把自己的对这个问题的认识记录下来,也希望能对别人有所帮助。

 

图像永远比文字更有说服力。下面是应用软件TotalCommander的主界面屏幕截图。TotalCommander的语言设置已经切换到中文。我们可以看到,在靠近底边的几个按钮的中文说明的显示就有字体高矮不一的问题。

TotalCommander的中文界面在英文Windows 10上显示时会有中文字体大小、高矮不一的问题。
TotalCommander的中文界面在英文Windows 10上显示时会有中文字体大小、高矮不一的问题。

 
除了TotalCommander,其它应用程序包括Windows自带的Notepad以及CMD也有类似的问题。

缺省情况下Notepad在英文Windows 10上显示中文也有中午字体大小不一的问题。
缺省情况下Notepad在英文Windows 10上显示中文也有中午字体大小不一的问题。

英文Windows 10自带的CMD在显示中文目录、文件名时也有问题。这个截图中中文目录名变成了几个方框。
英文Windows 10自带的CMD在显示中文目录、文件名时也有问题。这个截图中中文目录名变成了几个方框。

 

以上截图是在英文Windows 10上截取的。Windows的区域和语言设置如下图所示

截取以上截图时Windows 10的区域和语言设置。
截取以上截图时Windows 10的区域和语言设置。

 

在上面这个截图中,我们可以发现中文的显示其实很正常。这也就说明我们在TotalCommander、Notepad、以及CMD中所看到的中文显示问题是种特殊现象,它只发生在某些软件中,另外,虽然本文的截图是以中文为例,不过在英文Windows上显示日文、韩文也应该有类似的问题。

测试环境

本文所涉及的测试都是在英文Windows 10上使用以下软件来完成的:

 

  • TotalCommander 8.52 x64
  • CMD (system default)
  • Notepad (system default)

 

分析

上面的截图说明了两种问题:一是中文的显示使用了错误的字体,二是没有找到相应的中文字体。其中CMD中文本的显示可能有些特别,中文目录名是以方框的形式显示的。这些问题通常出现在显示中文、日文、韩文等多字节的文本时出现。解决的办法就是给应用软件指定正确的字体。

 

方法 1: 选用正确的字体

如果软件容许用户设置字体,比如TotalCommander可以容许用户选择语言以及字体等。我们可以考虑选择一个可以正常显示中文的字体,比如微软雅黑字体等。TotalCommander的字体设置和其它可选项等都可以在其配置对话框上修改。配置对话框可以通过菜单“配置–>选项”调用。关于字体的选项在对话框上的”字体“标签页。字体的缺省选项如下图所示

缺省情况下,中文界面的TotalCommander的字体设置对话框。
缺省情况下,中文界面的TotalCommander的字体设置对话框。

 
如前所述,我们可以选择包含中文字体信息的微软雅黑,启用后,我们可以看到,之前看到的问题没有了,中文显示正常了。

把界面字体设为微软雅黑后的TotalCommander字体设置对话框。
把界面字体设为微软雅黑后的TotalCommander字体设置对话框。

 
选择包含中文字体信息的字体,可以确保中文的显示正常。但是有时候我们可能不想采用这种办法。比如在有些情况下,尤其是在Notepad以及CMD之类的应用中,我们仍然希望当中、英文混排的时候,在确保中文(包括日、韩文)可以正常显示的前提下,英文能够用漂亮的等宽字体。在这种情况下,我们可以考虑使用下面将要提到的类似虚拟字体的技术来建立正确的字体映射,来达到多种语言文本都能正常显示的目的。

 

方法2:在Windows注册表创建正确的字体映射(fontlink)

Fontlink是Windows采用的一种类似虚拟字体的技术。使用Fontlink,某个字体可以和多个其它的字体建立连接关系。在这里,该字体通常被称作主字体,而其它那些与之连接的字体称作连接字体。在输出文本时,Windows如果在主字体中没有找到需要的字体信息,它会在连接字体中继续搜索。使用Fontlink技术,一个字体可以和多个其它的字体连接。这样,对于中文显示,基本思路就是我们可以给任何一个字体创建和中文字体比如微软雅黑的连接。这样可以保证英文文本可以使用用户指定的字体,同时中文也显得正常。

 
在网上搜索“中英文显示”,或者“fontlink 雅黑”等可以发现不少介绍通过创建相应的Fontlink来实现在Windows上完美中、英文混合显示的网页。关于如何在Windows注册表创建或者修改Fontlink设置,读者不妨参考搜索到的网页,这里只对具体步骤略作介绍,然后会着重讨论一下Fontlink里需要用到的一个重要的参数,也就是所谓的”缩放因子”(scaling factor)。网上能搜到的帖子或者网页关于缩放因子的介绍不多,也些甚至有误导的作用。本文稍后些会重点介绍。

 
Fontlink在Windows注册表中的具体键值保存在HKLM–>Software–>Microsoft–>Windows NT–>CurrentVersion–>Fontlink–>SystemLink。在英文版Windows 10上我们可以发现,系统已经定义了若干Fontlink。

注意:在增加或者修改Windows注册表键值之前,强烈建议把所要改动的键值导出并保存为磁盘文件以作为备份。

以TotalCommander为例,正如上面的屏幕截图所示,缺省字体是“Microsoft Sans Serif”。而该字体的缺省Fontlink设置如下所示:

Windows 10 English系统中,对应于Microsoft Sans Serif字体的缺省fontlink设置。
Windows 10 English系统中,对应于Microsoft Sans Serif字体的缺省fontlink设置。

当Windows需要在连接字体中搜索所需的字体信息的时候,它会在上面提到的这个键值所定义的字体列表中从上而下搜索,直到找到需要的字符信息。为了使得Windows能够正常显示中文信息,我们可以把对应的中文字体加到相应主字体的连接字体键值列表中。但是在正式修改前,先让我们来了解一下列表中每行文本的语法。

 

以微软雅黑字体为例,Fontlink列表中每个子项目的语法如下所示:

MSYH.TTC,Microsoft YaHei UI,128,96

 

Fontlink列表中的每行的所有文字唯一的定义了该项目。所以在Fontlink的注册表键值中,以下两行分别代表两个不同的子项目:

MSYH.TTC,Microsoft YaHei UI,128,96
MSYH.TTC,Microsoft YaHei UI

其中“128,96”称作缩放因子(scaling factor)。根据MSDN上的相关文档,两种主要的图形显示技术GDI以及GDI+在搜索Fontlink键值时所用的语法有所不同。简单来说,GDI只会选用那些给出缩放因子的项目,相反的,GDI+会自动忽略那些带缩放因子参数的项目。这也就是说,如果想让所增加的连接字体能同时被GDI和GDI+调用,我们必须在Fontlink的键值中增加两行:一行有缩放印子给GDI,一行没有给GDI+。TotalCommander显然是使用GDI技术的,所以我们需要在Fontlink中给出缩放因子。

 
关于缩放因子是如何被使用的,或者我们应该如何设置缩放因子,我找不到任何有用的信息。现在只知道,如果缩放因子设成“128,96”的话,该字体不会被缩放。而在我的测试中发现,这样的话,中文比英文显得有点高,需要把雅黑中文字体缩小一点。最后我设置的Fontlink如下所示。关于缩放因子,下面会有更多介绍。

在英文Windows 10上,如此设置Microsoft Sans Serif字体的fontlink可以完美显示中文。
在英文Windows 10上,如此设置Microsoft Sans Serif字体的fontlink可以完美显示中文。

 
注意:为了使得新的Fontlink注册表设置生效,我们需要在Windows注销并再次登录即可。并不需要重启电脑!
 

如此设置Microsoft Sans Serif的Fontlink注册表键值后,即使字体仍然是Microsoft Sans Serif,TotalCommander的字体设置对话框上的中文显示已经正常了。如下图所示

正确设置fontlink注册表之后的TotalCommander的字体设置对话框。
正确设置fontlink注册表之后的TotalCommander的字体设置对话框。

 

接下来,我想花点时间说说缩放因子,毫无疑问,当用GDI输出文本时,缩放因子会影响显示效果。我希望能够弄清楚这两个整数是如何被使用的。可惜我找不到任何有用的信息。所有能在网上找到的信息都没有提到具体这两个缩放因子是如何被使用的。而且经过测试后我发现,有些网页上建议把缺省的数值,128和96,分别乘以一个相同的数,然后把结果作为缩放因子写入Fontlink的键值中。这让我感到十分困惑,因为以我自己现有对缩放因子的理解,对两个缺省的数值乘以一个相同的数是不会产生任何不同效果的。

 
如前所述,我找不到任何关于这两个缩放因子的详细资料,唯一能找到的相关信息就是开源软件gdipp的一个源程序文件。在这个文件里,Fontlink里定义的两个缩放因子被用来以如下方式计算另外一个缩放参数:

new_info.scaling = (factor1 / 128.0) * (96.0 / factor2);

 

这至少说明如果给连个缺省的缩放因子乘以一个相关的系数是不会产生任何不同的效果的。根据上面这个公式,以及一些试验结果,我觉得我们至少可以对Fontlink中的缩放因子做出如下一些推断:

  1. 为了能使使用GDI技术输出文本的程序比如TotalCommander能够通过Fontlink使用多个字体,我们必须在Fontlink中给出带有缩放因子的项目
  2. 合适的缩放因子的数值可能和具体的显示设备有关。也就是说不同的显示设备对于同一个字体可能需要不一样的缩放因子
  3. 连接字体的显示大小未必和主字体相同。我们可能需要增加或者减小连接字体的大小。为了这个目的,我们可以保持其中一个缩放因子使用缺省数值,而只是相应的改变另外一个因子。具体保持哪个或者修改哪个不影响结果
  4. 把缩放因子的缺省数值乘以一个相同的数值后并不会导致文本输出后的结果

 
仍然以TotalCommander为例,让我们做几个试样,比较把缩放因子设成如下各种数值后的显示效果:

  1. 128,100, 或122, 96。显示结果应该一样。
  2. 128,128, 或64,64。显示结果应该一样。
  3. 128,72, 或171,92。显示结果应该一样。
在英文Windows 10的注册表中设置不同缩放因子后的显示效果比较。
在英文Windows 10的注册表中设置不同缩放因子后的显示效果比较。

在我的20英寸显示器上,Windows 10的分辨率设为1920×1080。如果使用缺省缩放因子,在TotalCommander中中文会显得比英文高一点,所以我需要把缩放因子设成“128,100”或者“122,96”以缩小中文。而对于系统自带的Notepad或者CMD,缺省的缩放因子就可以。

 

小结

在Windows 10上,如果系统语言是英文,那么中、日、韩文的显示可能会因为无法找到合适的字体信息而显得高矮不一。简单来说,可以有两种办法解决这个问题,那就是在相应的软件中选用正确的字体,或者在Windows注册表中创建正确的字体映射。

 
第二个方法,也就是创建正确的字体映射的方法,在多数情况下更可取,主要因为如下原因:

  1. 我们仍然希望英文能够使用我们想要的字体 (比如, Cosonlas)。
  2. 有些应用程序可能不容许我们修改字体。

 
使用Fontlink技术,一个主字体和多个其它字体连接起来,完美显示多种语言的文本。所连接字体可能和主字体的显示大小不匹配。所以有时我们需要在设置Fontlink时设定相应的缩放因子以达到更好的显示效果。

The post 完美解决中文在英文Windows上显示高矮不一的问题 appeared first on Shajisoft中文版.

]]>
https://shajisoft.com/shajisoft_wp/cn/%e5%ae%8c%e7%be%8e%e8%a7%a3%e5%86%b3%e4%b8%ad%e6%96%87%e5%9c%a8%e8%8b%b1%e6%96%87windows%e4%b8%8a%e6%98%be%e7%a4%ba%e9%ab%98%e7%9f%ae%e4%b8%8d%e4%b8%80%e7%9a%84%e9%97%ae%e9%a2%98/feed/ 7