Fix SVG rendering for scheme

This commit is contained in:
Alexander Nozik 2022-10-09 17:11:03 +03:00
parent 77e27c7eb6
commit 737bbbde6a
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
4 changed files with 165 additions and 101 deletions

View File

@ -10,7 +10,7 @@ val ktorVersion by extra("2.0.3")
allprojects {
group = "center.sciprog"
version = "0.1.0-dev-11"
version = "0.1.0-dev-12"
}
ksciencePublish{

View File

@ -172,7 +172,12 @@ public fun SchemeView(
center = feature.center.toOffset()
)
is SchemeLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset())
is SchemeLineFeature -> drawLine(
feature.color,
feature.a.toOffset(),
feature.b.toOffset(),
)
is SchemeArcFeature -> {
val topLeft = feature.oval.leftTop.toOffset()
val bottomRight = feature.oval.rightBottom.toOffset()

View File

@ -9,10 +9,14 @@ import androidx.compose.ui.graphics.drawscope.DrawContext
import androidx.compose.ui.graphics.drawscope.DrawTransform
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import org.jfree.svg.SVGGraphics2D
import java.awt.BasicStroke
import java.awt.Graphics2D
import java.awt.geom.Arc2D
internal fun Paint.toAwt(): java.awt.Paint {
return java.awt.Color(color.toArgb())
internal fun Graphics2D.setupPaint(p: Paint){
paint = java.awt.Color(p.color.toArgb())
stroke = BasicStroke(p.strokeWidth)
}
@ -73,7 +77,7 @@ internal fun DrawContext.asDrawTransform(): DrawTransform = object : DrawTransfo
}
}
internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
internal class SvgCanvas(val graphics: SVGGraphics2D) : Canvas {
override fun clipPath(path: Path, clipOp: ClipOp) {
TODO("Not yet implemented")
}
@ -112,19 +116,15 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
useCenter: Boolean,
paint: Paint,
) {
graphics.paint = paint.toAwt()
graphics.drawArc(
top.toInt(),
left.toInt(),
(right - left).toInt(),
(top - bottom).toInt(),
startAngle.toInt(),
sweepAngle.toInt()
graphics.setupPaint(paint)
val arc = Arc2D.Float(
left, top, (right - left), (top - bottom), -startAngle, -sweepAngle, Arc2D.OPEN
)
graphics.draw(arc)
}
override fun drawCircle(center: Offset, radius: Float, paint: Paint) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
graphics.drawOval(
(center.x - radius).toInt(),
(center.y - radius).toInt(),
@ -134,7 +134,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
}
override fun drawImage(image: ImageBitmap, topLeftOffset: Offset, paint: Paint) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
graphics.drawImage(image.toAwtImage(), null, topLeftOffset.x.toInt(), topLeftOffset.y.toInt())
}
@ -150,12 +150,12 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
}
override fun drawLine(p1: Offset, p2: Offset, paint: Paint) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
graphics.drawLine(p1.x.toInt(), p1.y.toInt(), p2.x.toInt(), p2.y.toInt())
}
override fun drawOval(left: Float, top: Float, right: Float, bottom: Float, paint: Paint) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
graphics.drawOval(
left.toInt(),
top.toInt(),
@ -165,13 +165,14 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
}
override fun drawPath(path: Path, paint: Paint) {
graphics.setupPaint(paint)
val skiaPath = path.asSkiaPath()
val points: List<Offset> = skiaPath.points.mapNotNull { it?.let { Offset(it.x, it.y) } }
drawPoints(PointMode.Lines, points, paint)
}
override fun drawPoints(pointMode: PointMode, points: List<Offset>, paint: Paint) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
val xs = IntArray(points.size) { points[it].x.toInt() }
val ys = IntArray(points.size) { points[it].y.toInt() }
when (pointMode) {
@ -218,7 +219,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
}
override fun drawRect(left: Float, top: Float, right: Float, bottom: Float, paint: Paint) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
graphics.drawRect(
left.toInt(),
top.toInt(),
@ -236,7 +237,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
radiusY: Float,
paint: Paint,
) {
graphics.paint = paint.toAwt()
graphics.setupPaint(paint)
graphics.drawRoundRect(
left.toInt(),
top.toInt(),
@ -285,7 +286,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
}
}
internal class SvgDrawContext(val graphics: Graphics2D, override var size: Size) : DrawContext {
internal class SvgDrawContext(val graphics: SVGGraphics2D, override var size: Size) : DrawContext {
override val canvas: Canvas = SvgCanvas(graphics)
override val transform: DrawTransform = asDrawTransform()

View File

@ -8,17 +8,19 @@ import androidx.compose.ui.graphics.drawscope.*
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import org.jfree.svg.SVGGraphics2D
import java.awt.BasicStroke
import java.awt.Font
import java.awt.Graphics2D
import java.awt.geom.AffineTransform
import java.awt.geom.Arc2D
import java.awt.image.AffineTransformOp
import java.awt.Color as AWTColor
private fun Color.toAWT(): java.awt.Color = AWTColor(toArgb())
private fun Brush.toAWT(): java.awt.Paint = TODO()
public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawScope {
public class SvgDrawScope(
private val graphics: SVGGraphics2D,
size: Size,
val defaultStrokeWidth: Float = 1f,
) : DrawScope {
override val layoutDirection: LayoutDirection
get() = LayoutDirection.Ltr
@ -27,6 +29,42 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
override val fontScale: Float get() = 1f
private fun setupStroke(strokeWidth: Float, cap: StrokeCap, join: StrokeJoin = StrokeJoin.Miter) {
val width = if (strokeWidth == 0f) defaultStrokeWidth else strokeWidth
val capValue = when (cap) {
StrokeCap.Butt -> BasicStroke.CAP_BUTT
StrokeCap.Round -> BasicStroke.CAP_ROUND
StrokeCap.Square -> BasicStroke.CAP_SQUARE
else -> BasicStroke.CAP_SQUARE
}
val joinValue = when (join) {
StrokeJoin.Bevel -> BasicStroke.JOIN_BEVEL
StrokeJoin.Miter -> BasicStroke.JOIN_MITER
StrokeJoin.Round -> BasicStroke.JOIN_ROUND
else -> BasicStroke.JOIN_MITER
}
graphics.stroke = BasicStroke(width, capValue, joinValue)
}
private fun setupStroke(stroke: Stroke) {
setupStroke(stroke.width, stroke.cap, stroke.join)
}
private fun setupColor(color: Color) {
graphics.paint = AWTColor(color.toArgb(), false)
}
private fun setupColor(brush: Brush) {
when (brush) {
is SolidColor -> {
graphics.paint = AWTColor(brush.value.toArgb(), false)
}
is ShaderBrush -> TODO()
}
}
override fun drawArc(
brush: Brush,
startAngle: Float,
@ -39,7 +77,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
setupColor(brush)
when (style) {
Fill -> graphics.fillArc(
topLeft.x.toInt(),
@ -50,14 +88,17 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
sweepAngle.toInt()
)
is Stroke -> graphics.drawArc(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
startAngle.toInt(),
sweepAngle.toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawArc(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
startAngle.toInt(),
sweepAngle.toInt()
)
}
}
}
@ -73,25 +114,24 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
setupColor(color)
when (style) {
Fill -> graphics.fillArc(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
startAngle.toInt(),
sweepAngle.toInt()
-startAngle.toInt(),
-sweepAngle.toInt()
)
is Stroke -> graphics.drawArc(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
startAngle.toInt(),
sweepAngle.toInt()
)
is Stroke -> {
setupStroke(style)
val arc = Arc2D.Float(
topLeft.x, topLeft.y, size.width, size.height, -startAngle, -sweepAngle, Arc2D.OPEN
)
graphics.draw(arc)
}
}
}
@ -105,7 +145,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
setupColor(brush)
when (style) {
Fill -> graphics.fillOval(
(center.x - radius).toInt(),
@ -114,12 +154,15 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
(radius * 2).toInt()
)
is Stroke -> graphics.drawOval(
(center.x - radius).toInt(),
(center.y - radius).toInt(),
(radius * 2).toInt(),
(radius * 2).toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawOval(
(center.x - radius).toInt(),
(center.y - radius).toInt(),
(radius * 2).toInt(),
(radius * 2).toInt()
)
}
}
}
@ -133,7 +176,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
setupColor(color)
when (style) {
Fill -> graphics.fillOval(
(center.x - radius).toInt(),
@ -142,12 +185,15 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
(radius * 2).toInt()
)
is Stroke -> graphics.drawOval(
(center.x - radius).toInt(),
(center.y - radius).toInt(),
(radius * 2).toInt(),
(radius * 2).toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawOval(
(center.x - radius).toInt(),
(center.y - radius).toInt(),
(radius * 2).toInt(),
(radius * 2).toInt()
)
}
}
}
@ -214,8 +260,8 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
graphics.stroke = BasicStroke(strokeWidth)
setupColor(brush)
setupStroke(strokeWidth, cap)
graphics.drawLine(start.x.toInt(), start.y.toInt(), end.x.toInt(), end.y.toInt())
}
@ -230,8 +276,8 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
graphics.stroke = BasicStroke(strokeWidth)
setupColor(color)
setupStroke(strokeWidth, cap)
graphics.drawLine(start.x.toInt(), start.y.toInt(), end.x.toInt(), end.y.toInt())
}
@ -244,7 +290,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
setupColor(brush)
when (style) {
Fill -> graphics.fillOval(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
is Stroke -> graphics.drawOval(
@ -265,7 +311,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
setupColor(color)
when (style) {
Fill -> graphics.fillOval(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
is Stroke -> graphics.drawOval(
@ -314,7 +360,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
setupColor(brush)
graphics.stroke = BasicStroke(strokeWidth)
val xs = IntArray(points.size) { points[it].x.toInt() }
val ys = IntArray(points.size) { points[it].y.toInt() }
@ -332,7 +378,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
setupColor(color)
graphics.stroke = BasicStroke(strokeWidth)
val xs = IntArray(points.size) { points[it].x.toInt() }
val ys = IntArray(points.size) { points[it].y.toInt() }
@ -348,15 +394,18 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
setupColor(brush)
when (style) {
Fill -> graphics.fillRect(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
is Stroke -> graphics.drawRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt()
)
}
}
}
@ -370,15 +419,18 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
setupColor(color)
when (style) {
Fill -> graphics.fillRect(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
is Stroke -> graphics.drawRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt()
)
}
}
}
@ -392,7 +444,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = brush.toAWT()
setupColor(brush)
when (style) {
Fill -> graphics.fillRoundRect(
topLeft.x.toInt(),
@ -403,14 +455,17 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
cornerRadius.y.toInt()
)
is Stroke -> graphics.drawRoundRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
cornerRadius.x.toInt(),
cornerRadius.y.toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawRoundRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
cornerRadius.x.toInt(),
cornerRadius.y.toInt()
)
}
}
}
@ -425,7 +480,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
colorFilter: ColorFilter?,
blendMode: BlendMode,
) {
graphics.paint = color.toAWT()
setupColor(color)
when (style) {
Fill -> graphics.fillRoundRect(
topLeft.x.toInt(),
@ -436,14 +491,17 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
cornerRadius.y.toInt()
)
is Stroke -> graphics.drawRoundRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
cornerRadius.x.toInt(),
cornerRadius.y.toInt()
)
is Stroke -> {
setupStroke(style)
graphics.drawRoundRect(
topLeft.x.toInt(),
topLeft.y.toInt(),
size.width.toInt(),
size.height.toInt(),
cornerRadius.x.toInt(),
cornerRadius.y.toInt()
)
}
}
}
@ -454,7 +512,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
font: Font,
color: Color,
) {
graphics.paint = color.toAWT()
setupColor(color)
graphics.font = font
graphics.drawString(text, x, y)
}