Як писати конспекти, якщо ти програміст

Коли в технічному вузі викладач змушує студентів писати конспекти від руки, виходить щось ось таке:
Фотка двох листів конспекту
Це – результат роботи програми, яка генерує рукописний текст користувальницьким почерком. Вона може змінювати товщину пера і колір пасти, писати букви разом чи окремо, підтримує лист на безлічі різних мов і потенційно здатна переносити слова по складах на багатьох з них. Написано на C++/Qt, є версії під Windows і Linux. Далі буде невеликий розбір рукописного письма, опис різних способів його імітації, розбір найбільш цікавих моментів роботи програми і посилання на репозиторій.
Чому програмна генерація індивідуального рукописного письма – це складно? Справа в тому, що рукописне письмо дуже мінливе, тут немає такої жорсткої зумовленості, як при друку. Для правдоподібною імітації рукописного письма треба враховувати як мінімум ось такі його особливості:
  • Накреслення літер залежить від того, які букви стоять поруч
  • Для кожного символу додаються рандомные і не дуже спотворення, з-за чого абсолютно ідентичні символи в тексті зазвичай не зустрічаються.
  • Слова можуть бути написані разом чи окремо. Також можна поєднувати обидва варіанти написання.
  • Змінюються ширина, висота і нахил, як символів, так і у рядків.
На все це впливає манера письма, вид письмовій приналежності, підкладка, швидкість письма, переважна рука, настрій і самопочуття писаря і ще купа всього. Тобто потрібно не просто враховувати величезну купу факторів, але і дозволити користувачеві програми налаштовувати їх за своїм розсудом.
Як це зазвичай роблять?
На практиці враховувати все це рідко коли буває потрібно. Наприклад, для маленької рукописної роздруківки на листівці або запрошення використовують звичайний рукописний шрифт OpenType. Втім, у певних умовах це може підійти і для конспекту. У мережі можна знайти інструкції, як створити індивідуальний шрифт самостійно і друкувати їм з MS Word, а для англомовних користувачів існують цілі генератори рукописних шрифтів.
Але при такому способі страждає правдоподібність: символи будуть абсолютно однаковими, рядки бездоганно рівними. Не буде ніякої випадковості, вырвиглазности і хаосу, які з мого досвіду характерні для переважної більшості конспектів, і навіть для акуратного конспекту така бездоганність неприродна.
як зробити краще?
Основна ідея така: беремо друкований текст, для кожного символу беремо рукописний гліф і розміщуємо його на віртуальному аркуші паперу в потрібне місце. При цьому для одного і того ж символу гліфів повинно бути декілька, а конкретний повинен вибиратися випадковим чином, інакше будуть ті ж проблеми, що і у шрифтів OpenType. Потім вже можна буде вносити різні спотворення як на весь аркуш паперу, так і для окремого рядка чи символу. Ймовірно, можна буде спотворювати гліфи таким чином, щоб з одного введеного гліфа отримати відразу готовий набір.
Все те ж саме можна робити і з лігатурами і, відповідно, комбінаціями символів, щоб враховувати вплив стоять поруч букв один на одного. Спойлер: на жаль, моя програма не підтримує лігатури і не може вносити спотворення в гліфи.
Я не перший, хто вирішив, що програмна генерація — це хороша ідея, і написав свою програму для створення рукописів. Мені відомі програми Синяк і Handwriter, а також сервіс Писар. У них, тим не менш, є певні недоліки, які надихнули мене на написання власної програми: у Синця, наприклад, лише один гліф на символ і деякі проблеми з юзабіліті, Handwriter платний, а Писар не дозволяє створити свій шрифт.
Векторний або растровий шрифт?
Раз ми говоримо про індивідуальний листі, треба передбачити можливість забити в програму свої гліфи. Досить очевидне рішення — дати користувачеві можливість роздрукувати шаблон для заповнення і потім брати гліфи з скана заповненого шаблону. Однак для цього потрібно вирішити наступні завдання:
  • Очистити шаблон від шуму
  • Розпізнати спеціальні мітки на шаблоні, щоб зрозуміти, до якого символу які гліфи
  • Вирізати кожен гліф з фону
Складність не в тому, щоб просто зробити це, а в тому, щоб зробити це якісно для незліченної безлічі сканерів з різними характеристиками, параметрами сканування і різної папером. Я вирішив, що мені не варто братися за таку об'ємну задачу.
Так що в моїй програмі використовується векторна графіка. Алгоритм створення шрифту тепер такий: користувач відкриває його улюблений векторний редактор, малює потрібні гліфи (бажано за допомогою планшета), зберігає їх, а потім завантажує програму. Мінуси такого рішення наступні:
  • Можна забути про імітацію взагалі будь-яких письмових приладдя, в тому числі кулькових ручок. Тепер текст як ніби написаний капілярною ручкою, і я не бачу способу це змінити.
  • Час на створення повного комплекту гліфів збільшується в кілька разів порівняно з часом заповнення паперового шаблону, а це осилить не кожен.
  • Графічні планшети у середнього користувача зустрічаються набагато рідше, ніж сканери, що ще сильніше зменшує потенційну аудиторію.
Але з'являються різні бонуси:
  • Можна легко і без побічних ефектів міняти колір пасти, товщину пера і розмір гліфів.
  • Можна скругляющі і згладжувати кути та кінці ліній.
  • З'єднувальні лінії для імітації злитого написання виглядають точно так само, як лінії букв.
  • Якість друку тепер залежить тільки від принтера.
  • Можна частково автоматизувати створення власного шрифту.
Розміщення символів на аркуші
Символи бувають різними: одні розташовуються строго в межах рядка, інші виступають за її край, треті лежать на верхній або нижній межі. Виступаючі частини символів при цьому можуть перебувати над рядом стоять символами або під ними. Тому для коректного розміщення символу потрібно знати, яка його частина буде перебувати в межах рядка і як щодо нього потрібно розташовувати інші символи.
Скріншот редактора шрифтів
Жовтий прямокутник – якраз та частина символу, що знаходиться в межах рядка
У редакторі шрифтів можна задати положення символу щодо рядки та інших символів, вказуючи межі символу жовтою рамкою. А ще тут, зрозуміло, ставляться у відповідність символи і конкретні гліфи.
Дані для злитого написання
Крім жовтої рамки в редакторі шрифтів помітні ще й два круглих покажчика. Це – точки, куди будуть приходити з'єднувальні лінії від сусідніх літер. Так, для злитого написання слова знаходяться поруч літери просто з'єднуються прямими лініями. По ідеї, краще було б використовувати сплайни, але якщо писати букви без довгих хвостиків, враховуючи, що програма буде малювати хвостики за користувача, в очі це кидатися не буде.
Часткова автоматизація створення шрифту
Вказувати все це вручну для кожного символу – застрелитися можна. Треба якось спростити процес створення свого шрифту.
По-перше, є автоматичне завантаження гліфів. При збереженні гліфа з улюбленого векторного редактора досить назвати файл за певним шаблоном, і програма віднесе його до потрібного символу. Такий Шаблон: сам символ, потім, якщо потрібно, номер; можна розділити їх нижнім підкресленням. І, оскільки Windows не бачить великої різниці між великими та малими літерами, для великих потрібно додати префікс «UP_». Правда, такий трюк працює не з усіма символами, оскільки далеко не всі можна використовувати в імені файлу, тому замість заборонених символів можна писати їх назва.
По-друге, при слитном написанні сполучна лінія, як правило, входить в початок першої лінії букви, а виходить з кінця останньої лінії. Оскільки, як правило, векторні редактори зберігають інформацію про лініях в тій послідовності, в якій лінії були намальовані, ми знаємо, яка лінія була намальована першою, а яка – останній. Тобто більшу частину роботи по розміщенню круглих покажчиків може взяти на себе програма. І бере.
І в-третіх, вказувати жовтий прямокутник програма теж може сама, просто поставивши його по краях гліфу. Це часто неправильно, але хоч якийсь відсоток правильно поставлених даних вже полегшить життя користувачу.
Перенос слів по складах
Щоб правильно розбити слова на склади використовується алгоритм П. Христового в модифікації Димченко і Варсанофьева. Якщо коротко: за допомогою регулярних виразів описуються дві групи букв, між якими повинен розташовуватися дефіс. Потім конкретне слово з допомогою послідовного застосування цих правил розбивається на склади, вибирається найближчий до краю дефіс і вся права від дефіса частина слова переноситься на новий рядок.
Такі правила вже є для російської мови. Вони не ідеально точні, але нібито покривають 99% всіх переносів. Також, думаю, їх можна розробити та деяких інших мов. Але не для всіх. Наприклад, в англійській для переносу слів по складах потрібно куди більш складний алгоритм, т. к. слова переносяться по звучанню, а не по написанню.
Ось так виглядають правила для російської мови:
  • «Х-ЛЛ»
  • «ГЛ»
  • «ГС-СГ»
  • «СГ-СГ»
  • «ГС-ССГ»
  • «ЦСС-ССГ»
Тут Л – будь-яка літера, Р – голосна, З – приголосна, Х – буква з набору «йьъ». Щоб надати користувачам можливість змінювати правила, не модифікуючи вихідний код, я виніс їх в окремий файл:
Файл з правилами переносу
Я дозволив собі дещо модифікувати оригінальні правила, щоб не допустити відриву однієї літери від слова.
Інші можливості
Векторна графіка дає можливість змінювати параметри ліній, зокрема, скругляющі їх краю і згладжувати кути, так чому б цим не скористатися? Крім того, не бачу причин якось обмежувати користувача в можливості налаштувати параметри аркуша і шрифту. Приблизне уявлення про основні налаштуваннях можна отримати, подивившись на скріншот:
Скріншот налаштувань
Ще трохи фоток конспекту
Кликабельно:
Фото 1
Фото 2
Фото 3
Джерело
Як і обіцяв – посилання на репозиторій: https://github.com/aizenbit/Scribbler
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.