Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99b32ab406 | ||
|
|
9951196477 | ||
|
|
0034e018aa | ||
|
|
69c175192a | ||
|
|
270bbfb3ab | ||
|
|
63e481ba29 | ||
|
|
7893cb1659 | ||
|
|
4d9c1386d7 | ||
|
|
0d88c49c2c | ||
|
|
785603ba93 | ||
|
|
1f972371d1 | ||
|
|
16ded48b20 | ||
|
|
696ada3de7 | ||
|
|
5db1c0abde | ||
|
|
ee1ca3a096 | ||
|
|
f4ef05670f | ||
|
|
8555032acc | ||
|
|
dfccf446e5 | ||
|
|
74d9255a80 | ||
|
|
f825d5211d | ||
|
|
5d00a3c3bd | ||
|
|
0d1c8192b8 | ||
|
|
ed296701fe | ||
|
|
b4294f637b | ||
|
|
1ee5a40d6e | ||
|
|
5ec7862f57 | ||
|
|
5bbe9790da | ||
|
|
dc7fc21780 | ||
|
|
00037d85de | ||
|
|
e79ff56105 | ||
|
|
ec2b8014ad | ||
|
|
9a9e4c8d83 | ||
|
|
d4ea373b62 | ||
|
|
ac2252b81c | ||
|
|
bd29dc05a9 | ||
|
|
7da29e1173 | ||
|
|
e10bf402dc | ||
|
|
d44916965e | ||
|
|
c0cabc34e9 | ||
|
|
3080f38f80 | ||
|
|
0e9012fe82 | ||
|
|
eced150111 | ||
|
|
7ef1429d17 | ||
|
|
9c26e52eb5 | ||
|
|
267882c42d | ||
|
|
04245a37e7 | ||
|
|
f33b99b2b2 | ||
|
|
7f8d16087e | ||
|
|
d994da27d7 | ||
|
|
507ccd46a9 | ||
|
|
1e5e6592ce | ||
|
|
919feb1b3e | ||
|
|
6957850277 |
No files matched your search
+3
-2
@@ -1,5 +1,6 @@
|
||||
|
||||
.DS_Store
|
||||
src/__pycache__
|
||||
dist/
|
||||
build/
|
||||
build/
|
||||
docs/_site/
|
||||
docs/.jekyll-cache/
|
||||
@@ -4,10 +4,16 @@
|
||||

