Skip to content

Instantly share code, notes, and snippets.

@timyates
Last active Oct 11, 2015
Embed
What would you like to do?
First pass at a Groovy clone of ASCIImage
package com.bloidonia.asciiimage
import java.awt.*
import java.awt.geom.*
import java.awt.image.BufferedImage
import java.util.List
class AsciImage {
static enum Type { POINT, PATH, LINE, ELLIPSE }
static class Element {
Type type
List<Point2D> points
}
final List<String> TOKENS = ['1'..'9', 'A'..'Z', 'a'..'n', 'p'..'z'].flatten() as List<String>
private parse(String lines) {
parse(lines.split(/\n/).findAll { it.trim().length() != 0 })
}
private List<Element> generate(Map<String,List<Point2D>> marks) {
[null, *TOKENS, null].collate(3, 1, false)
.collect { a, b, c -> [ previous:a, current:b, next:c ] }
.inject([]) { elements, pcn ->
if(marks[pcn.current]) {
if (marks[pcn.previous]) {
elements[-1].type = Type.PATH
elements[-1].points.addAll(marks[pcn.current])
}
else {
elements << new Element(points:marks[pcn.current], type: marks[pcn.current].size() == 1 ? Type.POINT : marks[pcn.current].size() == 2 ? Type.LINE : Type.ELLIPSE)
}
}
elements
}
}
private List<Element> parse(List<String> lines) {
if(lines == null) throw new RuntimeException("Lines cannot be null")
if(lines.size() == 0) throw new RuntimeException("Lines cannot be empty")
if(lines*.length().unique().size() != 1) throw new RuntimeException("Lines cannot be of different lengths")
lines = lines.collect { it.replaceAll(/\s+/, '') }
int rows = lines.size()
int columns = lines[0].length()
List<Integer> rowIdx = 0..<rows
def tokenMap = [:].withDefault {[]}
def tokens = [rowIdx,lines].transpose().inject(tokenMap) { marks, idxStrArr ->
idxStrArr[1].toList()
.eachWithIndex { entry, idx ->
if(TOKENS.contains(entry))
marks[entry] << new Point2D.Double(idx / (columns - 1), idxStrArr[0] / (lines.size() - 1))
}
marks
}
generate(tokens)
}
private generateBufferedImage(String lines, int width, int height) {
generateBufferedImage(lines.split(/\n/).findAll { it.trim().length() != 0 }, width, height)
}
private generateBufferedImage(List<String> lines, int width, int height) {
new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB).with { img ->
createGraphics().with {g ->
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
color = Color.WHITE
parse(lines).collect { element ->
if(element.type == Type.LINE) {
new Line2D.Double(element.points[0].x * width, element.points[0].y * height, element.points[1].x * width, element.points[0].y * height)
}
else if(element.type == Type.POINT) {
new Rectangle2D.Double(element.points[0].x * width - 0.5, element.points[0].y * height - 0.5, 0.5, 0.5)
}
else if(element.type == Type.PATH) {
new GeneralPath(GeneralPath.WIND_EVEN_ODD, element.points.size()).with { path ->
path.moveTo(element.points[0].x * width, element.points[0].y * height)
element.points.drop(1).each { Point2D pts ->
path.lineTo(pts.x * width, pts.y * height)
}
path.lineTo(element.points[0].x * width, element.points[0].y * height)
path
}
}
else if(element.type == Type.ELLIPSE) {
new Ellipse2D.Double(element.points.x.min() * width,
element.points.y.min() * height,
(element.points.x.max() - element.points.x.min()) * width,
(element.points.y.max() - element.points.y.min()) * height)
}
else {
throw new RuntimeException("Unknown type $element.type")
}
}.each { s ->
g.draw(s)
g.fill(s)
}
dispose()
}
img
}
}
}
new AsciImage().generateBufferedImage('''
· · · · · · · · · · · ·
· A · · · · · · · · A ·
· · · · · · · · · · · ·
· · · · · · 1 · · · · ·
· · · · · · o o · · · ·
· · · 6 o o 7 o o · · ·
· · · o o o o o o 2 · ·
· · · 5 o o 4 o o · · ·
· · · · · · o o · · · ·
· · · · · · 3 · · · · ·
· · · · · · · F · · F ·
· C · · · · · F · · F ·
· · · · · · · · · · · ·
''', 100, 100)
@timyates
Copy link
Author

timyates commented Mar 30, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment