From a0d606d5bc481ec9b3789dd737404beebca0df24 Mon Sep 17 00:00:00 2001 From: Lanius Trolling Date: Thu, 7 Mar 2024 08:20:38 -0500 Subject: [PATCH] Prevent client from rendering text on server if text is blank. Trim text in server before rendering. Switch from double to int. --- .../kotlin/info/mechyrdia/Factbooks.kt | 2 +- .../kotlin/info/mechyrdia/lore/fonts.kt | 38 +++++++++++++----- src/jvmMain/resources/static/init.js | 39 ++++++++++++------- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/jvmMain/kotlin/info/mechyrdia/Factbooks.kt b/src/jvmMain/kotlin/info/mechyrdia/Factbooks.kt index 92aeff3..9a8d379 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/Factbooks.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/Factbooks.kt @@ -275,7 +275,7 @@ fun Application.factbooks() { val text = call.receiveText() val svg = runInterruptible(Dispatchers.Default) { - MechyrdiaSansFont.renderTextToSvg(text, isBold, isItalic, align) + MechyrdiaSansFont.renderTextToSvg(text.trim(), isBold, isItalic, align) } call.respondText(svg, ContentType.Image.SVG) diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt index 5924dcd..f61f91c 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/fonts.kt @@ -22,13 +22,29 @@ import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty object MechyrdiaSansFont { - enum class Alignment(val amount: Double) { - LEFT(0.0), CENTER(0.5), RIGHT(1.0), + enum class Alignment { + LEFT { + override fun processWidth(widthDiff: Int): Int { + return 0 + } + }, + CENTER { + override fun processWidth(widthDiff: Int): Int { + return widthDiff / 2 + } + }, + RIGHT { + override fun processWidth(widthDiff: Int): Int { + return widthDiff + } + }; + + abstract fun processWidth(widthDiff: Int): Int } fun renderTextToSvg(text: String, bold: Boolean, italic: Boolean, align: Alignment): String { val (file, font) = getFont(bold, italic) - return layoutText(text, file, font, align.amount).toSvgDocument(96.0 / file.unitsPerEm) + return layoutText(text, file, font, align).toSvgDocument(80.0 / file.unitsPerEm, 12.0) } private val fontsRoot = File(Configuration.CurrentConfiguration.rootDir, "fonts") @@ -151,7 +167,7 @@ object MechyrdiaSansFont { return widths.zip(glyphPositions) { width, pos -> width + pos[2] }.sum() } - private fun layoutText(text: String, file: TTFFile, font: Font, alignAmount: Double): Shape { + private fun layoutText(text: String, file: TTFFile, font: Font, align: Alignment): Shape { val img = BufferedImage(256, 160, BufferedImage.TYPE_INT_ARGB) val g2d = img.createGraphics() try { @@ -164,7 +180,7 @@ object MechyrdiaSansFont { val lineAdjust = lineGlyphs.zip(lineBasics) { glyphs, widths -> file.getGlyphPositions(glyphs, widths) } val lineWidths = lineBasics.zip(lineAdjust) { width, adjust -> getWidth(width, adjust) } val blockWidth = lineWidths.max() - var ly = 0.0 + var ly = 0 yieldThread() @@ -173,7 +189,7 @@ object MechyrdiaSansFont { for ((li, line) in lines.withIndex()) { if (line.isNotBlank()) { val lineWidth = lineWidths[li] - val lx = (blockWidth - lineWidth) * alignAmount + val lx = align.processWidth(blockWidth - lineWidth) var cx = 0 var cy = 0 @@ -187,8 +203,7 @@ object MechyrdiaSansFont { val glyphShape = glyph.outline as GeneralPath val glyphShift = adjusted[ci] - tf.setToIdentity() - tf.translate(lx + cx + glyphShift[0], ly + cy + glyphShift[1]) + tf.setToTranslation((lx + cx + glyphShift[0]).toDouble(), (ly + cy + glyphShift[1]).toDouble()) shape.append(glyphShape.getPathIterator(tf), false) cx += glyphShift[2] + basicAdv[ci] @@ -210,12 +225,15 @@ object MechyrdiaSansFont { } } - private fun Shape.toSvgDocument(scale: Double): String { + private fun Shape.toSvgDocument(scale: Double, padding: Double = 0.0): String { return buildString { appendLine("") val viewBox = bounds2D - appendLine("") + val vBoxPad = padding / scale + val sizePad = padding * 2 + + appendLine("") appendLine(toSvgPath()) appendLine("") } diff --git a/src/jvmMain/resources/static/init.js b/src/jvmMain/resources/static/init.js index c1913ef..388ab35 100644 --- a/src/jvmMain/resources/static/init.js +++ b/src/jvmMain/resources/static/init.js @@ -25,20 +25,29 @@ await delay(delayLength); 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; + let outBlob; + if (inText.trim().length === 0) { + outBlob = new Blob([ + "\n", + "\n", + "\n" + ], {type: "image/svg+xml"}); + } else { + let queryString = "?"; + queryString += boldOpt.checked ? "bold=true&" : ""; + queryString += italicOpt.checked ? "italic=true&" : ""; + queryString += "align=" + alignOpt.value; + + 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) @@ -100,7 +109,9 @@ outputBox.value = inputBox.value; }); } + }); + window.addEventListener("load", function () { // Kishari alphabet const kishariAlphabetBoxes = document.getElementsByClassName("kishari-alphabet-box"); for (const kishariAlphabetBox of kishariAlphabetBoxes) { -- 2.25.1