调整光栅化文本的大小,使其看起来没有像素化


11

这是在文本编辑器中键入的一些文本的屏幕截图:

16像素高文字

这是较大尺寸的相同文本。

96像素高文字

请注意,在带有明显对角线笔划的字母(例如和)上,锯齿现象是显而易见的。此问题是光栅字体无法普及到TrueType等“可缩放”格式的主要原因。xz

但这可能不是光栅字体固有的问题,只是通常实现缩放字体的方式。这是使用简单的双线性插值结合阈值的替代渲染。

使用双线性插值渲染的96像素高文本

这比较平滑,但并不理想。对角线笔触仍然凹凸不平,弯曲的字母像co仍然是多边形。这在大尺寸情况下尤其明显。

那有更好的方法吗?

任务

编写一个带有三个命令行参数的程序。

resize INPUT_FILE OUTPUT_FILE SCALE_FACTOR

哪里

  • INPUT_FILE是输入文件的名称,假定它是在白色背景上包含黑色文本的图像文件。您可以使用任何方便的主流栅格图像格式(PNG,BMP等)。
  • OUTPUT_FILE是输出文件的名称。它可以是栅格图像或矢量图像格式。如果要执行类似ClearType的子像素渲染,则可以引入颜色。
  • SCALE_FACTOR是一个正浮点值,指示可以调整图像大小的大小。给定x × y px输入文件和缩放因子s,输出将具有sx × sy px 的大小(四舍五入为整数)。

您可以使用第三方的开源图像处理库。

除了您的代码外,请使用我的第一张图片作为输入1.333、1.5、2、3和4的比例因子包含程序的示例输出。您也可以尝试使用其他字体,包括按比例隔开的字体。

计分

这是一次人气竞赛。投票数量减去投票数量最多的条目将获胜。如果出现平局,则以较早的参赛者为准。

编辑:由于缺少条目而延长了截止日期。待定。

鼓励选民首先根据输出图像的外观进行判断,其次基于算法的简单/优雅。


SCALE_FACTOR总是> 1?
kennytm

@kennytm:是的。已编辑以明确列出比例因子。
dan04

我们可以假设图像中只有一行文本吗?
2015年

@GiantTree:是的。您可以根据需要支持多行文本,但这不是必需的。
dan04'5

Answers:


4

Ruby和RMagick

该算法非常简单-查找像素模式如下所示:

    ####
    ####
    ####
    ####
########
########
########
########

并添加三角形,使它们看起来像这样:

    ####
   #####
  ######
 #######
########
########
########
########

码:

#!/usr/bin/ruby

require 'rmagick'
require 'rvg/rvg'
include Magick

img = Image.read(ARGV[0] || 'img.png').first
pixels = []
img.each_pixel{|px, x, y|
    if px.red == 0 && px.green == 0 && px.blue == 0
        pixels.push [x, y]
    end
}

scale = ARGV[2].to_f || 5.0
rvg = RVG.new((img.columns * scale).to_i, (img.rows * scale).to_i)
    .viewbox(0, 0, img.columns, img.rows) {|cnv|
    # draw all regular pixels
    pixels.each do |p|
        cnv.rect(1, 1, p[0], p[1])
    end
    # now collect all 2x2 rectangles of pixels
    getpx = ->x, y { !!pixels.find{|p| p[0] == x && p[1] == y } }
    rects = [*0..img.columns].product([*0..img.rows]).map{|x, y|
        [[x, y], [
            [getpx[x, y  ], getpx[x+1, y  ]],
            [getpx[x, y+1], getpx[x+1, y+1]]
        ]]
    }
    # WARNING: ugly code repetition ahead
    # (TODO: ... fix that)
    # find this pattern:
    # ?X
    # XO
    # where X = black pixel, O = white pixel, ? = anything
    rects.select{|r| r[1][0][1] && r[1][1][0] && !r[1][2][1] }
        .each do |r|
            x, y = r[0]
            cnv.polygon x+1,y+1, x+2,y+1, x+1,y+2
        end
    # OX
    # X?
    rects.select{|r| r[1][0][1] && r[1][3][0] && !r[1][0][0] }
        .each do |r|
            x, y = r[0]
            cnv.polygon x+1,y+1, x+0,y+1, x+1,y+0
        end
    # X?
    # OX
    rects.select{|r| r[1][0][0] && r[1][4][1] && !r[1][5][0] }
        .each do |r|
            x, y = r[0]
            cnv.polygon x+1,y+1, x+0,y+1, x+1,y+2
        end
    # XO
    # ?X
    rects.select{|r| r[1][0][0] && r[1][6][1] && !r[1][0][1] }
        .each do |r|
            x, y = r[0]
            cnv.polygon x+1,y+1, x+2,y+1, x+1,y+0
        end
}
rvg.draw.write(ARGV[1] || 'out.png')

输出(单击任意可单独查看图像):

1.333

1.333

1.5

1.5

2

2

3

3

4

4

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.