Add Mechyrdia Sans font sample
authorLanius Trolling <lanius@laniustrolling.dev>
Sat, 3 Feb 2024 19:24:16 +0000 (14:24 -0500)
committerLanius Trolling <lanius@laniustrolling.dev>
Sat, 3 Feb 2024 19:24:16 +0000 (14:24 -0500)
src/jvmMain/kotlin/info/mechyrdia/Factbooks.kt
src/jvmMain/kotlin/info/mechyrdia/data/views_comment.kt
src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt [new file with mode: 0644]
src/jvmMain/kotlin/info/mechyrdia/lore/languages.kt [deleted file]
src/jvmMain/kotlin/info/mechyrdia/lore/parser_tags.kt
src/jvmMain/resources/fonts/mechyrdia-sans-bold-italic.ttf [new file with mode: 0644]
src/jvmMain/resources/fonts/mechyrdia-sans-bold.ttf [new file with mode: 0644]
src/jvmMain/resources/fonts/mechyrdia-sans-italic.ttf [new file with mode: 0644]
src/jvmMain/resources/fonts/mechyrdia-sans.ttf [new file with mode: 0644]
src/jvmMain/resources/static/init.js

index 36316cd47c0c471c6b539bd22df931bf5251a948..6974f158c1aeb153805bf87dd8131b6308801e88 100644 (file)
@@ -25,6 +25,9 @@ import io.ktor.server.routing.*
 import io.ktor.server.sessions.*
 import io.ktor.server.sessions.serialization.*
 import io.ktor.util.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runInterruptible
+import kotlinx.coroutines.withContext
 import org.slf4j.event.Level
 import java.io.File
 import java.io.IOException
