Как извлечь растровые данные из растрового шрифта TTF для отображения POV?

Я собрал несколько растровых шрифтов высотой 10 пикселей из репозитория dafont в формате TTF. Однако у меня возникли проблемы с извлечением из них фактических данных растрового изображения, поскольку они кажутся в векторной форме, и я не могу понять соответствие между размером точки и размером пикселя при рендеринге. Мне нужны предложения по программным инструментам, библиотекам или подходам для получения точных попиксельных растровых данных, соответствующих буквенным формам.

Пример шрифта, который имеет смысл проблемы: http://www.dafont.com/commodore-64-pixelized.font

Моя цель — использовать один или несколько из этих растровых шрифтов для управления дисплеем Persistence Of Vision (POV) на базе Arduino как часть http://shrimping.it проект.

Устройства POV используют линию светодиодов для рисования текста в воздухе путем включения и выключения светодиодов при перемещении устройства из стороны в сторону. Известным примером является MiniPOV от Adafruit http://www.ladyada.net/make/minipov3/

Чтобы написать код микроконтроллера для мигания светодиодами, мне нужно получить попиксельную информацию от шрифта, другими словами, мне нужна схема для извлечения данных из файлов формата TTF, которые мне предоставили, чтобы избежать сделать это вручную для каждого символа и каждого шрифта.

