Змініть розмір растрового тексту та зробіть його не піксельним


11

Це скріншот деякого тексту, набраного в текстовому редакторі:

Текст високою 16 пікселів

Це той самий текст у більшому розмірі.

96px-високий текст

Зверніть увагу на те, як видно згладжування на літерах з чіткими діагональними штрихами, як xі z. Ця проблема є основною причиною того, чому растрові шрифти втратили популярність до «масштабованих» форматів, таких як TrueType.

Але, можливо, це не властива проблема растрових шрифтів, як правило, як спосіб їх масштабування реалізується. Ось альтернативна візуалізація з використанням простої білінеарної інтерполяції в поєднанні з порогом .

Текст, високий 96 пікселів, відображений із білінеарною інтерполяцією

Це плавніше, але не ідеально. Діагональні штрихи все ще кумедні, а вигнуті літери начебто cі oє багатокутниками. Особливо це помітно при великих розмірах.

Так є кращий спосіб?

Завдання

Напишіть програму, яка бере три аргументи командного рядка.

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, використовуючи моє перше зображення як вхідне. Ви також можете спробувати його з іншими шрифтами, включаючи пропорційно розташовані.

Оцінка балів

Це конкурс на популярність. Виграє запис з найбільшою кількістю оновлених мінусів. У разі точного вирівнювання виграє попередній запис.

Редагувати : Термін продовжений через відсутність записів. TBA.

Виборцям рекомендується судити, головним чином, на основі того, наскільки добре виглядають вихідні зображення, і, вдруге, на простоті / елегантності алгоритму.


Є SCALE_FACTORзавжди> 1?
kennytm

@kennytm: Так. Відредагували, щоб чітко перерахувати масштабні фактори.
dan04

Чи можна припустити, що на зображенні є лише один рядок тексту?
GiantTree

@GiantTree: Так. Ви можете підтримувати багаторядковий текст, якщо хочете, але це не потрібно.
dan04

Відповіді:


4

Рубі, з 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.