@@ -260,12 +263,31 @@ fun Application.factbooks() {
                
                // Utilities
                
+               post("/mechyrdia-sans") {
+                       val queryString = call.request.queryParameters
+                       
+                       val isBold = "true".equals(queryString["bold"], ignoreCase = true)
+                       val isItalic = "true".equals(queryString["italic"], ignoreCase = true)
+                       
+                       val alignArg = queryString["align"]
+                       val align = MechyrdiaSansFont.Alignment.entries.singleOrNull {
+                               it.name.equals(alignArg, ignoreCase = true)
+                       } ?: MechyrdiaSansFont.Alignment.LEFT
+                       
+                       val text = call.receiveText()
+                       val svg = runInterruptible(Dispatchers.Default) {
+                               MechyrdiaSansFont.renderTextToSvg(text, isBold, isItalic, align)
+                       }
+                       
+                       call.respondText(svg, ContentType.Image.SVG)
+               }
+               
                post("/tylan-lang") {
-                       call.respondText(TylanAlphabet.tylanToFontAlphabet(call.receiveText()))
+                       call.respondText(TylanAlphabetFont.tylanToFontAlphabet(call.receiveText()))
                }
                
                post("/pokhwal-lang") {
-                       call.respondText(PokhwalishAlphabet.pokhwalToFontAlphabet(call.receiveText()))
+                       call.respondText(PokhwalishAlphabetFont.pokhwalToFontAlphabet(call.receiveText()))
                }
                
                post("/preview-comment") {
index 3f8ad93ae1d8c052ba3459ef6fae2840775dd301..7bf7da94d2c7c33f1a9513aef7d5679e459e1ca9 100644 (file)
@@ -500,7 +500,7 @@ suspend fun ApplicationCall.commentHelpPage(): HTML.() -> Unit = page("Commentin
                                        td {
                                                +"Writes text in the Tylan alphabet: "
                                                span(classes = "lang-tylan") {
-                                                       +TylanAlphabet.tylanToFontAlphabet("rheagda tulasra")
+                                                       +TylanAlphabetFont.tylanToFontAlphabet("rheagda tulasra")
                                                }
                                        }
                                }
@@ -518,7 +518,7 @@ suspend fun ApplicationCall.commentHelpPage(): HTML.() -> Unit = page("Commentin
                                        td {
                                                +"Writes text in the Pokhwalish alphabet: "
                                                span(classes = "lang-pokhwal") {
-                                                       +PokhwalishAlphabet.pokhwalToFontAlphabet("pokhvalsqo jargo")
+                                                       +PokhwalishAlphabetFont.pokhwalToFontAlphabet("pokhvalsqo jargo")
                                                }
                                        }
                                }
diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt
new file mode 100644 (file)
index 0000000..12e4d0c
--- /dev/null
@@ -0,0 +1,265 @@
+package info.mechyrdia.lore
+
+import java.awt.Font
+import java.awt.RenderingHints
+import java.awt.Shape
+import java.awt.geom.AffineTransform
+import java.awt.geom.GeneralPath
+import java.awt.geom.PathIterator
+import java.awt.image.BufferedImage
+
+object MechyrdiaSansFont {
+       enum class Alignment(val amount: Double) {
+               LEFT(0.0), CENTER(0.5), RIGHT(1.0),
+       }
+       
+       fun renderTextToSvg(text: String, bold: Boolean, italic: Boolean, align: Alignment, standalone: Boolean = true): String {
+               val font = if (bold) {
+                       if (italic)
+                               mechyrdiaSansBI
+                       else
+                               mechyrdiaSansB
+               } else
+                       if (italic)
+                               mechyrdiaSansI
+                       else
+                               mechyrdiaSans
+               
+               val shape = layoutText(text, font, align.amount)
+               return shape.toSvgDocument(standalone)
+       }
+       
+       private const val DEFAULT_FONT_SIZE = 48f
+       
+       private fun loadFont(font: String): Font {
+               return Font
+                       .createFont(Font.TRUETYPE_FONT, javaClass.getResourceAsStream("/fonts/$font.ttf")!!)
+                       .deriveFont(DEFAULT_FONT_SIZE)
+       }
+       
+       private val mechyrdiaSans = loadFont("mechyrdia-sans")
+       private val mechyrdiaSansB = loadFont("mechyrdia-sans-bold")
+       private val mechyrdiaSansI = loadFont("mechyrdia-sans-italic")
+       private val mechyrdiaSansBI = loadFont("mechyrdia-sans-bold-italic")
+       
+       private fun layoutText(text: String, font: Font, alignAmount: Double): Shape {
+               val img = BufferedImage(256, 160, BufferedImage.TYPE_INT_ARGB)
+               val g2d = img.createGraphics()
+               try {
+                       g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
+                       
+                       val fontMetrics = g2d.getFontMetrics(font)
+                       val lines = text.split("\r\n", "\n", "\r")
+                       val width = lines.maxOf { fontMetrics.stringWidth(it) }.toDouble()
+                       var y = 0.0
+                       
+                       val shape = GeneralPath()
+                       val tf = AffineTransform()
+                       for (line in lines) {
+                               if (line.isNotBlank()) {
+                                       val x = (width - fontMetrics.stringWidth(line)) * alignAmount
+                                       
+                                       val glyphs = font.layoutGlyphVector(g2d.fontRenderContext, line.toCharArray(), 0, line.length, Font.LAYOUT_LEFT_TO_RIGHT)
+                                       val textShape = glyphs.outline as GeneralPath
+                                       
+                                       tf.setToIdentity()
+                                       tf.translate(x, y)
+                                       shape.append(textShape.getPathIterator(tf), false)
+                               }
+                               
+                               y += fontMetrics.height
+                       }
+                       
+                       return shape
+               } finally {
+                       g2d.dispose()
+               }
+       }
+       
+       private fun Shape.toSvgDocument(standalone: Boolean = true): String {
+               return buildString {
+                       if (standalone)
+                               appendLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>")
+                       
+                       val viewBox = bounds2D
+                       appendLine("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"${viewBox.width * 2}\" height=\"${viewBox.height * 2}\" viewBox=\"${viewBox.minX} ${viewBox.minY} ${viewBox.width} ${viewBox.height}\">")
+                       appendLine(toSvgPath())
+                       appendLine("</svg>")
+               }
+       }
+       
+       private fun Shape.toSvgPath(): String {
+               return buildString {
+                       append("<path d=\"")
+                       
+                       val iterator = getPathIterator(null)
+                       val coords = DoubleArray(6)
+                       while (!iterator.isDone) {
+                               when (val segment = iterator.currentSegment(coords)) {
+                                       PathIterator.SEG_MOVETO -> {
+                                               append("M ${coords[0]},${coords[1]} ")
+                                       }
+                                       
+                                       PathIterator.SEG_LINETO -> {
+                                               append("L ${coords[0]},${coords[1]} ")
+                                       }
+                                       
+                                       PathIterator.SEG_QUADTO -> {
+                                               append("Q ${coords[0]},${coords[1]} ${coords[2]},${coords[3]} ")
+                                       }
+                                       
+                                       PathIterator.SEG_CUBICTO -> {
+                                               append("C ${coords[0]},${coords[1]} ${coords[2]},${coords[3]} ${coords[4]},${coords[5]} ")
+                                       }
+                                       
+                                       PathIterator.SEG_CLOSE -> {
+                                               append("Z ")
+                                       }
+                                       
+                                       else -> error("Invalid segment type $segment")
+                               }
+                               
+                               iterator.next()
+                       }
+                       
+                       append("\" fill-rule=\"")
+                       when (val winding = iterator.windingRule) {
+                               PathIterator.WIND_EVEN_ODD -> append("evenodd")
+                               PathIterator.WIND_NON_ZERO -> append("nonzero")
+                               else -> error("Invalid winding rule $winding")
+                       }
+                       
+                       append("\" />")
+               }
+       }
+}
+
+object TylanAlphabetFont {
+       private val allowedTranslitCharacters = setOf(
+               ' ', '\r', '\n', '\t',
+               'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'x', 'y',
+               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+               '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+',
+               '[', '{', '}', ']', '\\', '|', '/', '<',
+               '.', ',', ':', ';', '\'', '"', '?', '>',
+       )
+       
+       private val replacements = listOf(
+               Regex("([0-9xy]+)(?![\\s0-9xy])") to "$1 ",
+               Regex("(?<![\\s0-9xy])([0-9xy]+)") to " $1",
+               
+               Regex("([a-pr-v'])m(?![\\w'])") to "$1A",
+               Regex("([a-pr-v'])n(?![\\w'])") to "$1E",
+               Regex("([a-ps-v'])r(?![\\w'])") to "$1H",
+               Regex("([ac-fh-jl-or-v'])s(?![\\w'])") to "$1I",
+               Regex("([a-pr-v'])t(?![\\w'])") to "$1Q",
+               
+               Regex("x") to "M",
+               Regex("y") to "N",
+               Regex("[qw-z]") to "",
+               
+               Regex("ch") to "C",
+               Regex("dh") to "D",
+               Regex("sh") to "S",
+               Regex("th") to "T",
+               
+               Regex("bs") to "B",
+               Regex("gs") to "G",
+               Regex("ks") to "K",
+               Regex("ps") to "P",
+               
+               Regex("b'([Is])") to "b$1",
+               Regex("g'([Is])") to "g$1",
+               Regex("k'([Is])") to "k$1",
+               Regex("p'([Is])") to "p$1",
+               
+               Regex("ff") to "F",
+               Regex("fv") to "V",
+               Regex("hj") to "J",
+               Regex("lh") to "L",
+               Regex("ll") to "L",
+               Regex("hl") to "L",
+               Regex("rh") to "R",
+               Regex("rr") to "R",
+               Regex("hr") to "R",
+               Regex("d'h") to "dh",
+               Regex("l'h") to "lh",
+               Regex("l'J") to "lJ",
+               Regex("r'h") to "rh",
+               Regex("r'J") to "rJ",
+               Regex("s'h") to "sh",
+               Regex("t'h") to "th",
+               Regex("h'l") to "hl",
+               Regex("h'r") to "hr",
+               Regex("B'h") to "Bh",
+               Regex("G'h") to "Gh",
+               Regex("K'h") to "Kh",
+               Regex("P'h") to "Ph",
+               Regex("c(?!h)") to "",
+               
+               Regex("ae") to "W",
+               Regex("au") to "X",
+               Regex("ea") to "Y",
+               Regex("ei") to "Z",
+               Regex("eo") to "w",
+               Regex("eu") to "x",
+               Regex("oa") to "y",
+               Regex("ou") to "z",
+               Regex("oe") to "O",
+               Regex("ui") to "U",
+               
+               Regex("i([aeiouOUw-zW-Z])") to "ij$1",
+               Regex("^([aeiouOUw-zW-Z])") to "'$1",
+               Regex("([^'BCDFGJKLPR-TVbdf-hj-npr-tv])([aeiouOUw-zW-Z])") to "$1'$2",
+               Regex("([aeiouOUw-zW-Z])([aeiouOUw-zW-Z])") to "$1'$2",
+       )
+       
+       fun tylanToFontAlphabet(tylan: String) = replacements.fold(tylan.lowercase().filter { it in allowedTranslitCharacters }) { partial, (regex, replacement) ->
+               partial.replace(regex, replacement)
+       }
+}
+
+object PokhwalishAlphabetFont {
+       private val allowedTranslitCharacters = setOf(
+               ' ', '\r', '\n', '\t',
+               'a', 'b', 'c', 'd', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'y', 'z',
+               '.', ',', '\'', '?', '!',
+       )
+       
+       private val replacements = listOf(
+               // Vowels
+               Regex("aa") to "A",
+               Regex("ae") to "A",
+               Regex("ee") to "E",
+               Regex("ei") to "E",
+               Regex("ey") to "E",
+               Regex("ie") to "I",
+               Regex("ii") to "I",
+               Regex("iy") to "I",
+               Regex("ao") to "O",
+               Regex("au") to "O",
+               Regex("oo") to "O",
+               Regex("ou") to "U",
+               Regex("ue") to "U",
+               Regex("ui") to "U",
+               Regex("uu") to "U",
+               // Consonants
+               Regex("tz") to "C",
+               Regex("hh") to "K",
+               Regex("kh") to "K",
+               Regex("gh") to "G",
+               Regex("ng(?![aeiouAEIOU])") to "N",
+               Regex("ng([aeiouAEIOU])") to "Ng$1",
+               Regex("n'g") to "ng",
+               Regex("qh") to "Q",
+               Regex("th") to "T",
+               
+               Regex("ck") to "q",
+               Regex("c") to "",
+               Regex("k") to "q",
+       )
+       
+       fun pokhwalToFontAlphabet(pokhwal: String) = replacements.fold(pokhwal.lowercase().filter { it in allowedTranslitCharacters }) { partial, (regex, replacement) ->
+               partial.replace(regex, replacement)
+       }
+}
diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/languages.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/languages.kt
deleted file mode 100644 (file)
index 362eccf..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package info.mechyrdia.lore
-
-object TylanAlphabet {
-       private val allowedTranslitCharacters = setOf(
-               ' ', '\r', '\n', '\t',
-               'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'x', 'y',
-               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-               '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+',
-               '[', '{', '}', ']', '\\', '|', '/', '<',
-               '.', ',', ':', ';', '\'', '"', '?', '>',
-       )
-       
-       private val replacements = listOf(
-               Regex("([0-9xy]+)(?![\\s0-9xy])") to "$1 ",
-               Regex("(?<![\\s0-9xy])([0-9xy]+)") to " $1",
-               
-               Regex("([a-pr-v'])m(?![\\w'])") to "$1A",
-               Regex("([a-pr-v'])n(?![\\w'])") to "$1E",
-               Regex("([a-ps-v'])r(?![\\w'])") to "$1H",
-               Regex("([ac-fh-jl-or-v'])s(?![\\w'])") to "$1I",
-               Regex("([a-pr-v'])t(?![\\w'])") to "$1Q",
-               
-               Regex("x") to "M",
-               Regex("y") to "N",
-               Regex("[qw-z]") to "",
-               
-               Regex("ch") to "C",
-               Regex("dh") to "D",
-               Regex("sh") to "S",
-               Regex("th") to "T",
-               
-               Regex("bs") to "B",
-               Regex("gs") to "G",
-               Regex("ks") to "K",
-               Regex("ps") to "P",
-               
-               Regex("b'([Is])") to "b$1",
-               Regex("g'([Is])") to "g$1",
-               Regex("k'([Is])") to "k$1",
-               Regex("p'([Is])") to "p$1",
-               
-               Regex("ff") to "F",
-               Regex("fv") to "V",
-               Regex("hj") to "J",
-               Regex("lh") to "L",
-               Regex("ll") to "L",
-               Regex("hl") to "L",
-               Regex("rh") to "R",
-               Regex("rr") to "R",
-               Regex("hr") to "R",
-               Regex("d'h") to "dh",
-               Regex("l'h") to "lh",
-               Regex("l'J") to "lJ",
-               Regex("r'h") to "rh",
-               Regex("r'J") to "rJ",
-               Regex("s'h") to "sh",
-               Regex("t'h") to "th",
-               Regex("h'l") to "hl",
-               Regex("h'r") to "hr",
-               Regex("B'h") to "Bh",
-               Regex("G'h") to "Gh",
-               Regex("K'h") to "Kh",
-               Regex("P'h") to "Ph",
-               Regex("c(?!h)") to "",
-               
-               Regex("ae") to "W",
-               Regex("au") to "X",
-               Regex("ea") to "Y",
-               Regex("ei") to "Z",
-               Regex("eo") to "w",
-               Regex("eu") to "x",
-               Regex("oa") to "y",
-               Regex("ou") to "z",
-               Regex("oe") to "O",
-               Regex("ui") to "U",
-               
-               Regex("i([aeiouOUw-zW-Z])") to "ij$1",
-               Regex("^([aeiouOUw-zW-Z])") to "'$1",
-               Regex("([^'BCDFGJKLPR-TVbdf-hj-npr-tv])([aeiouOUw-zW-Z])") to "$1'$2",
-               Regex("([aeiouOUw-zW-Z])([aeiouOUw-zW-Z])") to "$1'$2",
-       )
-       
-       fun tylanToFontAlphabet(tylan: String) = replacements.fold(tylan.lowercase().filter { it in allowedTranslitCharacters }) { partial, (regex, replacement) ->
-               partial.replace(regex, replacement)
-       }
-}
-
-object PokhwalishAlphabet {
-       private val allowedTranslitCharacters = setOf(
-               ' ', '\r', '\n', '\t',
-               'a', 'b', 'c', 'd', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'y', 'z',
-               '.', ',', '\'', '?', '!',
-       )
-       
-       private val replacements = listOf(
-               // Vowels
-               Regex("aa") to "A",
-               Regex("ae") to "A",
-               Regex("ee") to "E",
-               Regex("ei") to "E",
-               Regex("ey") to "E",
-               Regex("ie") to "I",
-               Regex("ii") to "I",
-               Regex("iy") to "I",
-               Regex("ao") to "O",
-               Regex("au") to "O",
-               Regex("oo") to "O",
-               Regex("ou") to "U",
-               Regex("ue") to "U",
-               Regex("ui") to "U",
-               Regex("uu") to "U",
-               // Consonants
-               Regex("tz") to "C",
-               Regex("hh") to "K",
-               Regex("kh") to "K",
-               Regex("gh") to "G",
-               Regex("ng(?![aeiouAEIOU])") to "N",
-               Regex("ng([aeiouAEIOU])") to "Ng$1",
-               Regex("n'g") to "ng",
-               Regex("qh") to "Q",
-               Regex("th") to "T",
-               
-               Regex("ck") to "q",
-               Regex("c") to "",
-               Regex("k") to "q",
-       )
-       
-       fun pokhwalToFontAlphabet(pokhwal: String) = replacements.fold(pokhwal.lowercase().filter { it in allowedTranslitCharacters }) { partial, (regex, replacement) ->
-               partial.replace(regex, replacement)
-       }
-}
index 0ff8cff1abf6a86d0b29a0acdb2c01ec9503ec88..f1dc72ce837aeec4576625dd12f18ce477d58cc4 100644 (file)
@@ -322,7 +322,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
                TextParserTagType.Indirect { tagParam, content, _ ->
                        if (tagParam?.equals("tylan", ignoreCase = true) == true) {
                                val uncensored = TextParserState.uncensorText(content)
-                               val tylan = TylanAlphabet.tylanToFontAlphabet(uncensored)
+                               val tylan = TylanAlphabetFont.tylanToFontAlphabet(uncensored)
                                val recensored = TextParserState.censorText(tylan)
                                "<span class=\"lang-tylan\">$recensored</span>"
                        } else if (tagParam?.equals("thedish", ignoreCase = true) == true)
@@ -331,7 +331,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
                                "<span class=\"lang-kishari\">$content</span>"
                        else if (tagParam?.equals("pokhval", ignoreCase = true) == true || tagParam?.equals("pokhwal", ignoreCase = true) == true) {
                                val uncensored = TextParserState.uncensorText(content)
-                               val pokhwal = PokhwalishAlphabet.pokhwalToFontAlphabet(uncensored)
+                               val pokhwal = PokhwalishAlphabetFont.pokhwalToFontAlphabet(uncensored)
                                val recensored = TextParserState.censorText(pokhwal)
                                "<span class=\"lang-pokhwal\">$recensored</span>"
                        } else content
@@ -339,7 +339,22 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
        ),
        ALPHABET(
                TextParserTagType.Indirect { _, content, _ ->
-                       if (content.equals("tylan", ignoreCase = true)) {
+                       if (content.equals("mechyrdian", ignoreCase = true)) {
+                               """
+                                       |<div class="mechyrdia-sans-box">
+                                       |<p>Input Text:</p>
+                                       |<textarea class="input-box" spellcheck="false"></textarea>
+                                       |<p>Font options:</p>
+                                       |<ul>
+                                       |<li><label><input type="checkbox" class="bold-option"/>&nbsp;Bold</label></li>
+                                       |<li><label><input type="checkbox" class="ital-option"/>&nbsp;Italic</label></li>
+                                       |<li><label>Align:&nbsp;<select class="align-opts"><option value="left" selected>Left</option><option value="center">Center</option><option value="right">Right</option></select></label></li>
+                                       |</ul>
+                                       |<p>Rendered in Mechyrdia Sans:</p>
+                                       |<img class="output-img" style="display:block;max-width:100%"/>
+                                       |</div>
+                               """.trimMargin()
+                       } else if (content.equals("tylan", ignoreCase = true)) {
                                """
                                        |<div class="tylan-alphabet-box">
                                        |<p>Latin Alphabet:</p>
diff --git a/src/jvmMain/resources/fonts/mechyrdia-sans-bold-italic.ttf b/src/jvmMain/resources/fonts/mechyrdia-sans-bold-italic.ttf
new file mode 100644 (file)
index 0000000..f1be773
Binary files /dev/null and b/src/jvmMain/resources/fonts/mechyrdia-sans-bold-italic.ttf differ
diff --git a/src/jvmMain/resources/fonts/mechyrdia-sans-bold.ttf b/src/jvmMain/resources/fonts/mechyrdia-sans-bold.ttf
new file mode 100644 (file)
index 0000000..5155f69
Binary files /dev/null and b/src/jvmMain/resources/fonts/mechyrdia-sans-bold.ttf differ
diff --git a/src/jvmMain/resources/fonts/mechyrdia-sans-italic.ttf b/src/jvmMain/resources/fonts/mechyrdia-sans-italic.ttf
new file mode 100644 (file)
index 0000000..89fd2d8
Binary files /dev/null and b/src/jvmMain/resources/fonts/mechyrdia-sans-italic.ttf differ
diff --git a/src/jvmMain/resources/fonts/mechyrdia-sans.ttf b/src/jvmMain/resources/fonts/mechyrdia-sans.ttf
new file mode 100644 (file)
index 0000000..9bdb85c
Binary files /dev/null and b/src/jvmMain/resources/fonts/mechyrdia-sans.ttf differ
index 2efe1d9f8132fc78c0791000263ff687b3c2f738..b444c939ccdcda4f27eed079d5d99699d2d5b27c 100644 (file)
                });
        }
 
+       window.addEventListener("load", function () {
+               // Mechyrdian font
+               async function mechyrdianToFont(input, boldOpt, italicOpt, alignOpt, output) {
+                       const inText = input.value;
+
+                       await delay(1500);
+                       if (inText !== input.value) return;
+
+                       let queryString = "?";
+                       queryString += boldOpt.checked ? "bold=true&" : "";
+                       queryString += italicOpt.checked ? "italic=true&" : "";
+                       queryString += "align=" + alignOpt.value;
+
+                       const outBlob = await (await fetch('/mechyrdia-sans' + queryString, {
+                               method: 'POST',
+                               headers: {
+                                       'Content-Type': 'text/plain',
+                               },
+                               body: inText,
+                       })).blob();
+
+                       if (inText !== input.value) return;
+
+                       const prevObjectUrl = output.src;
+                       if (prevObjectUrl != null && prevObjectUrl.length > 0)
+                               URL.revokeObjectURL(prevObjectUrl);
+
+                       output.src = URL.createObjectURL(outBlob);
+               }
+
+               const mechyrdiaSansBoxes = document.getElementsByClassName("mechyrdia-sans-box");
+               for (const mechyrdiaSansBox of mechyrdiaSansBoxes) {
+                       const inputBox = mechyrdiaSansBox.getElementsByClassName("input-box")[0];
+                       const boldOpt = mechyrdiaSansBox.getElementsByClassName("bold-option")[0];
+                       const italicOpt = mechyrdiaSansBox.getElementsByClassName("ital-option")[0];
+                       const alignOpt = mechyrdiaSansBox.getElementsByClassName("align-opts")[0];
+                       const outputBox = mechyrdiaSansBox.getElementsByClassName("output-img")[0];
+
+                       const inputListener = () => mechyrdianToFont(inputBox, boldOpt, italicOpt, alignOpt, outputBox);
+                       boldOpt.addEventListener("change", inputListener);
+                       italicOpt.addEventListener("change", inputListener);
+                       alignOpt.addEventListener("change", inputListener);
+                       inputBox.addEventListener("input", inputListener);
+               }
+       });
+
        window.addEventListener("load", function () {
                // Tylan alphabet
                async function tylanToFont(input, output) {