I came up with some changes:
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.olive.oliveProgram
import org.openrndr.math.Vector2
import org.openrndr.math.map
class CenteredText(private val drawer: Drawer, fontPath: String, fontSize: Double) {
private val font = loadFont(fontPath, fontSize)
private val writer = Writer(drawer)
fun draw(text: String, pos: Vector2) {
drawer.fontMap = font
drawer.text(text, pos + Vector2(-writer.textWidth(text) / 2, font.height / 2))
}
}
fun main() = application {
configure {
width = 1024
height = 1024
}
oliveProgram {
var img = loadImage("/tmp/a.png")
val pixels = img.shadow
pixels.download()
val chars = listOf(
"%/*+-. ",
"╕╒╛╘╪╞╡╧╤",
"Ñs@#W$9876543210?!abc;:+=-,._",
"+"
)
val charSet = chars[2] // for debugging purposes
val centeredText = CenteredText(drawer, "data/fonts/default.otf", 64.0)
val tilesX = 16
val tilesY = 16
val tileW = img.width.toDouble() / tilesX
val tileH = img.height.toDouble() / tilesY
val pgr = renderTarget(img.width, img.height) {
colorBuffer()
}
extend {
drawer.isolatedWithTarget(pgr) {
clear(ColorRGBa.BLACK)
fill = ColorRGBa.WHITE
translate(tileW / 2, tileH / 2)
for (x in 0 until tilesX) {
for (y in 0 until tilesY) {
val px = (x * tileW).toInt()
val py = (y * tileH).toInt()
val color = pixels[px, py]
val brightness = color.luminance
val selector = brightness.map(0.0, 1.0, 0.0, charSet.length.toDouble()).toInt()
.coerceAtMost(charSet.length - 1)
centeredText.draw(charSet[selector].toString(), Vector2(x * tileW, y * tileH))
}
}
}
drawer.image(pgr.colorBuffer(0), 0.0, 0.0, width.toDouble(), height.toDouble())
}
}
}
One thing I changed is not to create a new Writer
instance for every character, by creating a class and keeping one instance of it. I made it specific for centering, but you could tweak it to accept an align
vector as you did, which is a cool idea. I saw this old post about aligning text, maybe there’s others.
One thing: it does centering of characters assuming the height values, which are equal for all characters, since this is a bitmap font and I don’t think it stores a bounding box of the actual drawing (so it’s the same size for .
than for 8
).
Maybe this is not a goal, but if you would like to center the drawing so that a .
could be drawn in the center of a O
, I think one would need an intermediate step of using the contours of the characters. Then you could get the bounding box, center it and either draw it directly (this would be heavier, because it’s harder to draw contours than bitmaps), or if real time performance is very important (to do this effect with video, for example) then you could create your own “font map”: a texture with all the characters drawn in the exact centers of tiles you can use.
Does this help you get closer?
Good point about imageMode
and textAlign
. An alternative to imageMode
is imageFit
, which is quite flexible in drawing images to fit or cover certain areas. For aligning I also wrote this: Aligning text in drawer.writer - #2 by abe I don’t remember if there’s some built-in feature to achieve this, but it would be nice to add.