Skip to content

Instantly share code, notes, and snippets.

@mindboard
Last active April 9, 2016 06:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindboard/54e85789eb9f9001202a082c249ac6d4 to your computer and use it in GitHub Desktop.
Save mindboard/54e85789eb9f9001202a082c249ac6d4 to your computer and use it in GitHub Desktop.
Creating png image from SVG command
import java.io.File
import java.awt.Color
import java.awt.Graphics2D
import java.awt.BasicStroke
import java.awt.image.BufferedImage
import java.awt.geom.AffineTransform
import java.awt.geom.GeneralPath as Path
import javax.imageio.ImageIO
import java.util.ArrayList
class SVGParser {
private val isUpperCase: (s:String)->Boolean = { it==it.toUpperCase() }
private fun createTokenList(svgCmds: String):ArrayList<Token> {
val tokenList = ArrayList<Token>()
val regex = Regex("[MmLlHhVvZz]")
svgCmds.forEach {
if( regex.matches( it.toString() ) ){
val token = Token(it)
tokenList.add(token)
}
else {
val lastToken = tokenList[tokenList.size-1]
lastToken.params += it.toString()
}
}
return tokenList
}
fun parse(svgCmds: String): Path {
val path = Path()
var currentX = 0f
var currentY = 0f
val proc:(token: Token, drawCmd:( x:Float, y:Float)->Unit )->Unit = { token, drawCmd ->
// x,y 値を得る
val x = token.getX(currentX)
val y = token.getY(currentY)
// 描写実行
drawCmd(x, y)
// currentX,Y 値の更新
currentX = x
currentY = y
}
createTokenList( svgCmds ).forEach { token->
val svgCmd = token.type
when(svgCmd) {
'M', 'm' -> proc(token, {x,y->path.moveTo(x, y)} )
'L', 'H', 'V', 'l', 'h', 'v' -> proc(token, {x,y->path.lineTo(x, y)} )
'Z', 'z' -> path.closePath()
}
}
return path
}
class Token(type: Char) {
val type = type
var params = ""
companion object { val BR = System.getProperty("line.separator") }
// 改行を削除
private fun fix(s: String): String = s.split( delimiters = BR ).map({it.trim()}).joinToString( separator = "" )
private fun toFloat( params: String, index: Int ): Float {
val fixedParams = fix(params)
val array = fixedParams.split( regex=Regex("[, ]") )
return if( index<array.size ){ array[index].toFloat() } else { 0f }
}
fun getX(currentX: Float):Float {
var retVal:Float = 0f
val v0 = toFloat(params,0)
when(type) {
'H' -> retVal = v0 // X座標だけがかわるタイプ
'h' -> retVal = v0 + currentX // X座標だけがかわるタイプ
'V','v' -> retVal = currentX // Y座標だけがかわるタイプ( Xはカレントを維持 )
'M','L' -> retVal = v0
'm','l' -> retVal = v0 + currentX
}
return retVal
}
fun getY(currentY: Float):Float {
var retVal:Float = 0f
val v0 = toFloat(params,0)
val v1 = toFloat(params,1)
when(type) {
'H','h' -> retVal = currentY // X座標だけがかわるタイプ ( Yはカレントを維持 )
'V' -> retVal = v0 // Y座標だけがかわるタイプ
'v' -> retVal = v0 + currentY // Y座標だけがかわるタイプ
'M','L' -> retVal = v1
'm','l' -> retVal = v1 + currentY
}
return retVal
}
}
}
//
// SVGの大きさは 24x24 を基準とする.
//
val svgCmds = if( args.size>0 ){ args[0] } else { "M16 6 l2.29 2.29 l-4.88 4.88 l-4 -4 L2 16.59 L3.41 18 l6 -6 l4 4 l6.3 -6.29 L22 12 V6 z" }
val outputPngFile = if( args.size>1 ){ File(args[1]) } else { File("r.png") }
val width = if(args.size>2){ args[2].toInt() } else { 96 }
val height = if(args.size>3){ args[3].toInt() } else { 96 }
val path = SVGParser().parse(svgCmds)
val img = BufferedImage( width, height, BufferedImage.TYPE_4BYTE_ABGR )
val g = img.graphics as Graphics2D
g.color = Color.WHITE
g.fillRect(0,0,width,height )
val scaleX = width.toDouble()/24.toDouble()
val scaleY = height.toDouble()/24.toDouble()
val transform = AffineTransform.getScaleInstance( scaleX, scaleY )
val path2 = path.createTransformedShape( transform )
g.color = Color.BLACK
g.fill(path2)
g.dispose()
ImageIO.write(img,"PNG", outputPngFile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment