Kerning w locie

10

Czy ktoś zna jakiś algorytm, który automatycznie obliczałby kerning znaków na podstawie kształtów glifów, gdy użytkownik wpisuje tekst?

Nie mam na myśli trywialnych obliczeń szerokości posunięć itp., Mam na myśli analizę kształtu glifów w celu oszacowania optymalnej wizualnie odległości między postaciami. Na przykład, jeśli ułożymy trzy znaki sekwencyjnie w linii, środkowy znak powinien WIDZIĆ SIĘ, aby znajdować się na środku linii, pomimo kształtów postaci. Przykład oświeca funkcjonalność kerningu w locie:

Przykład kerningu w locie:

Zrzut ekranu

Na powyższym zdjęciu awydaje się być zbyt poprawne. Powinien być przesunięty o określoną wartość w kierunku, Ttak aby wydawał się znajdować w środku Ti g. Algorytm powinien zbadać kształty Ti a(i ewentualnie także inne litery) oraz zdecydować, o ile anależy przesunąć w lewo. Algorytm powinien obliczyć tę pewną ilość - BEZ BADANIA MOŻLIWYCH PAR PAROWYCH CZCIONKI.

Zastanawiam się nad kodowaniem programu javascript (+ svg + html), który używa ręcznie rysowanych czcionek i wielu z nich nie ma par kerningu. Pola tekstowe będą edytowalne i mogą zawierać tekst wielu czcionek. Myślę, że kerning w locie może być jednym ze sposobów zapewnienia średniego przepływu tekstu w tym przypadku.

EDYCJA: Jednym z punktów wyjścia może być użycie czcionki svg, więc łatwo jest uzyskać wartości ścieżki. W czcionce svg ścieżka jest zdefiniowana w następujący sposób:

<glyph glyph-name="T" unicode="T" horiz-adv-x="1251" d="M531 0v1293h
-483v173h1162v-173h-485v-1293h-194z"/>

<glyph glyph-name="a" unicode="a" horiz-adv-x="1139" d="M828 131q-100 -85
-192.5 -120t-198.5 -35q-175 0 -269 85.5t-94 218.5q0 78 35.5 142.5t93
103.5t129.5 59q53 14 160 27q218 26 321 62q1 37 1 47q0 110 -51 155q-69 61
-205 61q-127 0 -187.5 -44.5t-89.5 -157.5l-176 24q24 113 79 182.5t159
107t241 37.5 q136 0 221 -32t125 -80.5t56 -122.5q9 -46 9 -166v-240q0
-251 11.5 -317.5t45.5 -127.5h-188q-28 56 -36 131zM813 533q-98 -40 -294
-68q-111 -16 -157 -36t-71 -58.5t-25 -85.5q0 -72 54.5 -120t159.5 -48q104
0 185 45.5t119 124.5q29 61 29 180v66z"/>

Algorytm (lub kod javascript) powinien w jakiś sposób zbadać te ścieżki i określić optymalną odległość między nimi.

Timo Kähkönen
źródło
1
Jeśli szukasz rozwiązania do kodowania, lepiej byłoby o to poprosić w SO. Czy tego szukasz? Jeśli tak, migruję tam pytanie.
Alan Gilbertson
2
Zgadzam się, że to SO pytanie. Zadałem to samo pytanie w SO, ale zostało zamknięte jako nie na temat. Następnie zapytał na matath.stackexchange, ale zdarzyło się to samo zamknięcie. To jest trzecie miejsce, może to właściwe miejsce, ktokolwiek wie.
Timo Kähkönen
2
Nie wiem, jak działa algorytm, ale InDesign może to zrobić: „Kerning optyczny dostosowuje odstępy między sąsiednimi znakami na podstawie ich kształtów. Niektóre czcionki zawierają solidne specyfikacje par jądra. Jednak gdy czcionka zawiera tylko minimalną liczbę wbudowanych kerning lub wcale, lub jeśli używasz dwóch różnych czcionek lub rozmiarów w jednym lub większej liczbie słów w linii, możesz skorzystać z opcji optycznego kerningu. ” help.adobe.com/en_US/indesign/cs/using/…
e100
2
Myślę, że jest to prawdopodobnie objęte ogólnym algorytmem - sekwencją kroków, które należy wykonać, aby rozwiązać problem. Ale nie sądzę, aby należały do ​​niego specyfiki implementacji w JS lub innym języku, i edytuję, aby wspomnieć tylko o JS jako przypadku użycia w tle.
e100
1
Myślę, że pierwszym porządkiem biznesu jest zdefiniowanie „optymalnego” w sposób przydatny dla algorytmu maszynowego.
horatio

Odpowiedzi:

4

Wiem, że to jest stare. Pracuję nad tym teraz w implementacji niestabilnego tekstu WebGL (cokolwiek). Rozwiązanie, nad którym pracuję, wygląda następująco:

  1. Uzyskaj bitmapowaną wersję pary glifów (lub zrób to z wektorami, jeśli chcesz)
  2. Dla każdego rzędu pikseli (lub dowolnej jednostki pionowej, jeśli korzystasz z wektorów), sprawdź, czy oba glify mają co najmniej jeden piksel
  3. Dla każdego rzędu, który przechodzi krok 2, oblicz odległość między skrajnym prawym pikselem pierwszego glifu a skrajnym lewym pikselem drugiego glifu
  4. Przesuń drugi glif najdalej w lewo, jak to możliwe, jednocześnie spełniając następujące kryteria:
    • przerwa w tym rzędzie pikseli jest większa niż określona przez ciebie minimalna przerwa
    • całkowity obszar (ignorowanie wierszy bez piksela w jednym z glifów) jest większy niż określony minimalny obszar

W ten sposób pusty „obszar” między literami powinien zostać ściśnięty do dość powszechnej średniej. Określ minimalną przerwę i minimalny obszar, używając metody prób i błędów oraz własnego gustu, i może pozwól, aby parametry te zostały również dostosowane przez innego agenta ... jak np. Wartość ręcznego kerningu.

tak :)

Edycja: Zaimplementowałem to teraz pomyślnie i działa naprawdę dobrze :)

jaya
źródło
Niezła odpowiedź! Witamy na GD.SE :)
Yisela,
Dzięki za powitanie: D !! Powinienem dodać, że obszar powinien być podzielony przez liczbę faktycznie testowanych wierszy (co tak naprawdę sprawia, że ​​jest to średnia przerwa, a nie tak naprawdę powierzchnia). Dobrze byłoby również sprawdzić, czy luka w wierszu jest statystyczną wartością odstającą i zignorować ten wiersz, jeśli tak jest. Pomoże to uniknąć ściśnięcia liter zbyt blisko, gdy jest duży otwór, taki jak w „G”
jaya
Wygląda na to, że istnieje kilka problemowych elementów potomnych, takich jak T- lub O ', na przykład w niektórych stylach czcionek niektórych czcionek. T - pozwól, aby łącznik zbliżył się zbyt blisko T, i nie dzieliłem żadnych pikseli w tym samym rzędzie, więc postanowiłem użyć najbliższych wierszy z jednym pikselem każdego, kiedy to się stanie. Aby powyższy algorytm był bardziej niezawodny, musisz jakoś sprawdzić tego rodzaju problemy. Dla moich celów nie było to konieczne.
jaya
3

Jest to dość prosty algorytm, który wypróbowałem raz i może być wystarczająco dobry.

Renderuj postacie w niskiej rozdzielczości - powiedzmy sześć lub siedem pikseli wysokości (wysokość typowego kapitału) mniej więcej tak samo w poziomie. Chcesz prostą binarną mapę miejsca, w którym jest pusta przestrzeń względem części litery, na prostej siatce niskiej rozdzielczości.

„Tucz” te mapy literowe. Oznacza to, że wypełnij każdą pustą komórkę, która sąsiaduje z wypełnioną komórką. Ma to na celu zajęcie pustego terytorium najbliższego krawędziom liter, aby sąsiednia litera nie zbliżyła się zbyt blisko.

Zagraj w „horizontal Tetris” z wynikowymi mapami liter. Niech grawitacja działa w lewo. Wypukły lewy „brzuch” „a” „wpadnie” do wnęki pod górną częścią „T”. Ile komórek poruszyło się „a”? Skaluj to w górę proporcjonalnie do rzeczywistego rozmiaru liter i to, jak daleko jest kernowanie rzeczywistej wysokiej rozdzielczości litery „a” w lewo.

DarenW
źródło
1
Dzięki! Aby zwizualizować algorytm, możesz podać przykład obrazu o niskiej rozdzielczości, używając par „db”, „AA”, „Ta” i „c-” za pomocą Arial.
Timo Kähkönen,
Dobry początek, ale myślę, że to może być ograniczona, gdzie pary znaków protruberant nie „Tetris” razem, na przykład „BD”, „TT”, „pq”, „GJ”
e100
@ e100: Na pierwszy rzut oka te konkretne pary nie miałyby nakładających się ramek ograniczających ...
horatio,
Ale ogólnie rzecz biorąc, powinny być kernowane mocniej niż „MM”, „NN” itp.
e100
2

Algorytmy automatycznego kerningu już istnieją. Żadne z nich nie jest głupie i zwykle wymaga trochę trzymania za rękę i ręcznej korekty niektórych aspektów, szczególnie jeśli twoje śledzenie jest stosunkowo ścisłe.

Ale te algorytmy służą do zastosowania kerningu do pliku czcionek , a nie do liter, które są generowane z pliku czcionek.

Czy rozważałeś zastosowanie automatycznego kerningu w pliku czcionek?

Fontforge (open source) i Fontlab (komercyjny) zawierają algorytmy automatycznego kerningu. Miałyby one stosunkowo stromą krzywą uczenia się - musisz znać techniczne aspekty działania czcionek.

Istnieje również iKern, który jest facetem, który oferuje komercyjną usługę kerningu czcionek , w której kernuje twoją czcionkę za ciebie i wykonuje dość dobrą robotę. Nie wiem, ile by to kosztowało.

thomasrutter
źródło
Ale tak naprawdę pytanie brzmi: „jak taki algorytm działałby?” - czy możesz dodać jakieś szczegóły na temat działania FontForge?
e100
1
Ich algorytm opisano tutaj .
thomasrutter
0

Nie mam czasu, aby przemyśleć to w pełni lub narysować ilustracje, ale miałem półpomysł oparty na pierwszym przecięciu każdego glifu w pionie.

Następnie dla każdej połowy określ dwie osie pionowe: - dwusieczną - dokładnie połowę między skrajną lewą i prawą - oś „ciężaru” - dokładnie połowę atramentu z każdej strony

Następnie przesuń sąsiadujący glif w kierunku lub od pół-glifu testowego w oparciu o względne położenia dwóch osi.

Na przykład w parze „AV” prawa połowa litery A jest ciężka z lewej strony i „przyciąga” V; lewa połowa litery V jest ciężka, „przyciąga” literę A, dzięki czemu są one znacznie skręcone razem.

Jestem jednak pewien, że wada „AA” byłaby zmiażdżona razem tak samo jak „AV”.

e100
źródło
0

Biorąc pod uwagę duże i małe litery, są 56X55=2652sytuacje, w których należy wziąć pod uwagę parę czcionek, wszystkie rozwiązania mogą być zepsute, ponieważ jeśli zmienisz styl czcionki, wszystkie reguły znikną.

Najlepszym sposobem jest użycie techniki uczenia maszynowego, próba ustanowienia modelu badania sieci neuronowej i zaimportowanie wielu tekstów obrazu jądra lub wektora lub podobnych rzeczy, wytrenowanie tego modelu i użycie tego wyuczonego modelu w celu inteligentnego dostosowania dowolnego rodzaju czcionki.

ponieważ nie ma statycznego algorytmu do idealnego dopasowania czcionki w katalogu głównym, uczenie maszynowe byłoby dobrym rozwiązaniem tego rodzaju problemu!

Super-ilad
źródło
Nie, jeśli istnieją tylko w większości subiektywne kryteria. „Czy to pies czy kot?”, Bez względu na to, jak dziwnie wygląda puchatek, wciąż ma dokładną odpowiedź. (Nawet jeśli weryfikacja wymaga weterynarza)
usr2564301