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")
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 {
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()
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
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]
}
}
- private fun Shape.toSvgDocument(scale: Double): String {
+ private fun Shape.toSvgDocument(scale: Double, padding: Double = 0.0): String {
return buildString {
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 * scale}\" height=\"${viewBox.height * scale}\" viewBox=\"${viewBox.minX} ${viewBox.minY} ${viewBox.width} ${viewBox.height}\">")
+ val vBoxPad = padding / scale
+ val sizePad = padding * 2
+
+ appendLine("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${(viewBox.width * scale) + sizePad}\" height=\"${(viewBox.height * scale) + sizePad}\" viewBox=\"${viewBox.minX - vBoxPad} ${viewBox.minY - vBoxPad} ${viewBox.width + (vBoxPad * 2)} ${viewBox.height + (vBoxPad * 2)}\">")
appendLine(toSvgPath())
appendLine("</svg>")
}
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([
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"0\" height=\"0\">\n",
+ "</svg>\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)
outputBox.value = inputBox.value;
});
}
+ });
+ window.addEventListener("load", function () {
// Kishari alphabet
const kishariAlphabetBoxes = document.getElementsByClassName("kishari-alphabet-box");
for (const kishariAlphabetBox of kishariAlphabetBoxes) {