До сих пор я экспериментировал с обработкой (http://processing.org), но я не вижу, как выбрать размер точки для визуализации TTF, чтобы шрифт рисовался с точным соответствием базовой сетке. пикселей. Получив это, я могу получить информацию, но, похоже, я не могу туда добраться. Значения textAscent и textDescent, сообщаемые Processing, кажутся ненужными, по крайней мере, для шрифтов, которые я пробовал.

Я тестирую следующие шрифты: Advocut, Andina, Aux DotBitC, BM tube, Commodore 64 Pixelised, Homespun BRK, Nayupixel, SG05 и Visitor. Вы можете получить любой из них самостоятельно, выполнив поиск на dafont.com, если вам нужно увидеть исходные данные, чтобы лучше понять проблему.


person user336590    schedule 20.10.2012    source источник


Ответы (2)


Я нашел исправление для этого, которое состоит из трех частей.

Этап 1

Сначала я использовал Python для вывода всех печатных графических символов ASCII из интерактивной оболочки Python, набрав «python», а затем...

import string
print(''.join([chr(x) for x in range(33,127)]))

... что дает следующую последовательность символов - опуская ПРОБЕЛ (32) и DEL (127)...

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

2 этап

Затем я запустил Inkscape, активировал видимую пиксельную сетку с помощью View> Grid и создал текстовый элемент, содержащий все эти символы в строке заданного шрифта. Я визуально проверил, какие символы вернулись к непиксельному глифу. (Если символ не указан полностью, я думаю, что он вставляет туда обычный векторный шрифт, который может быть нецелым числом пикселей, что портит горизонтальный кернинг и неправильно позиционирует оставшиеся символы, поэтому они должны быть заменены). Я заменил все непиксельные символы, которые я видел, просто знаком вопроса, символом, который, кажется, надежно присутствует и имеет целое число пикселей в этих шрифтах.

Когда все символы представляют собой чистые пиксельные символы, с выбранным текстовым элементом (чтобы полоса координат отображалась вверху) и с увеличением масштаба, я смог расположить текст на 0,0 и выбрать высоту в пикселях. вручную, что заставило пиксельные элементы выровняться с фоновой сеткой (убедившись, что символ блокировки был активирован для масштабирования горизонтальных и вертикальных размеров вместе, когда я переключился с высоты 8,9,10,11 пикселей. В некоторых случаях эти так называемые 10-пиксельные шрифты на самом деле имели высоту 8 или 11 пикселей, когда они выстраивались правильно, что объясняет некоторые проблемы.

Иногда точное отображение высоты было немного неточным, поэтому я настраивал его, следя за тем, чтобы количество пикселей по горизонтали было правильным (например, иногда фактическая высота была дробной, например, 618 пикселей в ширину, но 7,005 в высоту. Сканируя вдоль символов, вы можете увидеть, пиксели немного короче или немного длиннее, и установите ширину на целое число, пока пиксели не будут соответствовать сетке.Разница в высоте с плавающей запятой едва видна в Inkscape и не оказывает видимого влияния на экспорт (где дробь округляется), но если горизонтальный подсчет неправильный, выполняется сопоставление пикселей, и пиксели получаются размытыми по горизонтали из-за смещения при попытке квантования.

Наконец, когда текстовый элемент все еще выделен, я выбрал «Файл»> «Экспорт растрового изображения» и выбрал вкладку «Выбор». Экспорт PNG с 8, 10, 11 или любым другим количеством пикселей, которое было обнаружено на предыдущем шаге, создает пиксельную графику с идеальным отображением пикселей — файл, над которым можно написать простую процедуру для извлечения растрового изображения.

3 этап

Наконец, должна быть написана процедура для импорта PNG и извлечения правильной посимвольной информации для растрового изображения POV.

Я придумал процедуру, которая надежно определяет горизонтальную протяженность символов и может нарезать их на отдельные последовательности для моего POV. Это не моноширинные шрифты, поэтому ширина каждого символа непредсказуема, например. восклицательный знак часто имеет ширину всего два пикселя. Необходимо было закодировать особый случай для символа двойной кавычки, который содержит два пробела.

Источник моей процедуры извлечения теперь находится в...

http://shrimping.it/shrimp/project/pov/font/extract_font.py

... и может быть запущен над набором файлов png в каталоге, перейдя в каталог и запустив

python extract_font.py

Затем создаются отдельные растровые изображения для каждого символа, извлекаемые в отдельный каталог для каждого шрифта.

person user336590    schedule 20.10.2012
comment
Благодаря twitter.com/mgdm/status/259669824769245184 и twitter.com/gordonjcp/status/259664637342142464 за их предложения через Twitter. Через Stackoverflow пока ничего :( - person user336590; 20.10.2012
comment
Шрифт Andina кажется непригодным для использования в его нынешнем виде с использованием этого обходного пути, поскольку интервал между буквами варьируется и часто не является целым числом пикселей (например, символы ? и N имеют частичный интервал в пикселях). - person user336590; 20.10.2012
comment
У шрифта Nayupixel аналогичные проблемы с интервалами, но это не так уж плохо, и его можно восстановить, просто растянув горизонталь независимо от вертикали, а затем сведя его к растровому изображению с помощью Gimp Image›Mode›Indexed›1bit color. - person user336590; 20.10.2012
comment
Полученные изображения для шрифтов, которые были успешно сопоставлены с растровыми png, можно загрузить по адресу shrimping. это/креветки/проект/pov/шрифт/png - person user336590; 20.10.2012

Python3

Я пытался быть описательным, но вы можете упростить работу так, как вам нужно.

Требования: PIL (подушка)

PIL ImageDraw и ImageFont

# pip install Pillow
from PIL import Image, ImageFont, ImageDraw

# use a truetype font (.ttf)
# font file from fonts.google.com (https://fonts.google.com/specimen/Courier+Prime?query=courier)
font_path = "fonts/Courier Prime/"
font_name = "CourierPrime-Regular.ttf"
out_path = font_path

font_size = 16 # px
font_color = "#000000" # HEX Black

# Create Font using PIL
font = ImageFont.truetype(font_path+font_name, font_size)

# Copy Desired Characters from Google Fonts Page and Paste into variable
desired_characters = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽabcčćdđefghijklmnopqrsštuvwxyzž1234567890‘?’“!”(%)[#]{@}/&\<-+÷×=>®©$€£¥¢:;,.*"

# Loop through the characters needed and save to desired location
for character in desired_characters:
    
    # Get text size of character
    width, height = font.getsize(character)
    
    # Create PNG Image with that size
    img = Image.new("RGBA", (width, height))
    draw = ImageDraw.Draw(img)
    
    # Draw the character
    draw.text((-2, 0), str(character), font=font, fill=font_color)
    
    # Save the character as png
    try:
        img.save(out_path + str(ord(character)) + ".png")
    except:

        print(f"[-] Couldn't Save:\t{character}")
person Carson Stevens    schedule 13.04.2021