Last active
April 9, 2016 06:35
-
-
Save mindboard/54e85789eb9f9001202a082c249ac6d4 to your computer and use it in GitHub Desktop.
Creating png image from SVG command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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