Thay đổi kích thước văn bản rasterized và làm cho nó trông không bị lỗi


11

Đây là ảnh chụp màn hình của một số văn bản được nhập trong trình soạn thảo văn bản:

Văn bản cao 16px

Đây là cùng một văn bản ở kích thước lớn hơn.

Văn bản cao 96px

Lưu ý cách hiển thị răng cưa trên các chữ cái với các nét chéo nổi bật như xz. Vấn đề này là một lý do chính tại sao các phông chữ raster đã mất đi sự phổ biến đối với các định dạng có thể mở rộng được của Cameron như TrueType.

Nhưng có lẽ đây không phải là vấn đề cố hữu với phông chữ raster, chỉ với cách thức chia tỷ lệ của chúng thường được thực hiện. Đây là một kết xuất thay thế bằng cách sử dụng phép nội suy song tuyến đơn giản kết hợp với ngưỡng .

Văn bản cao 96px được hiển thị với phép nội suy song tuyến tính

Điều này mượt mà hơn, nhưng không lý tưởng. Các nét chéo vẫn còn gập ghềnh, và các chữ cái cong covẫn là đa giác. Điều này đặc biệt đáng chú ý ở kích thước lớn.

Vậy có cách nào tốt hơn không?

Nhiệm vụ

Viết chương trình có ba đối số dòng lệnh.

resize INPUT_FILE OUTPUT_FILE SCALE_FACTOR

Ở đâu

  • INPUT_FILE là tên của tệp đầu vào, được giả sử là tệp hình ảnh chứa văn bản màu đen trên nền trắng. Bạn có thể sử dụng bất kỳ định dạng hình ảnh raster chính (PNG, BMP, v.v.) thuận tiện.
  • OUTPUT_FILE là tên của tệp đầu ra. Nó có thể là một định dạng hình ảnh raster hoặc vector. Bạn có thể giới thiệu màu nếu bạn đang thực hiện một số kết xuất pixel phụ giống như ClearType.
  • SCALE_FACTOR là một giá trị dấu phẩy động dương cho biết mức độ hình ảnh có thể được thay đổi kích thước. Cho một tệp đầu vào x × y px và hệ số tỷ lệ s , đầu ra sẽ có kích thước sx × sy px (làm tròn đến số nguyên).

Bạn có thể sử dụng thư viện xử lý ảnh nguồn mở thứ ba.

Ngoài mã của bạn, hãy bao gồm các đầu ra mẫu của chương trình của bạn ở các hệ số tỷ lệ 1.333, 1.5, 2, 3 và 4 bằng cách sử dụng hình ảnh đầu tiên của tôi làm đầu vào. Bạn cũng có thể thử nó với các phông chữ khác, bao gồm các phông chữ theo tỷ lệ.

Chấm điểm

Đây là một cuộc thi phổ biến. Các mục có số lượng upvote lớn nhất trừ đi downvotes chiến thắng. Trong trường hợp hòa chính xác, mục trước đó sẽ thắng.

Chỉnh sửa : Thời hạn gia hạn do thiếu mục. TBA.

Các cử tri được khuyến khích đánh giá chủ yếu dựa trên hình ảnh đầu ra trông tốt như thế nào và thứ hai là sự đơn giản / thanh lịch của thuật toán.


SCALE_FACTORLuôn luôn là > 1?
kennytm

@kennytm: Vâng. Đã chỉnh sửa để liệt kê rõ ràng các yếu tố quy mô.
dan04

Chúng ta có thể giả sử chỉ có một dòng văn bản trong hình ảnh không?
GiantTree

@GiantTree: Vâng. Bạn có thể hỗ trợ văn bản nhiều dòng nếu bạn muốn, nhưng điều này không bắt buộc.
dan04

Câu trả lời:


4

Ruby, với RMagick

Thuật toán rất đơn giản, tìm các mẫu pixel trông như thế này:

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

và thêm hình tam giác để làm cho chúng trông như thế này:

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

Mã số:

#!/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')

Đầu ra (nhấp vào bất kỳ để xem hình ảnh của chính nó):

1.333

1.333

1,5

1,5

2

2

3

3

4

4

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.