|
||||
[](https://GitHub.com/IdreesInc/Monocraft/releases/)
|
||||
|
||||
## [`Download it here!`](https://github.com/IdreesInc/Monocraft/releases)
|
||||
<br/>
|
||||
|
||||

|
||||
|
||||
|
||||
The monospaced font for developers who like Minecraft a bit _too_ much.
|
||||
|
||||
If you'd like to see a vectorized version of this font, try [Miracode](https://github.com/IdreesInc/Miracode)!
|
||||
|
||||
*Notice: This project is not affiliated with Minecraft or Mojang in any way and is exclusively a fan project. This font emulates the typeface of the font used in the Minecraft UI, but it does not include any assets or font files from the original game.*
|
||||
|
||||
## Features
|
||||
@@ -15,7 +21,7 @@ The monospaced font for developers who like Minecraft a bit _too_ much.
|
||||
- Minecraft!
|
||||
- The characters in this font were based around the [typeface](https://github.com/IdreesInc/Minecraft-Font) used in the Minecraft UI, with each glyph updated for better readability and spacing
|
||||
- Monospaced!
|
||||
- Each of the 500+ glyphs included in this font have been carefully redesigned to work in a monospaced font
|
||||
- Each of the 1500+ glyphs included in this font have been carefully redesigned to work in a monospaced font
|
||||
- Thin characters like "i" and "l" have been reworked with tasteful tails and serifs to look better in a monospaced environment
|
||||
- Programming ligatures!
|
||||
- Add some spice to your programming life with all new ligature characters
|
||||
@@ -29,7 +35,7 @@ The monospaced font for developers who like Minecraft a bit _too_ much.
|
||||
|
||||
### Windows
|
||||
|
||||
Download the most recent `Monocraft.ttf` file from the [Releases](https://github.com/IdreesInc/Monocraft/releases) page. Right click on the downloaded font and select **Install**. You might need administrative access to install fonts, depending on your machine.
|
||||
Download the most recent `Monocraft.ttc` file from the [Releases](https://github.com/IdreesInc/Monocraft/releases) page. Right click on the downloaded font and select **Install**. You might need administrative access to install fonts, depending on your machine.
|
||||
|
||||
### Mac
|
||||
|
||||
@@ -42,11 +48,11 @@ brew install --cask font-monocraft
|
||||
|
||||
#### Manually
|
||||
|
||||
Download the most recent `Monocraft.ttf` file from the [Releases](https://github.com/IdreesInc/Monocraft/releases) page. Double click on the downloaded font file and select **Install Font** in the window that appears. More help available [here](https://support.apple.com/en-us/HT201749).
|
||||
Download the most recent `Monocraft.ttc` file from the [Releases](https://github.com/IdreesInc/Monocraft/releases) page. Double click on the downloaded font file and select **Install Font** in the window that appears. More help available [here](https://support.apple.com/en-us/HT201749).
|
||||
|
||||
### Linux
|
||||
|
||||
Download the most recent `Monocraft.ttf` file from the [Releases](https://github.com/IdreesInc/Monocraft/releases) page. Move the file to ~/.local/share/fonts (create the folder if it doesn't already exist). In a terminal, run `fc-cache -fv`. Alternatively, log out and log in again.
|
||||
Download the most recent `Monocraft.ttc` file from the [Releases](https://github.com/IdreesInc/Monocraft/releases) page. Move the file to ~/.local/share/fonts (create the folder if it doesn't already exist). In a terminal, run `fc-cache -fv`. Alternatively, log out and log in again.
|
||||
|
||||
## How to use
|
||||
|
||||
@@ -60,6 +66,8 @@ So far, the following ligatures have been added to the font:
|
||||
|
||||
<img src="images/ligatures.png" width="300">
|
||||
|
||||
And with the contributions of [@Ciubix8513](https://github.com/Ciubix8513), Monocraft now includes continuous ligatures that enable you to type arrows and lines that _just keep going_.
|
||||
|
||||
If there is another character combination that you feel could be a ligature, feel free to create an issue!
|
||||
|
||||
### How are these characters generated?
|
||||
@@ -72,4 +80,4 @@ I've got you covered, check out my rendition of the Minecraft typeface [here](ht
|
||||
|
||||
### What if I want to use a font that's actually good?
|
||||
|
||||
Understandable, check out [Fira Code](https://github.com/tonsky/FiraCode) for a font with amazing attention to detail, or [Scientifica](https://github.com/nerdypepper/scientifica) for a bitmap font similar to this.
|
||||
Understandable, check out [Fira Code](https://github.com/tonsky/FiraCode) for a font with amazing attention to detail, or [Scientifica](https://github.com/nerdypepper/scientifica) for a bitmap font similar to this. Feel free to also check out my font [Miracode](https://github.com/IdreesInc/Miracode) for a font based on Monocraft that's a little more usable!
|
||||
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
monocraft.idreesinc.com
|
||||
@@ -0,0 +1,3 @@
|
||||
gem "jekyll"
|
||||
gem "webrick"
|
||||
gem "jekyll-remote-theme"
|
||||
@@ -0,0 +1,78 @@
|
||||
GEM
|
||||
specs:
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
colorator (1.1.0)
|
||||
concurrent-ruby (1.3.4)
|
||||
em-websocket (0.5.3)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0)
|
||||
eventmachine (1.2.7)
|
||||
ffi (1.17.0-arm64-darwin)
|
||||
forwardable-extended (2.6.0)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.8.11)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jekyll (4.3.3)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
em-websocket (~> 0.5)
|
||||
i18n (~> 1.0)
|
||||
jekyll-sass-converter (>= 2.0, < 4.0)
|
||||
jekyll-watch (~> 2.0)
|
||||
kramdown (~> 2.3, >= 2.3.1)
|
||||
kramdown-parser-gfm (~> 1.0)
|
||||
liquid (~> 4.0)
|
||||
mercenary (>= 0.3.6, < 0.5)
|
||||
pathutil (~> 0.9)
|
||||
rouge (>= 3.0, < 5.0)
|
||||
safe_yaml (~> 1.0)
|
||||
terminal-table (>= 1.8, < 4.0)
|
||||
webrick (~> 1.7)
|
||||
jekyll-remote-theme (0.4.3)
|
||||
addressable (~> 2.0)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
|
||||
rubyzip (>= 1.3.0, < 3.0)
|
||||
jekyll-sass-converter (2.1.0)
|
||||
sassc (> 2.0.1, < 3.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
kramdown (2.3.1)
|
||||
rexml
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
liquid (4.0.3)
|
||||
listen (3.9.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.4.0)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (4.0.7)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.11.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.3.5)
|
||||
strscan
|
||||
rouge (3.26.1)
|
||||
rubyzip (2.3.2)
|
||||
safe_yaml (1.0.5)
|
||||
sassc (2.4.0)
|
||||
ffi (~> 1.9)
|
||||
strscan (3.1.0)
|
||||
terminal-table (2.0.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
unicode-display_width (1.8.0)
|
||||
webrick (1.7.0)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin
|
||||
|
||||
DEPENDENCIES
|
||||
jekyll
|
||||
jekyll-remote-theme
|
||||
webrick
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.17
|
||||
@@ -0,0 +1,3 @@
|
||||
remote_theme: IdreesInc/Jekyll-Project-Theme
|
||||
plugins:
|
||||
- jekyll-remote-theme
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
window_title: "Get Monocraft - The Minecraft Font for Devs"
|
||||
title: "Monocraft"
|
||||
subtitle: "the programming font for the minecraft obsessed"
|
||||
annotation: "*plus, it has ligatures!"
|
||||
source_code: "https://github.com/IdreesInc/Monocraft"
|
||||
background: "linear-gradient(90deg, #f5e1c4, #daf0d3, #BCE7FF)"
|
||||
layout: "project"
|
||||
---
|
||||
|
||||
{% include link.html
|
||||
url="https://github.com/IdreesInc/Monocraft/releases"
|
||||
text="download it here"
|
||||
%}
|
||||
|
||||
{% include link.html
|
||||
url="https://arstechnica.com/gaming/2022/09/developer-creates-delightful-programming-font-based-on-minecraft/"
|
||||
text="in the press"
|
||||
%}
|
||||
|
||||
{% include link.html
|
||||
url="https://socials.idreesinc.com"
|
||||
text="follow for updates"
|
||||
%}
|
||||
@@ -0,0 +1,139 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Epilogue:wght@400;500&display=swap');
|
||||
|
||||
html {
|
||||
font-family: 'Epilogue', sans-serif;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#foil {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 60%;
|
||||
height: 15%;
|
||||
left: 15%;
|
||||
top: 30%;
|
||||
transform: rotate(-20deg);
|
||||
background-image: url('foil.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
#intro-page {
|
||||
height: 100vh;
|
||||
width: 65%;
|
||||
margin-left: 30%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
#subtitle {
|
||||
font-size: 35px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
#links {
|
||||
font-family: Epilogue;
|
||||
font-size: 30px;
|
||||
margin-top: 30px;
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.link a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#github a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#github {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#annotation {
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
right: 40px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#me {
|
||||
font-size: 16px;
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 40px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#me a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
@media screen and (orientation:portrait) and (max-width: 85vh) {
|
||||
#foil {
|
||||
width: 90%;
|
||||
height: 11%;
|
||||
left: 5%;
|
||||
top: 27%;
|
||||
transform: rotate(-20deg);
|
||||
}
|
||||
|
||||
#intro-page {
|
||||
width: 80%;
|
||||
margin-top: -10%;
|
||||
margin-left: 10%;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 16vw;
|
||||
}
|
||||
|
||||
#subtitle {
|
||||
font-size: 6.4vw;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#links {
|
||||
font-size: 6vw;
|
||||
margin-top: 110px;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
#annotation {
|
||||
font-size: 3vw;
|
||||
position: absolute;
|
||||
bottom: 6vw;
|
||||
right: 25px;
|
||||
}
|
||||
|
||||
#me {
|
||||
font-size: 3vw;
|
||||
position: absolute;
|
||||
bottom: 1.5vw;
|
||||
right: 25px;
|
||||
}
|
||||
}
|
||||
+241
-17
@@ -6,25 +6,39 @@ a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
|
||||
! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
||||
¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á
|
||||
Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á
|
||||
â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý ÿ Ā ā Ă
|
||||
ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ
|
||||
ĥ Ĩ ĩ Ī ī Ĭ ĭ İ Ĵ ĵ Ķ ķ Ĺ ĺ Ļ ļ Ľ ľ Ł ł Ń ń Ņ ņ Ň ň Ō ō Ŏ ŏ Ő ő
|
||||
Œ œ Ŕ ŕ Ř ř Ś ś Ŝ ŝ Ş ş Š š Ť ť Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ŵ ŵ Ŷ ŷ Ÿ Ź
|
||||
ź Ż ż Ž
|
||||
¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ
|
||||
Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ Ā ā
|
||||
Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ ĥ Ĩ ĩ Ī ī Ĭ ĭ İ ı IJ ij Ĵ ĵ Ķ ķ
|
||||
ĸ Ĺ ĺ Ļ ļ Ľ ľ Ł ł Ń ń Ņ ņ Ň ň Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ř ř Ś ś Ŝ ŝ Ş ş Š š Ť ť Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ŵ
|
||||
ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž
|
||||
|
||||
ž Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǣ ǣ Ǧ ǧ Ǩ ǩ ǰ Ǵ ǵ Ǹ ǹ Ǽ ǽ Ș ș Ț ț Ȟ ȟ Ȧ ȧ Ȯ ȯ
|
||||
Ȳ ȳ Ѐ Ё Ђ Ѓ Є Ѕ І Ї Ј Љ Њ Ћ Ќ Ѝ Ў Џ А Б В Г Д Е Ж З И Й К Л М Н
|
||||
О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я а б в г д е ж з и й к л м н
|
||||
о п р с т у ф х ц ч ш щ ъ ы ь э ю я ѐ ё ђ ѓ є ѕ і ї ј љ њ ћ ќ ѝ
|
||||
ў џ
|
||||
ž ſ Ɓ Ƅ ƅ Ɔ Ɖ Ǝ Ə Ɛ Ƒ ƚ ƛ ƞ Ɵ Ƨ ƨ Ʃ ƪ Ʋ Ʒ Ƹ ƹ ƻ Ƽ ƽ ƾ ƿ ǀ ǁ ǂ ǃ lj Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ ǝ Ǣ ǣ Ǧ ǧ Ǩ ǩ
|
||||
Ǯ ǯ ǰ Ǵ ǵ Ƿ Ǹ ǹ Ǽ ǽ Ș ș Ț ț Ȝ ȝ Ȟ ȟ Ƞ ȡ Ȥ ȥ Ȧ ȧ Ȯ ȯ Ȳ ȳ ȴ ȵ ȶ Ⱥ Ȼ ȼ Ƚ Ⱦ Ɂ ɂ Ƀ Ʉ Ʌ Ɇ ɇ Ɉ ɉ Ɋ ɋ Ɍ
|
||||
ɍ Ɏ ɏ ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ ɛ ɜ ɝ ɞ ɟ ɠ ɡ ɢ ɤ ɥ ɦ ɧ ɨ ɪ ɫ ɬ ɭ ɮ ɯ ɰ ɱ ɲ ɳ ɴ ɵ ɷ ɸ ɹ ɺ ɻ ɼ ɾ ɿ ʀ
|
||||
ʁ ʄ ʅ ʆ ʇ ʈ ʉ ʊ ʋ ʌ ʍ ʎ ʏ ʑ ʒ ʓ ʔ ʕ ʖ ʗ ʘ ʙ ʚ ʛ ʜ ʝ ʞ ʟ ʠ ʡ ʢ ʬ ʻ ˌ ˙ ; · Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ
|
||||
Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω ϛ Ѐ Ё Ђ Ѓ Є Ѕ І Ї Ј
|
||||
Љ Њ Ћ Ќ Ѝ Ў Џ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я а б в г д е ж з и
|
||||
й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я ѐ ё ђ ѓ є ѕ і ї ј љ њ ћ ќ ѝ ў џ
|
||||
|
||||
Ӂ ӂ Ӑ ӑ Ӓ ӓ Ӗ ӗ Ӝ ӝ Ӟ ӟ Ӣ ӣ Ӥ ӥ Ӧ ӧ Ӭ ӭ Ӯ ӯ Ӱ ӱ Ӳ ӳ Ӵ ӵ Ӹ ӹ Ḃ ḃ
|
||||
Ḋ ḋ Ḟ ḟ Ḡ ḡ Ḣ ḣ Ḧ ḧ Ḱ ḱ Ḿ ḿ Ṁ ṁ Ṅ ṅ Ṕ ṕ Ṗ ṗ Ṙ ṙ Ṡ ṡ Ṫ ṫ Ṽ ṽ Ẁ ẁ
|
||||
Ẃ ẃ Ẅ ẅ Ẇ ẇ Ẋ ẋ Ẍ ẍ Ẏ ẏ Ẑ ẑ ẗ ẘ ẙ Ẽ ẽ Ỳ ỳ Ỹ ỹ
|
||||
Ѣ ѣ Ѳ ѳ Ѵ ѵ Ғ ғ Җ җ Қ қ Ң ң Ү ү Ұ ұ Һ һ Ӏ Ӂ ӂ Ӑ ӑ Ӓ ӓ Ӗ ӗ Ә ә Ӛ ӛ Ӝ ӝ Ӟ ӟ Ӣ ӣ Ӥ ӥ Ӧ ӧ Ө ө Ӫ ӫ Ӭ
|
||||
ӭ Ӯ ӯ Ӱ ӱ Ӳ ӳ Ӵ ӵ Ӹ ӹ Ԁ Ա Բ Գ Դ Ե Զ Է Ը Թ Ժ Ի Լ Խ Ծ Կ Հ Ձ Ղ Ճ Մ Յ Ն Շ Ո Չ Պ Ջ Ռ Ս Վ Տ Ր Ց Ւ Փ Ք
|
||||
Օ Ֆ ՙ ՚ ՛ ՜ ՝ ՞ ՟ ՠ ա բ գ դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն շ ո չ պ ջ ռ ս վ տ ր ց ւ փ ք օ ֆ
|
||||
և ֈ ֊ ֏ ־ ׃ ׆ א ב ג ד ה ו ז ח ט י ך כ ל ם מ ן נ ס ע ף פ ץ צ ק ר ש ת װ ױ ײ ׳ ״ ߈ Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ
|
||||
Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ Ⴧ Ⴭ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ
|
||||
რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჷ ჸ ჹ ჺ ჻ ჼ ჽ ჾ ჿ ᗡ ᗺ ᘔ ᚠ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ
|
||||
ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ
|
||||
ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ ᛱ ᛲ ᛳ ᛴ ᛵ ᛶ ᛷ ᛸ ᴀ ᴄ ᴅ ᴇ ᴉ ᴊ ᴋ ᴍ ᴏ ᴘ ᴚ ᴛ ᴜ ᴠ ᴡ ᴢ ᵷ ᶑ Ḃ ḃ Ḋ ḋ
|
||||
Ḟ ḟ Ḡ ḡ Ḣ ḣ Ḧ ḧ Ḱ ḱ Ḿ ḿ Ṁ ṁ Ṅ ṅ Ṕ ṕ Ṗ ṗ Ṙ ṙ Ṡ ṡ Ṫ ṫ Ṽ ṽ Ẁ ẁ Ẃ ẃ Ẅ ẅ Ẇ ẇ Ẋ ẋ Ẍ ẍ Ẏ ẏ Ẑ ẑ ẗ ẘ ẙ ẛ
|
||||
ẜ ẝ ẞ ẟ Ẽ ẽ Ỳ ỳ Ỹ ỹ Ỽ ỽ Ỿ ỿ ᾱ Ᾱ ῑ Ῑ ῡ Ῡ ‑ – — ‘ ’ ‚ “ ” „ † ‡ • … ‰ ‱ ′ ″ ‴ ‵ ‶ ‷ ‹ › ※ ‼ ‽ ⁂ ⁈
|
||||
⁉ ⁊ ⁋ ⁎ ⁏ ⁑ ⁒ ⁗ ⁰ ⁱ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₊ ₋ ₌ ₍ ₎ ₠ ₡ ₢ ₣ ₤ ₥ ₦ ₩ ₪
|
||||
|
||||
€ ← ↑ → ↓ ⇐ ⇑ ⇒ ⇓ ∀ ∷ ☺ ☻ ♥ ⨰ ⸚
|
||||
₫ € ₭ ₮ ₰ ₱ ₲ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ₺ ₻ ₼ ₽ ₾ ₿ ℗ ™ Ⅎ ⅁ ⅄ ⅋ ⅐ ⅑ ⅓ ⅔ ⅕ ⅖ ⅗ ⅙ ⅚ ⅛ ⅜ ⅝ ⅞ ⅟ ↉ ← ↑ → ↓ ↔ ⇄ ⇏
|
||||
⇐ ⇑ ⇒ ⇓ ⇔ ⇵ ∀ ∁ ∂ ∃ ∄ ∉ ∋ ∌ ∑ − ∓ ∛ ∜ ∝ ∞ ∥ ∧ ∨ ∩ ∫ ∮ ∴ ∵ ∷ ≔ ≠ ≢ ⊂ ⊃ ⊄ ⊅ ⊆ ⊇ ⊢ ⊤ ⊥ ⊨ ⊻ ⊼ ⊽ ⋃ ⋆
|
||||
⌀ ⌂ ⌘ ⌚ ⌛ ⏏ ⏩ ⏪ ⏭ ⏮ ⏯ ⏳ ⏴ ⏵ ⏶ ⏷ ⏸ ⏹ ⏺ ⏻ ⏼ ⏽ □ ▲ △ ▶ ▷ ▼ ▽ ◀ ◁ ◆ ◇ ○ ◎ ● ◘ ◦ ☀ ☁ ☂ ☃ ☄ ★ ☆ ☈ ☔ ☠
|
||||
☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ☹ ☺ ☻ ☽ ♀ ♂ ♠ ♡ ♢ ♣ ♤ ♥ ♦ ♧ ♩ ♪ ♫ ♬ ♭ ♮ ♯ ⚀ ⚁ ⚂ ⚃ ⚄ ⚅ ⚐ ⚑ ⚓ ⚔ ⚗ ⚡ ⚥ ⛄ ⛈ ⛏ ⛨ ✂ ✉
|
||||
✎ ✔ ✘ ❄ ❌ ❣ ❤ ⟘ ⥝ ⧈ ⨰ ⩑ ⩒ ⫃ ⫄ ⭐ ⭘ ⯪ ⯫ ⱥ ⱦ Ɑ Ɐ ⱱ ⴀ ⴁ ⴂ ⴃ ⴄ ⴅ ⴆ ⴇ ⴈ ⴉ ⴊ ⴋ ⴌ ⴍ ⴎ ⴏ ⴐ ⴑ ⴒ ⴓ ⴔ ⴕ ⴖ ⴗ
|
||||
ⴘ ⴙ ⴚ ⴛ ⴜ ⴝ ⴞ ⴟ ⴠ ⴡ ⴢ ⴣ ⴤ ⴥ ⸘ ⸚ ⸮ ⸵ ⸸ ⹁ ⹋ 〒 ㄥ Ꜧ ꜧ Ꜩ ꜩ ꜰ ꜱ ꜹ ꜻ Ꝛ ꝛ Ꝺ Ꞁ ꞁ Ꞩ ꞩ ꞯ Ʞ ff fi fl ffi ſt יִ ײַ שׂ
|
||||
בּ וּ כּ פּ תּ וֹ בֿ פֿ + �
|
||||
|
||||
--- Ligatures ---
|
||||
= = -> ==
|
||||
@@ -36,4 +50,214 @@ a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
< - -> <-
|
||||
- > -> ->
|
||||
= > -> =>
|
||||
< = > -> <=>
|
||||
< = > -> <=>
|
||||
< ! - - -> <!--
|
||||
= = > -> ==>
|
||||
= = = > -> ===>
|
||||
= = = = > -> ====>
|
||||
= = = = = > -> =====>
|
||||
= = = = = = >-> ======>
|
||||
= = = = = = = >-> =======>
|
||||
= = = = = = = = >-> ========>
|
||||
= = = = = = = = = >-> =========>
|
||||
= = = = = = = = = = >-> ==========>
|
||||
= = = = = = = = = = = >-> ===========>
|
||||
= = = = = = = = = = = = >-> ============>
|
||||
= = = = = = = = = = = = = >-> =============>
|
||||
= = = = = = = = = = = = = = >-> ==============>
|
||||
= = = = = = = = = = = = = = = >-> ===============>
|
||||
= = = = = = = = = = = = = = = = >-> ================>
|
||||
= = = = = = = = = = = = = = = = = >-> =================>
|
||||
= = = = = = = = = = = = = = = = = = >-> ==================>
|
||||
= = = = = = = = = = = = = = = = = = = >-> ===================>
|
||||
= = = = = = = = = = = = = = = = = = = = >-> ====================>
|
||||
= = = = = = = = = = = = = = = = = = = = = >-> =====================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = >-> ======================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = >-> =======================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = >-> ========================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = >-> =========================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = = >-> ==========================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = = = >-> ===========================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = = = = >-> ============================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = >-> =============================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = >-> ==============================>
|
||||
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = >-> ===============================>
|
||||
< = = -> <==
|
||||
< = = = -> <===
|
||||
< = = = = -> <====
|
||||
< = = = = = -> <=====
|
||||
< = = = = = =-> <======
|
||||
< = = = = = = =-> <=======
|
||||
< = = = = = = = =-> <========
|
||||
< = = = = = = = = =-> <=========
|
||||
< = = = = = = = = = =-> <==========
|
||||
< = = = = = = = = = = =-> <===========
|
||||
< = = = = = = = = = = = =-> <============
|
||||
< = = = = = = = = = = = = =-> <=============
|
||||
< = = = = = = = = = = = = = =-> <==============
|
||||
< = = = = = = = = = = = = = = =-> <===============
|
||||
< = = = = = = = = = = = = = = = =-> <================
|
||||
< = = = = = = = = = = = = = = = = =-> <=================
|
||||
< = = = = = = = = = = = = = = = = = =-> <==================
|
||||
< = = = = = = = = = = = = = = = = = = =-> <===================
|
||||
< = = = = = = = = = = = = = = = = = = = =-> <====================
|
||||
< = = = = = = = = = = = = = = = = = = = = =-> <=====================
|
||||
< = = = = = = = = = = = = = = = = = = = = = =-> <======================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = =-> <=======================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = =-> <========================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = =-> <=========================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = = =-> <==========================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = = = =-> <===========================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = = = = =-> <============================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = = = = = =-> <=============================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =-> <==============================
|
||||
< = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =-> <===============================
|
||||
- - > -> -->
|
||||
- - - > -> --->
|
||||
- - - - > -> ---->
|
||||
- - - - - > -> ----->
|
||||
- - - - - - >-> ------>
|
||||
- - - - - - - >-> ------->
|
||||
- - - - - - - - >-> -------->
|
||||
- - - - - - - - - >-> --------->
|
||||
- - - - - - - - - - >-> ---------->
|
||||
- - - - - - - - - - - >-> ----------->
|
||||
- - - - - - - - - - - - >-> ------------>
|
||||
- - - - - - - - - - - - - >-> ------------->
|
||||
- - - - - - - - - - - - - - >-> -------------->
|
||||
- - - - - - - - - - - - - - - >-> --------------->
|
||||
- - - - - - - - - - - - - - - - >-> ---------------->
|
||||
- - - - - - - - - - - - - - - - - >-> ----------------->
|
||||
- - - - - - - - - - - - - - - - - - >-> ------------------>
|
||||
- - - - - - - - - - - - - - - - - - - >-> ------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - >-> -------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - >-> --------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - >-> ---------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - >-> ----------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - >-> ------------------------>
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - >-> ------------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - >-> -------------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - >-> --------------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - >-> ---------------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - >-> ----------------------------->
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >-> ------------------------------>
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >-> ------------------------------->
|
||||
< - - -> <--
|
||||
< - - - -> <---
|
||||
< - - - - -> <----
|
||||
< - - - - - -> <-----
|
||||
< - - - - - --> <------
|
||||
< - - - - - - --> <-------
|
||||
< - - - - - - - --> <--------
|
||||
< - - - - - - - - --> <---------
|
||||
< - - - - - - - - - --> <----------
|
||||
< - - - - - - - - - - --> <-----------
|
||||
< - - - - - - - - - - - --> <------------
|
||||
< - - - - - - - - - - - - --> <-------------
|
||||
< - - - - - - - - - - - - - --> <--------------
|
||||
< - - - - - - - - - - - - - - --> <---------------
|
||||
< - - - - - - - - - - - - - - - --> <----------------
|
||||
< - - - - - - - - - - - - - - - - --> <-----------------
|
||||
< - - - - - - - - - - - - - - - - - --> <------------------
|
||||
< - - - - - - - - - - - - - - - - - - --> <-------------------
|
||||
< - - - - - - - - - - - - - - - - - - - --> <--------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - --> <---------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - --> <----------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - --> <-----------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - --> <------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - --> <-------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - - --> <--------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - - - --> <---------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <----------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <-----------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <------------------------------
|
||||
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <-------------------------------
|
||||
- - - -> ---
|
||||
- - - - -> ----
|
||||
- - - - - -> -----
|
||||
- - - - - - -> ------
|
||||
- - - - - - --> -------
|
||||
- - - - - - - --> --------
|
||||
- - - - - - - - --> ---------
|
||||
- - - - - - - - - --> ----------
|
||||
- - - - - - - - - - --> -----------
|
||||
- - - - - - - - - - - --> ------------
|
||||
- - - - - - - - - - - - --> -------------
|
||||
- - - - - - - - - - - - - --> --------------
|
||||
- - - - - - - - - - - - - - --> ---------------
|
||||
- - - - - - - - - - - - - - - --> ----------------
|
||||
- - - - - - - - - - - - - - - - --> -----------------
|
||||
- - - - - - - - - - - - - - - - - --> ------------------
|
||||
- - - - - - - - - - - - - - - - - - --> -------------------
|
||||
- - - - - - - - - - - - - - - - - - - --> --------------------
|
||||
- - - - - - - - - - - - - - - - - - - - --> ---------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - --> ----------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - --> -----------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - --> ------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - --> -------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - --> --------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - --> ---------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - --> ----------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - --> -----------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> ------------------------------
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> -------------------------------
|
||||
^ ^ -> ^^
|
||||
^ ^ ^ -> ^^^
|
||||
^ ^ ^ ^ -> ^^^^
|
||||
^ ^ ^ ^ ^ -> ^^^^^
|
||||
^ ^ ^ ^ ^ ^ -> ^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^-> ^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^-> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
+ + -> ++
|
||||
+ + + -> +++
|
||||
+ + + + -> ++++
|
||||
+ + + + + -> +++++
|
||||
+ + + + + + -> ++++++
|
||||
+ + + + + + +-> +++++++
|
||||
+ + + + + + + +-> ++++++++
|
||||
+ + + + + + + + +-> +++++++++
|
||||
+ + + + + + + + + +-> ++++++++++
|
||||
+ + + + + + + + + + +-> +++++++++++
|
||||
+ + + + + + + + + + + +-> ++++++++++++
|
||||
+ + + + + + + + + + + + +-> +++++++++++++
|
||||
+ + + + + + + + + + + + + +-> ++++++++++++++
|
||||
+ + + + + + + + + + + + + + +-> +++++++++++++++
|
||||
+ + + + + + + + + + + + + + + +-> ++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + +-> +++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + +-> ++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + +-> ++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + +-> ++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + +-> ++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + + +-> ++++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +-> ++++++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-> ++++++++++++++++++++++++++++++
|
||||
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-> +++++++++++++++++++++++++++++++
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 615 KiB After Width: | Height: | Size: 1019 KiB |
+14102
-5
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,197 @@
|
||||
[
|
||||
{
|
||||
"head": "=>",
|
||||
"body": "=",
|
||||
"head_name": "right thick arrow",
|
||||
"body_name": "equals sign",
|
||||
"direction": "right",
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
|
||||
"head_pixels": [
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"head": "<=",
|
||||
"body": "=",
|
||||
"head_name": "left thick arrow",
|
||||
"body_name": "equals sign",
|
||||
"direction": "left",
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
|
||||
"head_pixels": [
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"head": "->",
|
||||
"body": "-",
|
||||
"head_name": "right arrow",
|
||||
"body_name": "minus",
|
||||
"direction": "right",
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
|
||||
"head_pixels": [
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"head": "<-",
|
||||
"body": "-",
|
||||
"head_name": "left arrow",
|
||||
"body_name": "minus",
|
||||
"direction": "left",
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
|
||||
"head_pixels": [
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"head": "-",
|
||||
"body": "-",
|
||||
"head_name": "minus",
|
||||
"body_name": "minus",
|
||||
"direction": "left",
|
||||
"min_length": 2,
|
||||
"max_length": 30,
|
||||
|
||||
"head_pixels": [
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"head": "^",
|
||||
"body": "^",
|
||||
"head_name": "caret",
|
||||
"body_name": "caret",
|
||||
"direction": "right",
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
"head_pixels": [
|
||||
[0, 0, 1, 1, 0, 0],
|
||||
[0, 1, 0, 0, 1, 0],
|
||||
[1, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 1, 1, 0, 0],
|
||||
[0, 1, 0, 0, 1, 0],
|
||||
[1, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"head": "+",
|
||||
"body": "+",
|
||||
"head_name": "plus",
|
||||
"body_name": "plus",
|
||||
"direction": "right",
|
||||
"min_length": 1,
|
||||
"max_length": 30,
|
||||
"head_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
],
|
||||
"body_pixels": [
|
||||
[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,75 @@
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
import copy
|
||||
|
||||
|
||||
def generate_continuous_ligatures(filename):
|
||||
"""
|
||||
Generates continuous ligature data from a JSON file.
|
||||
|
||||
The JSON file should have the following structure:
|
||||
[
|
||||
{
|
||||
"head_name": "string",
|
||||
"body_name": "string",
|
||||
"head": "string",
|
||||
"body": "string",
|
||||
"direction": "left" or "right",
|
||||
"min_length": int,
|
||||
"max_length": int,
|
||||
"head_pixels": [[int, int, ...], ...],
|
||||
"body_pixels": [[int, int, ...], ...]
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
Returns a list of progress bars, where each progress bar is a dictionary with the following keys:
|
||||
- "name": a string representing the name of the progress bar
|
||||
- "ligature": a string representing the progress bar
|
||||
- "sequence": a list of integers representing the Unicode code points of the characters in the progress bar
|
||||
- "pixels": a list of integers representing the pixels of the progress bar
|
||||
"""
|
||||
continuous_ligatures = json.load(open(filename))
|
||||
out = []
|
||||
for ligature in continuous_ligatures:
|
||||
name = f'{ligature["head_name"]} {ligature["body_name"]} '
|
||||
body_pixels = ligature["body_pixels"]
|
||||
head_pixels = ligature["head_pixels"]
|
||||
body = [[] for _ in range(len(body_pixels))]
|
||||
for i in range( ligature["min_length"],ligature["max_length"] + 1):
|
||||
glyph = {}
|
||||
# Generate ligature data
|
||||
glyph["name"] = name + str(i);
|
||||
if ligature["direction"] == "right":
|
||||
glyph["ligature"] = ligature["body"] * i + ligature["head"]
|
||||
else:
|
||||
glyph["ligature"] = ligature["head"] + ligature["body"] * i
|
||||
glyph["sequence"] = [ord(c) for c in glyph["ligature"]]
|
||||
# Generate pixels
|
||||
# Expand the body by 1
|
||||
for k in range(len(body)):
|
||||
body[k] += body_pixels[k]
|
||||
pixels = []
|
||||
if ligature["direction"] == "right":
|
||||
pixels = copy.deepcopy(body)
|
||||
for j in range(len(pixels)):
|
||||
pixels[j] += head_pixels[j]
|
||||
else:
|
||||
pixels = copy.deepcopy(head_pixels)
|
||||
for j in range(len(pixels)):
|
||||
pixels[j] += body[j]
|
||||
glyph["pixels"] = pixels
|
||||
out.append(glyph)
|
||||
return out
|
||||
@@ -48,7 +48,7 @@ def generateExamples(characters, ligatures, charactersByCodepoint):
|
||||
index = 0
|
||||
characterOutput += "\n"
|
||||
if i in charactersByCodepoint:
|
||||
if index % 32 == 0:
|
||||
if index % 48 == 0:
|
||||
characterOutput += "\n"
|
||||
characterOutput += chr(i) + " "
|
||||
index += 1
|
||||
|
||||
+15
-1
@@ -149,5 +149,19 @@
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"ligature": "<!--",
|
||||
"name": "html comment",
|
||||
"sequence": [60, 33, 45, 45],
|
||||
"pixels": [
|
||||
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
+295
-38
@@ -1,5 +1,5 @@
|
||||
# Monocraft, a monospaced font for developers who like Minecraft a bit too much.
|
||||
# Copyright (C) 2022-2023 Idrees Hassan
|
||||
# Copyright (C) 2022-2024 Idrees Hassan
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -17,64 +17,236 @@ import os
|
||||
import fontforge
|
||||
import json
|
||||
import math
|
||||
import argparse
|
||||
from generate_diacritics import generateDiacritics
|
||||
from generate_examples import generateExamples
|
||||
from polygonizer import PixelImage, generatePolygons
|
||||
from generate_continuous_ligatures import generate_continuous_ligatures
|
||||
|
||||
PIXEL_SIZE = 120
|
||||
|
||||
characters = json.load(open("./characters.json"))
|
||||
diacritics = json.load(open("./diacritics.json"))
|
||||
ligatures = json.load(open("./ligatures.json"))
|
||||
ligatures += generate_continuous_ligatures("./continuous_ligatures.json")
|
||||
|
||||
characters = generateDiacritics(characters, diacritics)
|
||||
charactersByCodepoint = {}
|
||||
|
||||
def generateFont():
|
||||
monocraft = fontforge.font()
|
||||
monocraft.fontname = "Monocraft"
|
||||
monocraft.familyname = "Monocraft"
|
||||
monocraft.fullname = "Monocraft"
|
||||
monocraft.copyright = "Idrees Hassan, https://github.com/IdreesInc/Monocraft"
|
||||
monocraft.encoding = "UnicodeFull"
|
||||
monocraft.version = "2.5"
|
||||
monocraft.weight = "Regular"
|
||||
monocraft.ascent = PIXEL_SIZE * 8
|
||||
monocraft.descent = PIXEL_SIZE
|
||||
monocraft.em = PIXEL_SIZE * 9
|
||||
monocraft.upos = -PIXEL_SIZE # Underline position
|
||||
monocraft.addLookup("ligatures", "gsub_ligature", (), (("liga",(("dflt",("dflt")),("latn",("dflt")))),))
|
||||
monocraft.addLookupSubtable("ligatures", "ligatures-subtable")
|
||||
def parseArgs():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--output-ttc",
|
||||
action="store_true",
|
||||
dest="output_ttc",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--all",
|
||||
action="store_true",
|
||||
dest="all",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-O",
|
||||
"--black",
|
||||
action="store_true",
|
||||
dest="black",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-B",
|
||||
"--bold",
|
||||
action="store_true",
|
||||
dest="bold",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--semibold",
|
||||
action="store_true",
|
||||
dest="semibold",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--light",
|
||||
action="store_true",
|
||||
dest="light",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-L",
|
||||
"--extralight",
|
||||
action="store_true",
|
||||
dest="extralight",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--italic",
|
||||
action="store_true",
|
||||
dest="italic",
|
||||
)
|
||||
ret = parser.parse_args()
|
||||
if ret.all:
|
||||
ret.black = ret.bold = ret.semibold = ret.light = ret.extralight = ret.italic = True
|
||||
return ret
|
||||
|
||||
def generateFont(*, black=False, bold=False, semibold=False, light=False, extralight=False, italic=False, output_ttc=False, **kw):
|
||||
fontList = [
|
||||
fontforge.font(),
|
||||
fontforge.font() if italic else None,
|
||||
fontforge.font() if black else None,
|
||||
fontforge.font() if black and italic else None,
|
||||
fontforge.font() if bold else None,
|
||||
fontforge.font() if bold and italic else None,
|
||||
fontforge.font() if semibold else None,
|
||||
fontforge.font() if semibold and italic else None,
|
||||
fontforge.font() if light else None,
|
||||
fontforge.font() if light and italic else None,
|
||||
fontforge.font() if extralight else None,
|
||||
fontforge.font() if extralight and italic else None,
|
||||
]
|
||||
for font in fontList:
|
||||
if font is None:
|
||||
continue
|
||||
font.fontname = "Monocraft"
|
||||
font.familyname = "Monocraft"
|
||||
font.fullname = "Monocraft"
|
||||
font.copyright = "Idrees Hassan, https://github.com/IdreesInc/Monocraft"
|
||||
font.encoding = "UnicodeFull"
|
||||
font.version = "4.0"
|
||||
font.weight = "Regular"
|
||||
font.ascent = PIXEL_SIZE * 8
|
||||
font.descent = PIXEL_SIZE
|
||||
font.em = PIXEL_SIZE * 9
|
||||
font.upos = -PIXEL_SIZE # Underline position
|
||||
font.addLookup("ligatures", "gsub_ligature", (),
|
||||
(("liga", (("dflt", ("dflt")), ("latn", ("dflt")))), ))
|
||||
font.addLookupSubtable("ligatures", "ligatures-subtable")
|
||||
|
||||
font = fontList[0]
|
||||
if font is not None:
|
||||
font.macstyle = 0
|
||||
font.os2_stylemap = 0x40
|
||||
font = fontList[1]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Italic"
|
||||
font.fullname = "Monocraft Italic"
|
||||
font.macstyle = 2
|
||||
font.os2_stylemap = 1
|
||||
font.italicangle = -15
|
||||
font = fontList[2]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Black"
|
||||
font.fullname = "Monocraft Black"
|
||||
font.weight = "Black"
|
||||
font.macstyle = 1
|
||||
font.os2_stylemap = 0x20
|
||||
font = fontList[3]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Black-Italic"
|
||||
font.fullname = "Monocraft Black Italic"
|
||||
font.weight = "Black"
|
||||
font.macstyle = 3
|
||||
font.os2_stylemap = 0x21
|
||||
font.italicangle = -15
|
||||
font = fontList[4]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Bold"
|
||||
font.fullname = "Monocraft Bold"
|
||||
font.weight = "Bold"
|
||||
font.macstyle = 1
|
||||
font.os2_stylemap = 0x20
|
||||
font = fontList[5]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Bold-Italic"
|
||||
font.fullname = "Monocraft Bold Italic"
|
||||
font.weight = "Bold"
|
||||
font.macstyle = 3
|
||||
font.os2_stylemap = 0x21
|
||||
font.italicangle = -15
|
||||
font = fontList[6]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-SemiBold"
|
||||
font.fullname = "Monocraft SemiBold"
|
||||
font.weight = "Demi"
|
||||
font.macstyle = 1
|
||||
font.os2_stylemap = 0x20
|
||||
font = fontList[7]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-SemiBold-Italic"
|
||||
font.fullname = "Monocraft SemiBold Italic"
|
||||
font.weight = "Demi"
|
||||
font.macstyle = 3
|
||||
font.os2_stylemap = 0x21
|
||||
font.italicangle = -15
|
||||
font = fontList[8]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Light"
|
||||
font.fullname = "Monocraft Light"
|
||||
font.weight = "Light"
|
||||
font.macstyle = 0
|
||||
font.os2_stylemap = 0
|
||||
font = fontList[9]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-Light-Italic"
|
||||
font.fullname = "Monocraft Light Italic"
|
||||
font.weight = "Light"
|
||||
font.macstyle = 2
|
||||
font.os2_stylemap = 1
|
||||
font.italicangle = -15
|
||||
font = fontList[10]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-ExtraLight"
|
||||
font.fullname = "Monocraft ExtraLight"
|
||||
font.weight = "Extra-Light"
|
||||
font.macstyle = 0
|
||||
font.os2_stylemap = 0
|
||||
font = fontList[11]
|
||||
if font is not None:
|
||||
font.fontname = "Monocraft-ExtraLight-Italic"
|
||||
font.fullname = "Monocraft ExtraLight Italic"
|
||||
font.weight = "Extra-Light"
|
||||
font.macstyle = 2
|
||||
font.os2_stylemap = 1
|
||||
font.italicangle = -15
|
||||
|
||||
for character in characters:
|
||||
charactersByCodepoint[character["codepoint"]] = character
|
||||
monocraft.createChar(character["codepoint"], character["name"])
|
||||
pen = monocraft[character["name"]].glyphPen()
|
||||
top = 0
|
||||
drawn = character
|
||||
|
||||
image, kw = generateImage(character)
|
||||
drawImage(image, pen, **kw)
|
||||
monocraft[character["name"]].width = PIXEL_SIZE * 6
|
||||
createChar(fontList, character["codepoint"], character["name"], image, **kw)
|
||||
print(f"Generated {len(characters)} characters")
|
||||
|
||||
outputDir = "../dist/"
|
||||
if not os.path.exists(outputDir):
|
||||
os.makedirs(outputDir)
|
||||
|
||||
monocraft.generate(outputDir + "Monocraft-no-ligatures.ttf")
|
||||
if output_ttc:
|
||||
fontList[0].generateTtc(
|
||||
outputDir + "Monocraft-no-ligatures.ttc",
|
||||
[i for i in fontList[1:] if i is not None],
|
||||
ttcflags=("merge", ),
|
||||
layer=1,
|
||||
)
|
||||
|
||||
for ligature in ligatures:
|
||||
lig = monocraft.createChar(-1, ligature["name"])
|
||||
pen = monocraft[ligature["name"]].glyphPen()
|
||||
image, kw = generateImage(ligature)
|
||||
drawImage(image, pen, **kw)
|
||||
monocraft[ligature["name"]].width = PIXEL_SIZE * len(ligature["sequence"]) * 6
|
||||
lig.addPosSub("ligatures-subtable", tuple(map(lambda codepoint: charactersByCodepoint[codepoint]["name"], ligature["sequence"])))
|
||||
createChar(fontList, -1, ligature["name"], image, width=PIXEL_SIZE * len(ligature["sequence"]) * 6, **kw)
|
||||
for font in fontList:
|
||||
if font is None:
|
||||
continue
|
||||
font[ligature["name"]].addPosSub("ligatures-subtable", tuple(map(lambda codepoint: charactersByCodepoint[codepoint]["name"], ligature["sequence"])))
|
||||
print(f"Generated {len(ligatures)} ligatures")
|
||||
|
||||
monocraft.generate(outputDir + "Monocraft.ttf")
|
||||
monocraft.generate(outputDir + "Monocraft.otf")
|
||||
for font in fontList:
|
||||
if font is None:
|
||||
continue
|
||||
font.generate(f"{outputDir}{font.fontname}.otf")
|
||||
font.generate(f"{outputDir}{font.fontname}.ttf")
|
||||
|
||||
if output_ttc:
|
||||
fontList[0].generateTtc(
|
||||
outputDir + "Monocraft.ttc",
|
||||
[i for i in fontList[1:] if i is not None],
|
||||
ttcflags=("merge", ),
|
||||
layer=1,
|
||||
)
|
||||
|
||||
def generateImage(character):
|
||||
image = PixelImage()
|
||||
@@ -115,15 +287,15 @@ def imageFromArray(arr, x=0, y=0):
|
||||
y=y,
|
||||
width=len(arr[0]),
|
||||
height=len(arr),
|
||||
data=bytes(x for a in reversed(arr) for x in a),
|
||||
data=bytes(v for a in reversed(arr) for v in a),
|
||||
)
|
||||
|
||||
def drawImage(image, pen, *, dx=0, dy=0):
|
||||
for polygon in generatePolygons(image):
|
||||
def drawPolygon(poly, pen):
|
||||
for polygon in poly:
|
||||
start = True
|
||||
for x, y in polygon:
|
||||
x = (x + dx) * PIXEL_SIZE
|
||||
y = (y + dy) * PIXEL_SIZE
|
||||
x = int(math.floor(x * PIXEL_SIZE))
|
||||
y = int(math.floor(y * PIXEL_SIZE))
|
||||
if start:
|
||||
pen.moveTo(x, y)
|
||||
start = False
|
||||
@@ -131,5 +303,90 @@ def drawImage(image, pen, *, dx=0, dy=0):
|
||||
pen.lineTo(x, y)
|
||||
pen.closePath()
|
||||
|
||||
generateFont()
|
||||
generateExamples(characters, ligatures, charactersByCodepoint)
|
||||
BOLD_THIN_DISTS = {
|
||||
"Black": 0.3,
|
||||
"Bold": 0.2,
|
||||
"Demi": 0.1,
|
||||
"Light": -0.1,
|
||||
"Extra-Light": -0.3,
|
||||
}
|
||||
ITALIC_RATIO = math.tan(math.radians(15))
|
||||
|
||||
def boldify(p, boldness):
|
||||
l = len(p)
|
||||
for i in range(l):
|
||||
x, y = p[i]
|
||||
dx, dy = 0, 0
|
||||
px, py = p[i - 1]
|
||||
if px < x:
|
||||
dy += boldness
|
||||
elif px > x:
|
||||
dy -= boldness
|
||||
elif py < y:
|
||||
dx -= boldness
|
||||
else:
|
||||
dx += boldness
|
||||
px, py = p[(i + 1) % l]
|
||||
if px < x:
|
||||
dy -= boldness
|
||||
elif px > x:
|
||||
dy += boldness
|
||||
elif py < y:
|
||||
dx += boldness
|
||||
else:
|
||||
dx -= boldness
|
||||
yield (dx + x, dy + y)
|
||||
|
||||
def createChar(
|
||||
fontList,
|
||||
code,
|
||||
name,
|
||||
image=None,
|
||||
*,
|
||||
width=None,
|
||||
dx=0,
|
||||
dy=0,
|
||||
glyphclass=None,
|
||||
):
|
||||
if image is not None:
|
||||
poly = [[(x + dx, y + dy) for x, y in p]
|
||||
for p in generatePolygons(image)]
|
||||
|
||||
poly_b = None
|
||||
poly_t = None
|
||||
|
||||
for font in fontList:
|
||||
if font is None:
|
||||
continue
|
||||
char = font.createChar(code, name)
|
||||
#char.manualHints = True
|
||||
if glyphclass is not None:
|
||||
char.glyphclass = glyphclass
|
||||
if image is None:
|
||||
char.width = width if width is not None else PIXEL_SIZE * 6
|
||||
continue
|
||||
|
||||
p = poly
|
||||
try:
|
||||
dist = BOLD_THIN_DISTS[font.weight]
|
||||
except KeyError:
|
||||
dist = 0
|
||||
|
||||
if dist > 0:
|
||||
if poly_b is None:
|
||||
poly_b = [[(x + dx, y + dy) for x, y in p] for p in generatePolygons(image, join_polygons=False)]
|
||||
p = (boldify(p, dist) for p in poly_b)
|
||||
elif dist < 0:
|
||||
if poly_t is None:
|
||||
poly_t = [[(x + dx, y + dy) for x, y in p] for p in generatePolygons(image, join_polygons=False, exclude_corners=True)]
|
||||
p = (boldify(p, dist) for p in poly_t)
|
||||
|
||||
if font.macstyle & 2:
|
||||
p = (((x + y * ITALIC_RATIO, y) for x, y in p) for p in p)
|
||||
|
||||
drawPolygon(p, char.glyphPen())
|
||||
char.width = width if width is not None else PIXEL_SIZE * 6
|
||||
|
||||
args = parseArgs()
|
||||
generateFont(**vars(args))
|
||||
generateExamples(characters, ligatures, charactersByCodepoint)
|
||||
+328
-161
@@ -94,7 +94,7 @@ class PixelImage:
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
''' Sets a pixel at (x, y).
|
||||
|
||||
|
||||
Do nothing if out of bounds.
|
||||
'''
|
||||
x, y = key
|
||||
@@ -187,10 +187,36 @@ class PixelImage:
|
||||
|
||||
return ret
|
||||
|
||||
def crop(self, min_x, max_x, min_y, max_y):
|
||||
if max_x < min_x or max_y < min_y:
|
||||
raise ValueError('Invalid bounds')
|
||||
|
||||
def generatePolygons(image):
|
||||
min_x = max(min_x, self._x)
|
||||
max_x = min(max_x, self.x_end)
|
||||
min_y = max(min_y, self._y)
|
||||
max_y = min(max_y, self.y_end)
|
||||
if max_x <= min_x or max_y <= min_y:
|
||||
return PixelImage()
|
||||
|
||||
data = bytearray((max_x - min_x) * (max_y - min_y))
|
||||
ix = 0
|
||||
for j in range(min_y, max_y):
|
||||
for i in range(min_x, max_x):
|
||||
data[ix] = self[i, j]
|
||||
ix += 1
|
||||
|
||||
return PixelImage(
|
||||
x=min_x,
|
||||
y=min_y,
|
||||
width=max_x - min_x,
|
||||
height=max_y - min_y,
|
||||
data=data,
|
||||
)
|
||||
|
||||
|
||||
def generatePolygons(image, **kw):
|
||||
for segment, start_pos in segmentize(image):
|
||||
yield from polygonizeSegment(segment, start_pos)
|
||||
yield from polygonizeSegment(segment, start_pos, **kw)
|
||||
|
||||
|
||||
def segmentize(image):
|
||||
@@ -322,25 +348,20 @@ class CellFlag(IntFlag):
|
||||
return ret
|
||||
|
||||
|
||||
def polygonizeSegment(image, start_pos):
|
||||
x, y = start_pos
|
||||
class Turtle:
|
||||
__slots__ = ['img', 'x', 'y', 'dir']
|
||||
|
||||
# Make sure position is top left
|
||||
assert image[x, y]
|
||||
assert not (image[x - 1, y] or image[x - 1, y - 1] or image[x, y - 1]
|
||||
or image[x + 1, y - 1])
|
||||
|
||||
dir = CellFlag.RIGHT
|
||||
|
||||
def doMove():
|
||||
nonlocal x, y, dir
|
||||
def __init__(self, img, x, y, dir):
|
||||
self.img, self.x, self.y, self.dir = img, x, y, dir
|
||||
|
||||
def _move(self):
|
||||
# Set wall
|
||||
d_ccw, d_cw, d_rev = dir.ccw(), dir.cw(), dir.reverse()
|
||||
image[x, y] |= d_ccw
|
||||
d_ccw, d_cw, d_rev = self.dir.ccw(), self.dir.cw(), self.dir.reverse()
|
||||
p = self.x, self.y
|
||||
self.img[p] |= d_ccw
|
||||
|
||||
x_, y_ = d_ccw.move((x, y))
|
||||
assert not image[x_, y_] & CellFlag.ACTIVE
|
||||
p_ = d_ccw.move(p)
|
||||
assert not self.img[p_] & CellFlag.ACTIVE
|
||||
|
||||
# Build boundary wall from this point
|
||||
# For all diagrams, it is assumed movement direction is right
|
||||
@@ -348,252 +369,398 @@ def polygonizeSegment(image, start_pos):
|
||||
# ? . #
|
||||
# ? X ?
|
||||
# ? ? ?
|
||||
x_, y_ = (dir | d_ccw).move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = (self.dir | d_ccw).move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# Top-right corner
|
||||
ret = [(dir | d_ccw).corner((x, y))]
|
||||
ret = [(self.dir | d_ccw).corner(p)]
|
||||
|
||||
# ? . ^
|
||||
# ? X ?
|
||||
# ? ? ?
|
||||
x, y = x_, y_
|
||||
dir = d_ccw
|
||||
(self.x, self.y), self.dir = p_, d_ccw
|
||||
return ret
|
||||
|
||||
# ? . .
|
||||
# ? X #
|
||||
# ? ? ?
|
||||
x_, y_ = dir.move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = self.dir.move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# ? . .
|
||||
# ? X >
|
||||
# ? ? ?
|
||||
x, y = x_, y_
|
||||
self.x, self.y = p_
|
||||
return [] # No corner
|
||||
|
||||
# ? . .
|
||||
# ? X .
|
||||
# ? ? #
|
||||
x_, y_ = (dir | d_cw).move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = (self.dir | d_cw).move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# Two corners: top-right and bottom-right
|
||||
ret = [
|
||||
(dir | d_ccw).corner((x, y)),
|
||||
(dir | d_cw).corner((x, y)),
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
]
|
||||
|
||||
# ? . .
|
||||
# ? X .
|
||||
# ? ? >
|
||||
image[x, y] |= dir
|
||||
x, y = x_, y_
|
||||
self.img[p] |= self.dir
|
||||
self.x, self.y = p_
|
||||
return ret
|
||||
|
||||
# ? . .
|
||||
# ? X .
|
||||
# ? # .
|
||||
x_, y_ = d_cw.move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = d_cw.move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# Top-right corner
|
||||
ret = [(dir | d_ccw).corner((x, y))]
|
||||
ret = [(self.dir | d_ccw).corner(p)]
|
||||
|
||||
# ? . .
|
||||
# ? X .
|
||||
# ? v .
|
||||
image[x, y] |= dir
|
||||
x, y = x_, y_
|
||||
dir = d_cw
|
||||
self.img[p] |= self.dir
|
||||
(self.x, self.y), self.dir = p_, d_cw
|
||||
return ret
|
||||
|
||||
# ? . .
|
||||
# ? X .
|
||||
# # . .
|
||||
x_, y_ = (d_rev | d_cw).move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = (d_rev | d_cw).move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# Three corners: top-right, bottom-right, and bottom-left
|
||||
ret = [
|
||||
(dir | d_ccw).corner((x, y)),
|
||||
(dir | d_cw).corner((x, y)),
|
||||
(d_cw | d_rev).corner((x, y)),
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
(d_cw | d_rev).corner(p),
|
||||
]
|
||||
|
||||
# ? . .
|
||||
# ? X .
|
||||
# v . .
|
||||
image[x, y] |= dir | d_cw
|
||||
x, y = x_, y_
|
||||
dir = d_cw
|
||||
self.img[p] |= self.dir | d_cw
|
||||
(self.x, self.y), self.dir = p_, d_cw
|
||||
return ret
|
||||
|
||||
# ? . .
|
||||
# # X .
|
||||
# . . .
|
||||
x_, y_ = d_rev.move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = d_rev.move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# Two corners: top-right and bottom-right
|
||||
ret = [
|
||||
(dir | d_ccw).corner((x, y)),
|
||||
(dir | d_cw).corner((x, y)),
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
]
|
||||
|
||||
# ? . .
|
||||
# < X .
|
||||
# . . .
|
||||
image[x, y] |= dir | d_cw
|
||||
x, y = x_, y_
|
||||
dir = d_rev
|
||||
self.img[p] |= self.dir | d_cw
|
||||
(self.x, self.y), self.dir = p_, d_rev
|
||||
return ret
|
||||
|
||||
# # . .
|
||||
# . X .
|
||||
# . . .
|
||||
x_, y_ = (d_rev | d_ccw).move((x, y))
|
||||
if image[x_, y_] & CellFlag.ACTIVE:
|
||||
p_ = (d_rev | d_ccw).move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
# Four corners: top-right, bottom-right, bottom-left, and top-left
|
||||
ret = [
|
||||
(dir | d_ccw).corner((x, y)),
|
||||
(dir | d_cw).corner((x, y)),
|
||||
(d_cw | d_rev).corner((x, y)),
|
||||
(d_ccw | d_rev).corner((x, y)),
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
(d_cw | d_rev).corner(p),
|
||||
(d_ccw | d_rev).corner(p),
|
||||
]
|
||||
|
||||
# < . .
|
||||
# . X .
|
||||
# . . .
|
||||
image[x, y] |= dir | d_cw | d_rev
|
||||
x, y = x_, y_
|
||||
dir = d_rev
|
||||
self.img[p] |= self.dir | d_cw | d_rev
|
||||
(self.x, self.y), self.dir = p_, d_rev
|
||||
return ret
|
||||
|
||||
# . . .
|
||||
# . X .
|
||||
# . . .
|
||||
image[x, y] |= dir | d_cw | d_rev
|
||||
self.img[p] |= self.dir | d_cw | d_rev
|
||||
# Four corners: top-right, bottom-right, bottom-left, and top-left
|
||||
return [
|
||||
(dir | d_ccw).corner((x, y)),
|
||||
(dir | d_cw).corner((x, y)),
|
||||
(d_cw | d_rev).corner((x, y)),
|
||||
(d_ccw | d_rev).corner((x, y)),
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
(d_cw | d_rev).corner(p),
|
||||
(d_ccw | d_rev).corner(p),
|
||||
]
|
||||
|
||||
def find(l, x):
|
||||
try:
|
||||
return l.index(x)
|
||||
except ValueError:
|
||||
return None
|
||||
def _move_4way(self):
|
||||
# Set wall
|
||||
d_ccw, d_cw, d_rev = self.dir.ccw(), self.dir.cw(), self.dir.reverse()
|
||||
p = self.x, self.y
|
||||
self.img[p] |= d_ccw
|
||||
|
||||
# Generate outer polygon
|
||||
outer_poly = []
|
||||
line = doMove()
|
||||
i = find(line, start_pos)
|
||||
while i is None:
|
||||
outer_poly += line
|
||||
line = doMove()
|
||||
i = find(line, start_pos)
|
||||
outer_poly += line[:i + 1]
|
||||
p_ = d_ccw.move(p)
|
||||
assert not self.img[p_] & CellFlag.ACTIVE
|
||||
|
||||
assert checkPoly(outer_poly)
|
||||
# Build boundary wall from this point
|
||||
# For all diagrams, it is assumed movement direction is right
|
||||
|
||||
points_ = dict(
|
||||
zip(
|
||||
reversed(outer_poly),
|
||||
range(len(outer_poly) - 1, -1, -1),
|
||||
))
|
||||
points = defaultdict(set)
|
||||
for p in outer_poly:
|
||||
points[p].add(0)
|
||||
# ? . ?
|
||||
# ? X #
|
||||
# ? ? ?
|
||||
p_ = self.dir.move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
|
||||
poly = [(outer_poly, points_)]
|
||||
# ? . #
|
||||
# ? X #
|
||||
# ? ? ?
|
||||
p__ = d_ccw.move(p_)
|
||||
if self.img[p__] & CellFlag.ACTIVE:
|
||||
# Top-right corner
|
||||
ret = [(self.dir | d_ccw).corner(p)]
|
||||
|
||||
# Calculate bounding box
|
||||
x_min, y_min, x_max, y_max = x, y, x, y
|
||||
for x, y in outer_poly:
|
||||
if x_min > x:
|
||||
x_min = x
|
||||
if x_max < x:
|
||||
x_max = x
|
||||
if y_min > y:
|
||||
y_min = y
|
||||
if y_max < y:
|
||||
y_max = y
|
||||
# ? . ^
|
||||
# ? X #
|
||||
# ? ? ?
|
||||
(self.x, self.y), self.dir = p__, d_ccw
|
||||
return ret
|
||||
|
||||
# Generate inner polygon
|
||||
for y in range(y_min, y_max):
|
||||
for x in range(x_min, x_max):
|
||||
# ? . .
|
||||
# ? X #
|
||||
# ? ? ?
|
||||
else:
|
||||
# ? . .
|
||||
# ? X >
|
||||
# ? ? ?
|
||||
self.x, self.y = p_
|
||||
return [] # No corner
|
||||
|
||||
# ? . ?
|
||||
# ? X .
|
||||
# ? # ?
|
||||
p_ = d_cw.move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
self.img[p] |= self.dir
|
||||
|
||||
# ? . ?
|
||||
# ? X .
|
||||
# ? # #
|
||||
p__ = self.dir.move(p_)
|
||||
if self.img[p__] & CellFlag.ACTIVE:
|
||||
# Two corners: top-right and bottom-right
|
||||
ret = [
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
]
|
||||
|
||||
# ? . ?
|
||||
# ? X .
|
||||
# ? # >
|
||||
self.x, self.y = p__
|
||||
return ret
|
||||
|
||||
# ? . ?
|
||||
# ? X .
|
||||
# ? # .
|
||||
else:
|
||||
# Top-right corner
|
||||
ret = [(self.dir | d_ccw).corner(p)]
|
||||
|
||||
# ? . ?
|
||||
# ? X .
|
||||
# ? v .
|
||||
(self.x, self.y), self.dir = p_, d_cw
|
||||
return ret
|
||||
|
||||
# ? . ?
|
||||
# # X .
|
||||
# ? . ?
|
||||
p_ = d_rev.move(p)
|
||||
if self.img[p_] & CellFlag.ACTIVE:
|
||||
self.img[p] |= self.dir | d_cw
|
||||
|
||||
# ? . ?
|
||||
# # X .
|
||||
# # . ?
|
||||
p__ = d_cw.move(p_)
|
||||
if self.img[p__] & CellFlag.ACTIVE:
|
||||
# Three corners: top-right, bottom-right, and bottom-left
|
||||
ret = [
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
(d_cw | d_rev).corner(p),
|
||||
]
|
||||
|
||||
# ? . ?
|
||||
# # X .
|
||||
# v . .
|
||||
(self.x, self.y), self.dir = p__, d_cw
|
||||
return ret
|
||||
|
||||
# ? . ?
|
||||
# # X .
|
||||
# . . ?
|
||||
else:
|
||||
# Two corners: top-right and bottom-right
|
||||
ret = [
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
]
|
||||
|
||||
# ? . ?
|
||||
# < X .
|
||||
# . . ?
|
||||
(self.x, self.y), self.dir = p_, d_rev
|
||||
return ret
|
||||
|
||||
# ? . ?
|
||||
# . X .
|
||||
# ? . ?
|
||||
self.img[p] |= self.dir | d_cw | d_rev
|
||||
# Four corners: top-right, bottom-right, bottom-left, and top-left
|
||||
return [
|
||||
(self.dir | d_ccw).corner(p),
|
||||
(self.dir | d_cw).corner(p),
|
||||
(d_cw | d_rev).corner(p),
|
||||
(d_ccw | d_rev).corner(p),
|
||||
]
|
||||
|
||||
def trace(self, stop_pos, exclude_corners=False):
|
||||
poly = []
|
||||
while True:
|
||||
j = len(poly)
|
||||
poly += self._move_4way() if exclude_corners else self._move()
|
||||
try:
|
||||
i = poly.index(stop_pos, j)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
return poly[:i + 1]
|
||||
|
||||
|
||||
def polygonize(image, exclude_corners=False):
|
||||
image = PixelImage(image)
|
||||
|
||||
ret = []
|
||||
turtle = Turtle(image, 0, 0, CellFlag.LEFT)
|
||||
for y in range(image.y, image.y_end):
|
||||
for x in range(image.x, image.x_end):
|
||||
v = image[x, y]
|
||||
if not v & CellFlag.ACTIVE:
|
||||
continue
|
||||
|
||||
if not (image[x, y + 1] & CellFlag.ACTIVE or v & CellFlag.DOWN):
|
||||
dir = CellFlag.LEFT
|
||||
if not (v & CellFlag.UP or image[x, y - 1] & CellFlag.ACTIVE):
|
||||
turtle.dir, stop_pos = CellFlag.RIGHT, (x, y)
|
||||
elif not (v & CellFlag.RIGHT or image[x + 1, y] & CellFlag.ACTIVE):
|
||||
turtle.dir, stop_pos = CellFlag.DOWN, (x + 1, y)
|
||||
else:
|
||||
continue
|
||||
turtle.x, turtle.y = x, y
|
||||
|
||||
# Store iterator value
|
||||
p = x, y
|
||||
ret.append(turtle.trace(stop_pos, exclude_corners)[::-1])
|
||||
assert checkPoly(ret[-1])
|
||||
|
||||
inner_poly = []
|
||||
line = doMove()
|
||||
i = None
|
||||
while i is None:
|
||||
inner_poly += line
|
||||
line = doMove()
|
||||
i = find(line, inner_poly[0])
|
||||
inner_poly += line[:i]
|
||||
return ret
|
||||
|
||||
assert checkPoly(inner_poly)
|
||||
|
||||
j = len(poly)
|
||||
poly.append((
|
||||
inner_poly,
|
||||
dict(
|
||||
zip(
|
||||
reversed(inner_poly),
|
||||
range(len(inner_poly) - 1, -1, -1),
|
||||
)),
|
||||
))
|
||||
for i in inner_poly:
|
||||
points[i].add(j)
|
||||
def joinPolygons(polygons):
|
||||
def first_equals(i, j, *, key=lambda x: x):
|
||||
i, j = enumerate(map(key, i)), enumerate(map(key, j))
|
||||
try:
|
||||
(ai, av), (bi, bv) = next(i), next(j)
|
||||
while av!= bv:
|
||||
if av < bv:
|
||||
ai, av = next(i)
|
||||
else:
|
||||
bi, bv = next(j)
|
||||
return ai, bi
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
# Restore iterator value
|
||||
x, y = p
|
||||
def merge(i, j):
|
||||
r = []
|
||||
i, j = iter(i), iter(j)
|
||||
a, b = next(i, None), next(j, None)
|
||||
while a is not None and b is not None:
|
||||
if a[1] == b[1]:
|
||||
r.append((min(a[0], b[0]), a[1]))
|
||||
a, b = next(i, None), next(j, None)
|
||||
elif a[1] < b[1]:
|
||||
r.append(a)
|
||||
a = next(i, None)
|
||||
else:
|
||||
r.append(b)
|
||||
b = next(j, None)
|
||||
|
||||
# Try to join polygons
|
||||
for i in range(len(poly) - 1, -1, -1):
|
||||
inner_poly, points_ = poly[i]
|
||||
if a is not None:
|
||||
r.extend(i)
|
||||
elif b is not None:
|
||||
r.extend(j)
|
||||
|
||||
for v in points.values():
|
||||
if len(v) > 1 and i in v:
|
||||
j = min(v)
|
||||
break
|
||||
else:
|
||||
continue
|
||||
return r
|
||||
|
||||
outer_poly, points__ = poly[j]
|
||||
kf = lambda v: v[1]
|
||||
|
||||
for i_, p in enumerate(inner_poly):
|
||||
j_ = points__.get(p)
|
||||
if j_ is not None:
|
||||
break
|
||||
else:
|
||||
raise RuntimeError(
|
||||
f'Should not happened {inner_poly} {outer_poly}')
|
||||
def f(p):
|
||||
l = []
|
||||
x = None
|
||||
for i, v in sorted(enumerate(p), key=kf):
|
||||
if x != v:
|
||||
x = v
|
||||
l.append((i, v))
|
||||
return p, l
|
||||
|
||||
outer_poly[j_:j_] = [*inner_poly[i_:], *inner_poly[:i_]]
|
||||
points__.update(
|
||||
zip(
|
||||
reversed(outer_poly),
|
||||
range(len(outer_poly) - 1, -1, -1),
|
||||
))
|
||||
def checkPoints(p, l):
|
||||
if not checkPoly(p):
|
||||
return False
|
||||
for i in range(len(l)):
|
||||
j, v = l[i]
|
||||
if j >= len(p) or p[j] != v:
|
||||
print(f'{p}\n{l} Error at {i} ({j}, {v}) (got {None if j >= len(p) else p[j]})')
|
||||
return False
|
||||
if i < 1:
|
||||
continue
|
||||
_, t = l[i - 1]
|
||||
if t == v:
|
||||
print(f'{p}\n{l} Error at {i} ({j}, {v})')
|
||||
return False
|
||||
return True
|
||||
|
||||
del poly[i]
|
||||
for v in points.values():
|
||||
v.discard(i)
|
||||
points = [f(i) for i in polygons]
|
||||
for i in range(len(points) - 1, 0, -1):
|
||||
p, l = points[i]
|
||||
for j in range(i):
|
||||
p_, l_ = points[j]
|
||||
t = first_equals(l, l_, key=kf)
|
||||
if t is None:
|
||||
continue
|
||||
|
||||
# Emit polygons
|
||||
for i, _ in poly:
|
||||
yield i
|
||||
a, b = t
|
||||
a, _ = l[a]
|
||||
b, _ = l_[b]
|
||||
p = [*p[:a], *p_[b:], *p_[:b], *p[a:]]
|
||||
|
||||
t = len(p_)
|
||||
s = t - b + a
|
||||
r = a - b
|
||||
l = merge(
|
||||
((i + t if i >= a else i, v) for i, v in l),
|
||||
((i + r if i >= b else i + s, v) for i, v in l_),
|
||||
)
|
||||
|
||||
assert checkPoints(p, l)
|
||||
points[j] = p, l
|
||||
del points[i]
|
||||
break
|
||||
|
||||
return [p[0] for p in points]
|
||||
|
||||
|
||||
def generatePolygons(image, *, join_polygons=True, exclude_corners=False, **kw):
|
||||
ret = polygonize(image, exclude_corners)
|
||||
if join_polygons:
|
||||
ret = joinPolygons(ret)
|
||||
return ret
|
||||
|
||||
|
||||
def checkPoly(poly):
|
||||
@@ -651,7 +818,7 @@ def testChar(name, pixels):
|
||||
|
||||
print(f'Character: {name}\n{image}\n\n')
|
||||
|
||||
for poly in generatePolygons(image):
|
||||
for poly in generatePolygons(image, join_polygons=False, exclude_corners=True):
|
||||
print('Polygon:\n ' + '\n '.join(f'{x}, {y}'
|
||||
for x, y in poly) + '\n\n')
|
||||
|
||||
|
||||
Reference in new issue
Block a user